/** * @file PaiObject.h * @brief Pai数据基类定义 * @date 2011-6-20 */ #ifndef PAI_FRAME_IOBJECTMODEL_PAIOBJECT_H #define PAI_FRAME_IOBJECTMODEL_PAIOBJECT_H #include #include #include #include // #include "ObjectModelService.h" // #include "PaiObjectEventAgent.h" #include "Property.h" #include "PaiTypes.h" #include "Turtle.h" /** * @brief 创建一个对象 * @param[in] className 对象名称 * @param[in] uid 对象id */ #define DECLARE_PAI_OBJECT(className, uid) \ static pai::objectmodel::PaiObject* CreateInstance() \ { \ return new className(); \ } \ static const char* GetTypeIDString() \ { \ return uid; \ } \ virtual QUuid GetTypeID() const \ { \ return QUuid(uid); \ } /** * @brief 注册一个对象 * @param[in] className 对象名称 */ #define IMPLEMENT_PAI_OBJECT(className) \ namespace pai \ { \ namespace objectmodel \ { \ class regist##className \ { \ public:regist##className() \ { \ GetObjectModelService()->Register(QUuid(className::GetTypeIDString()), className::CreateInstance); \ } \ }; \ } \ } \ pai::objectmodel::regist##className g_##className##_creator; class QMutex; namespace pai { namespace objectmodel { /** * @class PaiObject * @brief The base class for all object model * @note 在所有获得子对象的函数接口中, * 凡是函数名是针对Object的,就会递归查找所有子项,并且包括自己,如: * GetObject * GetObjects * GetObjectByName * GetObjectByType * 凡是函数名是针对Child或Children的,就会只查找第一代子项,不包括自己,如: * GetChild * GetChildren * GetChildrenCount * GetChildByType * RemoveChild */ class PAI_OBJECTMODEL_EXPORT PaiObject : public QObject { // friend class pai::objectmodel::IProjectManager; public: DECLARE_PAI_OBJECT(PaiObject,"{00000000-0000-0000-0000-000000000000}") /** * @enum OverrideFlag * @brief 覆盖标识枚举变量 */ enum OverrideFlag { Override, ///< 覆盖 NoOverride ///< 不覆盖 }; /** * @enum Flag * @brief 对象的各种标识 */ enum Flag { VisibibleOnTree = 0x0001, ///< 该对象是否上树 Modified = 0x0002, ///< 用户是否在当前会话修改过该对象 // for the active status ACTIVE = 0x0004, ///< 活跃的(项目,工区...) INACTIVE = 0x0008, ///< 不活跃的(项目,工区...) ALL = 0x000C, ///< 所有的(项目,工区...) Loaded = 0x0010, ///< 该对象信息是否与数据库同步 DataLoaded = 0x0020, ///< 该对象数据是否已加载 ChildrenLoaded = 0x0040, ///< 是否已经加载子代,该标志只能在SynDB函数中设置 IgnoreSyncDB = 0x0080, ///< 同步时是否忽略该对象(不是指的该对象是否允许刷新) Syncabled = 0x0100, ///< 该节点是否可同步(该对象是否允许刷新) Closed = 0x0200, ///< 该对象是否处于关闭状态 Deleting = 0x0400, ///< 该对象是否正在删除过程中 Deletable = 0x0800, ///< 该对象是否可以被删除(指从数据树删除) DataModified = 0x1002, ///< 用户是否在当前会话修改过该对象的数据 Renameable = 0x2000, ///< 此对象是否可以重命名 ShadowNode = 0x4000 ///< 是否为影子节点,即删除时不用去判断其是否lock }; /** * @enum ExistFlag * @brief 存在的各种情况标识,即将废除 */ enum ExistFlag { EXIST_DBN_HDFSY = -3, ///< 数据库不存在HDFS存在 EXIST_DBY_HDFSN = -2, ///< 数据库存在HDFS不存在 EXIST_DB_ERROR = -1, ///< 数据库出错 EXIST_DBN_HDFSN = 0, ///< 数据库和HDFS都不存在 EXIST_DBY_HDFSY = 1 ///< 数据库和HDFS都存在 }; /** * @enum SortKeyFlag * @brief 排序关键字 */ enum SortKeyFlag { Sort_Key_Null = 0, ///< 没有排序关键字 Sort_By_Name, ///< 名称,标题等 Sort_By_CreateTime ///< 创建时间 }; /** * @enum MountTree * @brief 挂载数据树上枚举类型 */ enum MountTree { MountOnTree = 0, ///< 数据挂载上树 MountNoTree ///< 数据不上树 }; /** * @brief 构造函数 * @param[in] pParent 父对象句柄 */ PaiObject(PaiObject* pParent = NULL); /** * @brief 虚析构函数 */ virtual ~PaiObject(); /** * @brief 自我删除包括孩子在内 */ virtual void Delete(); /** * @brief 为对象设置ID * @param[in] id 需要设置的ID信息 */ void SetID(const QUuid & id); /** * @brief 获取对象的ID * @return 对象ID */ QUuid GetID() const; /** * @brief 设置DBID, (以后将会替换掉SetID) * @param[in] id 设置的DBID */ void SetDBID(const long long id); /** * @brief 获得对象DBID * @return 对象的DBID */ long long GetDBID() const; /** * @brief 设置 owner ID,即所有者的ID,在工区以下节点,值为所属工区 ID,如果是工区,则为所属项目ID,如果是项目则为0 * @param[in] id ID */ void SetOwnerID(long long id); /** * @brief 获得 owner ID * @return 返回owner ID */ long long GetOwnerID() const; /** * @brief 设置对象的名字标识 * @param[in] name 名字标识 */ virtual void SetName(const QString & name); /** * @brief 获取对象对应的名字标识 * @return 名字标识 * */ virtual QString GetName() const; /** * @brief 得到该对象的物理路径 "/project/survey/name",即三段式路径,与数据树的路径无关 * @return 对象的物理路径 */ virtual QString GetPhysicalFile() const; /** * @brief 设置对象的属性类型 * @param[in] type 对象的属性类型 */ void SetType(const pai::ios::DATA_TYPE & type); /** * @brief 获取对象的属性类型 * @return 对象的属性类型 */ pai::ios::DATA_TYPE GetType() const; /** * @brief 获取对象的类型名称 * @return 对象的类型名称 */ QString GetTypeName() const; /** * @brief 得到包含所有祖先名字的全路径名字,各级之间的名字以/分割,数据树的真实路径 * @return 对象的全路径 */ QString GetVisibleFile() const; /** * @brief 得到包含所有祖先名字的全路径名字,各级之间的名字以/分割,数据树的真实路径 * @return 对象的全路径 * TODO 仅供测井项目使用 */ QString GetFullPathName() const{return GetVisibleFile();}; /** * @brief 设置对象的Icon名称 * @param[in] iconName Icon名称 */ void SetIconName(const QString & iconName); /** * @brief 获得对象的Icon名称 * @return 对象的Icon名称 */ QString GetIconName() const; /** * @brief 获得大图标名,目前是在普通小图标名字的后面添加"_big"来组合成的,所也图标的真实名字必须和该规则一致 * 如:小图标名:project.png,那么对应的大图标名必须是project_big.png * @return 大图标名 */ QString GetBigIconName() const; /** * @brief 获取对象的父对象 * @return 父对象 */ PaiObject* GetParent() const; void SetParent(PaiObject*PParent); /** * @brief 根据返回值的类型,返回相应类型的父指针,包括父类的父类, 但只返回最接近的一个。 * @return 父类指针,在未找到时返回NULL */ template< typename T > T* GetForebear() const { PaiObject* pParent = GetParent(); while(pParent) { T* pT = dynamic_cast< T* > (pParent); if(pT) { return pT; } pParent = pParent->GetParent(); } return NULL; } /** * @brief 根据类型ID,返回相应类型的父指针,包括父类的父类, 但只返回最接近的一个。 * @param[in] typeID 类型ID * @return 父类指针,在未找到时返回NULL */ PaiObject* GetForebear(const QUuid & typeID) const; /** * @brief 向该对象上添加字节点 * @param[in] pChild 子对象指针 * @param[in] mountTree 数据挂载到树上标识 * @return 是否添加成功 */ virtual bool AddChild(PaiObject* pChild, MountTree mountTree = MountOnTree); /** * @brief 在iIndex之前插入一个孩子,插入后这个孩子指向了iIndex * @param[in] index 插入的索引 * @param[in] pChild 待插入的孩子 * @return 是否插入成功 */ virtual bool InsertChild(int index, PaiObject *pChild); /** * @brief 删除孩子节点 * @param[in] pChild 孩子节点指针 * @param[in] deleteChild 是否将孩子节点移除 * @return 是否删除成功 */ virtual bool RemoveChild(PaiObject *pChild, bool deleteChild = false); /** * @brief 获得对象的所有孩子节点 * @param[in,out] children 孩子节点列表 */ void GetChildren(QList< PaiObject* > & children) const; /** * @brief 获得该对象孩子节点数目 * @return 孩子节点数目 */ int GetChildrenCount(); /** * @brief 判断对象是否有孩子节点 * @return 是否有孩子节点 */ bool HasChildren(); /** * @brief 在孩子中查找数据库ID为dbid的孩子(只查找第一级) * @param[in] dbid 要查找的数据库ID * @return 找到返回对象指针,未找到返回NULL */ PaiObject* GetChild(const long long dbid) const; /** * @brief 根据id查找对应的对象 * @param[in] id 对象ID * @return 查找到的对象指针 */ PaiObject* GetObject(const QUuid & id) const; /** * @brief 通过孩子数据库ID查询对象 * @param[in] dbid 要查询对象的数据库ID * @return 查找到的对象指针 */ PaiObject* GetObject(const long long dbid) const; /** * @brief 根据孩子名称查找对象 * @param[in] name 孩子名称 * @return 查找到的对象指针 */ PaiObject* GetObjectByName(const QString & name,int depth) const; /** * @brief 根据孩子名称查找对象 * @param[in] name 孩子名称 * @return 查找到的对象指针 */ PaiObject* GetObjectByName(const QString & name) const; /** * @brief 根据孩子的名字和类型得到孩子的指针 * @param[in] name 欲查找孩子的名字 * @param[in] objectType 欲查找孩子的类型 * @return 查找到的对象指针 */ PaiObject* GetObjectByName(const QString & name, const QUuid & objectType) const; /** * @brief 递归地找出第一个具有指定类型的孩子. * @param[in] typeID 对象类型标志符 * @param[in] depth 递归深度,默认值10000,即全部搜索,1:搜索到自己的孩子 2:搜索到孩子的孩子 ...一次类推 * @return 查找到的对象指针 */ PaiObject* GetObjectByType(const QUuid & typeID, int depth = 10000) const; /** * @brief 找出第一个具有指定类型的孩子.(只差找第一级) * @param[in] typeID 对象类型标志符 * @return 查找到的对象指针 */ PaiObject* GetChildByType(const QUuid & typeID) const; /** * @brief 递归地找出所有具有指定类型的孩子. * @param[in,out] children 返回的指定类型的所有孩子 * @param[in] typeID 对象类型标志符 * @param[in] depth 递归深度,默认值10000,即全部搜索,1:搜索到自己的孩子 2:搜索到孩子的孩子 ...一次类推 */ void GetObjectByType(QList< pai::objectmodel::PaiObject* > & children, const QUuid & typeID, int depth = 10000) const; /** * @brief 获得所有该对象包含的DBID为dbid的对象列表,包括自己 * @param[in] dbid 要获得对象的DBID * @return 获得的对象列表 */ QList< PaiObject* > GetObjects(const long long dbid) const; /** * @brief 获得所有该对象包含的对象列表,包括自己 * @return 获得的对象列表 */ QList< PaiObject* > GetObjects() const; /** * @brief 根据指定的相等条件获取满足条件的对像 * @param[in,out] children 返回的满足条件的对象集合 * @param[in] equalCondition 相等条件 */ template< typename T > void GetObjects(QList< pai::objectmodel::PaiObject* > & children, const pai::EqualCondition< pai::objectmodel::PaiObject, T > & equalCondition) { foreach(PaiObject* pChild, m_children) { if(equalCondition(pChild)) { children.append(pChild); } pChild->GetObjects(children, equalCondition); } }; /** * @brief 是否拥有指定标志 * @param [in] flag 指定标志 * @return 是否拥有指定标志 */ bool HasFlag(Flag flag) const; /** * @brief 是否存在指定权限 * @param[in] type 传入的权限类型 * @note 这里int传入的值是JIOService里EOperation中的枚举类型 * 目前由于有其他工程包含了paiObject.所以不能直接添加Jioservice中的枚举类型 * 暂时用整形表示传入的枚举类型,以后进行修改。 * @return 是否存在指定权限 */ virtual bool HasPermissionFlag(int type) const; /** * @brief 该对象是否被修改 * @return 注意该函数会递归每个child,只要有一个孩子被修改则返回真,如果本身以及所有孩子都未被修改则返回假 */ bool HasModified() const; /** * @brief 该对象是否被修改了数据 * @return 是否被修改了数据 */ bool HasDataModified() const; /** * @brief 设置同步时是否忽略该对象 * @param[in] ignore 是否忽略 */ void SetIgnoreSyncDB(bool ignore); /** * @brief 设置是否为Shadow节点 * @param[in] shadow 是否为影子节点 */ void SetShadowNode(bool shadow); /** * @brief 设置该节点是否有同步功能(是否有Refresh菜单) * @param[in] enable 是否有同步功能 */ void SetSyncabled(bool enable); /** * @brief 获得属性信息,目前个别类型的属性信息需要单独构建 * @return 属性信息 */ virtual QString GetProperties(); /** * @brief 写入数据库,新建的过程,如果已存在请用UpdateToDB * @param[in,out] pErrorMessage 如果发生错误,在将错误信息添进pErrorMessage * @return 是否写入成功 */ virtual bool Save(QString *pErrorMessage = NULL); /** * @brief 更新入数据库 * @param[in,out] pErrorMessage 如果发生错误,在将错误信息添进pErrorMessage * @return 是否更新成功 */ virtual bool Update(QString *pErrorMessage = NULL); /** * @brief 写入数据库,新建的过程,如果已存在请用UpdateToDB * @param[in,out] pErrorMessage 如果发生错误,在将错误信息添进pErrorMessage * @return 是否写入成功 */ virtual bool SaveToDB(QString *pErrorMessage = NULL); /** * @brief 更新入数据库 * @param[in,out] pErrorMessage 如果发生错误,在将错误信息添进pErrorMessage * @return 是否更新成功 */ virtual bool UpdateToDB(QString *pErrorMessage = NULL); /** * @brief 在数据库中将该对象置于活动或非活动状态 * @param[in] status 活跃或非活跃标志(PaiObject::ACTIVE / PaiObject::INACTIVE) * @param[in,out] pErrorMessage 如果发生错误,在将错误信息添进pErrorMessage * @return 是否设置成功 */ virtual bool EnableToDB(const int & status, QString *pErrorMessage = NULL); /** * @brief 重新加载数据,不加载孩子,会调用Load函数 * @return 是否加载成功 */ bool Reload(); /** * @brief 同步该对象,包括数据,包括自身的数据和孩子的数据 * @param[in] mode 同步方式 * @return 是否同步成功 */ bool SyncDB(pai::SyncModes mode); /** * @brief 同步该对象的孩子,包括数据,但不包括自身的数据 * @param[in] recursion 是否同时同步所有子代 * @return 是否同步成功 */ bool SyncChildren(bool recursion); /** * @brief 获得最近缓冲的属性信息 * @return 最近缓冲的属性信息 */ QString GetBackupProperties() const; /** * @brief 得到已指定前缀加自然数命名的下一个孩子的名字 * @param[in] childNamePrefix 孩子名字的前缀 * @return 得到的孩子名称 */ QString GetNextChildName(const QString & childNamePrefix); /** * @brief 设置是否会发出EventAgent信号 * @param[in] yes 为真时将发射EventAgent信号,默认为真 */ void SetEventEnabled(bool yes); /** * @brief 获取是否会发出EventAgent信号 * @return 是否会发出EventAgent信号 */ bool IsEventEnabled(); /** * @brief 获取是否是大数据对象 * @return 是否是大数据对象 */ virtual bool IsBigDataObject() const; /** * @brief 将该对象显示为关闭状态 * @param[in,out] pErrorMessage 如果发生错误,在将错误信息添进pErrorMessage * @return 是否关闭成功 */ bool CloseObject(QString *pErrorMessage = NULL); /** * @brief 将该对象显示为打开状态 * @return 是否打开成功 */ bool OpenObject(); /** * @brief 设置是否要展开显示子对象 * @param[in] expand 是否要展开显示子对象 */ void SetExpand(bool expand); /** * @brief 获得时间戳,可以用来判断两个数据是否一致,或某数据是否需要更新 * @return 时间戳 */ long long GetTimeStamp() const; /** * @brief 通过比较的类型,比较两个对象的大小 * @param[in] pSrc 比较对象 * @param[in] pDest 被比较对象 * @param[in] key 比较类型关键字 * @return 即 *pSrc - *pDest 的值 */ static int SortDataCompare(PaiObject *pSrc, PaiObject *pDest, const SortKeyFlag key); /********************************************************** * 以下虚函数请务必在派生类中重新定义 * * 否则可能出现数据不对的情况,当然不是全 * * 部派生类都会调用到,但是定义后会更安全 * **********************************************************/ /** * @brief 对对象重命名 * @param[in] newName 新名称 * @param[in] override 如果新名称已经存在,是否进行覆盖的标识 */ virtual void Rename(const QString & newName, OverrideFlag override = NoOverride); /** * @brief 删除该对系对应的资源(数据库、HDFS...) * @param[in,out] pErrorMessage 如果发生错误,在将错误信息添进pErrorMessage * @return 是否删除成功 */ virtual bool Erase(QString *pErrorMessage = NULL); /** * @brief 加载DBID为dbid的数据,不加载孩子 * @param[in] dbid DBID * @return 是否加载成功 */ virtual bool Load(const long long dbid); /** * @brief 克隆参数对象 * @param[in] srcObject 源对象 * @note 派生类实现的时候,需掉在最后调用基类函数,不时所有的信息都会拷贝,请慎重使用该函数 */ virtual void Clone(const PaiObject & srcObject); /** * @brief 尝试删除对象,如果没法删除将返回无法删除的原因 * @param[in,out] message 无法删除的原因,只有当返回false时,才有效 * @return 判断是否可以删除 */ virtual bool TryDelete(QString & message); /** * @brief 添加获取对象占用内存大小的接口,供数据树内存查看工具调用 * @return 对象占用内存大小 */ virtual int GetMemorySize(); /** * @brief 获得要刷新的孩子列表 * @param[in,out] children 孩子列表 * @return 是否获得成功 */ virtual bool GetSyncChildren(QList< PaiObject* > & children); /** * @brief 根据owner id,获得owner下属于该类型所有的节点 * @param[in] ownerID 获得节点需要提供的宿主节点ID * @param[in] ownerType 获得节点需要提供的宿主节点类型 * @return owner下属于该类型所有的节点 */ virtual QList GetBrothers(long long ownerID, const QUuid & ownerType); protected: /** * @brief 设置该对象是否拥有指定标志 * @param[in] flag 指定标志 * @param[in] enable 标识该标记是否拥有 */ void SetFlagEnable(Flag flag, bool enable); /** * @brief 设置该对象是否被修改过 * @param[in] modified 是否被修改过 * @param[in] recursive 是否递归设置孩子的修改状态 */ void SetModified(bool modified, bool recursive); /** * @brief 删除所有孩子并释放所有孩子的内存 */ void ReleaseChildren(); /** * @brief 获得所有该对象包含的对象,包括自己 * @param[in,out] objects 获得的对象指针 */ void GetObjects(QList< PaiObject* > & objects) const; /** * @brief 获得节点排序的依据数据 * @param[in] key 排序的依据类型 * @return 排序比较的数据 */ virtual QVariant GetSortData(const SortKeyFlag key) const; /** * @brief 获取对象的创建时间 * @return 对象的创建时间 */ virtual long long GetCreateTime() const; /** * @brief 添加Load Loading 节点,只有当没有孩子时才会添加成功 * @param[in] mountTree 数据挂载到树上标识 * @return 是否添加成功 */ bool AddLazyLoadChild(MountTree mountTree = MountOnTree); /** * @brief 删除 Lazy Loading孩子节点 * @return 是否删除成功 */ bool RemoveLazyLoadChild(); /** * @brief 同步孩子节点信息 * @param[in] children 需要同步的孩子节点列表 */ void SyncChildren(QList< PaiObject* > & children); /** * @brief 设置对象的类型名称 * @param[in] typeName 对象的类型名称 */ void SetTypeName(const QString & typeName); /** * @brief 同步刷新后的必要信息,即从最新的对象(latestObject)中,取出必要的信息同步本对象 * @param[in] latestObject 有最新数据的对象 * @note 必要的信息只包括“name”和"time stamp" */ void SyncRefreshMsg(const PaiObject & latestObject); /** * @brief 设置时间戳,可以用来判断两个数据是否一致,或某数据是否需要更新 * @param[in] timeStamp 时间戳 */ void SetTimeStamp(const long long timeStamp); /** * @brief 添加自定的字符串比较函数,比较规则为当字符串不同时依据字符表顺序排序, * 如果只是字母大小写不同,则大写字符排在小写字母之前 * @param[in] tag1 需要标记的字符串 * @param[in] tag2 需要标记的字符串 * @return 两字符串有个相异字符Ascii码值的差值,整数表示后者在前,负数表示前者在前,0表示字符串无差异 */ static int SpecialCompare(const QString & tag1, const QString & tag2); public: // static pai::objectmodel::PaiObjectEventAgent m_EventAgent; ///< 全局事件类 protected: int m_flags; ///< 当前对象标识 QList< PaiObject* > m_children; ///< 记录孩子对象列表 QString m_properties; ///< 备份的属性信息 private: PaiObject *m_pParent; ///< 对象的父节点 long long m_OwnerID; ///< 即所有者的ID,在工区以下节点,值为所属工区ID,如果是工区,则为所属项目ID,如果是项目则为0, 无效:-1 QUuid m_id; ///< 对象ID long long m_dbid; ///< 对象dbid QString m_name; ///< 对象的名字 QString m_IconName; ///< 小图标 QString m_TypeName; ///< 用来表示类型名 long long m_TimeStamp; ///< 时间戳,用来记录对象的更新情况 bool m_EventEnabled; ///< 是否打开该对象与集中信号管理的连接 volatile bool m_SyncLockFlag; ///< 当由两个或多个线程在同时调用Sync函数的时候,降低添加相同孩子的几率 pai::ios::DATA_TYPE m_type; ///< 数据类型 QMutex *m_pChildMutex; ///< 当添加或删除孩子时加锁 }; } } #endif ///< PAI_FRAME_IOBJECTMODEL_PAIOBJECT_H