From d4a115df06b882ecf84a55d52eb6559febf18d25 Mon Sep 17 00:00:00 2001 From: Pieter Hijma Date: Thu, 10 Apr 2025 17:39:10 +0200 Subject: [PATCH 1/2] [Doc] Improve the App::Application documentation --- src/App/Application.cpp | 61 +-- src/App/Application.h | 1003 +++++++++++++++++++++++++++------------ 2 files changed, 723 insertions(+), 341 deletions(-) diff --git a/src/App/Application.cpp b/src/App/Application.cpp index b5df187731..fe2b62ebf2 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -425,14 +425,6 @@ void Application::setupPythonException(PyObject* module) //************************************************************************** // Interface -/// get called by the document when the name is changing -void Application::renameDocument(const char *OldName, const char *NewName) -{ - (void)OldName; - (void)NewName; - throw Base::RuntimeError("Renaming document internal name is no longer allowed!"); -} - Document* Application::newDocument(const char * proposedName, const char * proposedLabel, DocumentInitFlags CreateFlags) { bool isUsingDefaultName = Base::Tools::isNullOrEmpty(proposedName); @@ -1308,11 +1300,11 @@ Base::Reference Application::GetParameterGroupByPath(const char* return It->second->GetGroup(cName.c_str()); } -void Application::addImportType(const char* Type, const char* ModuleName) +void Application::addImportType(const char* filter, const char* moduleName) { FileTypeItem item; - item.filter = Type; - item.module = ModuleName; + item.filter = filter; + item.module = moduleName; // Extract each filetype from 'Type' literal std::string::size_type pos = item.filter.find("*."); @@ -1325,7 +1317,7 @@ void Application::addImportType(const char* Type, const char* ModuleName) } // Due to branding stuff replace "FreeCAD" with the branded application name - if (strncmp(Type, "FreeCAD", 7) == 0) { + if (strncmp(filter, "FreeCAD", 7) == 0) { std::string AppName = Config()["ExeName"]; AppName += item.filter.substr(7); item.filter = std::move(AppName); @@ -1337,26 +1329,26 @@ void Application::addImportType(const char* Type, const char* ModuleName) } } -void Application::changeImportModule(const char* Type, const char* OldModuleName, const char* NewModuleName) +void Application::changeImportModule(const char* filter, const char* oldModuleName, const char* newModuleName) { for (auto& it : _mImportTypes) { - if (it.filter == Type && it.module == OldModuleName) { - it.module = NewModuleName; + if (it.filter == filter && it.module == oldModuleName) { + it.module = newModuleName; break; } } } -std::vector Application::getImportModules(const char* Type) const +std::vector Application::getImportModules(const char* extension) const { std::vector modules; for (const auto & it : _mImportTypes) { const std::vector& types = it.types; for (const auto & jt : types) { #ifdef __GNUC__ - if (strcasecmp(Type,jt.c_str()) == 0) + if (strcasecmp(extension, jt.c_str()) == 0) #else - if (_stricmp(Type,jt.c_str()) == 0) + if (_stricmp(extension, jt.c_str()) == 0) #endif modules.push_back(it.module); } @@ -1405,16 +1397,16 @@ std::vector Application::getImportTypes() const return types; } -std::map Application::getImportFilters(const char* Type) const +std::map Application::getImportFilters(const char* extension) const { std::map moduleFilter; for (const auto & it : _mImportTypes) { const std::vector& types = it.types; for (const auto & jt : types) { #ifdef __GNUC__ - if (strcasecmp(Type,jt.c_str()) == 0) + if (strcasecmp(extension,jt.c_str()) == 0) #else - if (_stricmp(Type,jt.c_str()) == 0) + if (_stricmp(extension,jt.c_str()) == 0) #endif moduleFilter[it.filter] = it.module; } @@ -1433,11 +1425,11 @@ std::map Application::getImportFilters() const return filter; } -void Application::addExportType(const char* Type, const char* ModuleName) +void Application::addExportType(const char* filter, const char* moduleName) { FileTypeItem item; - item.filter = Type; - item.module = ModuleName; + item.filter = filter; + item.module = moduleName; // Extract each filetype from 'Type' literal std::string::size_type pos = item.filter.find("*."); @@ -1450,7 +1442,7 @@ void Application::addExportType(const char* Type, const char* ModuleName) } // Due to branding stuff replace "FreeCAD" with the branded application name - if (strncmp(Type, "FreeCAD", 7) == 0) { + if (strncmp(filter, "FreeCAD", 7) == 0) { std::string AppName = Config()["ExeName"]; AppName += item.filter.substr(7); item.filter = std::move(AppName); @@ -1462,26 +1454,26 @@ void Application::addExportType(const char* Type, const char* ModuleName) } } -void Application::changeExportModule(const char* Type, const char* OldModuleName, const char* NewModuleName) +void Application::changeExportModule(const char* filter, const char* oldModuleName, const char* newModuleName) { for (auto& it : _mExportTypes) { - if (it.filter == Type && it.module == OldModuleName) { - it.module = NewModuleName; + if (it.filter == filter && it.module == oldModuleName) { + it.module = newModuleName; break; } } } -std::vector Application::getExportModules(const char* Type) const +std::vector Application::getExportModules(const char* extension) const { std::vector modules; for (const auto & it : _mExportTypes) { const std::vector& types = it.types; for (const auto & jt : types) { #ifdef __GNUC__ - if (strcasecmp(Type,jt.c_str()) == 0) + if (strcasecmp(extension,jt.c_str()) == 0) #else - if (_stricmp(Type,jt.c_str()) == 0) + if (_stricmp(extension,jt.c_str()) == 0) #endif modules.push_back(it.module); } @@ -1530,16 +1522,16 @@ std::vector Application::getExportTypes() const return types; } -std::map Application::getExportFilters(const char* Type) const +std::map Application::getExportFilters(const char* extension) const { std::map moduleFilter; for (const auto & it : _mExportTypes) { const std::vector& types = it.types; for (const auto & jt : types) { #ifdef __GNUC__ - if (strcasecmp(Type,jt.c_str()) == 0) + if (strcasecmp(extension,jt.c_str()) == 0) #else - if (_stricmp(Type,jt.c_str()) == 0) + if (_stricmp(extension,jt.c_str()) == 0) #endif moduleFilter[it.filter] = it.module; } @@ -2889,7 +2881,6 @@ std::list Application::processFiles(const std::list& f void Application::processCmdLineFiles() { - // process files passed to command line const std::list files = getCmdLineFiles(); const std::list processed = processFiles(files); diff --git a/src/App/Application.h b/src/App/Application.h index fb593fe69e..35586b66b3 100644 --- a/src/App/Application.h +++ b/src/App/Application.h @@ -62,6 +62,7 @@ class Property; class AutoTransaction; class ExtensionContainer; +/// Options for acquiring links. enum GetLinkOption { /// Get all links (both directly and in directly) linked to the given object GetLinkRecursive = 1, @@ -73,128 +74,211 @@ enum GetLinkOption { GetLinkExternal = 8, }; +/// Options for message handling. enum class MessageOption { - Quiet, /**< Suppress error. */ - Error, /**< Print an error message. */ - Throw, /**< Throw an exception. */ + Quiet, ///< Suppress error. + Error, ///< Print an error message. + Throw, ///< Throw an exception. */ }; +/// Options for document initialization. struct DocumentInitFlags { - bool createView {true}; - bool temporary {false}; + bool createView {true}; ///< Whether to hide the document in the tree view. + bool temporary {false}; ///< Whether the document should be a temporary one. }; -/** The Application - * The root of the whole application - * @see App::Document +/** + * @brief The class that represents the whole application. + * + * This is a singleton class that represents the application without + * considering any GUI functionality. You can access it using + * App::GetApplication(). It contains functionality for transactions, system + * and user parameters, importing modules, paths used by the application, + * opening documents, handling links, and it defines signals used in the + * application. + * + * @see App::Document */ class AppExport Application { public: - //--------------------------------------------------------------------- - // exported functions go here +++++++++++++++++++++++++++++++++++++++++ - //--------------------------------------------------------------------- - - /** @name methods for document handling */ - //@{ - /** Creates a new document - * @param proposedName: a prototype name used to create the permanent Name for the document. - * It is converted to be like an identifier in a programming language, - * with no spaces and not starting with a number. This name gets also forced to be unique - * in this Application. You can obtain the unique name using doc.getDocumentName - * on the returned document. - * @param proposedLabel: a UTF8 name of any kind. It's that name normally shown to - * the user and stored in the App::Document::Label property. - */ - App::Document* newDocument(const char * proposedName=nullptr, const char * proposedLabel=nullptr, - DocumentInitFlags CreateFlags=DocumentInitFlags()); - /// Closes the document \a name and removes it from the application. - bool closeDocument(const char* name); - /// find a unique document name - std::string getUniqueDocumentName(const char *Name, bool tempDoc=false) const; - /// Open an existing document from a file - App::Document* openDocument(const char * FileName=nullptr, DocumentInitFlags initFlags = DocumentInitFlags{}); - /** Open multiple documents + /** + * @name Methods for document handling * - * @param filenames: input file names - * @param paths: optional input file path in case it is different from + * @{ + */ + + /** + * @brief Creates a new document. + * + * It is possible to propose a name that is converted to be like an + * identifier in a programming language, with no spaces and not starting + * with a number. This name gets also forced to be unique in the + * application. You can obtain the unique name using getDocumentName() on + * the returned document. + * + * @param[in] proposedName a prototype name used to create the permanent Name for the document. + * @param[in] proposedLabel: a UTF8 name of any kind that is normally shown to + * the user and stored in the App::Document::Label property. + * @param[in] CreateFlags: flags of type DocumentInitFlags to control the + * document creation. The default creates a non-temporary document that is + * shown in the tree view. + */ + App::Document* newDocument(const char* proposedName = nullptr, + const char* proposedLabel = nullptr, + DocumentInitFlags CreateFlags = DocumentInitFlags()); + /** + * @brief Closes the document and removes it from the application. + * + * @param[in] name The name of the document to close. + * @return Returns true if the document was found and closed, false otherwise. + */ + bool closeDocument(const char* name); + + /** + * @brief Acquire a unique document name from a proposed name. + * + * @param[in] Name The proposed name. + * @param[in] tempDoc Whether the document is temporary. + * + * @return Returns a unique document name based on the proposed name. + */ + std::string getUniqueDocumentName(const char* Name, bool tempDoc = false) const; + + /** + * @brief Open an existing document from a file. + * + * @param[in] FileName The file name to open. + * @param[in] initFlags: document initialization flags of type DocumentInitFlags. By default a + * non-temporary, non-hidden document. + * + * @return Returns the opened document, or `nullptr` if failed. + */ + App::Document* openDocument(const char* FileName = nullptr, + DocumentInitFlags initFlags = DocumentInitFlags {}); + + /** + * @brief Open multiple documents + * + * This function will also open any externally referenced files. + * + * @param[in] filenames The file names to open. + * @param[in] paths Optional input file path in case it is different from * filenames (mainly used during recovery). - * @param labels: optional label assign to document (mainly used during recovery). - * @param errs: optional output error message corresponding to each input + * @param[in] labels: optional label assign to document (mainly used during recovery). + * @param[out] errs: optional output error message corresponding to each input * file name. If errs is given, this function will catch all * Base::Exception and save the error message inside. Otherwise, it will - * throw on exception when opening the input files. - * @param createView: whether to signal Gui module to create view on restore. + * throw an exception when opening the input files. + * @param[in] initFlags: document initialization flags of type DocumentInitFlags. By default a + * non-temporary, non-hidden document. * - * @return Return opened document object corresponding to each input file - * name, which maybe NULL if failed. - * - * This function will also open any external referenced files. + * @return Return the opened document corresponding to each input file + * name, which maybe `nullptr` if failed. */ - std::vector openDocuments(const std::vector &filenames, - const std::vector *paths=nullptr, - const std::vector *labels=nullptr, - std::vector *errs=nullptr, - DocumentInitFlags initFlags = DocumentInitFlags{}); - /// Retrieve the active document + std::vector openDocuments(const std::vector& filenames, + const std::vector* paths = nullptr, + const std::vector* labels = nullptr, + std::vector* errs = nullptr, + DocumentInitFlags initFlags = DocumentInitFlags {}); + + /// Get the active document. App::Document* getActiveDocument() const; - /// Retrieve a named document + + /** + * @brief Retrieve a document based on its name. + * + * @param Name: the name of the document. + * @return Return the document with the given name, or `nullptr` if not found. + */ App::Document* getDocument(const char *Name) const; - /// Path matching mode for getDocumentByPath() - enum class PathMatchMode { - /// Match by resolving to absolute file path + /// %Path matching modes for getDocumentByPath() + enum class PathMatchMode + { + /// Match by resolving to absolute file path. MatchAbsolute = 0, - /** Match by absolute path first. If not found then match by resolving - * to canonical file path where any intermediate '.' '..' and symlinks - * are resolved. + + /** + * @brief Match by absolute path first. + * + * If not found then match by resolving to canonical file path where + * any intermediate '.' '..' and symlinks are resolved. */ MatchCanonical = 1, - /** Same as MatchCanonical, but if a document is found by canonical - * path match, which means the document can be resolved using two - * different absolute path, a warning is printed and the found document - * is not returned. This is to allow the caller to intentionally load - * the same physical file as separate documents. + + /** + * @brief Same as MatchCanonical but also warn. + * + * If a document is found by canonical path match, which means the + * document can be resolved using two different absolute path, a + * warning is printed and the found document is not returned. This is + * to allow the caller to intentionally load the same physical file as + * separate documents. */ MatchCanonicalWarning = 2, }; - /** Retrieve a document based on file path + + /** + * @brief Retrieve a document based on file path. * - * @param path: file path - * @param checkCanonical: file path matching mode, @sa PathMatchMode. - * @return Return the document found by matching with the given path + * @param[in] path: The file path. + * @param[in] checkCanonical: file path matching mode, @sa PathMatchMode. + * + * @return The document found by matching with the given path or `nullptr` + * if not successful. */ App::Document* getDocumentByPath(const char *path, PathMatchMode checkCanonical = PathMatchMode::MatchAbsolute) const; - /// gets the (internal) name of the document - const char * getDocumentName(const App::Document* ) const; - /// get a list of all documents in the application - std::vector getDocuments() const; - /// Set the active document - void setActiveDocument(App::Document* pDoc); - void setActiveDocument(const char* Name); - /// close all documents (without saving) - void closeAllDocuments(); - /// Add pending document to open together with the current opening document - int addPendingDocument(const char *FileName, const char *objName, bool allowPartial); - /// Indicate whether the application is opening (restoring) some document - bool isRestoring() const; - /// Indicate the application is closing all document - bool isClosingAll() const; - //@} + /// Gets the (internal) name of a given document. + const char* getDocumentName(const App::Document*) const; - /** @name Application-wide trandaction setting */ - //@{ - /** Setup a pending application-wide active transaction + /// Get a list of all documents in the application. + std::vector getDocuments() const; + + /// Set the active document. + void setActiveDocument(App::Document* pDoc); + + /// Set the active document. + void setActiveDocument(const char* Name); + + /// Close all documents (without saving) + void closeAllDocuments(); + + /** + * @brief Add a pending document to open together with the current opening + * document. * - * @param name: new transaction name - * @param persist: by default, if the calling code is inside any invocation - * of a command, it will be auto closed once all command within the current - * stack exists. To disable auto closing, set persist=true + * This function registers the filename and the object that is attempted to + * be loaded as a pending document. This allows it to be opened together + * with the current document. * - * @return The new transaction ID. + * @param[in] FileName: the file name of the pending document. + * @param[in] objName: the object that is attempted to be loaded. + * @param[in] allowPartial: whether to allow partial loading if some objects are missing. + * + * @return -1 if unsuccesful, 0 if the application is not restoring, and 1 + * if successfully added. + */ + int addPendingDocument(const char* FileName, const char* objName, bool allowPartial); + + /// Check whether the application is opening (restoring) some document. + bool isRestoring() const; + + /// Check whether the application is closing all documents. + bool isClosingAll() const; + /// @} + + /** + * @name Application-wide transaction handling. + * + * @{ + */ + + /** + * @brief Setup a pending application-wide active transaction. * * Call this function to setup an application-wide transaction. All current * pending transactions of opening documents will be committed first. @@ -202,264 +286,542 @@ public: * changes in any current opening document will auto create a transaction * with the given name and ID. If more than one document is changed, the * transactions will share the same ID, and will be undo/redo together. + * + * @param[in] name The new transaction name + * @param[in] persist By default, if the calling code is inside any invocation + * of a command, it will be auto closed once all command within the current + * stack exists. To disable auto closing, set to `true`. + * + * @return The new transaction ID. */ - int setActiveTransaction(const char *name, bool persist=false); - /// Return the current active transaction name and ID - const char *getActiveTransaction(int *tid=nullptr) const; - /** Commit/abort current active transactions + int setActiveTransaction(const char* name, bool persist = false); + + /** + * @brief Get the current active transaction name and ID. * - * @param abort: whether to abort or commit the transactions + * If there is no active transaction, an empty string is returned. * - * Bsides calling this function directly, it will be called by automatically - * if 1) any new transaction is created with a different ID, or 2) any - * transaction with the current active transaction ID is either committed or - * aborted + * @param[out] tid If not `nullptr`, the current active transaction ID is + * returned through this pointer. + * @return The current active transaction name. + */ + const char* getActiveTransaction(int* tid = nullptr) const; + + /** + * @brief Commit/abort current active transactions. + * + * @param[in] abort: whether to abort or commit the transactions + * @param[in] id: by default 0 meaning that the current active transaction ID is used. + * + * Besides calling this function directly, it will be called by + * automatically if 1) any new transaction is created with a different ID, + * or 2) any transaction with the current active transaction ID is either + * committed or aborted. */ void closeActiveTransaction(bool abort=false, int id=0); - //@} + /// @} // NOLINTBEGIN // clang-format off - /** @name Signals of the Application */ - //@{ - /// signal on new Document - fastsignals::signal signalNewDocument; - /// signal on document getting deleted - fastsignals::signal signalDeleteDocument; - /// signal on already deleted Document - fastsignals::signal signalDeletedDocument; - /// signal on relabeling Document (user name) - fastsignals::signal signalRelabelDocument; - /// signal on renaming Document (internal name) - fastsignals::signal signalRenameDocument; - /// signal on activating Document - fastsignals::signal signalActiveDocument; - /// signal on saving Document - fastsignals::signal signalSaveDocument; - /// signal on starting to restore Document - fastsignals::signal signalStartRestoreDocument; - /// signal on restoring Document - fastsignals::signal signalFinishRestoreDocument; - /// signal on pending reloading of a partial Document - fastsignals::signal signalPendingReloadDocument; - /// signal on starting to save Document - fastsignals::signal signalStartSaveDocument; - /// signal on saved Document - fastsignals::signal signalFinishSaveDocument; - /// signal on undo in document - fastsignals::signal signalUndoDocument; - /// signal on application wide undo - fastsignals::signal signalUndo; - /// signal on redo in document - fastsignals::signal signalRedoDocument; - /// signal on application wide redo - fastsignals::signal signalRedo; - /// signal before open active transaction - fastsignals::signal signalBeforeOpenTransaction; - /// signal before close/abort active transaction - fastsignals::signal signalBeforeCloseTransaction; - /// signal after close/abort active transaction - fastsignals::signal signalCloseTransaction; - /// signal on show hidden items - fastsignals::signal signalShowHidden; - /// signal on start opening document(s) - fastsignals::signal signalStartOpenDocument; - /// signal on finished opening document(s) - fastsignals::signal signalFinishOpenDocument; - //@} - - - /** @name Signals of the document - * This signals are an aggregation of all document. If you only - * the signal of a special document connect to the document itself + /** + * @name Signals of the Application + * + * @{ */ - //@{ - /// signal before change of doc property + + /// Signal on a newly created document. + fastsignals::signal signalNewDocument; + /// Signal on a document getting deleted. + fastsignals::signal signalDeleteDocument; + /// Signal that a document has been deleted. + fastsignals::signal signalDeletedDocument; + /// Signal on relabeling the document (the user provided name). + fastsignals::signal signalRelabelDocument; + /// Signal on renaming the document (internal name). + fastsignals::signal signalRenameDocument; + /// Signal on activating the document. + fastsignals::signal signalActiveDocument; + /// Signal on saving the document. + fastsignals::signal signalSaveDocument; + /// Signal on starting to restore the document. + fastsignals::signal signalStartRestoreDocument; + /// Signal after the document has restored. + fastsignals::signal signalFinishRestoreDocument; + /// Signal on pending reloading of a partial document. + fastsignals::signal signalPendingReloadDocument; + /// Signal on starting to save a document. + fastsignals::signal signalStartSaveDocument; + /// Signal after a document has been saved. + fastsignals::signal signalFinishSaveDocument; + /// Signal on an undo in a document. + fastsignals::signal signalUndoDocument; + /// Signal on an application wide undo. + fastsignals::signal signalUndo; + /// Signal on a redo in a document. + fastsignals::signal signalRedoDocument; + /// Signal on an application wide redo. + fastsignals::signal signalRedo; + /// Signal before opening an active transaction. + fastsignals::signal signalBeforeOpenTransaction; + /// Signal before closing/aborting an active transaction. + fastsignals::signal signalBeforeCloseTransaction; + /// Signal after closing/aborting an active transaction. + fastsignals::signal signalCloseTransaction; + /// Signal on show hidden items. + fastsignals::signal signalShowHidden; + /// Signal on starting to open document(s). + fastsignals::signal signalStartOpenDocument; + /// Signal after opening document(s) has finished. + fastsignals::signal signalFinishOpenDocument; + /// @} + + + /** + * @name Signals of the document + * @brief Signals for all documents. + * + * These signals are an aggregation of all documents. If you only require + * the signal of a special document, connect to the document itself. + * + * @{ + */ + + /// Signal before changing a document property. fastsignals::signal signalBeforeChangeDocument; - /// signal on changed doc property + /// Signal on a changed document property. fastsignals::signal signalChangedDocument; - /// signal on new Object + /// Signal on newly created object. fastsignals::signal signalNewObject; //fastsignals::signal m_sig; - /// signal on deleted Object + /// Signal on a deleted object. fastsignals::signal signalDeletedObject; - /// signal on changed Object + /// Signal before a changed property in an object. fastsignals::signal signalBeforeChangeObject; - /// signal on changed Object + /// Signal on a changed property in an object. fastsignals::signal signalChangedObject; - /// signal on relabeled Object + /// Signal on a relabeled object. fastsignals::signal signalRelabelObject; - /// signal on activated Object + /// Signal on an activated object. fastsignals::signal signalActivatedObject; - /// signal before recomputed document + /// Signal before recomputing a document. fastsignals::signal signalBeforeRecomputeDocument; - /// signal on recomputed document + /// Signal on a recomputed document. fastsignals::signal signalRecomputed; - /// signal on recomputed document object + /// Signal on a recomputed document object. fastsignals::signal signalObjectRecomputed; - // signal on opened transaction + /// Signal on an opened transaction. fastsignals::signal signalOpenTransaction; - // signal a committed transaction + /// Signal on a committed transaction. fastsignals::signal signalCommitTransaction; - // signal an aborted transaction + /// Signal on an aborted transaction. fastsignals::signal signalAbortTransaction; - //@} + /// @} - /** @name Signals of property changes - * These signals are emitted on property additions or removal. - * The changed object can be any sub-class of PropertyContainer. + /** + * @name Signals of property changes. + * @brief Signals for dynamic property changes. + * + * These signals are emitted on property additions or removal. The changed + * object can be any sub-class of a PropertyContainer. + * + * @{ */ - //@{ - /// signal on adding a dynamic property + + /// Signal on adding a dynamic property. fastsignals::signal signalAppendDynamicProperty; - /// signal on renaming a dynamic property + /// Signal on renaming a dynamic property. fastsignals::signal signalRenameDynamicProperty; - /// signal on about removing a dynamic property + /// Signal before removing a dynamic property. fastsignals::signal signalRemoveDynamicProperty; - /// signal on about changing the editor mode of a property + /// Signal before changing the editor mode of a property. fastsignals::signal signalChangePropertyEditor; - //@} + /// @} - /** @name Signals of extension changes - * These signals are emitted on dynamic extension addition. Dynamic extensions are the ones added by python (c++ ones are part - * of the class definition, hence not dynamic) - * The extension in question is provided as parameter. + /** + * @name Signals of extension changes + * + * These signals are emitted on dynamic extension addition. Dynamic + * extensions are the ones added by Python (C++ ones are part of the class + * definition, hence not dynamic). The extension in question is provided as + * parameter. + * + * @{ */ - //@{ - /// signal before adding the extension + + /// Signal before adding the extension. fastsignals::signal signalBeforeAddingDynamicExtension; - /// signal after the extension was added + /// Signal after the extension was added. fastsignals::signal signalAddedDynamicExtension; - //@} + /// @} // clang-format off // NOLINTEND - /** @name methods for parameter handling */ - //@{ - /// returns the system parameter - ParameterManager & GetSystemParameter(); - /// returns the user parameter - ParameterManager & GetUserParameter(); - /** Gets a parameter group by a full qualified path - * It's an easy method to get a group: - * \code + /** + * @name Methods for parameter handling. + * + * @{ + */ + + /// Get the system parameter manager. + ParameterManager& GetSystemParameter(); + + /// Get the the user parameter manager. + ParameterManager& GetUserParameter(); + + /** + * @brief Gets a parameter group by a fully qualified path. + * + * To get a parameter group: + * @code * // getting standard parameter - * ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Raytracing"); - * std::string cDir = hGrp->GetASCII("ProjectPath", ""); - * std::string cCameraName = hGrp->GetASCII("CameraName", "TempCamera.inc"); - * \endcode + * Base::Reference group = App::GetApplication() + * .GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Raytracing"); + * std::string projectPath = group->GetASCII("ProjectPath", ""); + * std::string cameraName = group->GetASCII("CameraName", "TempCamera.inc"); + * @endcode + * + * @param[in] sName The fully qualified path of the parameter group. + * + * @return Returns a reference to the parameter group. + * @throws Base::ValueError if the parameter group does not exist or there is no path separator. */ - Base::Reference GetParameterGroupByPath(const char* sName); + Base::Reference GetParameterGroupByPath(const char* sName); - ParameterManager * GetParameterSet(const char* sName) const; + /** + * @brief Get the parameter set by name. + * + * Typically the names of the parameter sets are "System parameter" and + * "User parameter". + * + * @sa GetSystemParameter() and GetUserParameter(). + * + * @param[in] sName The name of the parameter set. + * @return Returns the parameter set, or `nullptr` if not found. + */ + ParameterManager* GetParameterSet(const char* sName) const; + + /// Get a list of all parameter sets. const std::map> & GetParameterSetList() const; - void AddParameterSet(const char* sName); - void RemoveParameterSet(const char* sName); - //@} - /** @name methods for the open handler - * With this facility an Application module can register - * an ending (filetype) which it can handle to open. - * The ending and the module name are stored and if the file - * type is opened the module gets loaded and needs to register an - * OpenHandler class in the OpenHandlerFactorySingleton. - * After the module is loaded, an OpenHandler of this type is created - * and the file gets loaded. - * @see OpenHandler - * @see OpenHandlerFactorySingleton + /** + * @brief Add a new parameter set. + * + * If the parameter set already exists, nothing is done. + * + * @param[in] sName The name of the new parameter set. */ - //@{ - /// Register an import filetype and a module name - void addImportType(const char* Type, const char* ModuleName); - /// Change the module name of a registered filetype - void changeImportModule(const char* Type, const char* OldModuleName, const char* NewModuleName); - /// Return a list of modules that support the given filetype. - std::vector getImportModules(const char* Type) const; - /// Return a list of all modules. + void AddParameterSet(const char* sName); + + /** + * @brief Remove a parameter set. + * + * If the parameter set does not exist, nothing is done. + * + * @param[in] sName The name of the parameter set to remove. + */ + void RemoveParameterSet(const char* sName); + /// @} + + /** + * @name Import and export of files + * @brief Methods for importing and exporting file types. + * + * With this facility an application module can register a new file type + * which it can handle to import or export. The file type and module name + * are registered and if the file type is opened, the module gets loaded + * and importing or exporting is delegated to the module. + * + * @{ + */ + + /** + * @brief Register an import filetype given a filter. + * + * An example of a filter is: @c "STEP with colors (*.step *.STEP *.stp *.STP)". + * An example of a module is: @c "Import" or @c "Mesh". + * + * @param[in] filter The filter that describes the file type and extensions. + * @param[in] moduleName The module name that can handle this file type. + */ + void addImportType(const char* filter, const char* moduleName); + + /** + * @brief Change the module name of a registered filetype. + * + * @param[in] filter The file type filter (see addImportType()) + * @param[in] oldModuleName The old module name. + * @param[in] newModuleName The new module name. + */ + void changeImportModule(const char* filter, const char* oldModuleName, const char* newModuleName); + + /** + * @brief Get a list of import modules that support the given filetype. + * + * @param[in] extension The file type extension. + */ + std::vector getImportModules(const char* extension) const; + + /// Get a list of all import modules. std::vector getImportModules() const; - /// Return a list of filetypes that are supported by a module. + + /** + * @brief Get a list of filetypes that are supported by a module for import. + * + * @param[in] Module The module name. + * @return A list of file types (extensions) supported by the module. + */ std::vector getImportTypes(const char* Module) const; - /// Return a list of all filetypes. + + /// Get a list of all import filetypes represented as extensions. std::vector getImportTypes() const; - /// Return the import filters with modules of a given filetype. - std::map getImportFilters(const char* Type) const; - /// Return a list of all import filters. + + /** + * @brief Get the import filters with modules of a given filetype. + * + * @param[in] extension The file type represented by its extension. + * @return A map of filter description to module name. + */ + std::map getImportFilters(const char* extension) const; + + /// Get a mapping of all import filters to their modules. std::map getImportFilters() const; - //@} - //@{ - /// Register an export filetype and a module name - void addExportType(const char* Type, const char* ModuleName); - /// Change the module name of a registered filetype - void changeExportModule(const char* Type, const char* OldModuleName, const char* NewModuleName); - /// Return a list of modules that support the given filetype. - std::vector getExportModules(const char* Type) const; - /// Return a list of all modules. + + /** + * @brief Register an export filetype given a filter. + * + * @copydetails addImportType + */ + void addExportType(const char* filter, const char* moduleName); + + /** + * @copydoc changeImportModule + */ + void changeExportModule(const char* filter, const char* oldModuleName, const char* newModuleName); + + /** + * @brief Get a list of export modules that support the given filetype. + * + * @copydetails getImportModules + */ + std::vector getExportModules(const char* extension) const; + + /// Get a list of all export modules. std::vector getExportModules() const; - /// Return a list of filetypes that are supported by a module. + + /** + * @brief Get a list of filetypes that are supported by a module for export. + * + * @copydetails App::Application::getImportTypes(const char*) const + */ std::vector getExportTypes(const char* Module) const; - /// Return a list of all filetypes. + + /// Get a list of all export filetypes. std::vector getExportTypes() const; - /// Return the export filters with modules of a given filetype. - std::map getExportFilters(const char* Type) const; - /// Return a list of all export filters. + + /** + * @brief Get the export filters with modules of a given filetype. + * + * @copydetails App::Application::getImportFilters(const char*) const + */ + std::map getExportFilters(const char* extension) const; + + /// Get a mapping of all export filters to their modules. std::map getExportFilters() const; - //@} + /// @} - /** @name Init, Destruct an Access methods */ - //@{ + /** + * @name Init, Destruct and Access methods + * + * @{ + */ + + /** + * @brief Initialize the application. + * + * @param[in] argc The argument count. + * @param[in] argv The argument values. + */ static void init(int argc, char ** argv); - static void initTypes(); - static void destruct(); - static void destructObserver(); - static void processCmdLineFiles(); - static std::list getCmdLineFiles(); - static std::list processFiles(const std::list&); - static void runApplication(); - friend Application &GetApplication(); - static std::map &Config(){return mConfig;} - static int GetARGC(){return _argc;} - static char** GetARGV(){return _argv;} - static int64_t applicationPid(); - //@} - /** @name Application directories */ - //@{ + /// Initialize FreeCAD's type system for objects, properties, etc. + static void initTypes(); + + /// Destroy the application. + static void destruct(); + + /// Detach from the console. + static void destructObserver(); + + /// Process files passed to command line. + static void processCmdLineFiles(); + + /// Get the command line files. + static std::list getCmdLineFiles(); + + /** + * @brief Process a list of files. + * + * @param[in] files The list of files to process. + * + * @return Returns the list of files that have been processed. + */ + static std::list processFiles(const std::list& files); + + /// Run the application in a specific mode. + static void runApplication(); + + friend Application &GetApplication(); + + /// Get the application configuration map. + static std::map &Config(){return mConfig;} + + /// Get the argument count that was provided at the start of the application. + static int GetARGC(){return _argc;} + + /// Get the argument values that were provided at the start of the application. + static char** GetARGV(){return _argv;} + + /// Get the application process id. + static int64_t applicationPid(); + /// @} + + /** + * @name Application directories + * + * @{ + */ + + /// Get the home path of the application. static std::string getHomePath(); + + /// Get the exectuable name of the application. static std::string getExecutableName(); + + /// Get the executable name with version information. static std::string getNameWithVersion(); + + /// Check whether this is a development version. static bool isDevelopmentVersion(); - /// Access to the various directories for the program a replacement for the get*Path methods below + /** + * @brief Get the various application directories. + * + * Access to the various directories for the application. This + * functionality is a replacement for the get*Path methods below + */ static const std::unique_ptr& directories(); - /*! - Returns the temporary directory. By default, this is set to the - system's temporary directory but can be customized by the user. + /** + * @brief Get the temporary directory. + * + * By default, this is set to the system's temporary directory but can be + * customized by the user. */ static std::string getTempPath(); + + /** + * @brief Get a temporary file name. + * + * If @p FileName is provided, a unique temporary file name is generated + * based on the file name. Otherwise a random unique temporary file name + * is generated. + * + * @param[in] FileName: optional file name to append to the temporary path. + * @returns a unique temporary file name in the temporary path. + */ static std::string getTempFileName(const char* FileName=nullptr); + + /// Get the user cache path. static std::string getUserCachePath(); + + /// Get the user configuration path. static std::string getUserConfigPath(); + + /** + * @brief Get the user application data directory. + * + * This is typically @c .local/share on Linux, @c Library/Application + * Support on macOS, and @c AppData/Roaming on Windows. + */ static std::string getUserAppDataDir(); + + /// Get the user macro directory. static std::string getUserMacroDir(); + + /// Get the resource directory for the application. static std::string getResourceDir(); + + /** + * @brief Get the application library directory. + * + * This directory contains the shared libraries that the application needs + * to load. + */ static std::string getLibraryDir(); + + /// Get the application help directory. static std::string getHelpDir(); - //@} + /// @} - /** @name Verbose Information */ - //@{ + /** + * @name Verbosity Information + * + * @{ + */ + + /** + * @brief Get verbose information about the application. + * + * @param[in,out] str The text stream to write the information to. + * @param[in] mConfig The application configuration. + */ static void getVerboseCommonInfo(QTextStream& str, const std::map& mConfig); - static void getVerboseAddOnsInfo(QTextStream& str, const std::map& mConfig); - static void addModuleInfo(QTextStream& str, const QString& modPath, bool& firstMod); - static QString prettyProductInfoWrapper(); - static QString getValueOrEmpty(const std::map& map, const std::string& key); - static constexpr const char* verboseVersionEmitMessage{"verbose_version"}; - //@} - /** @name Link handling */ - //@{ + /** + * @brief Get verbose information about add-ons. + * + * @copydetails getVerboseCommonInfo + */ + static void getVerboseAddOnsInfo(QTextStream& str, const std::map& mConfig); + + /** + * @brief Add module info to the verbose output. + * + * This function is used to add information about a single add-on. + * + * @param[in,out] str The text stream to write the information to. + * @param[in] modPath The path of the module. + * @param[in,out] firstMod Whether this is the first module being added. + */ + static void addModuleInfo(QTextStream& str, const QString& modPath, bool& firstMod); + + /// Get a pretty formatted product information string. + static QString prettyProductInfoWrapper(); + + /** + * @brief Get a value from a map or an empty string. + * + * @param[in] map The map to search. + * @param[in] key The key to search for. + * @return Returns the value if found, or an empty string otherwise. + */ + static QString getValueOrEmpty(const std::map& map, const std::string& key); + + /** + * Constant that request verbose version information to be printed. + * + * If an exception has this message, it means that we will print verbosee + * version information. + */ + static constexpr const char* verboseVersionEmitMessage{"verbose_version"}; + /// @} + + /** + * @name Link handling + * + * @{ + */ /** * @brief Check for link recursion depth. @@ -476,18 +838,21 @@ public: */ int checkLinkDepth(int depth, MessageOption option = MessageOption::Error); - /** Return the links to a given object + /** + * @brief Get the links to a given object. * - * @param obj: the linked object. If NULL, then all links are returned. - * @param option: @sa App::GetLinkOption + * @param obj: the linked object. If `nullptr`, then all links are returned. + * @param options: a bitmask of GetLinkOption. * @param maxCount: limit the number of links returned, 0 means no limit + * + * @return A set of objects that link to the given object. */ std::set getLinksTo( const DocumentObject *, int options, int maxCount=0) const; /// Check if there is any link to the given object bool hasLinksTo(const DocumentObject *obj) const; - //@} + /// @} /// Gets the base progress indicator instance. Base::ProgressIndicator& getProgressIndicator() { return _progressIndicator; } @@ -495,41 +860,69 @@ public: friend class App::Document; protected: - /// get called by the document when the name is changing - void renameDocument(const char *OldName, const char *NewName); - - /** @name I/O of the document - * This slot gets connected to all App::Documents created + /** + * @name I/O of the document + * + * @brief Slots that get connected to all App::Documents created. + * + * @{ */ - //@{ + + /// A slot for before a property of a document is changed. void slotBeforeChangeDocument(const App::Document& doc, const App::Property& prop); + /// A slot for after a property of a document has changed. void slotChangedDocument(const App::Document& doc, const App::Property& prop); + /// A slot for a newly created object. void slotNewObject(const App::DocumentObject& obj); + /// A slot for a deleted object. void slotDeletedObject(const App::DocumentObject& obj); + /// A slot for before a property of an object is changed. void slotBeforeChangeObject(const App::DocumentObject& obj, const App::Property& prop); + /// A slot for after a property of an object has changed. void slotChangedObject(const App::DocumentObject& obj, const App::Property& prop); + /// A slot for when an object is relabeled. void slotRelabelObject(const App::DocumentObject& obj); + /// A slot for when an object is activated. void slotActivatedObject(const App::DocumentObject& obj); + /// A slot for when an undo is performed in a document. void slotUndoDocument(const App::Document& doc); + /// A slot for when an redo is performed in a document. void slotRedoDocument(const App::Document& doc); + /// A slot for when an object has been recomputed. void slotRecomputedObject(const App::DocumentObject& obj); + /// A slot for when a document has been recomputed. void slotRecomputed(const App::Document& doc); + /// A slot for before a document is recomputed. void slotBeforeRecompute(const App::Document& doc); + /// A slot for when a transaction is opened in a document. void slotOpenTransaction(const App::Document& doc, std::string name); + /// A slot for when a transaction is committed in a document. void slotCommitTransaction(const App::Document& doc); + /// A slot for when a transaction is aborted in a document. void slotAbortTransaction(const App::Document& doc); + /// A slot for when a document is about to be saved. void slotStartSaveDocument(const App::Document& doc, const std::string& filename); + /// A slot for when a document has been saved. void slotFinishSaveDocument(const App::Document& doc, const std::string& filename); + /// A slot for when the editor mode of a property is changed. void slotChangePropertyEditor(const App::Document& doc, const App::Property& prop); - //@} + /// @} - /// open single document only - App::Document* openDocumentPrivate(const char * FileName, const char *propFileName, - const char *label, bool isMainDoc, DocumentInitFlags initFlags, std::vector &&objNames); - - /// Helper class for App::Document to signal on close/abort transaction + /** + * Helper class for App::Document to signal on close/abort transaction. + * + * This class is a RAII helper that emits signals before and after + * close/abort of a transaction. If the instance goes out of scope, it + * emits the signals after if the correct conditions apply. + */ class AppExport TransactionSignaller { public: + /** + * Construct the signaller. + * + * @param[in] abort Whether to signal abort or commit. + * @param[in] signal Whether to actually emit the signals. + */ TransactionSignaller(bool abort, bool signal); ~TransactionSignaller(); private: @@ -537,21 +930,21 @@ protected: }; private: - /// Constructor. The passed configuration must last for the lifetime of the constructed Application + // Constructor. The passed configuration must last for the lifetime of the constructed Application // NOLINTNEXTLINE(runtime/references) explicit Application(std::map &mConfig); - /// Destructor + // Destructor virtual ~Application(); static void cleanupUnits(); + App::Document* openDocumentPrivate(const char * FileName, const char *propFileName, + const char *label, bool isMainDoc, DocumentInitFlags initFlags, std::vector &&objNames); + void setActiveDocumentNoSignal(App::Document* pDoc); - /** @name member for parameter */ - //@{ static Base::Reference _pcSysParamMngr; static Base::Reference _pcUserParamMngr; - //@} //--------------------------------------------------------------------- // python exports goes here +++++++++++++++++++++++++++++++++++++++++++ @@ -614,35 +1007,33 @@ private: friend class ApplicationObserver; - /** @name Private Init, Destruct an Access methods */ - //@{ + /* Private Init, Destruct, and Access methods */ static void initConfig(int argc, char ** argv); static void initApplication(); static void logStatus(); // the one and only pointer to the application object static Application *_pcSingleton; - /// checks if the environment is alright + // checks if the environment is alright //static void CheckEnv(void); - /// Search for the FreeCAD home path based on argv[0] - /*! + // Search for the FreeCAD home path based on argv[0] + /* * There are multiple implementations of this method per-OS */ static std::string FindHomePath(const char* sCall); - /// Print the help message + // Print the help message static void PrintInitHelp(); - /// figure out some things + // figure out some things static void ExtractUserPath(); - /// load the user and system parameter set + // load the user and system parameter set static void LoadParameters(); - /// puts the given env variable in the config + // puts the given env variable in the config static void SaveEnv(const char *); - /// startup configuration container + // startup configuration container static std::map mConfig; - /// Management of and access to applications directories + // Management of and access to applications directories static std::unique_ptr _appDirs; static int _argc; static char ** _argv; - //@} struct FileTypeItem { std::string filter; @@ -650,7 +1041,7 @@ private: std::vector types; }; - /// open ending information + // open ending information std::vector _mImportTypes; std::vector _mExportTypes; std::map DocMap; @@ -687,7 +1078,7 @@ private: static Base::ConsoleObserverFile *_pConsoleObserverFile; }; -/// Singleton getter of the Application +/// Get the singleton Application instance. inline App::Application &GetApplication(){ return *App::Application::_pcSingleton; } From 393434026a225a5fc2c2f191d5244cf2ab32bc04 Mon Sep 17 00:00:00 2001 From: Pieter Hijma Date: Wed, 15 Oct 2025 21:35:03 +0200 Subject: [PATCH 2/2] Doc: Add a topic for App::Application --- src/App/Application.h | 6 ++- src/App/core-app.dox | 86 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 85 insertions(+), 7 deletions(-) diff --git a/src/App/Application.h b/src/App/Application.h index 35586b66b3..68331e12cf 100644 --- a/src/App/Application.h +++ b/src/App/Application.h @@ -89,6 +89,7 @@ struct DocumentInitFlags { /** * @brief The class that represents the whole application. + * @ingroup ApplicationGroup * * This is a singleton class that represents the application without * considering any GUI functionality. You can access it using @@ -1078,7 +1079,10 @@ private: static Base::ConsoleObserverFile *_pConsoleObserverFile; }; -/// Get the singleton Application instance. +/** + * @brief Get the singleton Application instance. + * @ingroup ApplicationGroup + */ inline App::Application &GetApplication(){ return *App::Application::_pcSingleton; } diff --git a/src/App/core-app.dox b/src/App/core-app.dox index 7dd9afc185..4a665598a1 100644 --- a/src/App/core-app.dox +++ b/src/App/core-app.dox @@ -4,10 +4,10 @@ * @brief The part of FreeCAD that works without GUI (console or server mode) * * @details It contains the App namespace and defines core concepts such as - * @ref DocumentGroup "Document", @ref DocumentObjectGroup "Document Object", - * @ref PropertyFramework "Property Framework", @ref ExpressionFramework - * "Expression Framework", and the @ref ExtensionFramework "Extension - * Framework". + * @ref ApplicationGroup "Application", @ref DocumentGroup "Document", @ref + * DocumentObjectGroup "DocumentObject", @ref PropertyFramework "Property + * Framework", @ref ExpressionFramework "Expression Framework", and the @ref + * ExtensionFramework "Extension Framework". * * The largest difference between the functionality in @ref BASE "Base" * compared to %App is that %App introduces the notion of properties, both used @@ -16,6 +16,80 @@ * @ref App::Application "Application". */ +/** + * @defgroup ApplicationGroup Application + * @ingroup APP + * @brief The class that represents the running FreeCAD application. + * + * The App::Application class is a singleton class that represents the running + * FreeCAD application. It can be obtained by App::GetApplication(). It + * manages the opened documents and provides various forms of functionality + * that are briefly discussed below. + * + * @section SecApplicationInitialization Initialization and Configuration + * + * On application start, the FreeCAD type system is initialized and the command + * line arguments are processed, possible opening FreeCAD files or executing + * FreeCAD macros. The internal configuration that contains various paths is + * set up and after that the `user.cfg` and `system.cfg` file are parsed and + * made available by @ref App::Application::GetUserParameter() + * "GetUserParameter()" and @ref App::Application::GetSystemParameter() + * "GetSystemParameter()". + * + * FreeCAD obtains various resources from different paths that can be accessed + * by means of functions such as @ref App::Application::GetHomePath() + * "GetHomePath" or the more generic function @ref + * App::Application::directories "directories()" that provides an @ref + * App::ApplicationDirectories "ApplicationDirectories" class. + * + * @section SecApplicationDocuments Document management + * + * An important role is managing FreeCAD documents. The application class + * allows opening and closing documents, creating unique and valid names and + * labels for the files, and setting or opening a file as the active file. + * + * Moreover, there is support for special files such as temporary files that + * may or may not be hidden in the tree or partially loaded files where not all + * objects are loaded. + * + * FreeCAD has a wide range of file formats that it can import and export. It + * is possible to install a file type filter together with a module name that + * then becomes responsible for importing or exporting the file types of the + * filter. An example of a filter is @c "STEP with colors (*.step *.STEP *.stp + * *.STP)" and the file types that will be associated with this filter are + * represented by the extensions and will be @c "step" and @c "stp" (matching + * is case-insensitive). + * + * @section SecApplicationTransactions Application-wide transactions + * + * In @ref SecUndoRedo "Documents" we explain more about the transaction + * system. Although transactions are mainly a feature of documents and + * document objects, there is also applicaton-wide functionality that allows + * creating transactions in multiple documents sharing the same transaction ID. + * + * @section SecApplicationLinks Links between document objects + * + * Although links occur between document objects and are as such more a topic + * of @ref GroupDocumentObject "DocumentObjects", App::Application provides + * functions to check for cyclic dependencies and obtaining links to a document + * object. + * + * @section SecApplicationSignals Signals + * + * The application class has various signals that can be connected to. There + * are various categories of signals: + * - on the level of the application, such as with new or deleted documents or + * transactions, + * - on the level of documents, such as with changed properties of documents or + * document objects, or with newly added objects, + * - on the level of objects, such as newly added properties, + * - on the level of extensions, such as newly added extensions. + * + * Many of the signals are also available on the document level and typically + * the application class has slots that connect to these document signals when + * a document is opened. + */ + /** * @defgroup DocumentGroup Document * @ingroup APP @@ -127,7 +201,7 @@ */ /** - * @defgroup DocumentObjectGroup Document Object + * @defgroup DocumentObjectGroup DocumentObject * @ingroup APP * @brief %Base class of all objects handled in the @ref App::Document "Document". * @@ -398,7 +472,7 @@ /** * @defgroup ExtensionFramework Extension framework * @ingroup APP - * @brief The extension system provides a way to extend the functionality of Document Objects. + * @brief The extension system provides a way to extend the functionality of @ref DocumentObjectGroup "DocumentObjects". * * The concept of extensions provides a way to extend the functionality of * objects in FreeCAD despite Python's limitations with multiple inheritance