1343 lines
34 KiB
C++
1343 lines
34 KiB
C++
/**
|
||
* @file PaiObject.cpp
|
||
* @date 2013-03-15
|
||
*/
|
||
#include <QFile>
|
||
#include <QTime>
|
||
#include <QTextStream>
|
||
#include <QMutex>
|
||
#include <QObject>
|
||
|
||
#include "PaiObject.h"
|
||
#include "PaiObjectRecycler.h"
|
||
#include "PaiHtmlProperties.h"
|
||
#include "PaiLazyLoadNode.h"
|
||
// #include "error.h"
|
||
// #include "Log.h"
|
||
#include "PaiMetaTypes.h"
|
||
|
||
using namespace pai::objectmodel;
|
||
|
||
// IMPLEMENT_PAI_OBJECT(PaiObject)
|
||
|
||
// pai::objectmodel::PaiObjectEventAgent pai::objectmodel::PaiObject::m_EventAgent;
|
||
|
||
PaiObject::PaiObject(PaiObject* pParent) :
|
||
m_flags(VisibibleOnTree | Syncabled),
|
||
m_properties(QObject::tr("Loading...")),
|
||
m_pParent(pParent),
|
||
m_OwnerID(-1),
|
||
m_id(QUuid::createUuid()),
|
||
m_dbid(0),
|
||
m_name(""), // 初始化名字必须为空,请不要轻易修改其初始化方法
|
||
m_TimeStamp(0),
|
||
m_EventEnabled(false), // 默认都不可以发送事件
|
||
m_SyncLockFlag(false),
|
||
m_type(pai::ios::UNKNOW)
|
||
{
|
||
m_pChildMutex = new QMutex();
|
||
}
|
||
|
||
PaiObject::~PaiObject()
|
||
{
|
||
if(m_children.count() > 0)
|
||
{
|
||
ReleaseChildren();
|
||
}
|
||
delete m_pChildMutex;
|
||
}
|
||
|
||
void PaiObject::Delete()
|
||
{
|
||
// ReleaseChildren();
|
||
|
||
// // 并不真正释放该控件,而是放入回收站来管理,由回收站决定何时释放
|
||
// m_pParent = NULL;
|
||
// GetObjectModelService()->GetObjectRecycler()->Push(this);
|
||
}
|
||
|
||
void PaiObject::ReleaseChildren()
|
||
{
|
||
// QList< PaiObject* >::iterator it = m_children.begin();
|
||
// while(it != m_children.end())
|
||
// {
|
||
// m_EventAgent.RemoveObjectChild(this, (*it));
|
||
// (*it)->Delete();
|
||
// ++it;
|
||
// }
|
||
// m_children.clear();
|
||
}
|
||
|
||
void PaiObject::Clone(const PaiObject & srcObject)
|
||
{
|
||
if(GetTypeID() != srcObject.GetTypeID())
|
||
{
|
||
QString errMsg = QObject::tr("Clone PaiObject failed! the type of %1 seems different with %2!").
|
||
arg(srcObject.GetName()).arg(GetName());
|
||
// throw pai::error::invalid_argument(errMsg.toStdString());
|
||
}
|
||
|
||
// m_id 不在Clone()函数拷贝之列
|
||
m_dbid = srcObject.m_dbid;
|
||
m_IconName = srcObject.m_IconName;
|
||
m_TypeName = srcObject.m_TypeName;
|
||
m_type = srcObject.m_type;
|
||
m_properties = srcObject.m_properties;
|
||
m_flags = srcObject.m_flags;
|
||
m_TimeStamp = srcObject.m_TimeStamp;
|
||
|
||
// 直接用m_name进行比对,GetName是虚函数,可能返回的不是m_name的值
|
||
if(m_name != srcObject.m_name)
|
||
{
|
||
SetName(srcObject.m_name); // a signal will be emit to changed the name of data tree node
|
||
}
|
||
}
|
||
|
||
void PaiObject::SetType(const pai::ios::DATA_TYPE & type)
|
||
{
|
||
m_type = type;
|
||
}
|
||
|
||
pai::ios::DATA_TYPE PaiObject::GetType() const
|
||
{
|
||
return m_type;
|
||
}
|
||
|
||
void PaiObject::SetID(const QUuid & id)
|
||
{
|
||
m_id = id;
|
||
}
|
||
|
||
QUuid PaiObject::GetID() const
|
||
{
|
||
return m_id;
|
||
}
|
||
|
||
void PaiObject::SetDBID(long long id)
|
||
{
|
||
if(m_dbid != id)
|
||
{
|
||
m_dbid = id;
|
||
|
||
// m_EventAgent.ObjectPropertyChanged(this, QString("DBID"), QVariant(m_dbid));
|
||
}
|
||
}
|
||
|
||
long long PaiObject::GetDBID() const
|
||
{
|
||
return m_dbid;
|
||
}
|
||
|
||
void PaiObject::SetOwnerID(long long id)
|
||
{
|
||
m_OwnerID = id;
|
||
}
|
||
|
||
long long PaiObject::GetOwnerID() const
|
||
{
|
||
return m_OwnerID;
|
||
}
|
||
|
||
PaiObject* PaiObject::GetParent() const
|
||
{
|
||
return m_pParent;
|
||
}
|
||
void PaiObject::SetParent(PaiObject*pParent)
|
||
{
|
||
m_pParent=pParent;
|
||
}
|
||
|
||
bool PaiObject::AddLazyLoadChild(MountTree mountTree)
|
||
{
|
||
if(GetChildrenCount() == 0)
|
||
{
|
||
bool bHasModified = HasModified();
|
||
bool bAdded = AddChild(new PaiLazyLoadNode, mountTree);
|
||
SetModified(bHasModified, false);
|
||
return bAdded;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
bool PaiObject::RemoveLazyLoadChild()
|
||
{
|
||
foreach(PaiObject *pChild, m_children)
|
||
{
|
||
if(pChild->GetTypeID() == QUuid(PaiLazyLoadNode::GetTypeIDString()))
|
||
{
|
||
bool bHasModified = HasModified();
|
||
bool bRemoved = RemoveChild(pChild, true);
|
||
SetModified(bHasModified, false);
|
||
return bRemoved;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
bool PaiObject::AddChild(PaiObject *pChild, MountTree mountTree)
|
||
{
|
||
m_pChildMutex->lock();
|
||
|
||
if(!m_children.contains(pChild))
|
||
{
|
||
foreach(PaiObject *pChildObj, m_children)
|
||
{
|
||
if((pChildObj->GetID() == pChild->GetID()) ||
|
||
((pChild->GetDBID() != 0) && (pChildObj->GetDBID() == pChild->GetDBID())))
|
||
{
|
||
m_pChildMutex->unlock();
|
||
return false;
|
||
}
|
||
}
|
||
|
||
if(pChild->m_pParent != this)
|
||
{
|
||
pChild->m_pParent = this;
|
||
}
|
||
|
||
SetFlagEnable(Modified, true);
|
||
|
||
m_children.push_back(pChild);
|
||
|
||
if(mountTree == MountOnTree)
|
||
{
|
||
// m_EventAgent.AddObjectChildren(this, QList< PaiObject* > () << pChild);
|
||
}
|
||
|
||
m_pChildMutex->unlock();
|
||
|
||
return true;
|
||
}
|
||
|
||
m_pChildMutex->unlock();
|
||
|
||
return false;
|
||
}
|
||
|
||
void PaiObject::SyncChildren(QList< PaiObject* > & children)
|
||
{
|
||
m_pChildMutex->lock();
|
||
|
||
// 检查并去掉重复添加项
|
||
QString repearItems;
|
||
for(int i = 0; i < children.count(); ++i)
|
||
{
|
||
PaiObject *pSrcObj = children.at(i);
|
||
|
||
for(int j = i + 1; j < children.count(); ++j)
|
||
{
|
||
PaiObject *pDestObj = children.at(j);
|
||
|
||
if((!pSrcObj) || ((pSrcObj->GetDBID() != 0) && (pSrcObj->GetDBID() == pDestObj->GetDBID())))
|
||
{
|
||
repearItems += (QObject::tr("%1:%2\n").arg(pDestObj->GetName()).arg(pDestObj->GetDBID()));
|
||
|
||
delete pDestObj;
|
||
children.removeOne(pDestObj);
|
||
--j; // 下一次循环仍在该位置
|
||
}
|
||
}
|
||
}
|
||
|
||
QList< PaiObject* > removedData = m_children;
|
||
QList< PaiObject* > addedData;
|
||
QList< PaiObject* > needUpdateData;
|
||
QList< PaiObject* > newUpdateData;
|
||
|
||
// 查询需要新添加和要删除的孩子
|
||
foreach(PaiObject *pChild, children)
|
||
{
|
||
PaiObject *pTreeData = GetChild(pChild->GetDBID());
|
||
if(pTreeData)
|
||
{
|
||
removedData.removeAll(pTreeData);
|
||
newUpdateData.append(pChild);
|
||
needUpdateData.append(pTreeData);
|
||
}
|
||
else
|
||
{
|
||
if(!pChild->HasFlag(Closed) && pChild->HasFlag(Syncabled))
|
||
{
|
||
pChild->AddLazyLoadChild(MountNoTree);
|
||
}
|
||
pChild->m_pParent = this;
|
||
addedData.append(pChild);
|
||
}
|
||
}
|
||
children.clear(); // 尽早清除,防止再被使用
|
||
|
||
SetFlagEnable(Modified, true);
|
||
|
||
// 添加新增的孩子
|
||
if(!addedData.empty())
|
||
{
|
||
m_children.append(addedData);
|
||
}
|
||
|
||
// RemoveChild也会加锁,所以为了不发生死锁,先解锁
|
||
m_pChildMutex->unlock();
|
||
|
||
// 同步去除的孩子
|
||
foreach(PaiObject *pChild, removedData)
|
||
{
|
||
if(!pChild->HasFlag(PaiObject::IgnoreSyncDB))
|
||
{
|
||
RemoveChild(pChild, true);
|
||
}
|
||
}
|
||
removedData.clear();
|
||
|
||
// 更新需要更新的对象
|
||
for(int i = 0; i < needUpdateData.count(); ++i)
|
||
{
|
||
if(newUpdateData.at(i)->GetTimeStamp() > needUpdateData.at(i)->GetTimeStamp())
|
||
{
|
||
needUpdateData.at(i)->SyncRefreshMsg(*(newUpdateData.at(i)));
|
||
delete newUpdateData.at(i);
|
||
}
|
||
}
|
||
needUpdateData.clear();
|
||
newUpdateData.clear();
|
||
|
||
// // 解锁之后再发送信号,防止在主线程执行死锁
|
||
// if(!addedData.empty())
|
||
// {
|
||
// m_EventAgent.AddObjectChildren(this, addedData);
|
||
|
||
// // 向数据树发送关闭信号(如果将来采取更换图标的方式,则不需要以下调用)
|
||
// foreach(PaiObject *pChild, addedData)
|
||
// {
|
||
// if(pChild->HasFlag(Closed))
|
||
// {
|
||
// m_EventAgent.CloseObject(pChild, true);
|
||
// }
|
||
// }
|
||
// }
|
||
|
||
// if(!repearItems.isEmpty())
|
||
// {
|
||
// pai::log::Error((QObject::tr("Refresh \"%1\" failed! Found repeat item:\n%2").arg(GetName()).arg(repearItems)).toStdString());
|
||
// //m_EventAgent.RefreshObjectFailed(this, QObject::tr("Refresh \"%1\" failed! Found repeat item:\n%2").arg(repearItems));
|
||
// }
|
||
}
|
||
|
||
bool PaiObject::InsertChild(int index, PaiObject *pChild)
|
||
{
|
||
if((pChild == NULL) || (index < 0) || (index > m_children.count()))
|
||
{
|
||
return false;
|
||
}
|
||
|
||
m_pChildMutex->lock();
|
||
|
||
if(!m_children.contains(pChild))
|
||
{
|
||
foreach(PaiObject *pChildObj, m_children)
|
||
{
|
||
if((pChildObj->GetID() == pChild->GetID()) ||
|
||
((pChild->GetDBID() != 0) && (pChildObj->GetDBID() == pChild->GetDBID())))
|
||
{
|
||
m_pChildMutex->unlock();
|
||
return false;
|
||
}
|
||
}
|
||
|
||
if(pChild->m_pParent != this)
|
||
{
|
||
pChild->m_pParent = this;
|
||
}
|
||
|
||
SetFlagEnable(Modified, true);
|
||
|
||
m_children.insert(index, pChild);
|
||
|
||
// m_EventAgent.InsertObjectChild(this, pChild, index);
|
||
|
||
m_pChildMutex->unlock();
|
||
|
||
return true;
|
||
}
|
||
|
||
m_pChildMutex->unlock();
|
||
|
||
return false;
|
||
}
|
||
|
||
bool PaiObject::RemoveChild(PaiObject *pChild, bool deleteChild)
|
||
{
|
||
m_pChildMutex->lock();
|
||
|
||
int nRemoved = m_children.removeAll(pChild);
|
||
|
||
SetFlagEnable(Modified, true);
|
||
|
||
if(deleteChild && (nRemoved == 1))
|
||
{
|
||
pChild->SetFlagEnable(Deleting, true);
|
||
// m_EventAgent.RemoveObjectChild(this, pChild);
|
||
pChild->Delete();
|
||
}
|
||
|
||
m_pChildMutex->unlock();
|
||
|
||
return nRemoved == 1;
|
||
}
|
||
|
||
bool PaiObject::CloseObject(QString *pErrorMessage)
|
||
{
|
||
if(!HasFlag(Closed)) // 如果没有关闭则采取关闭操作
|
||
{
|
||
if(TryDelete(*pErrorMessage) == false)
|
||
{
|
||
return false;
|
||
}
|
||
// 更改数据库
|
||
if(!EnableToDB(INACTIVE))
|
||
{
|
||
return false;
|
||
}
|
||
|
||
// 设置关闭标志
|
||
SetFlagEnable(PaiObject::Closed, true);
|
||
|
||
// 去掉子项,这个必须在发送关闭信号之前,否则影响主工具栏对action的检查,见34860
|
||
foreach(PaiObject *pObj, m_children)
|
||
{
|
||
RemoveChild(pObj, true);
|
||
}
|
||
|
||
// 向数据树发送关闭信号(如果将来采取更换图标的方式,则不需要以下调用)
|
||
// m_EventAgent.CloseObject(this, true);
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
bool PaiObject::OpenObject()
|
||
{
|
||
if(HasFlag(Closed)) // 如果没有打开则采取打开操作
|
||
{
|
||
// // 更改数据库
|
||
// if(!EnableToDB(ACTIVE))
|
||
// {
|
||
// return false;
|
||
// }
|
||
|
||
// // 设置打开标志
|
||
// SetFlagEnable(PaiObject::Closed, false);
|
||
|
||
// // 挂载子项,这里从异步改为同步,是因为下面发送信号引起的主工具栏检查action权限时,需要工程先挂载好工区,否则判断错误。见34860
|
||
// SyncDB(Own | Children | Force);
|
||
|
||
// // 向数据树发送打开信号(如果将来采取更换图标的方式,则不需要以下调用)
|
||
// m_EventAgent.CloseObject(this, false);
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
void PaiObject::SetExpand(bool expand)
|
||
{
|
||
// m_EventAgent.ObjectPropertyChanged(this, QString("NodeExpand"), QVariant(expand));
|
||
}
|
||
|
||
void PaiObject::GetChildren(QList< PaiObject* > & children) const
|
||
{
|
||
children = m_children;
|
||
}
|
||
|
||
int PaiObject::GetChildrenCount()
|
||
{
|
||
return m_children.count();
|
||
}
|
||
|
||
bool PaiObject::HasChildren()
|
||
{
|
||
return !m_children.isEmpty();
|
||
}
|
||
|
||
PaiObject* PaiObject::GetChild(const long long dbid) const
|
||
{
|
||
foreach(PaiObject* pChild, m_children)
|
||
{
|
||
if(pChild)
|
||
{
|
||
if(pChild->GetDBID() == dbid)
|
||
{
|
||
return pChild;
|
||
}
|
||
}
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
PaiObject* PaiObject::GetObject(const QUuid & id) const
|
||
{
|
||
if(this->m_id == id)
|
||
{
|
||
return const_cast< pai::objectmodel::PaiObject* > (this);
|
||
}
|
||
foreach(PaiObject *pChild, m_children)
|
||
{
|
||
if(pChild != NULL)
|
||
{
|
||
PaiObject *pFindObj = pChild->GetObject(id);
|
||
if(pFindObj != NULL)
|
||
{
|
||
return pFindObj;
|
||
}
|
||
}
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
PaiObject* PaiObject::GetObject(const long long dbid) const
|
||
{
|
||
if(dbid == m_dbid)
|
||
{
|
||
return const_cast< pai::objectmodel::PaiObject* > (this);
|
||
}
|
||
foreach(PaiObject *pChild, m_children)
|
||
{
|
||
if(pChild != NULL)
|
||
{
|
||
PaiObject* pFindObj = pChild->GetObject(dbid);
|
||
if(pFindObj)
|
||
{
|
||
return pFindObj;
|
||
}
|
||
}
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
void PaiObject::GetObjects(QList< PaiObject* > & objects) const
|
||
{
|
||
objects.append(const_cast< PaiObject* > (this));
|
||
|
||
foreach(PaiObject *pChild, m_children)
|
||
{
|
||
if(pChild != NULL)
|
||
{
|
||
pChild->GetObjects(objects);
|
||
}
|
||
}
|
||
}
|
||
|
||
QList< PaiObject* > PaiObject::GetObjects(const long long dbid) const
|
||
{
|
||
QList< PaiObject* > ids;
|
||
QList< PaiObject* > objs;
|
||
|
||
GetObjects(objs);
|
||
|
||
foreach(PaiObject *pObj, objs)
|
||
{
|
||
if(pObj && (pObj->GetDBID() == dbid))
|
||
{
|
||
ids.append(pObj);
|
||
}
|
||
}
|
||
|
||
return ids;
|
||
}
|
||
|
||
QList< PaiObject* > PaiObject::GetObjects() const
|
||
{
|
||
QList< PaiObject* > objs;
|
||
GetObjects(objs);
|
||
return objs;
|
||
}
|
||
|
||
PaiObject* PaiObject::GetObjectByName(const QString & name,int depth) const
|
||
{
|
||
if(this->m_name == name)
|
||
{
|
||
return const_cast< pai::objectmodel::PaiObject* > (this);
|
||
}
|
||
depth--;
|
||
if(depth>=0)
|
||
foreach(PaiObject *pChild, m_children)
|
||
{
|
||
PaiObject *pFindObj = pChild->GetObjectByName(name,depth);
|
||
if(pFindObj != NULL)
|
||
{
|
||
return pFindObj;
|
||
}
|
||
}
|
||
return NULL;
|
||
}
|
||
PaiObject* PaiObject::GetObjectByName(const QString & name) const
|
||
{
|
||
if(this->m_name == name)
|
||
{
|
||
return const_cast< pai::objectmodel::PaiObject* > (this);
|
||
}
|
||
foreach(PaiObject *pChild, m_children)
|
||
{
|
||
PaiObject *pFindObj = pChild->GetObjectByName(name);
|
||
if(pFindObj != NULL)
|
||
{
|
||
return pFindObj;
|
||
}
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
PaiObject* PaiObject::GetObjectByName(const QString & name, const QUuid & objectType) const
|
||
{
|
||
QString name1=name;
|
||
if(name1.indexOf("(3")>=0) {
|
||
name1=name1.replace("(3",":");
|
||
}
|
||
if((this->GetTypeID() == objectType) && (this->m_name == name1))
|
||
{
|
||
return const_cast< pai::objectmodel::PaiObject* > (this);
|
||
}
|
||
foreach(PaiObject *pChild, m_children)
|
||
{
|
||
PaiObject *pFindObject = pChild->GetObjectByName(name1, objectType);
|
||
if(pFindObject != NULL)
|
||
{
|
||
return pFindObject;
|
||
}
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
PaiObject* PaiObject::GetChildByType(const QUuid & typeID) const
|
||
{
|
||
foreach(PaiObject *pChild, m_children)
|
||
{
|
||
if(pChild->GetTypeID() == typeID)
|
||
{
|
||
return const_cast< pai::objectmodel::PaiObject* > (pChild);
|
||
}
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
PaiObject* PaiObject::GetObjectByType(const QUuid & typeID, int depth) const
|
||
{
|
||
if(this->GetTypeID() == typeID)
|
||
{
|
||
return const_cast< pai::objectmodel::PaiObject* > (this);
|
||
}
|
||
|
||
depth--;
|
||
if(depth >= 0)
|
||
{
|
||
foreach(PaiObject *pChild, m_children)
|
||
{
|
||
if(pChild)
|
||
{
|
||
pChild = pChild->GetObjectByType(typeID, depth);
|
||
if(pChild)
|
||
{
|
||
return pChild;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
void PaiObject::GetObjectByType(QList< pai::objectmodel::PaiObject* > & children, const QUuid & typeID, int depth) const
|
||
{
|
||
if(this->GetTypeID() == typeID)
|
||
{
|
||
children.append(const_cast< pai::objectmodel::PaiObject* > (this));
|
||
}
|
||
|
||
depth--;
|
||
if(depth >= 0)
|
||
{
|
||
foreach(PaiObject *pChild, m_children)
|
||
{
|
||
if(pChild)
|
||
{
|
||
pChild->GetObjectByType(children, typeID, depth);
|
||
}
|
||
}
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
void PaiObject::SetName(const QString & newName)
|
||
{
|
||
QString oldName(m_name);
|
||
if(oldName != newName)
|
||
{
|
||
m_name = newName;
|
||
|
||
SetFlagEnable(Modified, true);
|
||
|
||
// // 对象名发生改变,该信号可以通知数据树,更新为最新的名字
|
||
// m_EventAgent.ObjectPropertyChanged(this, QString("Name"), QVariant(m_name));
|
||
|
||
// // 对象被重命名,初始化命名,不算重命名,这里排除
|
||
// if(!oldName.isEmpty())
|
||
// {
|
||
// m_EventAgent.RenamedObject(this, newName, oldName);
|
||
// }
|
||
}
|
||
}
|
||
|
||
QString PaiObject::GetName() const
|
||
{
|
||
return m_name;
|
||
}
|
||
|
||
QString PaiObject::GetPhysicalFile() const
|
||
{
|
||
return QString("");
|
||
}
|
||
|
||
QString PaiObject::GetVisibleFile() const
|
||
{
|
||
QString fullPathName(m_name);
|
||
PaiObject* pParent = m_pParent;
|
||
while(pParent != NULL)
|
||
{
|
||
if(pParent->m_name != "")
|
||
{
|
||
fullPathName.prepend("/");
|
||
fullPathName.prepend(pParent->m_name);
|
||
}
|
||
pParent = pParent->m_pParent;
|
||
}
|
||
return fullPathName.prepend("/");
|
||
}
|
||
|
||
void PaiObject::SetIconName(const QString & iconName)
|
||
{
|
||
m_IconName = iconName;
|
||
}
|
||
|
||
QString PaiObject::GetIconName() const
|
||
{
|
||
return m_IconName;
|
||
}
|
||
|
||
QString PaiObject::GetBigIconName() const
|
||
{
|
||
QString iconName = m_IconName;
|
||
iconName.insert(iconName.lastIndexOf('.'), "_big");
|
||
|
||
return iconName;
|
||
}
|
||
|
||
bool PaiObject::HasFlag(Flag flag) const
|
||
{
|
||
return (m_flags & flag) == flag;
|
||
}
|
||
|
||
void PaiObject::SetFlagEnable(Flag flag, bool enable)
|
||
{
|
||
if(enable)
|
||
{
|
||
m_flags |= flag;
|
||
}
|
||
else
|
||
{
|
||
m_flags = m_flags & ~flag;
|
||
}
|
||
// m_EventAgent.ObjectPropertyChanged(this, QString("Flag"), QVariant(m_flags));
|
||
}
|
||
|
||
bool PaiObject::HasDataModified() const
|
||
{
|
||
return HasFlag(DataModified);
|
||
}
|
||
|
||
bool PaiObject::HasModified() const
|
||
{
|
||
if(HasFlag(Modified))
|
||
{
|
||
return true;
|
||
}
|
||
|
||
foreach(PaiObject *pChild, m_children)
|
||
{
|
||
if(pChild->HasModified())
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
void PaiObject::SetModified(bool modified, bool recursive)
|
||
{
|
||
SetFlagEnable(Modified, modified);
|
||
|
||
if(recursive)
|
||
{
|
||
foreach(PaiObject *pChild, m_children)
|
||
{
|
||
pChild->SetModified(modified, recursive);
|
||
}
|
||
}
|
||
}
|
||
|
||
QString PaiObject::GetNextChildName(const QString & childNamePrefix)
|
||
{
|
||
int nOrderNum = 0;
|
||
QString nextChildName = childNamePrefix + "1";//缺省值,如果没有孩子则返回它
|
||
|
||
int i = 0;
|
||
while(i != m_children.size())
|
||
{
|
||
nextChildName = childNamePrefix + QString::number(++nOrderNum);
|
||
i = 0;
|
||
foreach(PaiObject *pChild, m_children)
|
||
{
|
||
if(pChild->GetName() == nextChildName)
|
||
{
|
||
break;
|
||
}
|
||
++i;
|
||
}
|
||
}
|
||
return nextChildName;
|
||
}
|
||
|
||
bool PaiObject::Save(QString * /*pErrorMessage*/)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
bool PaiObject::Update(QString * /*pErrorMessage*/)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
bool PaiObject::SaveToDB(QString * /*pErrorMessage*/)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
bool PaiObject::UpdateToDB(QString * /*pErrorMessage*/)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
bool PaiObject::Erase(QString * /*pErrorMessage*/)
|
||
{
|
||
// 此处抛出异常,既可以保证需要删除的派生类有提示,也可防止不能删除的派生类被删除
|
||
// throw pai::error::io_error("Please define [Erase] function in derived class!");
|
||
return false;
|
||
}
|
||
|
||
bool PaiObject::EnableToDB(const int& /*status*/, QString * /*pErrorMessage*/)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
QString PaiObject::GetProperties()
|
||
{
|
||
// try
|
||
{
|
||
std::vector< std::vector< pai::ios::property::PropertyItem > > itemgroup;
|
||
pai::ios::property::Property property;
|
||
property.GetProperty(GetDBID(), GetType(), itemgroup);
|
||
QString typeName;
|
||
if((itemgroup.size()) > 0 && (itemgroup.at(0).size() > 0))
|
||
{
|
||
typeName = "Type: " + QString(itemgroup.at(0).at(0).GetPropertyValue().c_str());
|
||
}
|
||
PaiHtmlProperties properties(GetBigIconName(), GetName(), typeName);
|
||
|
||
m_properties = properties.GetHtml(itemgroup); // 更新备份的属性信息加快相应速度
|
||
return m_properties;
|
||
}
|
||
// catch(pai::error::generic_error& e)
|
||
// {
|
||
// pai::log::Error(_FLF(QObject::tr("%1\nErrorCode:%2").arg(e.what()).arg(e.which()).toStdString()));
|
||
// return QObject::tr("Sorry, load properties failed!");
|
||
// }
|
||
// catch(std::exception &e)
|
||
// {
|
||
// pai::log::Error(_FLF(QObject::tr("Load properties filed:%1\n%2").arg(GetName()).arg(e.what()).toStdString()));
|
||
// return QObject::tr("Sorry, load properties failed!");
|
||
// }
|
||
// catch(...)
|
||
// {
|
||
// pai::log::Error(_FLF(QObject::tr("Unknown error when load properties for \"%1\"").arg(GetName()).toStdString()));
|
||
// return QObject::tr("Sorry, load properties failed!");
|
||
// }
|
||
}
|
||
|
||
QString PaiObject::GetBackupProperties() const
|
||
{
|
||
return m_properties;
|
||
}
|
||
|
||
void PaiObject::SetEventEnabled(bool yes)
|
||
{
|
||
m_EventEnabled = yes;
|
||
}
|
||
|
||
bool PaiObject::IsEventEnabled()
|
||
{
|
||
return m_EventEnabled;
|
||
}
|
||
|
||
bool PaiObject::IsBigDataObject() const
|
||
{
|
||
return false;
|
||
}
|
||
|
||
bool PaiObject::GetSyncChildren(QList< PaiObject* > & /*children*/)
|
||
{
|
||
return true;
|
||
}
|
||
|
||
QList<PaiObject*> PaiObject::GetBrothers(long long /*ownerID*/, const QUuid & /*ownerType*/)
|
||
{
|
||
return QList<PaiObject*>();
|
||
}
|
||
|
||
QString PaiObject::GetTypeName() const
|
||
{
|
||
return m_TypeName;
|
||
}
|
||
|
||
void PaiObject::SetTypeName(const QString & typeName)
|
||
{
|
||
m_TypeName = typeName;
|
||
}
|
||
|
||
bool PaiObject::Load(const long long /*dbid*/)
|
||
{
|
||
// 此处抛出异常,既可以保证需要从后台加载的派生类有提示,也可防止不能加载的派生类被错误加载
|
||
// throw pai::error::io_error("Please define [Load] function in derived class!");
|
||
return false;
|
||
}
|
||
|
||
bool PaiObject::Reload()
|
||
{
|
||
return Load(GetDBID());
|
||
}
|
||
|
||
bool PaiObject::SyncDB(pai::SyncModes mode)
|
||
{
|
||
// if(mode & pai::Own)
|
||
// {
|
||
// PaiObject *pObj = GetObjectModelService()->CreateObject(GetTypeID());
|
||
// if(pObj)
|
||
// {
|
||
// try
|
||
// {
|
||
// pObj->Load(GetDBID());
|
||
// //校验Load函数的DBID设置的正确性
|
||
// if(pObj->GetDBID() > 0 && pObj->GetDBID() != this->GetDBID())
|
||
// {
|
||
// throw pai::error::db_error("Load failure with database ID.", pai::error::ERR_NO_RESULT);
|
||
// }
|
||
// //更新与数据库不同步对象
|
||
// SyncRefreshMsg(*pObj);
|
||
// }
|
||
// catch(pai::error::generic_error & e)
|
||
// {
|
||
// if(e.which() == pai::error::ERR_NO_RESULT)
|
||
// {
|
||
// PaiObject * pParent = this->GetParent();
|
||
// if(pParent)
|
||
// {
|
||
// pParent->RemoveChild(this, true);
|
||
// delete pObj;
|
||
// pObj = NULL;
|
||
// return true;
|
||
// }
|
||
// }
|
||
|
||
// pai::log::Error(_FLF(QObject::tr("%1\nMore details:%2 ErrCode:%3") .arg(e.get_ui_message()).arg(
|
||
// e.what()).arg(e.which()).toStdString()));
|
||
// ::LogStackTrace(::GetStackTrace());
|
||
|
||
// // 此处异常信息应为已经格式化的用户可读信息,如不对,须在它处修改。
|
||
// m_EventAgent.RefreshObjectFailed(this, QObject::tr("Load %1 failed!").arg(e.what()));
|
||
// }
|
||
// catch(...)
|
||
// {
|
||
// pai::log::Error(_FLF(QObject::tr("Load \"%1\" failed!").arg(GetName()).toStdString()));
|
||
// ::LogStackTrace(::GetStackTrace());
|
||
|
||
// m_EventAgent.RefreshObjectFailed(this, QObject::tr("Load \"%1\" failed!").arg(GetName()));
|
||
// }
|
||
|
||
// delete pObj;
|
||
// pObj = NULL;
|
||
// }
|
||
// }
|
||
// if(mode & pai::Recursion)
|
||
// {
|
||
// return SyncChildren(true);
|
||
// }
|
||
// else if(mode & Children)
|
||
// {
|
||
// return SyncChildren(false);
|
||
// }
|
||
return true;
|
||
}
|
||
|
||
bool PaiObject::SyncChildren(bool recursion)
|
||
{
|
||
return true;
|
||
// // 降低同时多个线程同时同步统一个对象的几率
|
||
// while(m_SyncLockFlag)
|
||
// {
|
||
// // Sleep是以毫秒为单位,不要用QT的sleep函数,系统更改时间后,该函数会出问题
|
||
// turtle::GetTurtleAPI()->Sleep(1000);
|
||
// }
|
||
// m_SyncLockFlag = true;
|
||
|
||
// try
|
||
// {
|
||
// if(HasFlag(PaiObject::Closed) || !HasFlag(PaiObject::Syncabled))
|
||
// {
|
||
// m_SyncLockFlag = false;
|
||
// return true;
|
||
// }
|
||
|
||
// // 设置已同步标志位,该语句尽量考前以防止该函数同时被调用
|
||
// SetFlagEnable(PaiObject::ChildrenLoaded, true);
|
||
|
||
// QList< PaiObject* > children;
|
||
|
||
// QTime tmpTime(0, 0, 0, 0);
|
||
// tmpTime.start();
|
||
|
||
// bool success = GetSyncChildren(children);
|
||
|
||
// // ----------------- 记录接口相应时间,TODO 将会移除 ------------------------------
|
||
// int timeSpan = tmpTime.elapsed();
|
||
// QFile file("/tmp/refresh.csv");
|
||
// if(!file.exists())
|
||
// {
|
||
// file.open(QIODevice::Append | QIODevice::WriteOnly | QIODevice::Text);
|
||
// file.close();
|
||
// }
|
||
// if(!file.isOpen())
|
||
// {
|
||
// file.open(QIODevice::Append | QIODevice::WriteOnly | QIODevice::Text);
|
||
// }
|
||
// QTextStream txtOutput(&file);
|
||
// txtOutput << GetName() << "," << GetTypeName() << ", " << children.count() << " ," << timeSpan << endl;
|
||
// file.close();
|
||
|
||
// if(success)
|
||
// {
|
||
// // 去掉LazyLoad节点
|
||
// RemoveLazyLoadChild();
|
||
|
||
// // 同步节点孩子
|
||
// SyncChildren(children);
|
||
|
||
// // 备份属性信息,便于快速显示
|
||
// GetProperties();
|
||
|
||
// // 递归同步
|
||
// if(recursion)
|
||
// {
|
||
// foreach(PaiObject *pObject, m_children)
|
||
// {
|
||
// if(!HasFlag(PaiObject::Closed) && HasFlag(PaiObject::Syncabled))
|
||
// {
|
||
// pObject->SyncChildren(recursion);
|
||
// }
|
||
// }
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// m_EventAgent.RefreshObjectFailed(this, QObject::tr("Get children failed!"));
|
||
// }
|
||
|
||
// file.close();
|
||
|
||
// m_SyncLockFlag = false;
|
||
// return success;
|
||
// }
|
||
// catch(pai::error::generic_error & e)
|
||
// {
|
||
// m_SyncLockFlag = false;
|
||
|
||
// pai::log::Error(_FLF(QObject::tr("%1\nMore details:%2 ErrCode:%3")
|
||
// .arg(e.get_ui_message()).arg(e.what()).arg(e.which()).toStdString()));
|
||
// ::LogStackTrace(::GetStackTrace());
|
||
|
||
// // 此处异常信息应为已经格式化的用户可读信息,如不对,须在它处修改。
|
||
// m_EventAgent.RefreshObjectFailed(this, QObject::tr("Refresh \"%1\" failed! -- %2").arg(GetName()).arg(e.what()));
|
||
// return false;
|
||
// }
|
||
// catch(std::exception &e)
|
||
// {
|
||
// m_SyncLockFlag = false;
|
||
|
||
// pai::log::Error(_FLF(QObject::tr("%1").arg(e.what()).toStdString()));
|
||
// ::LogStackTrace(::GetStackTrace());
|
||
|
||
// m_EventAgent.RefreshObjectFailed(this, QObject::tr("Refresh \"%1\" failed! -- %2").arg(GetName()).arg(e.what()));
|
||
// return false;
|
||
// }
|
||
// catch(...)
|
||
// {
|
||
// m_SyncLockFlag = false;
|
||
|
||
// pai::log::Error(_FLF(QObject::tr("Refresh \"%1\" failed!").arg(GetName()).toStdString()));
|
||
// ::LogStackTrace(::GetStackTrace());
|
||
|
||
// m_EventAgent.RefreshObjectFailed(this, QObject::tr("Refresh \"%1\" failed!").arg(GetName()));
|
||
// return false;
|
||
// }
|
||
}
|
||
|
||
void PaiObject::SetIgnoreSyncDB(bool ignore)
|
||
{
|
||
SetFlagEnable(PaiObject::IgnoreSyncDB, ignore);
|
||
}
|
||
|
||
void PaiObject::SetShadowNode(bool shadow)
|
||
{
|
||
SetFlagEnable(PaiObject::ShadowNode, shadow);
|
||
}
|
||
|
||
void PaiObject::SetSyncabled(bool enable)
|
||
{
|
||
SetFlagEnable(PaiObject::Syncabled, enable);
|
||
}
|
||
|
||
bool PaiObject::HasPermissionFlag(int type) const
|
||
{
|
||
//此处只是用来处理PaiObject对象,PaiProject与PaiSurvey分别单独实现
|
||
//缺省继承工区的权限,这里耦合了PaiSurvey的类型ID
|
||
PaiObject *survey = GetForebear(QUuid("{eea801c0-a17f-4dea-b639-c88c4cfe8752}"));
|
||
if(survey != NULL)
|
||
{
|
||
if(type >= 2 && (!(type & 16)))//这里的2就是JIOService发布的EOperation.h中的UPDATE的枚举值;这里的16就是JIOService发布的EOperation.h中的MANAGE_PERMISSION的枚举值
|
||
{
|
||
return (survey->HasPermissionFlag(2));//如果工区有更新权限,则孩子有crud全部权限,否则对该type没有权限
|
||
}
|
||
return survey->HasPermissionFlag(type); //获取工区对应的权限
|
||
}
|
||
return true;
|
||
}
|
||
|
||
QVariant PaiObject::GetSortData(const SortKeyFlag key) const
|
||
{
|
||
if(key == Sort_By_Name)
|
||
{
|
||
return GetName();
|
||
}
|
||
else if(key == Sort_By_CreateTime)
|
||
{
|
||
return GetCreateTime();
|
||
}
|
||
else
|
||
{
|
||
return QVariant(); // 默认不调整顺序
|
||
}
|
||
}
|
||
|
||
long long PaiObject::GetCreateTime() const
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
int PaiObject::SortDataCompare(PaiObject *pSrc, PaiObject *pDest, const SortKeyFlag key)
|
||
{
|
||
if(pSrc && pDest)
|
||
{
|
||
QVariant src = pSrc->GetSortData(key);
|
||
QVariant dest = pDest->GetSortData(key);
|
||
|
||
//特殊处理一下joblog,无论任何排序规则
|
||
if(src.userType() == qMetaTypeId< pai::AlwaysBottom > ())//src is a JobLog
|
||
{
|
||
return 1;
|
||
}
|
||
if(dest.userType() == qMetaTypeId< pai::AlwaysBottom > ())//dest is a JobLog
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
if(key == Sort_Key_Null)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
if((src.type() == QVariant::String) && (dest.type() == QVariant::String)) // 字符串比较
|
||
{
|
||
return SpecialCompare(src.toString(), dest.toString());
|
||
}
|
||
else if((src.type() == QVariant::Int) && (dest.type() == QVariant::Int)) // 整形比较
|
||
{
|
||
return src.toInt() - dest.toInt();
|
||
}
|
||
else if((src.type() == QVariant::LongLong) && (dest.type() == QVariant::LongLong)) // 整形比较
|
||
{
|
||
// 防止长整型转化为整型产生溢出
|
||
if(src.toLongLong() - dest.toLongLong() == 0)
|
||
{
|
||
return 0;
|
||
}
|
||
else if(src.toLongLong() - dest.toLongLong() < 0)
|
||
{
|
||
return -1;
|
||
}
|
||
else
|
||
{
|
||
return 1;
|
||
}
|
||
}
|
||
else if((src.type() == QVariant::Double) && (dest.type() == QVariant::Double)) // 浮点数比较
|
||
{
|
||
if(qAbs(src.toDouble() - dest.toDouble()) < 10e-20)
|
||
{
|
||
return 0;
|
||
}
|
||
else if((src.toDouble() - dest.toDouble()) > 0)
|
||
{
|
||
return 1;
|
||
}
|
||
else
|
||
{
|
||
return -1;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
return 0; // 不支持部分目前认为相等
|
||
}
|
||
}
|
||
|
||
return 0; // 认为相等
|
||
}
|
||
|
||
void PaiObject::Rename(const QString & /*newName*/, OverrideFlag /*override*/)
|
||
{
|
||
// 此处抛出异常,既可以保证需要重命名的派生类有提示,也可防止不能重命名的派生类被重命名
|
||
// throw pai::error::io_error("Please define [Rename] function in derived class!");
|
||
}
|
||
|
||
long long PaiObject::GetTimeStamp() const
|
||
{
|
||
return m_TimeStamp;
|
||
}
|
||
|
||
void PaiObject::SetTimeStamp(const long long timeStamp)
|
||
{
|
||
// 只有有更新才可以修改
|
||
if(timeStamp > GetTimeStamp())
|
||
{
|
||
m_TimeStamp = timeStamp;
|
||
|
||
// 通知有更新
|
||
// m_EventAgent.ObjectPropertyChanged(this, QString("Update"), m_TimeStamp);
|
||
}
|
||
}
|
||
|
||
int PaiObject::SpecialCompare(const QString & tag1, const QString & tag2)
|
||
{
|
||
int ret = QString::compare(tag1, tag2, Qt::CaseInsensitive);
|
||
|
||
int i = 0;
|
||
const int sep = 'a' - 'A';//英文字母大小写的差值
|
||
|
||
while(tag1.length() > i && tag2.length() > i)
|
||
{
|
||
char a = tag1.at(i).toLatin1();
|
||
char b = tag2.at(i).toLatin1();
|
||
|
||
if(tag1.at(i) == tag2.at(i))
|
||
{
|
||
//如果相等则继续比较
|
||
}
|
||
else if(a >= 'A' && a <= 'z' && b >= 'A' && b <= 'z')
|
||
{
|
||
//如果两个都是英文字母,且是相同字母(只是大小写的却别),则返回差异
|
||
if(a - b == sep || b - a == sep)
|
||
{
|
||
ret = a - b;
|
||
}
|
||
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
//如果不相等,则直接退出循环
|
||
break;
|
||
}
|
||
|
||
i++;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
void PaiObject::SyncRefreshMsg(const PaiObject & latestObject)
|
||
{
|
||
if(latestObject.m_dbid > 0 && m_dbid != latestObject.m_dbid)
|
||
{
|
||
QString errMsg = QObject::tr("SyncRefreshMsg from \"%1\" to \"%2\" failed! \n"
|
||
"the DBID must be the same one(%3, %4)!").arg(latestObject.GetName()).arg(GetName())
|
||
.arg(latestObject.GetDBID()).arg(GetDBID());
|
||
// throw pai::error::invalid_argument(errMsg.toStdString());
|
||
}
|
||
|
||
if(latestObject.GetTimeStamp() > GetTimeStamp())
|
||
{
|
||
//在与数据库不同步的情况下,更新当前对象同步数据库
|
||
Clone(latestObject);
|
||
// m_EventAgent.RefreshedObject(this);
|
||
}
|
||
}
|
||
|
||
PaiObject* PaiObject::GetForebear(const QUuid & typeID) const
|
||
{
|
||
PaiObject *pParent = GetParent();
|
||
|
||
while(pParent)
|
||
{
|
||
if(pParent->GetTypeID() == typeID)
|
||
{
|
||
return pParent;
|
||
}
|
||
|
||
pParent = pParent->GetParent();
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
bool PaiObject::TryDelete(QString & message)
|
||
{
|
||
// if(GetObjectModelService()->GetObjectLockManager()->IsObjectLocked(GetDBID(), true) == true)
|
||
// {
|
||
// QMap< long long, QString > map = GetObjectModelService()->GetObjectLockManager()->GetLockedObjects(this);
|
||
// if(message.isEmpty() == false)
|
||
// {
|
||
// message.append("\n");
|
||
// }
|
||
// foreach(const QString & info, map)
|
||
// {
|
||
// message.append(info);
|
||
// }
|
||
// return false;
|
||
// }
|
||
// else
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
|
||
int PaiObject::GetMemorySize()
|
||
{
|
||
return 0;
|
||
}
|