/*************************************************************************** * (c) Jürgen Riegel (juergen.riegel@web.de) 2002 * * * * This file is part of the FreeCAD CAx development system. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License (LGPL) * * as published by the Free Software Foundation; either version 2 of * * the License, or (at your option) any later version. * * for detail see the LICENCE text file. * * * * FreeCAD 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 Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with FreeCAD; if not, write to the Free Software * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * * USA * * * * Juergen Riegel 2002 * ***************************************************************************/ #ifndef APP_APPLICATION_H #define APP_APPLICATION_H #include #include #include #include #include #include namespace Base { class ConsoleObserverStd; class ConsoleObserverFile; } namespace App { class Document; class DocumentObject; class ApplicationObserver; class Property; class AutoTransaction; enum GetLinkOption { /// Get all links (both directly and in directly) linked to the given object GetLinkRecursive = 1, /// Get link array element instead of the array GetLinkArrayElement = 2, /// Get linked object instead of the link, no effect if GetLinkRecursive GetLinkedObject = 4, /// Get only external links, no effect if GetLinkRecursive GetLinkExternal = 8, }; /** The Application * The root of the whole application * @see App::Document */ class AppExport Application { public: //--------------------------------------------------------------------- // exported functions goes here +++++++++++++++++++++++++++++++++++++++ //--------------------------------------------------------------------- /** @name methods for document handling */ //@{ /** Creates a new document * The first name is a the identifier and some kind of an internal (english) * name. It has 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 avoid the renaming by using getUniqueDocumentName() * to get a unique name before calling newDoucument(). * The second name is a UTF8 name of any kind. It's that name normally shown to * the user and stored in the App::Document::Name property. */ App::Document* newDocument(const char * Name=0l, const char * UserName=0l, bool createView=true); /// 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) const; /// Open an existing document from a file App::Document* openDocument(const char * FileName=0l, bool createView=true); /** Open multiple documents * * @param filenames: input file names * @param 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 * 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. * * @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. */ std::vector openDocuments(const std::vector &filenames, const std::vector *paths=0, const std::vector *labels=0, std::vector *errs=0, bool createView = true); /// Retrieve the active document App::Document* getActiveDocument(void) const; /// Retrieve a named document App::Document* getDocument(const char *Name) 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(void); /// 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; //@} /** @name Application-wide trandaction setting */ //@{ /** Setup a pending application-wide active transaction * * @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 * * @return The new transaction ID. * * Call this function to setup an application-wide transaction. All current * pending transactions of opening documents will be committed first. * However, no new transaction is created by this call. Any subsequent * 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. */ int setActiveTransaction(const char *name, bool persist=false); /// Return the current active transaction name and ID const char *getActiveTransaction(int *tid=0) const; /** Commit/abort current active transactions * * @param abort: whether to abort or commit the transactions * * 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 */ void closeActiveTransaction(bool abort=false, int id=0); //@} /** @name Signals of the Application */ //@{ /// signal on new Document boost::signals2::signal signalNewDocument; /// signal on document getting deleted boost::signals2::signal signalDeleteDocument; /// signal on already deleted Document boost::signals2::signal signalDeletedDocument; /// signal on relabeling Document (user name) boost::signals2::signal signalRelabelDocument; /// signal on renaming Document (internal name) boost::signals2::signal signalRenameDocument; /// signal on activating Document boost::signals2::signal signalActiveDocument; /// signal on saving Document boost::signals2::signal signalSaveDocument; /// signal on starting to restore Document boost::signals2::signal signalStartRestoreDocument; /// signal on restoring Document boost::signals2::signal signalFinishRestoreDocument; /// signal on starting to save Document boost::signals2::signal signalStartSaveDocument; /// signal on saved Document boost::signals2::signal signalFinishSaveDocument; /// signal on undo in document boost::signals2::signal signalUndoDocument; /// signal on application wide undo boost::signals2::signal signalUndo; /// signal on redo in document boost::signals2::signal signalRedoDocument; /// signal on application wide redo boost::signals2::signal signalRedo; /// signal before close/abort active transaction boost::signals2::signal signalBeforeCloseTransaction; /// signal after close/abort active transaction boost::signals2::signal signalCloseTransaction; /// signal on show hidden items boost::signals2::signal signalShowHidden; /// signal on start opening document(s) boost::signals2::signal signalStartOpenDocument; /// signal on finished opening document(s) boost::signals2::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 */ //@{ /// signal before change of doc property boost::signals2::signal signalBeforeChangeDocument; /// signal on changed doc property boost::signals2::signal signalChangedDocument; /// signal on new Object boost::signals2::signal signalNewObject; //boost::signals2::signal m_sig; /// signal on deleted Object boost::signals2::signal signalDeletedObject; /// signal on changed Object boost::signals2::signal signalBeforeChangeObject; /// signal on changed Object boost::signals2::signal signalChangedObject; /// signal on relabeled Object boost::signals2::signal signalRelabelObject; /// signal on activated Object boost::signals2::signal signalActivatedObject; /// signal before recomputed document boost::signals2::signal signalBeforeRecomputeDocument; /// signal on recomputed document boost::signals2::signal signalRecomputed; /// signal on recomputed document object boost::signals2::signal signalObjectRecomputed; // signal on opened transaction boost::signals2::signal signalOpenTransaction; // signal a committed transaction boost::signals2::signal signalCommitTransaction; // signal an aborted transaction boost::signals2::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. */ //@{ /// signal on adding a dynamic property boost::signals2::signal signalAppendDynamicProperty; /// signal on about removing a dynamic property boost::signals2::signal signalRemoveDynamicProperty; /// signal on about changing the editor mode of a property boost::signals2::signal signalChangePropertyEditor; //@} /** @name methods for parameter handling */ //@{ /// returns the system parameter ParameterManager & GetSystemParameter(void) ; /// returns the user parameter ParameterManager & GetUserParameter(void) ; /** Gets a parameter group by a full qualified path * It's an easy method to get a 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 GetParameterGroupByPath(const char* sName); ParameterManager * GetParameterSet(const char* sName) const; const std::map & GetParameterSetList(void) const; void AddParameterSet(const char* sName); void RemoveParameterSet(const char* sName); //@} /** @name methods for the open handler * With this facility a Application module can register * a ending (filetype) which he can handle to open. * The ending and the module name are stored and if the file * type is opened the module get loaded and need to register a * OpenHandler class in the OpenHandlerFactorySingleton. * After the module is loaded a OpenHandler of this type is created * and the file get loaded. * @see OpenHandler * @see OpenHandlerFactorySingleton */ //@{ /// Register an import filetype and a module name void addImportType(const char* Type, const char* ModuleName); /// Return a list of modules that support the given filetype. std::vector getImportModules(const char* Type) const; /// Return a list of all modules. std::vector getImportModules() const; /// Return a list of filetypes that are supported by a module. std::vector getImportTypes(const char* Module) const; /// Return a list of all filetypes. std::vector getImportTypes(void) 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. std::map getImportFilters(void) const; //@} //@{ /// Register an export filetype and a module name void addExportType(const char* Type, const char* ModuleName); /// Return a list of modules that support the given filetype. std::vector getExportModules(const char* Type) const; /// Return a list of all modules. std::vector getExportModules() const; /// Return a list of filetypes that are supported by a module. std::vector getExportTypes(const char* Module) const; /// Return a list of all filetypes. std::vector getExportTypes(void) 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. std::map getExportFilters(void) const; //@} /** @name Init, Destruct an Access methods */ //@{ static void init(int argc, char ** argv); static void initTypes(void); static void destruct(void); static void destructObserver(void); static void processCmdLineFiles(void); static std::list getCmdLineFiles(); static std::list processFiles(const std::list&); static void runApplication(void); friend Application &GetApplication(void); static std::map &Config(void){return mConfig;} static int GetARGC(void){return _argc;} static char** GetARGV(void){return _argv;} //@} /** @name Application directories */ //@{ const char* getHomePath(void) const; const char* getExecutableName(void) const; /*! Returns 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(); static std::string getTempFileName(const char* FileName=0); static std::string getUserAppDataDir(); static std::string getUserMacroDir(); static std::string getResourceDir(); static std::string getHelpDir(); //@} /** @name Link handling */ //@{ /** Check for link recursion depth * * @param depth: current depth * @param no_throw: whether to throw exception * * @return Return the maximum remaining depth. * * The function uses an internal count of all objects in all documents as * the limit of recursion depth. */ int checkLinkDepth(int depth, bool no_throw=true); /** Return the links to a given object * * @param obj: the linked object. If NULL, then all links are returned. * @param option: @sa App::GetLinkOptions * @param maxCount: limit the number of links returned, 0 means no limit */ 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; //@} 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 get connected to all App::Documents created */ //@{ void slotBeforeChangeDocument(const App::Document&, const App::Property&); void slotChangedDocument(const App::Document&, const App::Property&); void slotNewObject(const App::DocumentObject&); void slotDeletedObject(const App::DocumentObject&); void slotBeforeChangeObject(const App::DocumentObject&, const App::Property& Prop); void slotChangedObject(const App::DocumentObject&, const App::Property& Prop); void slotRelabelObject(const App::DocumentObject&); void slotActivatedObject(const App::DocumentObject&); void slotUndoDocument(const App::Document&); void slotRedoDocument(const App::Document&); void slotRecomputedObject(const App::DocumentObject&); void slotRecomputed(const App::Document&); void slotBeforeRecompute(const App::Document&); void slotOpenTransaction(const App::Document&, std::string); void slotCommitTransaction(const App::Document&); void slotAbortTransaction(const App::Document&); void slotStartSaveDocument(const App::Document&, const std::string&); void slotFinishSaveDocument(const App::Document&, const std::string&); void slotChangePropertyEditor(const App::Document&, const App::Property &); //@} /// open single document only App::Document* openDocumentPrivate(const char * FileName, const char *propFileName, const char *label, bool isMainDoc, bool createView, const std::set &objNames); /// Helper class for App::Document to signal on close/abort transaction class AppExport TransactionSignaller { public: TransactionSignaller(bool abort,bool signal); ~TransactionSignaller(); private: bool abort; }; private: /// Constructor Application(std::map &mConfig); /// Destructor virtual ~Application(); /** @name member for parameter */ //@{ static ParameterManager *_pcSysParamMngr; static ParameterManager *_pcUserParamMngr; //@} //--------------------------------------------------------------------- // python exports goes here +++++++++++++++++++++++++++++++++++++++++++ //--------------------------------------------------------------------- // static python wrapper of the exported functions static PyObject* sGetParam (PyObject *self,PyObject *args); static PyObject* sSaveParameter (PyObject *self,PyObject *args); static PyObject* sGetVersion (PyObject *self,PyObject *args); static PyObject* sGetConfig (PyObject *self,PyObject *args); static PyObject* sSetConfig (PyObject *self,PyObject *args); static PyObject* sDumpConfig (PyObject *self,PyObject *args); static PyObject* sAddImportType (PyObject *self,PyObject *args); static PyObject* sGetImportType (PyObject *self,PyObject *args); static PyObject* sAddExportType (PyObject *self,PyObject *args); static PyObject* sGetExportType (PyObject *self,PyObject *args); static PyObject* sGetResourceDir (PyObject *self,PyObject *args); static PyObject* sGetUserAppDataDir (PyObject *self,PyObject *args); static PyObject* sGetUserMacroDir (PyObject *self,PyObject *args); static PyObject* sGetHelpDir (PyObject *self,PyObject *args); static PyObject* sGetHomePath (PyObject *self,PyObject *args); static PyObject* sLoadFile (PyObject *self,PyObject *args); static PyObject* sOpenDocument (PyObject *self,PyObject *args); static PyObject* sSaveDocument (PyObject *self,PyObject *args); static PyObject* sSaveDocumentAs (PyObject *self,PyObject *args); static PyObject* sNewDocument (PyObject *self,PyObject *args); static PyObject* sCloseDocument (PyObject *self,PyObject *args); static PyObject* sActiveDocument (PyObject *self,PyObject *args); static PyObject* sSetActiveDocument (PyObject *self,PyObject *args); static PyObject* sGetDocument (PyObject *self,PyObject *args); static PyObject* sListDocuments (PyObject *self,PyObject *args); static PyObject* sAddDocObserver (PyObject *self,PyObject *args); static PyObject* sRemoveDocObserver (PyObject *self,PyObject *args); static PyObject *sIsRestoring (PyObject *self,PyObject *args); static PyObject *sSetLogLevel (PyObject *self,PyObject *args); static PyObject *sGetLogLevel (PyObject *self,PyObject *args); static PyObject *sCheckLinkDepth (PyObject *self,PyObject *args); static PyObject *sGetLinksTo (PyObject *self,PyObject *args); static PyObject *sGetDependentObjects(PyObject *self,PyObject *args); static PyObject *sSetActiveTransaction (PyObject *self,PyObject *args); static PyObject *sGetActiveTransaction (PyObject *self,PyObject *args); static PyObject *sCloseActiveTransaction(PyObject *self,PyObject *args); static PyObject *sCheckAbort(PyObject *self,PyObject *args); static PyMethodDef Methods[]; friend class ApplicationObserver; /** @name Private Init, Destruct an Access methods */ //@{ static void initConfig(int argc, char ** argv); static void initApplication(void); static void logStatus(void); // the one and only pointer to the application object static Application *_pcSingleton; /// argument helper function static void ParseOptions(int argc, char ** argv); /// checks if the environment is allreight //static void CheckEnv(void); /// 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 static void PrintInitHelp(void); /// figure out some things static void ExtractUserPath(); /// load the user and system parameter set static void LoadParameters(void); /// puts the given env variable in the config static void SaveEnv(const char *); /// startup configuration container static std::map mConfig; static int _argc; static char ** _argv; //@} struct FileTypeItem { std::string filter; std::string module; std::vector types; }; /// open ending information std::vector _mImportTypes; std::vector _mExportTypes; std::map DocMap; std::map mpcPramManager; std::map &_mConfig; App::Document* _pActiveDoc; std::deque _pendingDocs; std::deque _pendingDocsReopen; std::map > _pendingDocMap; bool _isRestoring; bool _allowPartial; bool _isClosingAll; // for estimate max link depth int _objCount; friend class AutoTransaction; std::string _activeTransactionName; int _activeTransactionID; int _activeTransactionGuard; bool _activeTransactionTmpName; static Base::ConsoleObserverStd *_pConsoleObserverStd; static Base::ConsoleObserverFile *_pConsoleObserverFile; }; /// Singleton getter of the Application inline App::Application &GetApplication(void){ return *App::Application::_pcSingleton; } /// Helper class to manager transaction (i.e. undo/redo) class AppExport AutoTransaction { private: /// Private new operator to prevent heap allocation void* operator new(size_t size); public: /** Constructor * * @param name: optional new transaction name on construction * @param tmpName: if true and a new transaction is setup, the name given is * considered as temporary, and subsequent construction of this class (or * calling Application::setActiveTransaction()) can override the transaction * name. * * The constructor increments an internal counter * (Application::_activeTransactionGuard). The counter prevents any new * active transaction being setup. It also prevents close (i.e. commits) the * current active transaction until it reaches zero. It does not have any * effect on aborting transaction, though. */ AutoTransaction(const char *name=0, bool tmpName=false); /** Destructor * * This destructor decrease an internal counter * (Application::_activeTransactionGuard), and will commit any current * active transaction when the counter reaches zero. */ ~AutoTransaction(); /** Close or abort the transaction * * This function can be used to explicitly close (i.e. commit) the * transaction, if the current transaction ID matches the one created inside * the constructor. For aborting, it will abort any current transaction */ void close(bool abort=false); /** Enable/Disable any AutoTransaction instance in the current stack * * Once disabled, any empty temporary named transaction is closed. If there * are non-empty or non-temperary named active transaction, it will not be * auto closed. * * This function may be used in, for example, Gui::Document::setEdit() to * allow a transaction live past any command scope. */ static void setEnable(bool enable); private: int tid = 0; }; } // namespace App #endif // APP_APPLICATION_H