Property: * Extended property status bitset. Mirror most of PropertyType and allow dynamic change property type. * Cache property name and type to improve performance * Centralize property status change signalling * Change aboutToSetValue()/hasSetValue() to virtual * Add new API getFullName() to obtain full quanlified name of the property AtomicPropertyChangeInterface: * Allow calling aboutToSetValue()/hasSetValue() when actually changed PropertyLists: * Refactor implementation by an abstract class PropertyListBase and a template class PropertyListsT, to allow better code reuse. PropertyListT is derived from AtomicPropertyChangeInterface to allow more efficient change on individual elements. * All list type property now accept setting python value as a dictionary with index as key to set individual element of a list. * Add touch list for more efficient handling of value changes. The list contains the index of changed value. And empty touch list should be treated as the entire list is changed. PropertyContainerPy expose this functionality with getPropertyTouchList(). PropertyPersistentObject: * New property to allow dynamic creation of any FreeCAD object derived from Base::Persistence, and use it as a property. DynamicProperty: * Use boost multi_index_container for efficient property lookup while keeping order. * Modify to be allowed to use in PropertyContainer directly PropertyContainer: * Use boost multi_index_container for efficient property lookup while keeping order. * Allow adding/removing dynamic property on all property container * Modify Save/Restore() to persist property status, and better handle transient property which can now be dynamically enabled/disabled per object. * Add new API getFullName() to obtain full quanlified name of the property. Implemented by Document, DocumentObject, and also ViewProviderDocumentObject if future patch DocumentObject and FeaturePython are modified to accommondate the dynamic property changes. Removed get/setCustomAttribute() implementation from DocumentObjectPy, and rely on PropertyContainerPy for the implementation, because of the additional dynamic property support in property container. Gui::ViewProviderDocumentObject, which is derived from PropertyContainer, is also modified accordingly
464 lines
21 KiB
C++
464 lines
21 KiB
C++
/***************************************************************************
|
|
* (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 <boost/signals2.hpp>
|
|
|
|
#include <vector>
|
|
#include <deque>
|
|
|
|
#include <Base/PyObjectBase.h>
|
|
#include <Base/Parameter.h>
|
|
#include <Base/Observer.h>
|
|
|
|
|
|
namespace Base
|
|
{
|
|
class ConsoleObserverStd;
|
|
class ConsoleObserverFile;
|
|
}
|
|
|
|
namespace App
|
|
{
|
|
|
|
class Document;
|
|
class DocumentObject;
|
|
class ApplicationObserver;
|
|
class Property;
|
|
|
|
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);
|
|
/// 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);
|
|
/// 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<App::Document*> getDocuments() const;
|
|
/// Set the active document
|
|
void setActiveDocument(App::Document* pDoc);
|
|
void setActiveDocument(const char *Name);
|
|
/// close all documents (without saving)
|
|
void closeAllDocuments(void);
|
|
//@}
|
|
|
|
/** @name Signals of the Application */
|
|
//@{
|
|
/// signal on new Document
|
|
boost::signals2::signal<void (const Document&)> signalNewDocument;
|
|
/// signal on document getting deleted
|
|
boost::signals2::signal<void (const Document&)> signalDeleteDocument;
|
|
/// signal on already deleted Document
|
|
boost::signals2::signal<void ()> signalDeletedDocument;
|
|
/// signal on relabeling Document (user name)
|
|
boost::signals2::signal<void (const Document&)> signalRelabelDocument;
|
|
/// signal on renaming Document (internal name)
|
|
boost::signals2::signal<void (const Document&)> signalRenameDocument;
|
|
/// signal on activating Document
|
|
boost::signals2::signal<void (const Document&)> signalActiveDocument;
|
|
/// signal on saving Document
|
|
boost::signals2::signal<void (const Document&)> signalSaveDocument;
|
|
/// signal on starting to restore Document
|
|
boost::signals2::signal<void (const Document&)> signalStartRestoreDocument;
|
|
/// signal on restoring Document
|
|
boost::signals2::signal<void (const Document&)> signalFinishRestoreDocument;
|
|
/// signal on starting to save Document
|
|
boost::signals2::signal<void (const Document&, const std::string&)> signalStartSaveDocument;
|
|
/// signal on saved Document
|
|
boost::signals2::signal<void (const Document&, const std::string&)> signalFinishSaveDocument;
|
|
/// signal on undo in document
|
|
boost::signals2::signal<void (const Document&)> signalUndoDocument;
|
|
/// signal on redo in document
|
|
boost::signals2::signal<void (const Document&)> signalRedoDocument;
|
|
/// signal on show hidden items
|
|
boost::signals2::signal<void (const Document&)> signalShowHidden;
|
|
//@}
|
|
|
|
|
|
/** @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<void (const App::Document&, const App::Property&)> signalBeforeChangeDocument;
|
|
/// signal on changed doc property
|
|
boost::signals2::signal<void (const App::Document&, const App::Property&)> signalChangedDocument;
|
|
/// signal on new Object
|
|
boost::signals2::signal<void (const App::DocumentObject&)> signalNewObject;
|
|
//boost::signals2::signal<void (const App::DocumentObject&)> m_sig;
|
|
/// signal on deleted Object
|
|
boost::signals2::signal<void (const App::DocumentObject&)> signalDeletedObject;
|
|
/// signal on changed Object
|
|
boost::signals2::signal<void (const App::DocumentObject&, const App::Property&)> signalBeforeChangeObject;
|
|
/// signal on changed Object
|
|
boost::signals2::signal<void (const App::DocumentObject&, const App::Property&)> signalChangedObject;
|
|
/// signal on relabeled Object
|
|
boost::signals2::signal<void (const App::DocumentObject&)> signalRelabelObject;
|
|
/// signal on activated Object
|
|
boost::signals2::signal<void (const App::DocumentObject&)> signalActivatedObject;
|
|
/// signal on recomputed document
|
|
boost::signals2::signal<void (const App::Document&)> signalRecomputed;
|
|
/// signal on recomputed document object
|
|
boost::signals2::signal<void (const App::DocumentObject&)> signalObjectRecomputed;
|
|
// signal on opened transaction
|
|
boost::signals2::signal<void (const App::Document&, std::string)> signalOpenTransaction;
|
|
// signal a committed transaction
|
|
boost::signals2::signal<void (const App::Document&)> signalCommitTransaction;
|
|
// signal an aborted transaction
|
|
boost::signals2::signal<void (const App::Document&)> 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<void (const App::Property&)> signalAppendDynamicProperty;
|
|
/// signal on about removing a dynamic property
|
|
boost::signals2::signal<void (const App::Property&)> signalRemoveDynamicProperty;
|
|
/// signal on about changing the editor mode of a property
|
|
boost::signals2::signal<void (const App::Document&, const App::Property&)> 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<ParameterGrp> GetParameterGroupByPath(const char* sName);
|
|
|
|
ParameterManager * GetParameterSet(const char* sName) const;
|
|
const std::map<std::string,ParameterManager *> & 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<std::string> getImportModules(const char* Type) const;
|
|
/// Return a list of all modules.
|
|
std::vector<std::string> getImportModules() const;
|
|
/// Return a list of filetypes that are supported by a module.
|
|
std::vector<std::string> getImportTypes(const char* Module) const;
|
|
/// Return a list of all filetypes.
|
|
std::vector<std::string> getImportTypes(void) const;
|
|
/// Return the import filters with modules of a given filetype.
|
|
std::map<std::string, std::string> getImportFilters(const char* Type) const;
|
|
/// Return a list of all import filters.
|
|
std::map<std::string, std::string> 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<std::string> getExportModules(const char* Type) const;
|
|
/// Return a list of all modules.
|
|
std::vector<std::string> getExportModules() const;
|
|
/// Return a list of filetypes that are supported by a module.
|
|
std::vector<std::string> getExportTypes(const char* Module) const;
|
|
/// Return a list of all filetypes.
|
|
std::vector<std::string> getExportTypes(void) const;
|
|
/// Return the export filters with modules of a given filetype.
|
|
std::map<std::string, std::string> getExportFilters(const char* Type) const;
|
|
/// Return a list of all export filters.
|
|
std::map<std::string, std::string> 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<std::string> getCmdLineFiles();
|
|
static std::list<std::string> processFiles(const std::list<std::string>&);
|
|
static void runApplication(void);
|
|
friend Application &GetApplication(void);
|
|
static std::map<std::string,std::string> &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<DocumentObject*> 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 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 &);
|
|
//@}
|
|
|
|
private:
|
|
/// Constructor
|
|
Application(std::map<std::string,std::string> &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 *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 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<std::string,std::string> mConfig;
|
|
static int _argc;
|
|
static char ** _argv;
|
|
//@}
|
|
|
|
struct FileTypeItem {
|
|
std::string filter;
|
|
std::string module;
|
|
std::vector<std::string> types;
|
|
};
|
|
|
|
/// open ending information
|
|
std::vector<FileTypeItem> _mImportTypes;
|
|
std::vector<FileTypeItem> _mExportTypes;
|
|
std::map<std::string,Document*> DocMap;
|
|
std::map<std::string,ParameterManager *> mpcPramManager;
|
|
std::map<std::string,std::string> &_mConfig;
|
|
App::Document* _pActiveDoc;
|
|
|
|
// for estimate max link depth
|
|
int _objCount;
|
|
|
|
static Base::ConsoleObserverStd *_pConsoleObserverStd;
|
|
static Base::ConsoleObserverFile *_pConsoleObserverFile;
|
|
};
|
|
|
|
/// Singleton getter of the Application
|
|
inline App::Application &GetApplication(void){
|
|
return *App::Application::_pcSingleton;
|
|
}
|
|
|
|
} // namespace App
|
|
|
|
|
|
#endif // APP_APPLICATION_H
|