#include #include #include #include #include #include #include "objectcontroller.h" #include "qtvariantproperty.h" #include "qtgroupboxpropertybrowser.h" #include "qttreepropertybrowser.h" #include "qtpropertybrowser.h" #include "variantfactory.h" #include "variantmanager.h" #include "vpControls/VTableControl.h" #include "vpControls/VPieChart.h" #include "vpControls/VCustomPlot.h" #include "vpControls/VImageControl.h" #include "UiManager.h" // #include "WindowAppUiView.h" #define PROPERTY_EX_MISC "杂项" QMap propertyNamesMap; class ObjectControllerPrivate { // 基础属性的中英文对照表 ObjectControllerPrivate() { propertyNamesMap.insert("tip", "文本"); propertyNamesMap.insert("title", "标题"); propertyNamesMap.insert("dataLink", "链接"); propertyNamesMap.insert("textColor", "文本色"); propertyNamesMap.insert("bgColor", "背景色"); propertyNamesMap.insert("Red", "红"); propertyNamesMap.insert("Green", "绿"); propertyNamesMap.insert("Blue", "蓝"); propertyNamesMap.insert("Alpha", "明度"); propertyNamesMap.insert("font", "字体"); propertyNamesMap.insert("enable", "启用"); propertyNamesMap.insert("rowCount", "行数"); propertyNamesMap.insert("colCount", "列数"); propertyNamesMap.insert("borderColor", "边框色"); propertyNamesMap.insert("sliceCount", "分块数"); propertyNamesMap.insert("lineCount", "曲线数"); propertyNamesMap.insert("objCount", "图层数"); propertyNamesMap.insert("tupleCount", "文本数"); propertyNamesMap.insert("displayCount", "显示数"); propertyNamesMap.insert("geometry", "形状"); propertyNamesMap.insert("interactions", "交互模式"); propertyNamesMap.insert("drawingMode", "绘图模式"); propertyNamesMap.insert("rangeX", "x轴范围"); propertyNamesMap.insert("rangeY", "y轴范围"); propertyNamesMap.insert("tickCountX", "x网格数"); propertyNamesMap.insert("tickCountY", "y网格数"); m_pVcontrol = nullptr; q_ptr = nullptr; m_object = nullptr; m_browser = nullptr; m_manager = nullptr; m_readOnlyManager = nullptr; } ObjectController *q_ptr; Q_DECLARE_PUBLIC(ObjectController) public: void expandAll(); void collapseAll(); void saveExpandedState(); void restoreExpandedState(); // 数值变更 void slotValueChanged(QtProperty *property, const QVariant &value); //======================================================= // 辅助类型转换函数 int enumToInt(const QMetaEnum &metaEnum, int enumValue) const; int intToEnum(const QMetaEnum &metaEnum, int intValue) const; int flagToInt(const QMetaEnum &metaEnum, int flagValue) const; int intToFlag(const QMetaEnum &metaEnum, int intValue) const; bool isSubValue(int value, int subValue) const; bool isPowerOf2(int value) const; // 获取属性的中文名称 QString chName(const QString& enName); //======================================================= // 基础控件相关 // 设置控件属性 void setBasicControlProperties(const QMetaObject* metaObject); // 设置复杂控件属性 void setComplexControlProperties(const QMetaObject* metaObject); // 构建新的基础属性表 void buildBasicProperty(const QMetaObject* metaObject, QtProperty*& classProperty); // 更新基础属性 void changeBasicProperties(QtProperty* property, const QVariant& value); // 更新基础属性表 void updateBasicProperties(const QMetaObject* metaObject); // 2022-2-12 更新geometry属性 // (针对geometry专门处理一下,因为这个属性比较特殊,不需要手工处理,只需要刷新一下界面) void changeGeometryProperty(const QVariant& value); // 2022-2-13 用户控件到属性表的同步 void syncToPropertyTable(QObject* pControl, const OBJECT_SYNC_PROPERTY& syncInfo); // 2022-2-14 保存到同步列表中 void saveToSyncProperty(OBJECT_SYNC_TYPE type, QtVariantProperty* prop); //======================================================= // 复杂控件相关 // 构建控件扩展属性表 void buildExtendProperty(QtProperty*& objectProperty); // 构建控件扩展属性表中的主索引部分 void buildPropertyMainLinks(QtProperty*& objectProperty); // 构建控件扩展属性表中的分组部分 void buildPropertyGroups(QtProperty*& objectProperty); // 构建控件扩展属性表中的子分组部分(2022-1-25,增加了分组ID) void buildPropertySubGroup(const int groupID, const PROPERTY_EX_SUBGROUP& prop, QtProperty*& subGroupRoot); // 修改控件的扩展属性 void changeExtendProperties(QtProperty* property, const QVariant& value); //// 更新基础属性表 //void updateBasicProperties(const QMetaObject* metaObject); // 更新扩展属性表 void updateExtendProperties(QtProperty*& objectProperty); //// 动态增加新的属性项 //void appendExtendPropertiesCount(const int fixCount, const QString& propertyName); //// 动态减少新的属性项 //void removeExtendPropertiesCount(const int fixCount, const QString& propertyName); // 动态调整属性项 void updateExtendPropertiesCount(const int newCount, const QString& propertyName); // 仅展开扩展属性项 void setExtendItemsExpandOnly(); //// 2022-2-7为了解决反序列化时数据链接数值无法自动显示的问题,增加此函数 //void setDataLinkItem(QtVariantProperty*& item, const DataLink& dataLink); //// 根据类型获取对应的VControlObject指针 //VControlObject* controlObject(); // 当前控件是否是 Table bool isVTableControl(); // 当前控件是否是 Pie bool isVPieChart(); // 当前控件是否是 Wave bool isVCustomPlot(); // 当前控件是否是 Image bool isVImageControl(); public: // 绑定的控件对象指针 QObject *m_object; // Object的VControlObject对象 VControlObject *m_pVcontrol; // 属性和QMetaObject的双向对应关系(用于简单控件) // QMap m_classToProperty; // 属性和Index索引的对应关系 QMap m_propertyToIndex; // QMetaObject和索引以及对应属性的关系 // QMap > m_classToIndexToProperty; QMap > m_objectToIndexToProperty; // 每个属性是否展开 QMap m_propertyToExpanded; // 属性表顶层节点 QList m_topLevelProperties; // 2021-9-11 修改 此处直接使用 QtTreePropertyBrowser 指针即可 QtTreePropertyBrowser *m_browser; // 属性数据结构管理者 QtVariantPropertyManager *m_manager; // 只读属性数据结构管理者 QtVariantPropertyManager *m_readOnlyManager; // 2021-12-2 属性指针与属性名字对应关系 QMap m_propertyToName; // 2022-1-15,每个控件对应的属性分组根节点 QMap < const QObject*, QVector> m_objectToGroups; // 2021-12-3 控件与对应的扩展子属性组 // QMap < const QObject*, QVector> m_objectToSubGroups; // 2022-1-25,由于此处数据结构变动,Group-SubGroup的关系只能这样定义了 QMap < const QtProperty*, QVector> m_groupToSubGroups; // 2021-12-23 用于保存对象以及扩展属性的对应关系,用于后续更新 QMap> m_objectToNameToProperty; // 属性和QObject的双向对应关系(用于复杂控件) QMap m_objectToProperty; // 2022-2-13 使用,用于控件属性到属性表的同步 QMap> m_objectToSyncProperty; }; //======================================================================= // // 简单控件属性表处理 // //======================================================================= /// /// 设置控件属性 /// /// void ObjectControllerPrivate::setBasicControlProperties(const QMetaObject* metaObject) { if (!metaObject) { return; } // 取出属于本控件的控件属性组 QtProperty* objectProperty = m_objectToProperty.value(m_object); // 重新创建新的属性表 if (!objectProperty) { // 首先添加基础属性 buildBasicProperty(metaObject, objectProperty); } // 如果之前已经创建过本类型控件的属性表,那么直接从数据结构中更新即可 else { // 首先更新基础属性 // updateProperties(metaObject); } // 保存根节点 m_topLevelProperties.append(objectProperty); // 界面中添加此根节点 m_browser->addProperty(objectProperty); // 基础属性表全部不展开 this->collapseAll(); } /// /// 构建新的基础属性表 /// /// /// void ObjectControllerPrivate::buildBasicProperty(const QMetaObject *metaObject, QtProperty*& objectProperty) { // 清空需要同步的属性关系,重新建立 // m_objectToSyncProperty.clear(); // 获取类名,根据类型名建立属性表根节点 QString className = QLatin1String(metaObject->className()); // 创建根节点 objectProperty = m_manager->addProperty(QtVariantPropertyManager::groupTypeId(), className); // 保存根节点和控件对象的对应关系 m_objectToProperty[m_object] = objectProperty; int nPropertyCount = metaObject->propertyCount(); int nPropertyOffset = metaObject->propertyOffset(); // 遍历所有的固定属性执行添加 for (int idx = nPropertyOffset; idx < nPropertyCount; idx++) { // 取出对应的固定属性 QMetaProperty metaProperty = metaObject->property(idx); // 取出属性的Type值 int type = metaProperty.userType(); // 准备添加子属性节点(注意要保存带值的子属性,需要用QtVariantProperty类型) QtVariantProperty* subProperty = 0; // 翻译后的属性名称 QString propertyName = chName(metaProperty.name()); // 确保是所支持的类型 if (m_manager->isPropertyTypeSupported(type)) { // 添加属性 subProperty = m_manager->addProperty(type, propertyName); // 设置值 // 2022-2-8 针对数据连接专门处理了一下,要不直接从metaProperty里读不出来 if (propertyName != "链接") { QVariant var = metaProperty.read(m_object); subProperty->setValue(var); } else { subProperty->setValue(m_pVcontrol->m_Property.m_DataLink.toString()); } if (propertyName == "图层数" || propertyName == "文本数" || propertyName == "显示数" || propertyName == "曲线数" ) { subProperty->setAttribute(QLatin1String("minimum"), 0); subProperty->setAttribute(QLatin1String("maximum"), 10); subProperty->setAttribute(QLatin1String("singleStep"), 1); } // 2022-2-13 如果属性是形状或者标题,则需要额外保存一下 else if (propertyName == "标题") { saveToSyncProperty(OBJECT_SYNC_TYPE::SYNC_TITLE, subProperty); } else if (propertyName == "形状") { saveToSyncProperty(OBJECT_SYNC_TYPE::SYNC_GEOMETRY, subProperty); //QMap syncProp; //syncProp.insert(OBJECT_SYNC_TYPE::SYNC_TITLE, subProperty); //m_objectToSyncProperty.insert(m_object, syncProp); } } // 设置无效属性 else { subProperty = m_readOnlyManager->addProperty(QVariant::String, propertyName); subProperty->setValue(QLatin1String("< Unknown Type >")); subProperty->setEnabled(false); } // 根节点下添加此子节点 objectProperty->addSubProperty(subProperty); // 保存此子属性和索引值的对应关系 m_propertyToIndex[subProperty] = idx; // 保存根节点下所有子节点和子属性的对应关系 m_objectToIndexToProperty[m_object][idx] = subProperty; } } /// /// 更新基础属性表 /// /// /// void ObjectControllerPrivate::updateBasicProperties(const QMetaObject* metaObject) { if (!metaObject) { return; } // 遍历所有的属性更新数值 for (int idx = metaObject->propertyOffset(); idx < metaObject->propertyCount(); idx++) { QMetaProperty metaProperty = metaObject->property(idx); if (metaProperty.isReadable()) { // 从数据结构中找到对应的子属性 if (m_objectToIndexToProperty.contains(m_object) && m_objectToIndexToProperty[m_object].contains(idx)) { QtVariantProperty* subProperty = m_objectToIndexToProperty[m_object][idx]; // 设置属性值 QVariant propertyValue = metaProperty.read(m_object); subProperty->setValue(propertyValue); } } } } /// /// 2022-2-12 更新geometry属性 /// (针对geometry专门处理一下,因为这个属性比较特殊,不需要手工处理,只需要刷新一下界面) /// void ObjectControllerPrivate::changeGeometryProperty(const QVariant& value) { // WindowAppUiView* pUiView = g_pUiManager->getViewByControl(m_pVcontrol); // 按照属性表中的值重新设置控件形状 m_pVcontrol->m_pWidget->setGeometry(value.toRect()); // 界面中刷新此控件 g_pUiManager->refreshControlDrawPoint(m_pVcontrol); } /// /// 同步指定的属性值到属性表中 /// /// /// void ObjectControllerPrivate::syncToPropertyTable(QObject* pControl, const OBJECT_SYNC_PROPERTY& syncInfo) { QtVariantProperty* syncProp = nullptr; // 找出需要同步的Property指针 QVector& propInfos = m_objectToSyncProperty[pControl]; for (auto propInfo : propInfos) { if (propInfo.type == syncInfo.type) { syncProp = propInfo.prop; break; } } if (syncProp == nullptr) { //qWarning() << "[Error] ObjectControllerPrivate::syncToPropertyTable - syncProp is nullptr."; return; } int idx = m_propertyToIndex.value(syncProp); // 更新MetaObject中的值 const QMetaObject* metaObject = m_object->metaObject(); QMetaProperty metaProperty = metaObject->property(idx); metaProperty.write(m_object, syncInfo.value); // 更新对应的属性表 syncProp->setValue(syncInfo.value); } /// /// 2022-2-14 保存到同步列表中 /// /// /// void ObjectControllerPrivate::saveToSyncProperty(OBJECT_SYNC_TYPE type, QtVariantProperty* prop) { OBJECT_SYNC_PROPERTY propInfo; propInfo.type = type; propInfo.prop = prop; if (!m_objectToSyncProperty.contains(m_object)) { QVector syncProps; syncProps.push_back(propInfo); m_objectToSyncProperty.insert(m_object, syncProps); } else { QVector& syncProps = m_objectToSyncProperty[m_object]; syncProps.push_back(propInfo); } } //======================================================================= // // 复杂控件属性表处理 // //======================================================================= /// /// 设置复杂控件属性 /// void ObjectControllerPrivate::setComplexControlProperties(const QMetaObject* metaObject) { if (!m_object) { return; } // 取出属于本控件的控件属性组 QtProperty* objectProperty = m_objectToProperty.value(m_object); // 重新创建新的属性表 if (!objectProperty) { // 首先建立基础属性 buildBasicProperty(metaObject, objectProperty); // 继续建立扩展属性 buildExtendProperty(objectProperty); } // 如果之前已经创建过本类型控件的属性表,那么直接从数据结构中更新即可 else { // 首先更新基础属性 // updateProperties(metaObject); // 继续更新扩展属性 // updateExtendProperties(objectProperty); } // 保存根节点 m_topLevelProperties.append(objectProperty); // 界面中添加此根节点 m_browser->addProperty(objectProperty); // 基础属性表全部不展开 this->collapseAll(); // 只展开扩展属性表以及子属性表的部分 this->setExtendItemsExpandOnly(); } ///// ///// 为复杂控件增加其中的基础属性 ///// ///// ///// //void ObjectControllerPrivate::buildBasicProperties(const QMetaObject* metaObject, QtProperty*& objectProperty) //{ // // buildProperties(metaObject, objectProperty); // //} // // ///// ///// 为复杂控件更新基础属性表 ///// ///// //void ObjectControllerPrivate::updateBasicProperties(const QMetaObject* metaObject) //{ // this->updateProperties(metaObject); //} /// /// 构建控件扩展属性表(仅复杂控件才有) /// /// /// void ObjectControllerPrivate::buildExtendProperty(QtProperty*& objectProperty) { // 构建控件扩展属性表中的主索引部分 this->buildPropertyMainLinks(objectProperty); // 构建控件扩展属性表中的分组部分 this->buildPropertyGroups(objectProperty); } /// /// 构建控件扩展属性表中的主索引部分 /// /// void ObjectControllerPrivate::buildPropertyMainLinks(QtProperty*& objectProperty) { // 取出对应的扩展属性 const CONTROL_PROPERTY_EX& propex = m_pVcontrol->m_PropertyEx; // 建立主索引分类节点 QtProperty* groupRoot = m_manager->addProperty( QtVariantPropertyManager::groupTypeId(), propex.m_strTitle ); // 控件刷新索引链接 QtVariantProperty* item = m_manager->addProperty( VariantManager::tagDataLinkTypeId(), propex.m_refreshLink.title ); // 设置索引连接数值 // this->setDataLinkItem(item, propex.m_refreshLink); item->setValue(propex.m_refreshLink.toString()); // 保存子项和名字的对应关系 m_propertyToName.insert(item, propex.m_refreshLink.title); // 添加此主刷新索引 groupRoot->addSubProperty(item); // 保存本属性对应关系,用于后续查找和更新 m_objectToNameToProperty[m_object][propex.m_refreshLink.title] = item; // 控件主索引链接 for (int i = 0; i < propex.m_mainDataLinks.size(); i++) { const DataLink& dataLink = propex.m_mainDataLinks[i]; // 添加索引Property item = m_manager->addProperty( VariantManager::tagDataLinkTypeId(), dataLink.title ); // 数据链接值 item->setValue(dataLink.toString()); // 保存子项和名字的对应关系 m_propertyToName.insert(item, dataLink.title); // 添加此主索引 groupRoot->addSubProperty(item); // 保存本属性对应关系,用于后续查找和更新 m_objectToNameToProperty[m_object][dataLink.title] = item; } // 在数据结构中保存本分类节点信息 m_objectToGroups[m_object].push_back(groupRoot); // 在控件属性表中添加本属性分组根节点 objectProperty->addSubProperty(groupRoot); } /// /// 构建控件扩展属性表中的分组部分 /// /// void ObjectControllerPrivate::buildPropertyGroups(QtProperty*& objectProperty) { // 取出对应的扩展属性 const CONTROL_PROPERTY_EX& propex = m_pVcontrol->m_PropertyEx; // 循环添加控件扩展属性的每一个分组 for (int i = 0; i < propex.m_groups.size(); i++) { const PROPERTY_EX_GROUP& group = propex.m_groups[i]; // 建立分类根节点 QtProperty* groupRoot = m_manager->addProperty( QtVariantPropertyManager::groupTypeId(), group.strTitle ); // 循环将所有子项添加到属性表中 for (int j = 0; j < group.subGroups.size(); j++) { this->buildPropertySubGroup(i, group.subGroups[j], groupRoot); } // 在数据结构中保存本分类节点信息 m_objectToGroups[m_object].push_back(groupRoot); // 在控件属性表中添加本属性分组根节点 objectProperty->addSubProperty(groupRoot); } } /// /// 更新扩展属性表 /// void ObjectControllerPrivate::updateExtendProperties(QtProperty*& objectProperty) { Q_UNUSED(objectProperty); } /// /// 向界面属性表中增加属性内容(2022-1-25,增加了分组ID) /// Table 扩展属性项:列名、数据链接 /// Pie 扩展属性项:分块名、分块颜色、数据链接 /// Image 扩展属性项1:图层颜色、图层透明度、图层线宽、图层数据链接 /// Image 扩展属性项2:文本颜色、文本横坐标、文本纵坐标、文本尺寸 /// /// void ObjectControllerPrivate::buildPropertySubGroup( const int groupID, const PROPERTY_EX_SUBGROUP& subGroupInfo, QtProperty*& subGroupRoot ) { // 创建子分组 QtProperty* subGroup = m_manager->addProperty( QtVariantPropertyManager::groupTypeId(), subGroupInfo.strTitle ); // 子分组属性项 QtVariantProperty* item = nullptr; // --------- 数据链接部分 // 循环添加所有数据链接 for (int i = 0; i < subGroupInfo.dataLinks.size(); i++) { const DataLink& dataLink = subGroupInfo.dataLinks[i]; // 数据链接项名 item = m_manager->addProperty( VariantManager::tagDataLinkTypeId(), dataLink.title ); // 数据链接值 item->setValue(dataLink.toString()); // 添加数据链接 subGroup->addSubProperty(item); // 保存子项和名字的对应关系 m_propertyToName.insert(item, dataLink.title); // 保存本属性对应关系,用于后续查找和更新 m_objectToNameToProperty[m_object][dataLink.title] = item; } // --------- 杂项部分 // 创建杂项子分组 QtProperty* subMiscGroup = m_manager->addProperty( QtVariantPropertyManager::groupTypeId(), PROPERTY_EX_MISC ); // 1. // 名称 (Table、Pie、Wave) if (!this->isVImageControl()) { item = m_manager->addProperty(QVariant::String, subGroupInfo.strValueName); // 子项值 item->setValue(subGroupInfo.strValue); // 添加子项 subMiscGroup->addSubProperty(item); // 保存子项和名字的对应关系 m_propertyToName.insert(item, subGroupInfo.strValueName); // 2021-12-24 保存本属性对应关系,用于后续查找和更新 m_objectToNameToProperty[m_object][subGroupInfo.strValueName] = item; } // 2. // 颜色(Pie、Wave、Image) if (!this->isVTableControl() && !subGroupInfo.strColorName.isEmpty()) { // 分块颜色项名 item = m_manager->addProperty(QVariant::Color, subGroupInfo.strColorName); // 颜色数值 item->setValue(subGroupInfo.color); // 添加颜色子项 subMiscGroup->addSubProperty(item); // 保存子项和名字的对应关系 m_propertyToName.insert(item, subGroupInfo.strColorName); // 2021-12-24 保存本属性对应关系,用于后续查找和更新 m_objectToNameToProperty[m_object][subGroupInfo.strColorName] = item; } // 3. // 如果是Image控件,还需要加入其他杂项 if (this->isVImageControl()) { // 如果是HObject子分组 if (groupID == GROUP_INDEX_HOBJECT) { // 线宽 // 线宽项名 item = m_manager->addProperty(QVariant::Int, subGroupInfo.strLineWidthName); // 线宽数值 item->setValue(subGroupInfo.nLineWidth); // 添加线宽子项 subMiscGroup->addSubProperty(item); // 保存子项和名字的对应关系 m_propertyToName.insert(item, subGroupInfo.strLineWidthName); // 保存本属性对应关系,用于后续查找和更新 m_objectToNameToProperty[m_object][subGroupInfo.strLineWidthName] = item; } // 如果是HTuple子分组 else if (groupID == GROUP_INDEX_HTUPLE) { // 坐标 // 坐标项名 item = m_manager->addProperty(QVariant::Point, subGroupInfo.strPtName); // 坐标数值 item->setValue(subGroupInfo.pt); // 添加坐标子项 subMiscGroup->addSubProperty(item); // 保存子项和名字的对应关系 m_propertyToName.insert(item, subGroupInfo.strPtName); // 保存本属性对应关系,用于后续查找和更新 m_objectToNameToProperty[m_object][subGroupInfo.strPtName] = item; //// 坐标(数据链接) //// 数据链接项名 //item = m_manager->addProperty( // VariantManager::tagDataLinkTypeId(), // subGroupInfo.dataLinkPoint.title //); //// 数据链接值 //item->setValue(""); //// 添加数据链接 //subMiscGroup->addSubProperty(item); //// 保存子项和名字的对应关系 //m_propertyToName.insert(item, subGroupInfo.dataLinkPoint.title); //// 保存本属性对应关系,用于后续查找和更新 //m_objectToNameToProperty[m_object][subGroupInfo.dataLinkPoint.title] = item; // 尺寸 // 尺寸项名 item = m_manager->addProperty(QVariant::Int, subGroupInfo.strSize); // 尺寸数值 item->setValue(subGroupInfo.nSize); // 添加尺寸子项 subMiscGroup->addSubProperty(item); // 保存子项和名字的对应关系 m_propertyToName.insert(item, subGroupInfo.strSize); // 保存本属性对应关系,用于后续查找和更新 m_objectToNameToProperty[m_object][subGroupInfo.strSize] = item; } // 如果是 Display 子分组 else if (groupID == GROUP_INDEX_DISPLAY) { } // 如果是Save 子分组 else if (groupID == GROUP_INDEX_SAVE) { // 1 启用存图(复选框) { item = m_manager->addProperty(QVariant::Bool, subGroupInfo.strSaveImage); item->setValue(subGroupInfo.bEnSaveImage); // 添加坐标子项 subMiscGroup->addSubProperty(item); // 保存子项和名字的对应关系 m_propertyToName.insert(item, subGroupInfo.strSaveImage); // 保存本属性对应关系,用于后续查找和更新 m_objectToNameToProperty[m_object][subGroupInfo.strSaveImage] = item; } // 2 启用转储(复选框) { item = m_manager->addProperty(QVariant::Bool, subGroupInfo.strDumpWindow); item->setValue(subGroupInfo.bEnDumpWindow); // 添加坐标子项 subMiscGroup->addSubProperty(item); // 保存子项和名字的对应关系 m_propertyToName.insert(item, subGroupInfo.strDumpWindow); // 保存本属性对应关系,用于后续查找和更新 m_objectToNameToProperty[m_object][subGroupInfo.strDumpWindow] = item; } // 3 启用应用状态(复选框) { item = m_manager->addProperty(QVariant::Bool, subGroupInfo.strExecuteState); item->setValue(subGroupInfo.bEnExecuteState); // 添加坐标子项 subMiscGroup->addSubProperty(item); // 保存子项和名字的对应关系 m_propertyToName.insert(item, subGroupInfo.strExecuteState); // 保存本属性对应关系,用于后续查找和更新 m_objectToNameToProperty[m_object][subGroupInfo.strExecuteState] = item; } // 4 命名方式(下拉列表 1、序号模式,2、日期模式,3、链接模式 ) { item = m_manager->addProperty(QtVariantPropertyManager::enumTypeId(), subGroupInfo.strSaveMode); QStringList enumNames; enumNames << "序号模式" << "日期模式" << "链接模式"; item->setAttribute(QLatin1String("enumNames"), enumNames); item->setValue(subGroupInfo.nSaveMode); // 添加坐标子项 subMiscGroup->addSubProperty(item); // 保存子项和名字的对应关系 m_propertyToName.insert(item, subGroupInfo.strSaveMode); // 保存本属性对应关系,用于后续查找和更新 m_objectToNameToProperty[m_object][subGroupInfo.strSaveMode] = item; } // 5 BufferSize { item = m_manager->addProperty(QVariant::Int, subGroupInfo.strBufferSize); item->setValue(subGroupInfo.nBufferSize); item->setAttribute(QLatin1String("minimum"), 10); item->setAttribute(QLatin1String("maximum"), 999); item->setAttribute(QLatin1String("singleStep"), 1); // 添加坐标子项 subMiscGroup->addSubProperty(item); // 保存子项和名字的对应关系 m_propertyToName.insert(item, subGroupInfo.strBufferSize); // 保存本属性对应关系,用于后续查找和更新 m_objectToNameToProperty[m_object][subGroupInfo.strBufferSize] = item; } // 6 Free Time { item = m_manager->addProperty(QVariant::Int, subGroupInfo.strFreeTime); item->setValue(subGroupInfo.nFreeTime); item->setAttribute(QLatin1String("minimum"), 10); item->setAttribute(QLatin1String("maximum"), 500); item->setAttribute(QLatin1String("singleStep"), 1); // 添加坐标子项 subMiscGroup->addSubProperty(item); // 保存子项和名字的对应关系 m_propertyToName.insert(item, subGroupInfo.strFreeTime); // 保存本属性对应关系,用于后续查找和更新 m_objectToNameToProperty[m_object][subGroupInfo.strFreeTime] = item; } // TODO: 此处,需要完成存储组的默认折叠 } // 不应该执行到这里 else { qDebug() << "[Error] ObjectControllerPrivate::buildPropertySubGroup - invalid groupID: " << groupID; } } // 4. // 如果是曲线控件,还需要加入其他杂项 if (this->isVCustomPlot()) { // 线宽 // 线宽项名 item = m_manager->addProperty(QVariant::Int, subGroupInfo.strLineWidthName); // 线宽数值 item->setValue(subGroupInfo.nLineWidth); // 添加线宽子项 subMiscGroup->addSubProperty(item); // 保存子项和名字的对应关系 m_propertyToName.insert(item, subGroupInfo.strLineWidthName); // 保存本属性对应关系,用于后续查找和更新 m_objectToNameToProperty[m_object][subGroupInfo.strLineWidthName] = item; } // 添加杂项分组 subGroup->addSubProperty(subMiscGroup); // 添加子分组 subGroupRoot->addSubProperty(subGroup); // 保存这个SubGroup的信息(用于删除使用) QtProperty* curGroup = m_objectToGroups[m_object][groupID]; m_groupToSubGroups[curGroup].push_back(subGroup); // m_objectToSubGroups[m_object].push_back(subGroup); } void ObjectControllerPrivate::saveExpandedState() { } void ObjectControllerPrivate::restoreExpandedState() { } /// /// 属性表数据变动槽函数 /// void ObjectControllerPrivate::slotValueChanged(QtProperty *property, const QVariant &value) { // qDebug() << "ObjectControllerPrivate::slotValueChanged - Property: " << property->propertyName() << " - Value: " << value; // 2022-2-12 如果更新的是geometry if (property->propertyName()=="形状") { this->changeGeometryProperty(value); } // 基础属性 if (m_propertyToIndex.contains(property)) { this->changeBasicProperties(property, value); } // 动态属性 else { // 动态改变复杂控件的扩展属性 this->changeExtendProperties(property, value); } } /// /// 更新基础属性 /// /// /// void ObjectControllerPrivate::changeBasicProperties(QtProperty* property, const QVariant& value) { int idx = m_propertyToIndex.value(property); const QMetaObject* metaObject = m_object->metaObject(); QMetaProperty metaProperty = metaObject->property(idx); metaProperty.write(m_object, value); updateBasicProperties(metaObject); //// 2022-2-14 修正,似乎不需要这么复杂,简化逻辑提高了效率 //// updateBasicProperties(metaObject); //QtVariantProperty* subProperty = m_objectToIndexToProperty[m_object][idx]; //subProperty->setValue(value); // 此处需要进行额外处理,如果改变的是扩展属性数量的关联Key,需要更新对应的扩展属性数量 QString propertyName = metaProperty.name(); // 如果改变了复杂控件扩展属性的数量 if (propertyName == TABLE_COL_COUNT_NAME || propertyName == PIE_SLICE_COUNT_NAME || propertyName == CUSTOM_PLOT_COUNT_NAME || propertyName == IMAGE_OBJ_COUNT_NAME || propertyName == IMAGE_MSG_COUNT_NAME || propertyName == IMAGE_DISPLAY_COUNT_NAME ) { // 调整对应的属性数量 // 新的属性数量 int newCount = value.toInt(); // 动态更新属性数量 this->updateExtendPropertiesCount(newCount, propertyName); } } /// /// 修改控件的扩展属性 /// /// /// void ObjectControllerPrivate::changeExtendProperties(QtProperty* property, const QVariant& value) { // 找到属性对应的属性名字 if (m_propertyToName.contains(property)) { // 获取属性名字 QString strValueTitle = m_propertyToName[property]; // 调用虚函数更新对应的控件属性值 m_pVcontrol->changeExProperties(strValueTitle, value); } } ///// ///// 增加新的属性项 ///// ///// ///// //void ObjectControllerPrivate::appendExtendPropertiesCount(const int fixCount, const QString& propertyName) //{ // //// 首先调用虚函数变更控件中扩展属性的数量 // //m_pVcontrol->updateExPropertyCount(fixCount); // // //// 从对应的子属性组中获取最新的属性数据 // //const QVector& propsItems = m_pVcontrol->getPropertyEx().m_subGroups[groupID]; // // // // 同步进行界面信息变更 // //int nStart = m_pVcontrol->getPropertyExSubGroupCountByID(groupID) - fixCount; // //int nEnd = nStart + fixCount; // //for (int i = nStart; i < nEnd; i++) // //{ // // this->addExtendPropertiesSubGroup(propsItems[i], m_objectToExRoots[m_object][groupID]); // //} // //} // // ///// ///// 减少新的属性项 ///// ///// ///// //void ObjectControllerPrivate::removeExtendPropertiesCount(const int fixCount, const QString& propertyName) //{ // //// 首先控件中减少数据结构信息(虚函数) // //m_pVcontrol->updateExPropertyCount(fixCount); // // // // 同步进行界面信息变更 // // int nDelCount = -fixCount; // // // // 从后往前依次删除掉属性 // // for (int i = 0; i < nDelCount; i++) // // { // // QtProperty* pDelSubGroup = m_objectToSubGroups[m_object].back(); // // // // 删除子属性 // // m_objectToExRoots[m_object]->removeSubProperty(pDelSubGroup); // // //m_objectToSubGroups[m_object].pop_back(); // // } //} /// /// 动态调整属性项 /// /// /// void ObjectControllerPrivate::updateExtendPropertiesCount(const int newCount, const QString& propertyName) { // 需要调整的属性数量 int nFixCount = newCount - m_pVcontrol->getExPropertyCountByName(propertyName); // GroupID int nGroupID = m_pVcontrol->getGroupIDByName(propertyName); // 检查有效性 if (nGroupID < 0) { qDebug() << "[Error] ObjectControllerPrivate::updateExtendPropertiesCount - nGroupID in invalid: " << nGroupID; return; } // 2022-1-23 由于属性表中的0号分组是主索引链接分组,所以此处取到的nGroupID + 才是真实的属性表分组ID int nPropGroupID = nGroupID + 1; // 变更控件中扩展属性对应的数据结构数量(虚函数) m_pVcontrol->updateExPropertyCount(nFixCount, propertyName); // 需要增加 if (nFixCount > 0) { // 获取最新的子分组数据 // 从对应的子属性组中获取最新的属性数据 const QVector& subGroups = m_pVcontrol->m_PropertyEx.m_groups[nGroupID].subGroups; int nStart = m_pVcontrol->getExPropertyCountByID(nGroupID) - nFixCount; int nEnd = nStart + nFixCount; // 把新增加的subGroup数据结构添加到属性表中 for (int i = nStart; i < nEnd; i++) { this->buildPropertySubGroup(nGroupID, subGroups[i], m_objectToGroups[m_object][nPropGroupID]); } } // 需要减少 else { // 从后往前依次删除掉属性 for (int i = 0; i < -nFixCount; i++) { // QtProperty* pDelSubGroup = m_objectToSubGroups[m_object].back(); // 从分组中找到对应的子分组 QtProperty* curGroup = m_objectToGroups[m_object][nGroupID]; QtProperty* pDelSubGroup = m_groupToSubGroups[curGroup].back(); // 删除子属性 m_objectToGroups[m_object][nPropGroupID]->removeSubProperty(pDelSubGroup); m_groupToSubGroups[curGroup].pop_back(); } } // 基础属性表全部不展开 this->collapseAll(); // 只展开扩展属性表以及子属性表的部分 this->setExtendItemsExpandOnly(); } /// /// 仅展开扩展属性项 /// void ObjectControllerPrivate::setExtendItemsExpandOnly() { // 2022-1-12 遍历所有的子属性项进行判断 for (int i = 0; i < m_objectToGroups[m_object].size(); i++) { QtProperty* prop = m_objectToGroups[m_object][i]; if (!prop || m_browser->items(prop).size() <= 0) { return; } // 枚举所有子项逐一进行展开 QtBrowserItem* pExRoot = m_browser->items(prop).at(0); m_browser->setExpanded(pExRoot, true); // Groups QList pGroups = pExRoot->children(); for (QtBrowserItem* group : pGroups) { m_browser->setExpanded(group, true); //// subgroups //QList subGroups = group->children(); //for (QtBrowserItem* subGroup : subGroups) //{ // m_browser->setExpanded(subGroup, true); //} } } } ///// ///// 2022-2-7为了解决反序列化时数据链接数值无法自动显示的问题,增加此函数 ///// ///// //void ObjectControllerPrivate::setDataLinkItem(QtVariantProperty*& item, const DataLink& dataLink) //{ // item->setValue(dataLink.toString()); // // // //if (propex.m_refreshLink.value.size() <= 0) // //{ // // item->setValue(""); // //} // //else // //{ // // item->setValue(propex.m_refreshLink.toString()); // //} //} //=================================================================== // // ObjectController // //=================================================================== /// /// /// /// ObjectController::ObjectController(QWidget *parent) : QWidget(parent) { d_ptr = new ObjectControllerPrivate; d_ptr->q_ptr = this; d_ptr->m_object = nullptr; /* QScrollArea *scroll = new QScrollArea(this); scroll->setWidgetResizable(true); d_ptr->m_browser = new QtGroupBoxPropertyBrowser(this); QVBoxLayout *layout = new QVBoxLayout(this); layout->setMargin(0); layout->addWidget(scroll); scroll->setWidget(d_ptr->m_browser); */ // 生成属性浏览控件 QtTreePropertyBrowser *browser = new QtTreePropertyBrowser(this); browser->setRootIsDecorated(false); d_ptr->m_browser = browser; QVBoxLayout *layout = new QVBoxLayout(this); layout->setMargin(0); // 添加新的属性表到界面中 layout->addWidget(d_ptr->m_browser); d_ptr->m_readOnlyManager = new QtVariantPropertyManager(this); // 2021-9-11 修改,此处生成 扩展的 VariantManager 对象 VariantManager* pVariantManager = new VariantManager(this); d_ptr->m_manager = pVariantManager; pVariantManager->setPropertyEditor(d_ptr->m_browser); // d_ptr->m_manager = new QtVariantPropertyManager(this); // 此处生成扩展的 VariantFactory 对象 QtVariantEditorFactory *factory = new VariantFactory(this); d_ptr->m_browser->setFactoryForManager(d_ptr->m_manager, factory); // 绑定数据更新消息 connect(d_ptr->m_manager, SIGNAL(valueChanged(QtProperty *, const QVariant &)), this, SLOT(slotValueChanged(QtProperty *, const QVariant &))); } ObjectController::~ObjectController() { delete d_ptr; } /// /// 设置对象属性 /// /// void ObjectController::setObject(QObject *object) { // 根据控件类型分别进行不同的处理 // 根据控件类型的不同,分为设置基础控件属性和复杂控件属性 // Memo:基础控件属性的设置和复杂控件属性的设置还是有很大区别 // 基础控件可以根据metaObject来分类设置属性表,因为同一个metaObject类型的属性表项是完全一致的,直接更新即可 // 而复杂控件的属性表项是动态变化的,无法直接根据metaObject类型来成组设置,所以每次切换控件都需要清空删除后重新来过 // // QString name = object->objectName(); //如果设置的控件已经是当前控件则不处理 if (d_ptr->m_object == object) { return; } // 清空属性表 this->clearProperties(); // 将新的对象指针保存 d_ptr->m_object = object; if (!d_ptr->m_object) { return; } // 2021-12-28 转换成VControlObject指针留着后面使用 d_ptr->m_pVcontrol = VControlObject::controlPtr(d_ptr->m_object); // 将简单控件的处理逻辑和复杂控件完全分开 if (this->isBasicControl()) { // 添加基础控件的属性,设置对应属性表(新建或更新) d_ptr->setBasicControlProperties(d_ptr->m_object->metaObject()); } else { if (!d_ptr->m_pVcontrol) { return; } // 添加复杂控件的属性,设置对应属性表(新建或更新) d_ptr->setComplexControlProperties(d_ptr->m_object->metaObject()); } //// 还原属性结构中子属性的展开状态 //d_ptr->restoreExpandedState(); // 展开所有节点 // d_ptr->expandAll(); } QObject *ObjectController::object() const { return d_ptr->m_object; } /// /// 清空属性表 /// void ObjectController::clearProperties() { // 删除旧属性表中的内容 if (d_ptr->m_object) { //// 保存当前属性表中子属性的状态 //d_ptr->saveExpandedState(); // 枚举属性表中之前的所有属性进行删除 QListIterator it(d_ptr->m_topLevelProperties); while (it.hasNext()) { d_ptr->m_browser->removeProperty(it.next()); } d_ptr->m_topLevelProperties.clear(); //// 2022-1-6增加,切换控件时需要清除相关的数据结构 //d_ptr->m_subGroups.clear(); // d_ptr->m_exPropertiesRoot = nullptr; } } /// /// 2021-12-25增加,删除对应属性表相关的数据结构 /// /// void ObjectController::delObject(QObject* object) { d_ptr->m_object = object; if (!d_ptr->m_object) { return; } // 清空对应的数据结构 d_ptr->m_objectToIndexToProperty.remove(object); d_ptr->m_objectToProperty.remove(object); d_ptr->m_objectToNameToProperty.remove(object); // 清除当前分组中的所有子分组属性表 for (QtProperty* group : d_ptr->m_objectToGroups[object]) { d_ptr->m_groupToSubGroups.remove(group); } d_ptr->m_objectToGroups.remove(object); // 清空最终属性表 clearProperties(); d_ptr->m_object = nullptr; } /// /// 2022-2-13 用于控件数值改变后向属性表同步 /// /// /// void ObjectController::syncToObject(QObject* pControl, const OBJECT_SYNC_PROPERTY& syncInfo) { // 暂时未使用到pControl,因为ObjectController本身是绑定了控件指针的 // 同步到属性表 d_ptr->syncToPropertyTable(pControl, syncInfo); } /// /// 是否是基础类型控件 /// /// bool ObjectController::isBasicControl() { QString className = object()->metaObject()->className(); if (className != CLASS_NAME_TABLECONTROL && className != CLASS_NAME_CUSTOMPLOT && className != CLASS_NAME_PIECHART && className != CLASS_NAME_IMAGECONTROL ) { return true; } return false; } //=================================================================== // // 辅助函数 // //=================================================================== int ObjectControllerPrivate::enumToInt(const QMetaEnum& metaEnum, int enumValue) const { QMap valueMap; // dont show multiple enum values which have the same values int pos = 0; for (int i = 0; i < metaEnum.keyCount(); i++) { int value = metaEnum.value(i); if (!valueMap.contains(value)) { if (value == enumValue) { return pos; } valueMap[value] = pos++; } } return -1; } int ObjectControllerPrivate::intToEnum(const QMetaEnum& metaEnum, int intValue) const { QMap valueMap; // dont show multiple enum values which have the same values QList values; for (int i = 0; i < metaEnum.keyCount(); i++) { int value = metaEnum.value(i); if (!valueMap.contains(value)) { valueMap[value] = true; values.append(value); } } if (intValue >= values.count()) { return -1; } return values.at(intValue); } bool ObjectControllerPrivate::isSubValue(int value, int subValue) const { if (value == subValue) { return true; } int i = 0; while (subValue) { if (!(value & (1 << i))) { if (subValue & 1) { return false; } } i++; subValue = subValue >> 1; } return true; } bool ObjectControllerPrivate::isPowerOf2(int value) const { while (value) { if (value & 1) { return value == 1; } value = value >> 1; } return false; } /// /// 获取属性的中文名称 /// /// /// QString ObjectControllerPrivate::chName(const QString& enName) { // 中文属性名称 QString propertyName = propertyNamesMap.value(enName); if (propertyName.isEmpty()) { return enName; } return propertyName; } int ObjectControllerPrivate::flagToInt(const QMetaEnum& metaEnum, int flagValue) const { if (!flagValue) { return 0; } int intValue = 0; QMap valueMap; // dont show multiple enum values which have the same values int pos = 0; for (int i = 0; i < metaEnum.keyCount(); i++) { int value = metaEnum.value(i); if (!valueMap.contains(value) && isPowerOf2(value)) { if (isSubValue(flagValue, value)) { intValue |= (1 << pos); } valueMap[value] = pos++; } } return intValue; } int ObjectControllerPrivate::intToFlag(const QMetaEnum& metaEnum, int intValue) const { QMap valueMap; // dont show multiple enum values which have the same values QList values; for (int i = 0; i < metaEnum.keyCount(); i++) { int value = metaEnum.value(i); if (!valueMap.contains(value) && isPowerOf2(value)) { valueMap[value] = true; values.append(value); } } int flagValue = 0; int temp = intValue; int i = 0; while (temp) { if (i >= values.count()) { return -1; } if (temp & 1) { flagValue |= values.at(i); } i++; temp = temp >> 1; } return flagValue; } void ObjectControllerPrivate::expandAll() { //打开所有节点 QtTreePropertyBrowser* browser = (QtTreePropertyBrowser*)m_browser; browser->expandAll(); } void ObjectControllerPrivate::collapseAll() { //折叠所有节点 QtTreePropertyBrowser* browser = (QtTreePropertyBrowser*)m_browser; browser->collapseAll(); //展开父节点 QList items = browser->topLevelItems(); for (QtBrowserItem* item : items) { browser->setExpanded(item, true); } } /// /// 当前控件是否是 Table /// /// bool ObjectControllerPrivate::isVTableControl() { QString className = m_object->metaObject()->className(); if (className == CLASS_NAME_TABLECONTROL) { return true; } return false; } /// /// 当前控件是否是 Pie /// /// bool ObjectControllerPrivate::isVPieChart() { QString className = m_object->metaObject()->className(); if (className == CLASS_NAME_PIECHART) { return true; } return false; } /// /// 当前控件是否是 Wave /// /// bool ObjectControllerPrivate::isVCustomPlot() { QString className = m_object->metaObject()->className(); if (className == CLASS_NAME_CUSTOMPLOT) { return true; } return false; } /// /// 当前控件是否是 Image /// /// bool ObjectControllerPrivate::isVImageControl() { QString className = m_object->metaObject()->className(); if (className == CLASS_NAME_IMAGECONTROL) { return true; } return false; } #include "moc_objectcontroller.cpp"