add custom HMI image element
This commit is contained in:
parent
fadc343c88
commit
742ea36c3d
|
|
@ -58,9 +58,10 @@ set(H_HEADER_FILES
|
|||
include/monitorItemsDlg.h
|
||||
include/monitorPagesDlg.h
|
||||
include/baseDockWidget.h
|
||||
include/enhancedToolBar.h
|
||||
include/toolBarConfig.h
|
||||
include/enhancedToolBar.h
|
||||
include/configToolBar.h
|
||||
include/draggableToolButton.h
|
||||
|
||||
common/include/tools.h
|
||||
common/include/httpInterface.h
|
||||
|
|
@ -71,6 +72,11 @@ set(H_HEADER_FILES
|
|||
common/include/structDataSource.h
|
||||
common/include/extraPropertyManager.h
|
||||
|
||||
common/include/pluginCommon/iCanvasItem.h
|
||||
common/include/pluginCommon/iPlugin.h
|
||||
common/include/pluginCommon/iShapeFactory.h
|
||||
common/include/pluginCommon/iPluginAdapter.h
|
||||
|
||||
common/core_model/types.h
|
||||
common/core_model/topology.h
|
||||
common/core_model/diagram.h
|
||||
|
|
@ -95,9 +101,10 @@ set(CPP_SOURCE_FILES
|
|||
source/monitorItemsDlg.cpp
|
||||
source/monitorPagesDlg.cpp
|
||||
source/baseDockWidget.cpp
|
||||
source/enhancedToolBar.cpp
|
||||
source/toolBarConfig.cpp
|
||||
source/enhancedToolBar.cpp
|
||||
source/configToolBar.cpp
|
||||
source/draggableToolButton.cpp
|
||||
|
||||
common/source/httpInterface.cpp
|
||||
common/source/tools.cpp
|
||||
|
|
@ -152,6 +159,7 @@ include_directories(${PostgreSQL_INCLUDE_DIRS})
|
|||
target_include_directories(DiagramDesigner PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
target_include_directories(DiagramDesigner PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/common")
|
||||
target_include_directories(DiagramDesigner PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/PropertyEditor/source/include)")
|
||||
target_include_directories(DiagramDesigner PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/pluginManager/include)")
|
||||
target_link_libraries(DiagramDesigner PUBLIC Qt${QT_VERSION_MAJOR}::Core
|
||||
Qt${QT_VERSION_MAJOR}::Gui
|
||||
Qt${QT_VERSION_MAJOR}::Widgets)
|
||||
|
|
@ -178,8 +186,10 @@ add_subdirectory(PropertyEditor)
|
|||
add_subdirectory(diagramCavas)
|
||||
add_subdirectory(diagramUtils)
|
||||
add_subdirectory(diagramCommunication)
|
||||
add_subdirectory(pluginManager)
|
||||
|
||||
target_link_libraries(DiagramDesigner PRIVATE PropertyEditor)
|
||||
target_link_libraries(DiagramDesigner PRIVATE diagramCavas diagramUtils diagramCommunication)
|
||||
target_link_libraries(DiagramDesigner PRIVATE diagramCavas diagramUtils diagramCommunication pluginManager)
|
||||
|
||||
file(COPY setting.xml DESTINATION "${CMAKE_BINARY_DIR}/${dd_PlatformDir}/bin")
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,11 @@ enum GraphicsItemType
|
|||
GIT_3wTransformer= QGraphicsItem::UserType + 67,
|
||||
GIT_node= QGraphicsItem::UserType + 79,
|
||||
GIT_bay= QGraphicsItem::UserType + 80, //间隔
|
||||
|
||||
GIT_Image = QGraphicsItem::UserType + 110, //图形item
|
||||
GIT_Text = QGraphicsItem::UserType + 111, //文本item
|
||||
|
||||
GIT_PluginItem = QGraphicsItem::UserType + 120, //自定义Item
|
||||
//======================================
|
||||
GIT_baseNode = QGraphicsItem::UserType + 199,
|
||||
GIT_baseBus = QGraphicsItem::UserType + 200,
|
||||
|
|
|
|||
|
|
@ -227,6 +227,23 @@ struct HMIImageRef //人机界面中的图片引用
|
|||
}
|
||||
};
|
||||
|
||||
struct HMICustomImageRef //人机界面中图片item的引用
|
||||
{
|
||||
int id = -1;
|
||||
QUuid hmiId;
|
||||
QString model;
|
||||
QUuid itemId;
|
||||
QByteArray hash256;
|
||||
|
||||
bool operator==(const HMICustomImageRef& other) const
|
||||
{
|
||||
return hmiId == other.hmiId &&
|
||||
model == other.model &&
|
||||
itemId == other.itemId &&
|
||||
hash256 == other.hash256;
|
||||
}
|
||||
};
|
||||
|
||||
struct MonitorItemDisplayInfo //监控模式显示信息
|
||||
{
|
||||
int nItemType; //设备类型
|
||||
|
|
|
|||
|
|
@ -164,6 +164,22 @@ private:
|
|||
PropertyModel pm; //工程模的选择状态
|
||||
};
|
||||
|
||||
class GraphicProperty:public ModelProperty //非模型图元属性
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
GraphicProperty(QObject* parent);
|
||||
virtual ~GraphicProperty();
|
||||
|
||||
void setGraphicType(int n) {nGraphicType = n;}
|
||||
int getGraphicType() {return nGraphicType;}
|
||||
void setContent(const QString& str) {sContent = str;}
|
||||
QString getContent() {return sContent;}
|
||||
protected:
|
||||
int nGraphicType = -1; //图形类型 0图像1文字
|
||||
QString sContent;
|
||||
};
|
||||
|
||||
class BaseProperty:public ModelProperty //图像工程模模属性类,存放电路元件属性
|
||||
{
|
||||
Q_OBJECT
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
//ICanvasItem.h
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QRectF>
|
||||
#include <QPainter>
|
||||
|
||||
class ICanvasItem : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
virtual ~ICanvasItem() = default;
|
||||
|
||||
// 基本信息
|
||||
virtual QString typeId() const = 0;
|
||||
virtual QString displayName() const = 0;
|
||||
|
||||
// 几何属性
|
||||
virtual QRectF bounds() const = 0;
|
||||
virtual void setBounds(const QRectF &rect) = 0;
|
||||
|
||||
// 绘制
|
||||
virtual void draw(QPainter *painter, const QRectF &rect) = 0;
|
||||
|
||||
// 属性管理
|
||||
virtual QVariant property(const QString &key) const = 0;
|
||||
virtual void setProperty(const QString &key, const QVariant &value) = 0;
|
||||
|
||||
signals:
|
||||
void boundsChanged(const QRectF &newBounds);
|
||||
void propertyChanged(const QString &key, const QVariant &value);
|
||||
};
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
// include/plugin_manager/IPlugin.h
|
||||
#pragma once
|
||||
|
||||
#include <QtPlugin>
|
||||
#include <QIcon>
|
||||
#include "iCanvasItem.h"
|
||||
|
||||
// 形状描述
|
||||
struct ShapeDescriptor {
|
||||
QString id; // 形状标识符
|
||||
QString name; // 显示名称
|
||||
QString category; // 分类
|
||||
QString iconPath; // 图标路径
|
||||
QVariantMap defaults; // 默认属性
|
||||
};
|
||||
|
||||
// 插件描述
|
||||
struct PluginDescriptor {
|
||||
QString id; // 插件ID
|
||||
QString name; // 插件名称
|
||||
QString version; // 版本
|
||||
QString author; // 作者
|
||||
QString description; // 描述
|
||||
};
|
||||
|
||||
// 插件接口
|
||||
class IPlugin : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit IPlugin(QObject *parent = nullptr) : QObject(parent) {}
|
||||
virtual ~IPlugin() = default;
|
||||
|
||||
// 插件信息
|
||||
virtual PluginDescriptor descriptor() const = 0;
|
||||
|
||||
// 支持的形状
|
||||
virtual QList<ShapeDescriptor> shapes() const = 0;
|
||||
|
||||
// 创建形状
|
||||
virtual ICanvasItem* createShape(const QString &shapeId) = 0;
|
||||
|
||||
// 插件生命周期
|
||||
virtual bool initialize() = 0;
|
||||
virtual void shutdown() = 0;
|
||||
|
||||
// 图标获取
|
||||
virtual QIcon shapeIcon(const QString &shapeId) const = 0;
|
||||
};
|
||||
|
||||
Q_DECLARE_INTERFACE(IPlugin, "com.canvas.plugin/1.0")
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
//iPluginAdapter.h
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QPainter>
|
||||
#include <QRectF>
|
||||
#include <QPainterPath>
|
||||
|
||||
// 插件适配器抽象接口
|
||||
class IPluginAdapter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit IPluginAdapter(QObject *parent = nullptr) : QObject(parent) {}
|
||||
virtual ~IPluginAdapter() = default;
|
||||
|
||||
// 基本属性
|
||||
virtual QString adapterType() const = 0;
|
||||
virtual QString pluginType() const = 0;
|
||||
|
||||
// 几何属性
|
||||
virtual QRectF bounds() const = 0;
|
||||
virtual void setBounds(const QRectF &bounds) = 0;
|
||||
|
||||
// 绘制
|
||||
virtual void paint(QPainter *painter,
|
||||
const QRectF &bounds) = 0;
|
||||
|
||||
// 形状
|
||||
virtual QPainterPath shape() const = 0;
|
||||
|
||||
// 属性访问
|
||||
virtual QVariant property(const QString &key) const = 0;
|
||||
virtual void setProperty(const QString &key, const QVariant &value) = 0;
|
||||
|
||||
// 操作
|
||||
virtual void move(const QPointF &delta) = 0;
|
||||
virtual void resize(const QRectF &newBounds) = 0;
|
||||
|
||||
// 状态
|
||||
virtual bool isSelected() const = 0;
|
||||
virtual void setSelected(bool selected) = 0;
|
||||
|
||||
// 序列化
|
||||
virtual QVariantMap saveState() const = 0;
|
||||
virtual bool loadState(const QVariantMap &state) = 0;
|
||||
signals:
|
||||
void boundsChanged(const QRectF &newBounds);
|
||||
void propertyChanged(const QString &key, const QVariant &value);
|
||||
void selectionChanged(bool selected);
|
||||
void adapterChanged();
|
||||
};
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
//IShapeFactory.h
|
||||
#pragma once
|
||||
|
||||
#include "iCanvasItem.h"
|
||||
#include "iPlugin.h"
|
||||
#include <QMap>
|
||||
|
||||
// 形状工厂接口(纯接口,不用于插件)
|
||||
class IShapeFactory
|
||||
{
|
||||
public:
|
||||
virtual ~IShapeFactory() = default;
|
||||
|
||||
// 创建形状
|
||||
virtual ICanvasItem* create(const QString &shapeId) = 0;
|
||||
|
||||
// 查询
|
||||
virtual QStringList availableShapes() const = 0;
|
||||
virtual bool contains(const QString &shapeId) const = 0;
|
||||
|
||||
// 获取形状信息
|
||||
virtual ShapeDescriptor shapeDescriptor(const QString &shapeId) const = 0;
|
||||
virtual QIcon shapeIcon(const QString &shapeId) const = 0;
|
||||
};
|
||||
|
|
@ -60,6 +60,17 @@ BaseModelProperty::BaseModelProperty(QObject* parent)
|
|||
BaseModelProperty::~BaseModelProperty()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**************************图形类********************************/
|
||||
GraphicProperty::GraphicProperty(QObject* parent)
|
||||
: ModelProperty(parent)
|
||||
{
|
||||
|
||||
}
|
||||
GraphicProperty::~GraphicProperty()
|
||||
{
|
||||
|
||||
}
|
||||
/****************************工程模****************************/
|
||||
|
||||
|
|
|
|||
|
|
@ -53,14 +53,17 @@ set(DIAGRAMCAVAS_HEADER_FILES
|
|||
include/createHMIdlg.h
|
||||
include/graphicsDataModel/baseModel.h
|
||||
include/graphicsDataModel/fixedPortsModel.h
|
||||
include/graphicsItem/graphicsBaseItem.h
|
||||
include/graphicsItem/graphicsItemGroup.h
|
||||
#include/graphicsItem/graphicsPolygonItem.h
|
||||
include/graphicsItem/handleRect.h
|
||||
include/graphicsItem/handleText.h
|
||||
include/graphicsItem/itemControlHandle.h
|
||||
include/graphicsItem/itemPort.h
|
||||
include/graphicsItem/electricBayItem.h
|
||||
include/graphicsItem/itemControlHandle.h
|
||||
include/graphicsItem/graphicsBaseItem.h
|
||||
|
||||
include/graphicsItem/pluginItemFactory.h
|
||||
include/graphicsItem/pluginItemWrapper.h
|
||||
|
||||
include/graphicsItem/functionModelItem/electricFunctionModelConnectLineItem.h
|
||||
include/graphicsItem/functionModelItem/electricFunctionModelPortItem.h
|
||||
|
|
@ -83,6 +86,7 @@ set(DIAGRAMCAVAS_HEADER_FILES
|
|||
include/graphicsItem/functionModelItem/electricFunctionModelSvgItemPI.h
|
||||
include/graphicsItem/functionModelItem/electricFunctionModelSvgItemPT.h
|
||||
include/graphicsItem/functionModelItem/graphicsFunctionModelItem.h
|
||||
include/graphicsItem/functionModelItem/electricFunctionModelSvgItemImage.h
|
||||
|
||||
include/baseModelItem/electricBaseModelSvgItem.h
|
||||
include/baseModelItem/electricBaseModelLineItem.h
|
||||
|
|
@ -177,14 +181,17 @@ set(DIAGRAMCAVAS_SOURCE_FILES
|
|||
source/createHMIdlg.cpp
|
||||
source/graphicsDataModel/baseModel.cpp
|
||||
source/graphicsDataModel/fixedPortsModel.cpp
|
||||
source/graphicsItem/graphicsBaseItem.cpp
|
||||
source/graphicsItem/graphicsItemGroup.cpp
|
||||
#source/graphicsItem/graphicsPolygonItem.cpp
|
||||
source/graphicsItem/handleRect.cpp
|
||||
source/graphicsItem/handleText.cpp
|
||||
source/graphicsItem/itemControlHandle.cpp
|
||||
source/graphicsItem/itemPort.cpp
|
||||
source/graphicsItem/electricBayItem.cpp
|
||||
source/graphicsItem/itemControlHandle.cpp
|
||||
source/graphicsItem/graphicsBaseItem.cpp
|
||||
|
||||
source/graphicsItem/pluginItemFactory.cpp
|
||||
source/graphicsItem/pluginItemWrapper.cpp
|
||||
|
||||
source/graphicsItem/functionModelItem/electricFunctionModelConnectLineItem.cpp
|
||||
source/graphicsItem/functionModelItem/electricFunctionModelPortItem.cpp
|
||||
|
|
@ -207,6 +214,7 @@ set(DIAGRAMCAVAS_SOURCE_FILES
|
|||
source/graphicsItem/functionModelItem/electricFunctionModelSvgItemPI.cpp
|
||||
source/graphicsItem/functionModelItem/electricFunctionModelSvgItemPT.cpp
|
||||
source/graphicsItem/functionModelItem/graphicsFunctionModelItem.cpp
|
||||
source/graphicsItem/functionModelItem/electricFunctionModelSvgItemImage.cpp
|
||||
|
||||
source/baseModelItem/electricBaseModelSvgItem.cpp
|
||||
source/baseModelItem/electricBaseModelLineItem.cpp
|
||||
|
|
@ -291,6 +299,7 @@ target_include_directories(diagramCavas PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/inclu
|
|||
|
||||
target_link_libraries(diagramCavas PRIVATE diagramUtils)
|
||||
target_link_libraries(diagramCavas PRIVATE diagramCommunication)
|
||||
target_link_libraries(diagramCavas PRIVATE pluginManager)
|
||||
target_link_libraries(diagramCavas PUBLIC PropertyEditor)
|
||||
|
||||
target_compile_definitions(diagramCavas
|
||||
|
|
|
|||
|
|
@ -48,15 +48,20 @@ public:
|
|||
~FixedPortsModel();
|
||||
public:
|
||||
QMap<QUuid,ItemPageInfo> allNodePos() const;
|
||||
QMap<QUuid,ItemPageInfo> allGraphicItemPos() const; //所有图形对象位置
|
||||
QVector<ModelProperty*> allConnectionProperty();
|
||||
QMap<QUuid,GraphicsFunctionModelItem*>& allItems();
|
||||
QMap<QUuid,GraphicsFunctionModelItem*>& allGraphicItems() {return _graphicItem;}
|
||||
bool addNodeItem(QUuid uuid,GraphicsFunctionModelItem*);
|
||||
bool addGraphicItem(QUuid uuid,GraphicsFunctionModelItem*);
|
||||
QString addNodeItem(QUuid id,QPointF pos,double width = 0,double height = 0,double rotate = 0);
|
||||
QString addGraphicItem(QUuid id,QString name,QPointF pos,int type,QString sContent = "",double width = 0,double height = 0,double rotate = 0); //0图形1文字
|
||||
GraphicsFunctionModelItem* nodeItem(QUuid uuid);
|
||||
BaseProperty* addNodeData(QUuid id,int type,QString name,QString modelName); //对应component数据,一个data可对应多个item(id,类型,名称,工程模名)
|
||||
void loadNodeDataFromDataBase(); //从数据库加载数据
|
||||
QString addConnectLline(QUuid lineId,QUuid srcId,QUuid destId,QUuid srcPort,QUuid destPort);
|
||||
void deleteNodeItem(GraphicsFunctionModelItem*);
|
||||
void deleteGraphicItem(GraphicsFunctionModelItem*);
|
||||
//QJsonObject saveNode(QUuid const) const;
|
||||
void saveNode(int nPageId);
|
||||
void setScene(DesignerScene* p){_scene = p;}
|
||||
|
|
@ -79,7 +84,9 @@ public:
|
|||
void insertProjectModelName(QString,QString); //插入工程模类型(生成工程模时调用)
|
||||
void showProjectIconSettingDlg(GraphicsFunctionModelItem*); //显示工程模图标设置(设置使用图标)
|
||||
void updateItemIcon(QString sMeta,QString sModel,QMap<QString,QByteArray>,QString sIndex = "",int type = 0,int slot = 0); //更新指定模型的图标 sIndex:索引下标,为空全部更新 sTemplate模板名 type基础类型 slot HMI资源中的槽位
|
||||
void updateCustomItemIcon(QUuid itemId,QMap<QString,QByteArray> mapData); //更新graphic对象的图片
|
||||
void updateModelIcon(QString sMeta,QString sModel,QMap<QString,QByteArray>,QString sIndex = ""); //更新某类模型的所有图标
|
||||
void updateCustomById(QUuid itemId,QMap<QString,QByteArray>); //更新指定custom对象的图片
|
||||
/*************************间隔*****************************/
|
||||
void addBayItem(QUuid,ModelFunctionType = ModelFunctionType::ProjectModel);
|
||||
bool addBayItem(QUuid,ElectricBayItem*,ModelFunctionType = ModelFunctionType::ProjectModel);
|
||||
|
|
@ -116,8 +123,11 @@ public:
|
|||
QMap<MonitorItemTypeStruct,QMap<MonitorItemStateStruct,MonitorItemDisplayInfo>>& getMonitorDisplaySetting(){return m_monitorDisplaySetting;}
|
||||
|
||||
QList<HMIImageRef>& getHMIimageRef(){return _HMIimageRef;}
|
||||
QList<HMICustomImageRef>& getHMICustomImageRef(){return _HMICustomImageRef;}
|
||||
int imageRefExist(QString model,QByteArray hash256);
|
||||
int customImageRefExist(QUuid uid,QByteArray hash256);
|
||||
void updateHMIRef(QUuid hmiId,QString model,QByteArray hash256,int slot); //更新img引用
|
||||
void updateHMICustomRef(QUuid hmiId,QString model,QUuid itemId,QByteArray hash256); //更新customImg引用
|
||||
/************************数据显示*************************/
|
||||
void setCurItemPropertyDlg(ItemPropertyDlg* p) {m_curPropertyDlg = p;}
|
||||
ItemPropertyDlg* getCurItemPropertyDlg() {return m_curPropertyDlg;}
|
||||
|
|
@ -142,6 +152,7 @@ public:
|
|||
|
||||
QMap<QUuid,GraphicsFunctionModelItem*> getHMIItems(){return _nodeItem;}
|
||||
QMap<QUuid,ElectricBayItem*> getProjectBayItems(){return _bayItem;}
|
||||
QMap<QUuid,GraphicsFunctionModelItem*> getGraphicItems(){return _graphicItem;}
|
||||
|
||||
void setPageState(int n) {_pageState = n;}
|
||||
int getPageState() {return _pageState;}
|
||||
|
|
@ -165,6 +176,7 @@ private:
|
|||
|
||||
QMap<QUuid,GraphicsFunctionModelItem*> _nodeItem; //工程模对象
|
||||
QMap<QUuid,ElectricBayItem*> _bayItem; //间隔对象
|
||||
QMap<QUuid,GraphicsFunctionModelItem*> _graphicItem; //图形对象(图片,文字等)
|
||||
|
||||
QString _pageName;
|
||||
QPointer<DiagramCavas> _cavas;
|
||||
|
|
@ -193,6 +205,7 @@ private:
|
|||
QString _lastSaveTime; //页面上次保存时间
|
||||
|
||||
QList<HMIImageRef> _HMIimageRef; //当前HMI中图片的引用关系
|
||||
QList<HMICustomImageRef> _HMICustomImageRef; //当前HMI中图片项的引用
|
||||
public:
|
||||
static bool _dataInitialised;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef ELECBAYITEM_H
|
||||
#define ELECBAYITEM_H
|
||||
|
||||
#include "graphicsBaseItem.h"
|
||||
#include "graphicsItem/graphicsBaseItem.h"
|
||||
#include "baseProperty.h"
|
||||
|
||||
class ElectricBayItem :public GraphicsNonStandardItem
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef ELECTRICFUNCTIONMODELSVGITEMIMAGE_H
|
||||
#define ELECTRICFUNCTIONMODELSVGITEMIMAGE_H
|
||||
|
||||
/*****************自定义图形类*******************/
|
||||
#include "electricFunctionModelSvgItem.h"
|
||||
|
||||
class ElectricFunctionModelSvgItemImage :public ElectricFunctionModelSvgItem
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ElectricFunctionModelSvgItemImage(const QRect &rect,QGraphicsItem *parent = 0);
|
||||
virtual ~ElectricFunctionModelSvgItemImage();
|
||||
virtual void setImage_1(QFileInfo) override;
|
||||
protected:
|
||||
virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) override;
|
||||
private:
|
||||
void initial();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef GRAPHICSFUNCTIONMODELITEM_H
|
||||
#define GRAPHICSFUNCTIONMODELITEM_H
|
||||
|
||||
#include "../graphicsBaseItem.h"
|
||||
#include "graphicsItem/graphicsBaseItem.h"
|
||||
|
||||
class GraphicsFunctionModelItem : public GraphicsProjectModelItem //功能模item
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef GRAPHICSITEMGROUP_H
|
||||
#define GRAPHICSITEMGROUP_H
|
||||
|
||||
#include "graphicsBaseItem.h"
|
||||
#include "graphicsItem/graphicsBaseItem.h"
|
||||
|
||||
|
||||
class GraphicsItemGroup : public QObject, public AbstractShapeType<QGraphicsItemGroup>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef GRAPHICSPOLYGONITEM_H
|
||||
#define GRAPHICSPOLYGONITEM_H
|
||||
|
||||
#include "graphicsBaseItem.h"
|
||||
#include "graphicsItem/graphicsBaseItem.h"
|
||||
|
||||
class GraphicPolygonItem : public GraphicsProjectModelItem
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
// src/canvas/PluginItemFactory.h
|
||||
#pragma once
|
||||
|
||||
#include "export.hpp"
|
||||
#include "functionModelItem/graphicsFunctionModelItem.h"
|
||||
#include <QObject>
|
||||
|
||||
class PluginManager;
|
||||
class ICanvasItem;
|
||||
|
||||
class DIAGRAM_DESIGNER_PUBLIC PluginItemFactory : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static PluginItemFactory* instance();
|
||||
|
||||
// 删除拷贝构造函数和赋值运算符
|
||||
PluginItemFactory(const PluginItemFactory&) = delete;
|
||||
PluginItemFactory& operator=(const PluginItemFactory&) = delete;
|
||||
|
||||
// 设置插件管理器
|
||||
void setPluginManager(PluginManager *manager);
|
||||
PluginManager* pluginManager() const;
|
||||
|
||||
// 创建图形项
|
||||
GraphicsFunctionModelItem* createItem(const QString &shapeId,
|
||||
QGraphicsItem *parent = nullptr);
|
||||
|
||||
// 从插件项创建图形项
|
||||
GraphicsFunctionModelItem* createItemFromPlugin(ICanvasItem *pluginItem,
|
||||
QGraphicsItem *parent = nullptr);
|
||||
|
||||
signals:
|
||||
void itemCreated(GraphicsFunctionModelItem *item);
|
||||
void creationFailed(const QString &shapeId, const QString &error);
|
||||
|
||||
private:
|
||||
// 内联定义Private类
|
||||
class Private
|
||||
{
|
||||
public:
|
||||
PluginManager *pluginManager = nullptr;
|
||||
|
||||
Private() = default;
|
||||
~Private() = default;
|
||||
};
|
||||
|
||||
explicit PluginItemFactory(QObject *parent = nullptr);
|
||||
~PluginItemFactory() = default; // QScopedPointer自动管理内存
|
||||
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
//pluginItemWrapper.h
|
||||
#pragma once
|
||||
|
||||
#include "functionModelItem/graphicsFunctionModelItem.h"
|
||||
#include "pluginCommon/iCanvasItem.h"
|
||||
#include <QObject>
|
||||
|
||||
// 内部包装器,不暴露给外部
|
||||
class PluginItemWrapper : public GraphicsFunctionModelItem
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PluginItemWrapper(ICanvasItem *pluginItem, QGraphicsItem *parent = nullptr);
|
||||
virtual ~PluginItemWrapper();
|
||||
|
||||
// 克隆
|
||||
virtual GraphicsFunctionModelItem* clone() const override;
|
||||
|
||||
// 绘图
|
||||
virtual void paint(QPainter *painter,
|
||||
const QStyleOptionGraphicsItem *option,
|
||||
QWidget *widget = nullptr) override;
|
||||
|
||||
virtual QRectF boundingRect() const override;
|
||||
virtual QPainterPath shape() const override;
|
||||
|
||||
// 几何操作
|
||||
virtual void updateCoordinate() override;
|
||||
virtual void resize(int handle, double dx, double dy, const QPointF &pos) override;
|
||||
virtual void move(const QPointF &delta) override;
|
||||
|
||||
// 获取插件项
|
||||
ICanvasItem* pluginItem() const;
|
||||
|
||||
protected:
|
||||
virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;
|
||||
|
||||
private:
|
||||
ICanvasItem *m_pluginItem = nullptr;
|
||||
QRectF m_cachedBounds;
|
||||
|
||||
void updateCache();
|
||||
void connectSignals();
|
||||
QVariantMap saveState() const;
|
||||
bool loadStateIntoPluginItem(ICanvasItem *pluginItem, const QVariantMap &state) const;
|
||||
void copyPropertiesFrom(const PluginItemWrapper *source);
|
||||
|
||||
private slots:
|
||||
void onPluginBoundsChanged(const QRectF &newBounds);
|
||||
void onPluginPropertyChanged(const QString &key, const QVariant &value);
|
||||
};
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include "baseSelector.h"
|
||||
//#include "global.h"
|
||||
#include <graphicsItem/graphicsBaseItem.h>
|
||||
#include "graphicsItem/graphicsBaseItem.h"
|
||||
|
||||
|
||||
class EditingSelector : public BaseSelector
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#include "baseModelItem/electricBaseModelSvgItem.h"
|
||||
#include "graphicsItem/itemControlHandle.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QStyleOption>
|
||||
|
|
|
|||
|
|
@ -144,8 +144,6 @@ void DesignerScene::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
|
|||
if(m_pDrawingPanel)
|
||||
{
|
||||
DiagramMode mode = m_pDrawingPanel->getMode();
|
||||
if(mode == DM_run)
|
||||
return;
|
||||
m_pDrawingPanel->selectorManager()->getWorkingSelector()->dragEnterEvent(event, this,mode);
|
||||
update();
|
||||
}
|
||||
|
|
@ -158,8 +156,6 @@ void DesignerScene::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
|
|||
if(m_pDrawingPanel)
|
||||
{
|
||||
DiagramMode mode = m_pDrawingPanel->getMode();
|
||||
if(mode == DM_run)
|
||||
return;
|
||||
m_pDrawingPanel->selectorManager()->getWorkingSelector()->dragMoveEvent(event, this,mode);
|
||||
update();
|
||||
}
|
||||
|
|
@ -172,8 +168,6 @@ void DesignerScene::dropEvent(QGraphicsSceneDragDropEvent *event)
|
|||
if(m_pDrawingPanel)
|
||||
{
|
||||
DiagramMode mode = m_pDrawingPanel->getMode();
|
||||
if(mode == DM_run)
|
||||
return;
|
||||
m_pDrawingPanel->selectorManager()->getWorkingSelector()->dropEvent(event, this,mode);
|
||||
update();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -223,6 +223,14 @@ void DiagramCavas::onSignal_savePage()
|
|||
DataBase::GetInstance()->insertHMIimageRefBatch(imgRefLst); //全部重新插入
|
||||
}
|
||||
|
||||
QList<HMICustomImageRef>& imgCustomRefLst = pMonitor->getModelController()->getHMICustomImageRef(); //获取当前HMI所有custom引用
|
||||
if(imgCustomRefLst.size()){
|
||||
auto lstRef = DataBase::GetInstance()->getHMICustomRefAll(imgCustomRefLst.first().hmiId);
|
||||
if(lstRef.size())
|
||||
DataBase::GetInstance()->removeHMICustomRefAll(imgCustomRefLst.first().hmiId);
|
||||
DataBase::GetInstance()->insertHMICustomRefBatch(imgCustomRefLst);
|
||||
}
|
||||
|
||||
if(DataBase::GetInstance()->getHMIdByName(pEntity->name()).isNull()) //不存在,创建
|
||||
DataBase::GetInstance()->insertHMI(QUuid(pEntity->id()),pEntity->name(),pEntity->name(),pMonitor->getDiagramInfo());
|
||||
else
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include "graphicsItem/functionModelItem/electricFunctionModelSvgItem2wTransformer.h"
|
||||
#include "graphicsItem/functionModelItem/electricFunctionModelSvgItem3wTransformer.h"
|
||||
#include "graphicsItem/functionModelItem/electricFunctionModelConnectLineItem.h"
|
||||
#include "graphicsItem/functionModelItem/electricFunctionModelSvgItemImage.h"
|
||||
|
||||
#include "graphicsItem/itemPort.h"
|
||||
#include "designerScene.h"
|
||||
|
|
@ -41,7 +42,6 @@
|
|||
#include "projectModelManager.h"
|
||||
#include "projectIconSetting.h"
|
||||
#include "monitorPanel.h"
|
||||
#include "designerView.h"
|
||||
#include "uiCommunicationBus.h"
|
||||
#include "instance/dataAccessor.h"
|
||||
#include "graphicsItem/handleText.h"
|
||||
|
|
@ -102,6 +102,23 @@ QMap<QUuid,ItemPageInfo> FixedPortsModel::allNodePos() const
|
|||
return map;
|
||||
}
|
||||
|
||||
QMap<QUuid,ItemPageInfo> FixedPortsModel::allGraphicItemPos() const
|
||||
{
|
||||
QMap<QUuid,ItemPageInfo> map;
|
||||
for(auto pItem:_graphicItem)
|
||||
{
|
||||
ItemPageInfo info;
|
||||
double dWidth = pItem->boundingRect().width();
|
||||
double dHeight = pItem->boundingRect().height();
|
||||
info.pos = pItem->scenePos()/*+QPointF(dWidth*0.5,dHeight*0.5)*/;
|
||||
info.dWidth = dWidth;
|
||||
info.dHeight = dHeight;
|
||||
info.dRotate = pItem->rotation();
|
||||
map.insert(pItem->itemId(),info);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
QVector<ModelProperty*> FixedPortsModel::allConnectionProperty()
|
||||
{
|
||||
QVector<ModelProperty*> vec;
|
||||
|
|
@ -155,9 +172,77 @@ bool FixedPortsModel::addNodeItem(QUuid uuid,GraphicsFunctionModelItem* pItem)
|
|||
}
|
||||
}
|
||||
|
||||
bool FixedPortsModel::addGraphicItem(QUuid uuid,GraphicsFunctionModelItem* pItem)
|
||||
{
|
||||
if(_graphicItem.contains(uuid))
|
||||
return false;
|
||||
else
|
||||
{
|
||||
pItem->setHandle(this);
|
||||
_graphicItem.insert(uuid,pItem);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
QString FixedPortsModel::addGraphicItem(QUuid id,QString name,QPointF pos,int type,QString sContent,double width,double height,double rotate)
|
||||
{
|
||||
GraphicProperty* pro = nullptr;
|
||||
GraphicsFunctionModelItem* item = nullptr;
|
||||
if(_graphicItem.contains(id))
|
||||
return "exist";
|
||||
double dX = 0.0;
|
||||
double dY = 0.0;
|
||||
if(type == 0){ //图像
|
||||
|
||||
if(width == 0 && height == 0){
|
||||
dX = 30;
|
||||
dY = 30;
|
||||
}
|
||||
else{
|
||||
dX = width;
|
||||
dY = height;
|
||||
}
|
||||
item = new ElectricFunctionModelSvgItemImage(QRect(-dX*0.5, -dY*0.5, dX, dY));
|
||||
item->setItemType(GIT_Image);
|
||||
pro = new GraphicProperty(item);
|
||||
pro->setGraphicsType(GIT_Image);
|
||||
pro->setModelName("customImage");
|
||||
pro->setGraphicType(0);
|
||||
//pro->setContent();
|
||||
}
|
||||
else if(type == 1){ //文字
|
||||
//pro = new ModelProperty();
|
||||
}
|
||||
|
||||
if(item)
|
||||
{
|
||||
item->setItemId(id);
|
||||
pro->setUuid(id);
|
||||
pro->setType(-1);
|
||||
item->editShape(0, pos);
|
||||
item->setPos(pos);
|
||||
item->setRotation(rotate);
|
||||
_scene->addItem(item);
|
||||
item->addPoint(pos);
|
||||
item->setProperty(pro); //绑定模型
|
||||
//item->updateByProperty(); //使用模型更新自身
|
||||
item->setHandle(this);
|
||||
_graphicItem.insert(id,item);
|
||||
if(name.isEmpty()){ //如果不给名称则给个默认值
|
||||
pro->setName("item_"+QString::number(_graphicItem.size()));
|
||||
}
|
||||
else{
|
||||
pro->setName(name);
|
||||
}
|
||||
|
||||
}
|
||||
return pro?pro->name():"err";
|
||||
}
|
||||
|
||||
QString FixedPortsModel::addNodeItem(QUuid id,QPointF pos,double width,double height,double rotate)
|
||||
{
|
||||
//todo:load图形时必有拓扑实体,关联到对应的entity
|
||||
|
||||
BaseProperty* pro = nullptr;
|
||||
GraphicsFunctionModelItem* item = nullptr;
|
||||
QMap<QUuid,BaseProperty*> mapData = BasePropertyManager::instance().getEntityData(); //加载的图形必定关联component(todo:完善判断条件,如判断拓扑节点)
|
||||
|
|
@ -905,6 +990,15 @@ void FixedPortsModel::deleteNodeItem(GraphicsFunctionModelItem* pItem)
|
|||
}
|
||||
}
|
||||
|
||||
void FixedPortsModel::deleteGraphicItem(GraphicsFunctionModelItem* pItem)
|
||||
{
|
||||
for(auto iter = _graphicItem.begin();iter != _graphicItem.end();++iter){
|
||||
if(iter.value() == pItem){
|
||||
delete _graphicItem.take(iter.key());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FixedPortsModel::saveNode(int nPageId)
|
||||
{
|
||||
QList<GridInfo> lstGrid = DataBase::GetInstance()->getAllGrid();
|
||||
|
|
@ -1933,6 +2027,24 @@ void FixedPortsModel::updateItemIcon(QString sMeta,QString sModel,QMap<QString,Q
|
|||
updateModelIcon(sMeta,sModel,mapData,sIndex);
|
||||
}
|
||||
|
||||
void FixedPortsModel::updateCustomItemIcon(QUuid itemId,QMap<QString,QByteArray> mapData)
|
||||
{
|
||||
if(mapData.size() == 1){ //单项设置
|
||||
QByteArray sha256Hash = QCryptographicHash::hash(mapData.first(), QCryptographicHash::Sha256).toHex();
|
||||
QMap<QByteArray,HMIImageInfo>& mapResource = ProjectModelManager::instance().getHMIimageMap(); //更新总HMI资源
|
||||
if(!mapResource.contains(sha256Hash)){ //库中不存在则新建
|
||||
HMIImageInfo imageInfo;
|
||||
imageInfo.baseType = -1; //未定义类型
|
||||
imageInfo.imageName = mapData.firstKey();
|
||||
imageInfo.hash256 = sha256Hash;
|
||||
imageInfo.svgData = mapData.first();
|
||||
mapResource.insert(sha256Hash,imageInfo);
|
||||
}
|
||||
updateHMICustomRef(QUuid(_widget->getEntity()->id()),"customImage",itemId,sha256Hash); //更新本页的custom引用
|
||||
}
|
||||
//updateCustomById(itemId,mapData); //不需要更新其他custom对象
|
||||
}
|
||||
|
||||
void FixedPortsModel::updateModelIcon(QString sMeta,QString sModel,QMap<QString,QByteArray> mapData,QString sIndex)
|
||||
{
|
||||
for(auto &pItem:_nodeItem){
|
||||
|
|
@ -1952,6 +2064,24 @@ void FixedPortsModel::updateModelIcon(QString sMeta,QString sModel,QMap<QString,
|
|||
}
|
||||
}
|
||||
|
||||
void FixedPortsModel::updateCustomById(QUuid itemId,QMap<QString,QByteArray> mapData)
|
||||
{
|
||||
for(auto &pItem:_graphicItem){
|
||||
auto pro = pItem->getProperty();
|
||||
|
||||
if(pro->uuid() == itemId){
|
||||
auto pI = dynamic_cast<ElectricFunctionModelSvgItem*>(pItem);
|
||||
auto pG = dynamic_cast<ElectricFunctionModelSvgGroup*>(pItem);
|
||||
if(pI){
|
||||
pI->updateMapSvg(mapData,"");
|
||||
}
|
||||
if(pG){
|
||||
pG->updateMapSvg(mapData,"");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FixedPortsModel::addBayItem(QUuid id,ModelFunctionType tpe)
|
||||
{
|
||||
if(tpe == ModelFunctionType::BaseModel){
|
||||
|
|
@ -2389,6 +2519,16 @@ int FixedPortsModel::imageRefExist(QString model,QByteArray hash256)
|
|||
return -1;
|
||||
}
|
||||
|
||||
int FixedPortsModel::customImageRefExist(QUuid uid,QByteArray hash256)
|
||||
{
|
||||
for(auto& info:_HMICustomImageRef)
|
||||
{
|
||||
if(uid == info.itemId && hash256 == info.hash256)
|
||||
return _HMICustomImageRef.indexOf(info);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void FixedPortsModel::updateHMIRef(QUuid hmiId,QString model,QByteArray hash256,int slot)
|
||||
{
|
||||
HMIImageRef ref;
|
||||
|
|
@ -2404,3 +2544,19 @@ void FixedPortsModel::updateHMIRef(QUuid hmiId,QString model,QByteArray hash256,
|
|||
_HMIimageRef.append(ref);
|
||||
}
|
||||
}
|
||||
|
||||
void FixedPortsModel::updateHMICustomRef(QUuid hmiId,QString model,QUuid itemId,QByteArray hash256)
|
||||
{
|
||||
HMICustomImageRef ref;
|
||||
ref.hmiId = hmiId;
|
||||
ref.model = model;
|
||||
ref.itemId = itemId;
|
||||
ref.hash256 = hash256;
|
||||
int index = customImageRefExist(itemId,hash256);
|
||||
if(index != -1){ //已存在,替换
|
||||
_HMICustomImageRef[index] = ref;
|
||||
}
|
||||
else{ //新建
|
||||
_HMICustomImageRef.append(ref);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#include "graphicsItem/functionModelItem/electricFunctionModelSvgItem.h"
|
||||
#include "graphicsItem/itemControlHandle.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QStyleOption>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
#include "graphicsItem/functionModelItem/electricFunctionModelSvgItemImage.h"
|
||||
#include "graphicsDataModel/fixedPortsModel.h"
|
||||
#include "baseProperty.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QStyleOption>
|
||||
#include <QGraphicsScene>
|
||||
#include <QGraphicsView>
|
||||
|
||||
ElectricFunctionModelSvgItemImage::ElectricFunctionModelSvgItemImage(const QRect &rect, QGraphicsItem *parent)
|
||||
: ElectricFunctionModelSvgItem(rect,parent)
|
||||
{
|
||||
initial();
|
||||
}
|
||||
|
||||
ElectricFunctionModelSvgItemImage::~ElectricFunctionModelSvgItemImage()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ElectricFunctionModelSvgItemImage::setImage_1(QFileInfo info)
|
||||
{
|
||||
QByteArray svgData;
|
||||
QFile svgFile(info.absoluteFilePath());
|
||||
|
||||
if (svgFile.open(QIODevice::ReadOnly)) {
|
||||
svgData = svgFile.readAll();
|
||||
svgFile.close();
|
||||
} else {
|
||||
qDebug() << "can't open imgfile" << svgFile.errorString();
|
||||
}
|
||||
|
||||
QMap<QString,QByteArray> mapData;
|
||||
if(!svgData.isEmpty()){
|
||||
mapData["customImage"] = svgData;
|
||||
updateMapSvg(mapData,"customImage");
|
||||
loadSvg(svgData);
|
||||
updateItem();
|
||||
}
|
||||
|
||||
QString sMeta;
|
||||
QString sModel;
|
||||
QUuid itemId;
|
||||
if(_property){
|
||||
sMeta = _property->metaModelName();
|
||||
sModel = _property->modelName();
|
||||
itemId = _property->uuid();
|
||||
}
|
||||
|
||||
if(_pHandle)
|
||||
_pHandle->updateCustomItemIcon(itemId,mapData);
|
||||
|
||||
GraphicsBaseItem::setImage_1(info);
|
||||
}
|
||||
|
||||
|
||||
void ElectricFunctionModelSvgItemImage::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
|
||||
{
|
||||
ElectricFunctionModelSvgItem::paint(painter,option,widget);
|
||||
}
|
||||
|
||||
void ElectricFunctionModelSvgItemImage::initial()
|
||||
{
|
||||
setHandleIfShow(H_textCaption,false);
|
||||
setHandleVisible(false);
|
||||
setFunctionHandleIfShow(false);
|
||||
setFunctionHandleEnaable(false);
|
||||
if(!_itemImgIndex.contains("es"))
|
||||
_itemImgIndex.append("es");
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
// src/canvas/PluginItemFactory.cpp
|
||||
#include "diagramCavas/include/graphicsItem/pluginItemFactory.h"
|
||||
#include "include/graphicsItem/pluginItemWrapper.h"
|
||||
#include "pluginManager/include/pluginManager.h"
|
||||
#include <QDebug>
|
||||
|
||||
PluginItemFactory* PluginItemFactory::instance()
|
||||
{
|
||||
static PluginItemFactory instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
PluginItemFactory::PluginItemFactory(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
void PluginItemFactory::setPluginManager(PluginManager *manager)
|
||||
{
|
||||
d->pluginManager = manager;
|
||||
}
|
||||
|
||||
GraphicsFunctionModelItem* PluginItemFactory::createItem(const QString &shapeId,
|
||||
QGraphicsItem *parent)
|
||||
{
|
||||
if (!d->pluginManager) {
|
||||
qWarning() << "PluginManager not set";
|
||||
emit creationFailed(shapeId, "PluginManager not set");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 1. 通过插件管理器创建原始插件项
|
||||
ICanvasItem *pluginItem = d->pluginManager->createItem(shapeId);
|
||||
if (!pluginItem) {
|
||||
qWarning() << "Failed to create plugin item:" << shapeId;
|
||||
emit creationFailed(shapeId, "Plugin item creation failed");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 2. 创建包装器
|
||||
GraphicsFunctionModelItem *item = createItemFromPlugin(pluginItem, parent);
|
||||
|
||||
if (item) {
|
||||
emit itemCreated(item);
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
GraphicsFunctionModelItem* PluginItemFactory::createItemFromPlugin(
|
||||
ICanvasItem *pluginItem, QGraphicsItem *parent)
|
||||
{
|
||||
if (!pluginItem) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 创建包装器
|
||||
PluginItemWrapper *wrapper = new PluginItemWrapper(pluginItem, parent);
|
||||
|
||||
if (!wrapper) {
|
||||
qWarning() << "PluginItemFactory: Failed to create wrapper";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 设置基本属性
|
||||
wrapper->setItemType(GIT_PluginItem);
|
||||
wrapper->setName(pluginItem->displayName());
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
|
@ -0,0 +1,451 @@
|
|||
// pluginItemWrapper.cpp
|
||||
#include "graphicsItem/pluginItemWrapper.h"
|
||||
#include "pluginManager/include/pluginManager.h"
|
||||
#include <QDebug>
|
||||
#include <QPainter>
|
||||
#include <QStyleOptionGraphicsItem>
|
||||
|
||||
PluginItemWrapper::PluginItemWrapper(ICanvasItem *pluginItem, QGraphicsItem *parent)
|
||||
: GraphicsFunctionModelItem(parent)
|
||||
, m_pluginItem(pluginItem)
|
||||
{
|
||||
if (!m_pluginItem) {
|
||||
qWarning() << "PluginItemWrapper: pluginItem is null!";
|
||||
return;
|
||||
}
|
||||
|
||||
// 设置类型
|
||||
m_Itemtype = GIT_PluginItem;
|
||||
|
||||
// 设置初始名称
|
||||
setName(m_pluginItem->displayName());
|
||||
|
||||
// 连接信号
|
||||
connectSignals();
|
||||
|
||||
// 初始化缓存
|
||||
updateCache();
|
||||
|
||||
// 更新坐标
|
||||
updateCoordinate();
|
||||
|
||||
qDebug() << "PluginItemWrapper created for:" << m_pluginItem->typeId();
|
||||
}
|
||||
|
||||
PluginItemWrapper::~PluginItemWrapper()
|
||||
{
|
||||
// 删除插件项
|
||||
if (m_pluginItem) {
|
||||
m_pluginItem->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
GraphicsFunctionModelItem* PluginItemWrapper::clone() const
|
||||
{
|
||||
if (!m_pluginItem) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 获取场景中的PluginManager
|
||||
PluginManager *manager = PluginManager::instance();
|
||||
if (!manager) {
|
||||
qWarning() << "PluginManager not available for cloning";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 获取插件类型
|
||||
QString pluginType = m_pluginItem->typeId();
|
||||
|
||||
// 保存当前状态
|
||||
QVariantMap state = saveState();
|
||||
|
||||
// 创建新的插件项
|
||||
ICanvasItem *newPluginItem = manager->createItem(pluginType);
|
||||
if (!newPluginItem) {
|
||||
qWarning() << "Failed to create plugin item for cloning:" << pluginType;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 恢复状态
|
||||
if (!loadStateIntoPluginItem(newPluginItem, state)) {
|
||||
qWarning() << "Failed to restore state for cloned item";
|
||||
delete newPluginItem;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 创建新的包装器
|
||||
PluginItemWrapper *clone = new PluginItemWrapper(newPluginItem, parentItem());
|
||||
|
||||
// 复制变换属性
|
||||
clone->setPos(pos());
|
||||
clone->setRotation(rotation());
|
||||
clone->setScale(scale());
|
||||
clone->setZValue(zValue());
|
||||
|
||||
// 复制其他属性
|
||||
clone->copyPropertiesFrom(this);
|
||||
|
||||
qDebug() << "Cloned plugin item:" << pluginType;
|
||||
return clone;
|
||||
}
|
||||
|
||||
void PluginItemWrapper::paint(QPainter *painter,
|
||||
const QStyleOptionGraphicsItem *option,
|
||||
QWidget *widget)
|
||||
{
|
||||
if (!painter || !m_pluginItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
painter->save();
|
||||
|
||||
// 设置抗锯齿
|
||||
painter->setRenderHint(QPainter::Antialiasing, true);
|
||||
|
||||
// 让插件绘制
|
||||
m_pluginItem->draw(painter, m_cachedBounds);
|
||||
|
||||
// 如果选中,绘制控制框
|
||||
if (option && (option->state & QStyle::State_Selected)) {
|
||||
painter->setPen(QPen(QColor(0, 120, 215), 1, Qt::DashLine));
|
||||
painter->setBrush(Qt::NoBrush);
|
||||
|
||||
// 绘制选中框
|
||||
QRectF selectRect = m_cachedBounds.adjusted(-2, -2, 2, 2);
|
||||
painter->drawRect(selectRect);
|
||||
|
||||
// 绘制控制点
|
||||
const qreal handleSize = 6.0;
|
||||
QRectF handleRect(-handleSize/2, -handleSize/2, handleSize, handleSize);
|
||||
|
||||
QBrush handleBrush(QColor(0, 120, 215));
|
||||
QPen handlePen(Qt::white, 1);
|
||||
|
||||
// 绘制8个控制点
|
||||
QPointF corners[] = {
|
||||
m_cachedBounds.topLeft(),
|
||||
m_cachedBounds.topRight(),
|
||||
m_cachedBounds.bottomRight(),
|
||||
m_cachedBounds.bottomLeft(),
|
||||
QPointF(m_cachedBounds.center().x(), m_cachedBounds.top()),
|
||||
QPointF(m_cachedBounds.right(), m_cachedBounds.center().y()),
|
||||
QPointF(m_cachedBounds.center().x(), m_cachedBounds.bottom()),
|
||||
QPointF(m_cachedBounds.left(), m_cachedBounds.center().y())
|
||||
};
|
||||
|
||||
for (const QPointF &corner : corners) {
|
||||
painter->save();
|
||||
painter->translate(corner);
|
||||
painter->setPen(handlePen);
|
||||
painter->setBrush(handleBrush);
|
||||
painter->drawEllipse(handleRect);
|
||||
painter->restore();
|
||||
}
|
||||
}
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
QRectF PluginItemWrapper::boundingRect() const
|
||||
{
|
||||
qreal margin = 4.0; // 为控制点留出空间
|
||||
return m_cachedBounds.adjusted(-margin, -margin, margin, margin);
|
||||
}
|
||||
|
||||
QPainterPath PluginItemWrapper::shape() const
|
||||
{
|
||||
QPainterPath path;
|
||||
|
||||
if (!m_pluginItem) {
|
||||
return path;
|
||||
}
|
||||
|
||||
// 创建简单的矩形路径
|
||||
// 插件可以提供更精确的形状,这里简化处理
|
||||
path.addRect(m_cachedBounds);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
void PluginItemWrapper::updateCoordinate()
|
||||
{
|
||||
if (!m_pluginItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新基类属性
|
||||
QRectF bounds = m_pluginItem->bounds();
|
||||
m_dWidth = bounds.width();
|
||||
m_dHeight = bounds.height();
|
||||
|
||||
// 更新包围框
|
||||
m_boundingRect = bounds;
|
||||
|
||||
// 更新变换
|
||||
setTransformOriginPoint(bounds.center());
|
||||
|
||||
// 调用基类更新
|
||||
GraphicsFunctionModelItem::updateCoordinate();
|
||||
|
||||
// 更新句柄位置
|
||||
updateHandles();
|
||||
}
|
||||
|
||||
void PluginItemWrapper::resize(int handle, double dx, double dy, const QPointF &pos)
|
||||
{
|
||||
if (!m_pluginItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
QRectF bounds = m_pluginItem->bounds();
|
||||
QRectF newBounds = bounds;
|
||||
|
||||
// 根据控制点调整大小
|
||||
switch (handle) {
|
||||
case H_leftTop:
|
||||
newBounds.setTopLeft(newBounds.topLeft() + QPointF(dx, dy));
|
||||
break;
|
||||
case H_top:
|
||||
newBounds.setTop(newBounds.top() + dy);
|
||||
break;
|
||||
case H_rightTop:
|
||||
newBounds.setTopRight(newBounds.topRight() + QPointF(dx, dy));
|
||||
break;
|
||||
case H_right:
|
||||
newBounds.setRight(newBounds.right() + dx);
|
||||
break;
|
||||
case H_rightBottom:
|
||||
newBounds.setBottomRight(newBounds.bottomRight() + QPointF(dx, dy));
|
||||
break;
|
||||
case H_bottom:
|
||||
newBounds.setBottom(newBounds.bottom() + dy);
|
||||
break;
|
||||
case H_leftBottom:
|
||||
newBounds.setBottomLeft(newBounds.bottomLeft() + QPointF(dx, dy));
|
||||
break;
|
||||
case H_left:
|
||||
newBounds.setLeft(newBounds.left() + dx);
|
||||
break;
|
||||
default:
|
||||
// 不是控制点,直接移动
|
||||
move(QPointF(dx, dy));
|
||||
return;
|
||||
}
|
||||
|
||||
// 确保大小有效
|
||||
if (newBounds.width() < 10) {
|
||||
newBounds.setWidth(10);
|
||||
}
|
||||
if (newBounds.height() < 10) {
|
||||
newBounds.setHeight(10);
|
||||
}
|
||||
|
||||
if (newBounds.isValid() && newBounds != bounds) {
|
||||
m_pluginItem->setBounds(newBounds);
|
||||
}
|
||||
}
|
||||
|
||||
void PluginItemWrapper::move(const QPointF &delta)
|
||||
{
|
||||
if (!m_pluginItem || delta.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QRectF bounds = m_pluginItem->bounds();
|
||||
bounds.translate(delta);
|
||||
m_pluginItem->setBounds(bounds);
|
||||
}
|
||||
|
||||
ICanvasItem* PluginItemWrapper::pluginItem() const
|
||||
{
|
||||
return m_pluginItem;
|
||||
}
|
||||
|
||||
QVariant PluginItemWrapper::itemChange(GraphicsItemChange change, const QVariant &value)
|
||||
{
|
||||
if (!m_pluginItem) {
|
||||
return GraphicsFunctionModelItem::itemChange(change, value);
|
||||
}
|
||||
|
||||
switch (change) {
|
||||
case ItemSelectedChange:
|
||||
// 选中状态变化
|
||||
if (value.toBool()) {
|
||||
// 选中时的处理
|
||||
setHandleVisible(true);
|
||||
} else {
|
||||
// 取消选中的处理
|
||||
setHandleVisible(false);
|
||||
}
|
||||
break;
|
||||
|
||||
case ItemPositionChange: {
|
||||
// 位置变化
|
||||
QPointF newPos = value.toPointF();
|
||||
QPointF delta = newPos - pos();
|
||||
|
||||
// 更新插件项的位置
|
||||
QRectF bounds = m_pluginItem->bounds();
|
||||
bounds.translate(delta);
|
||||
m_pluginItem->setBounds(bounds);
|
||||
|
||||
return newPos;
|
||||
}
|
||||
|
||||
case ItemRotationChange:
|
||||
// 旋转变化
|
||||
// 插件项可能需要处理旋转
|
||||
break;
|
||||
|
||||
case ItemScaleChange:
|
||||
// 缩放变化
|
||||
// 插件项可能需要处理缩放
|
||||
break;
|
||||
|
||||
case ItemZValueChange:
|
||||
// Z值变化
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return GraphicsFunctionModelItem::itemChange(change, value);
|
||||
}
|
||||
|
||||
void PluginItemWrapper::updateCache()
|
||||
{
|
||||
if (m_pluginItem) {
|
||||
m_cachedBounds = m_pluginItem->bounds();
|
||||
}
|
||||
}
|
||||
|
||||
void PluginItemWrapper::connectSignals()
|
||||
{
|
||||
if (!m_pluginItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 使用旧式语法连接
|
||||
connect(m_pluginItem, SIGNAL(boundsChanged(QRectF)),
|
||||
this, SLOT(onPluginBoundsChanged(QRectF)));
|
||||
|
||||
connect(m_pluginItem, SIGNAL(propertyChanged(QString, QVariant)),
|
||||
this, SLOT(onPluginPropertyChanged(QString, QVariant)));
|
||||
}
|
||||
|
||||
QVariantMap PluginItemWrapper::saveState() const
|
||||
{
|
||||
QVariantMap state;
|
||||
|
||||
if (!m_pluginItem) {
|
||||
return state;
|
||||
}
|
||||
|
||||
// 保存基本属性
|
||||
state["type"] = m_pluginItem->typeId();
|
||||
state["displayName"] = m_pluginItem->displayName();
|
||||
|
||||
// 保存几何信息
|
||||
QRectF bounds = m_pluginItem->bounds();
|
||||
state["x"] = bounds.x();
|
||||
state["y"] = bounds.y();
|
||||
state["width"] = bounds.width();
|
||||
state["height"] = bounds.height();
|
||||
|
||||
// 保存插件特定属性
|
||||
// 这里可以保存插件的关键属性
|
||||
QStringList propertyKeys = {"fillColor", "borderColor", "borderWidth", "cornerRadius"};
|
||||
for (const QString &key : propertyKeys) {
|
||||
QVariant value = m_pluginItem->property(key);
|
||||
if (value.isValid()) {
|
||||
state[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
bool PluginItemWrapper::loadStateIntoPluginItem(ICanvasItem *pluginItem, const QVariantMap &state) const
|
||||
{
|
||||
if (!pluginItem) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 设置几何信息
|
||||
if (state.contains("x") && state.contains("y") &&
|
||||
state.contains("width") && state.contains("height")) {
|
||||
QRectF bounds(
|
||||
state["x"].toReal(),
|
||||
state["y"].toReal(),
|
||||
state["width"].toReal(),
|
||||
state["height"].toReal()
|
||||
);
|
||||
|
||||
if (bounds.isValid()) {
|
||||
pluginItem->setBounds(bounds);
|
||||
}
|
||||
}
|
||||
|
||||
// 设置插件属性
|
||||
QStringList propertyKeys = {"fillColor", "borderColor", "borderWidth", "cornerRadius"};
|
||||
for (const QString &key : propertyKeys) {
|
||||
if (state.contains(key)) {
|
||||
pluginItem->setProperty(key, state[key]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PluginItemWrapper::copyPropertiesFrom(const PluginItemWrapper *source)
|
||||
{
|
||||
if (!source) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 复制基类属性
|
||||
m_type = source->m_type;
|
||||
m_pen = source->m_pen;
|
||||
m_brush = source->m_brush;
|
||||
m_dWidth = source->m_dWidth;
|
||||
m_dHeight = source->m_dHeight;
|
||||
m_boundingRect = source->m_boundingRect;
|
||||
m_Itemtype = source->m_Itemtype;
|
||||
|
||||
// 复制可见性和使能状态
|
||||
setVisible(source->isVisible());
|
||||
setEnabled(source->isEnabled());
|
||||
|
||||
// 复制工具提示
|
||||
setToolTip(source->toolTip());
|
||||
|
||||
// 复制自定义数据
|
||||
setData(0, source->data(0));
|
||||
|
||||
// 生成新的ID
|
||||
setItemId(QUuid::createUuid());
|
||||
}
|
||||
|
||||
void PluginItemWrapper::onPluginBoundsChanged(const QRectF &newBounds)
|
||||
{
|
||||
m_cachedBounds = newBounds;
|
||||
|
||||
// 更新坐标
|
||||
updateCoordinate();
|
||||
|
||||
// 通知变化
|
||||
emit itemChanged();
|
||||
}
|
||||
|
||||
void PluginItemWrapper::onPluginPropertyChanged(const QString &key, const QVariant &value)
|
||||
{
|
||||
Q_UNUSED(key);
|
||||
Q_UNUSED(value);
|
||||
|
||||
// 属性变化,需要重绘
|
||||
update();
|
||||
|
||||
// 通知变化
|
||||
emit itemChanged();
|
||||
}
|
||||
|
|
@ -48,8 +48,8 @@ void MonitorPanel::initial()
|
|||
|
||||
createToolBar();
|
||||
_sideBar = new MonitorSideBarDlg(this);
|
||||
_hSplitter->addWidget(_sideBar);
|
||||
_sideBar->show();
|
||||
//_hSplitter->addWidget(_sideBar);
|
||||
//_sideBar->show();
|
||||
_pConfigDlg = new MonitorConfigDlg(this);
|
||||
_detailAttributeDlg = new MonitorDetailAttributeDlg(this);
|
||||
_displaySettingDlg = new MonitorDisplaySettingDlg(this);
|
||||
|
|
@ -151,6 +151,36 @@ QJsonObject MonitorPanel::getDiagramInfo()
|
|||
}
|
||||
obj["nodes"] = arr;
|
||||
|
||||
QJsonArray arrGraphic;
|
||||
QMap<QUuid,ItemPageInfo> mapGraphicPos = _pModel->allGraphicItemPos(); //graphic item位置
|
||||
QMap<QUuid,GraphicsFunctionModelItem*> mapGraphicItem = _pModel->allGraphicItems();
|
||||
for(auto pItem:_pModel->allGraphicItems())
|
||||
{
|
||||
ItemPageInfo info;
|
||||
double dWidth = pItem->boundingRect().width();
|
||||
double dHeight = pItem->boundingRect().height();
|
||||
QPointF pos = pItem->scenePos();
|
||||
double rotation = pItem->rotation();
|
||||
|
||||
QJsonObject node;
|
||||
node["id"] = pItem->itemId().toString();
|
||||
node["x"] = pos.x();
|
||||
node["y"] = pos.y();
|
||||
node["width"] = dWidth;
|
||||
node["height"] = dHeight;
|
||||
node["rotate"] = rotation;
|
||||
|
||||
GraphicProperty* pPro = dynamic_cast<GraphicProperty*>(pItem->getProperty());
|
||||
if(pPro){
|
||||
node["name"] = pPro->name();
|
||||
node["type"] = pPro->getGraphicType();
|
||||
node["modeName"] = pPro->modelName();
|
||||
node["content"] = pPro->getContent();
|
||||
}
|
||||
arrGraphic.append(node);
|
||||
}
|
||||
obj["graphicNode"] = arrGraphic;
|
||||
|
||||
QJsonArray arrConnect;
|
||||
QVector<ModelProperty*> vec = _pModel->allConnectionProperty();
|
||||
for(auto& pPro:vec){
|
||||
|
|
@ -219,6 +249,49 @@ void MonitorPanel::loadNodes(QJsonObject obj)
|
|||
}
|
||||
}
|
||||
|
||||
QMap<QByteArray,HMIImageInfo> mapHmiSource = ProjectModelManager::instance().getHMIimageMap(); //获取所有hmi资源
|
||||
|
||||
QList<HMICustomImageRef> lstRef = DataBase::GetInstance()->getHMICustomRefAll(QUuid(_pEntity->id()));
|
||||
_pModel->getHMICustomImageRef() = lstRef;
|
||||
|
||||
QJsonArray graphicNodesJsonArray = obj["graphicNode"].toArray();
|
||||
|
||||
for (QJsonValueRef nodeJson : graphicNodesJsonArray)
|
||||
{
|
||||
QJsonObject node = nodeJson.toObject();
|
||||
QUuid itemId = QUuid(node["id"].toString());
|
||||
QString sName = node["name"].toString();
|
||||
int nType = node["type"].toInt(); //图形item的类型 0图像1文字
|
||||
QString sModeName = node["modeName"].toString(); //模型名,定值
|
||||
QString sContent = node["content"].toString();
|
||||
double dX = node["x"].toDouble();
|
||||
double dY = node["y"].toDouble();
|
||||
double dWidth = node["width"].toDouble();
|
||||
double dHeight = node["height"].toDouble();
|
||||
double dRotate = node["rotate"].toDouble();
|
||||
|
||||
if(_pModel)
|
||||
{
|
||||
QString res = _pModel->addGraphicItem(itemId,sName,QPointF(dX,dY),nType,sModeName,dWidth,dHeight,dRotate); //创建图形对象
|
||||
if(res != "err"){
|
||||
if(nType == 0){ //图片类型
|
||||
QMap<QString,QByteArray> mapData;
|
||||
for(auto& customRef:lstRef){
|
||||
if(customRef.itemId == itemId){
|
||||
QString sImage = mapHmiSource.value(customRef.hash256).imageName;
|
||||
QByteArray data = mapHmiSource.value(customRef.hash256).svgData;
|
||||
mapData.insert(sImage,data);
|
||||
}
|
||||
}
|
||||
if(!mapData.isEmpty())
|
||||
_pModel->updateCustomById(itemId,mapData); //更新item引用的图片
|
||||
}
|
||||
else if(nType == 1){ //文字类型
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QJsonArray connectArr = obj["connections"].toArray();
|
||||
for(QJsonValueRef connectJson:connectArr)
|
||||
|
|
@ -341,8 +414,6 @@ void MonitorPanel::loadNodes(QJsonObject obj)
|
|||
break;
|
||||
}
|
||||
|
||||
QMap<QByteArray,HMIImageInfo> mapHmiSource = ProjectModelManager::instance().getHMIimageMap(); //获取所有hmi资源
|
||||
|
||||
QList<HierarchyItem> lstFirst;
|
||||
|
||||
for(auto& pOtherItem:_pModel->getProjectBayItems())
|
||||
|
|
|
|||
|
|
@ -572,32 +572,34 @@ void BaseSelector::dragMoveEvent(QGraphicsSceneDragDropEvent *event, DesignerSce
|
|||
|
||||
void BaseSelector::dropEvent(QGraphicsSceneDragDropEvent *event, DesignerScene*,DiagramMode sceneMode)
|
||||
{
|
||||
if(sceneMode == DM_edit)
|
||||
if(sceneMode == DM_run)
|
||||
{
|
||||
if (event->mimeData()->hasText()) {
|
||||
QString text = event->mimeData()->text();
|
||||
QString uuid = QString::fromLocal8Bit(event->mimeData()->data("application/id"));
|
||||
QString sType = QString::fromLocal8Bit(event->mimeData()->data("application/x-tooltype"));
|
||||
// 根据拖拽的数据创建相应的图形项并添加到场景中
|
||||
QGraphicsTextItem *textItem = new QGraphicsTextItem(text);
|
||||
textItem->setPos(event->scenePos());
|
||||
//QGraphicsTextItem *textItem = new QGraphicsTextItem(text);
|
||||
//textItem->setPos(event->scenePos());
|
||||
//addItem(textItem);
|
||||
event->acceptProposedAction();
|
||||
|
||||
//根据data数据新增拖拽的item
|
||||
QMap<QUuid,GraphicsFunctionModelItem*> items = _model->allItems();
|
||||
if(items.contains(QUuid(uuid))){
|
||||
QMessageBox::information(NULL, QString::fromWCharArray(L"提示"), QString::fromWCharArray(L"此对象在当前页已存在"));
|
||||
return;
|
||||
int nGraphicType = -1;
|
||||
if(sType == "image")
|
||||
nGraphicType = 0;
|
||||
else if(sType == "text")
|
||||
nGraphicType = 1;
|
||||
else
|
||||
nGraphicType = -1;
|
||||
|
||||
if(nGraphicType == 0 || nGraphicType == -1){ //图形类
|
||||
_model->addGraphicItem(QUuid::createUuid(),"",event->scenePos(),nGraphicType);
|
||||
}
|
||||
else{
|
||||
_model->addNodeItem(QUuid(uuid),event->scenePos());
|
||||
|
||||
}
|
||||
|
||||
event->acceptProposedAction();
|
||||
}
|
||||
}
|
||||
else if(sceneMode == DM_baseModel)
|
||||
{
|
||||
int a = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "graphicsItem/itemPort.h"
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
#include <QGraphicsView>
|
||||
#include <graphicsItem/graphicsBaseItem.h>
|
||||
#include "graphicsItem/graphicsBaseItem.h"
|
||||
#include "baseProperty.h"
|
||||
|
||||
MovingSelector::MovingSelector(FixedPortsModel* model,QObject *parent)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include "util/rotationSelector.h"
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
#include <QGraphicsView>
|
||||
#include <graphicsItem/graphicsBaseItem.h>
|
||||
#include "graphicsItem/graphicsBaseItem.h"
|
||||
|
||||
|
||||
RotationSelector::RotationSelector(FixedPortsModel* model,QObject *parent)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include "util/scalingSelector.h"
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
#include <QGraphicsView>
|
||||
#include <graphicsItem/graphicsBaseItem.h>
|
||||
#include "graphicsItem/graphicsBaseItem.h"
|
||||
|
||||
ScalingSelector::ScalingSelector(FixedPortsModel* model,QObject *parent)
|
||||
: BaseSelector(model,parent)
|
||||
|
|
|
|||
|
|
@ -177,6 +177,12 @@ public:
|
|||
bool removeHMIRef(QUuid hmiId,QString model); //移除hmi中某类模型的图片引用
|
||||
bool removeHMIRefAll(QUuid hmiId); //移除某个HMI中所有引用关系
|
||||
|
||||
bool inserHMICustomRef(QUuid hmiId,QString model,QUuid itemId,QByteArray hash256); //图片item使用的图片
|
||||
bool insertHMICustomRefBatch(const QList<HMICustomImageRef>& refList);
|
||||
QList<HMICustomImageRef> getHMICustomRefAll(QUuid hmiId);
|
||||
QList<HMICustomImageRef> getHMICustomRef(QUuid hmiId,QUuid itemId);
|
||||
bool removeHMICustomRef(QUuid hmiId,QUuid itemId);
|
||||
bool removeHMICustomRefAll(QUuid hmiId);
|
||||
public:
|
||||
/***********************************editor编辑器**********************************************/
|
||||
bool insertEditorProject(QUuid,QString,QString);
|
||||
|
|
|
|||
|
|
@ -3408,31 +3408,83 @@ bool DataBase::insertHMIimagesBatch(const QVector<HMIImageInfo>& imageList)
|
|||
return true;
|
||||
}
|
||||
|
||||
// 准备批量参数
|
||||
QStringList sqlStatements;
|
||||
QList<QVariantList> paramsList;
|
||||
int successCount = 0;
|
||||
int totalCount = imageList.size();
|
||||
|
||||
QString strSQL = "INSERT INTO diagramui_hmi_image(type, svg_name, svg_hash, svg_data) VALUES (?, ?, ?, ?)";
|
||||
|
||||
for (const auto& image : imageList) {
|
||||
sqlStatements.append(strSQL);
|
||||
|
||||
QVariantList params;
|
||||
params.append(image.baseType);
|
||||
params.append(image.imageName);
|
||||
params.append(image.hash256);
|
||||
params.append(image.svgData);
|
||||
|
||||
paramsList.append(params);
|
||||
// 使用单个事务
|
||||
if (!db.transaction()) {
|
||||
LOG_ERROR("DB", "Start transaction failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// 使用现有批量执行函数,强制使用事务
|
||||
executeBatchSQL(sqlStatements, false, paramsList, true);
|
||||
return true;
|
||||
// 使用单个准备好的语句
|
||||
QSqlQuery insertQuery(db);
|
||||
if (!insertQuery.prepare(
|
||||
"INSERT INTO diagramui_hmi_image(type, svg_name, svg_hash, svg_data) "
|
||||
"VALUES (?, ?, ?, ?)")) {
|
||||
LOG_ERROR("DB", "Prepare insert statement failed.");
|
||||
db.rollback();
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& image : imageList) {
|
||||
// 重新绑定参数
|
||||
insertQuery.bindValue(0, image.baseType);
|
||||
insertQuery.bindValue(1, image.imageName);
|
||||
insertQuery.bindValue(2, image.hash256);
|
||||
insertQuery.bindValue(3, image.svgData);
|
||||
|
||||
if (!insertQuery.exec()) {
|
||||
QSqlError error = insertQuery.lastError();
|
||||
QString errorText = error.databaseText();
|
||||
auto errorType = error.type(); // Qt6: 返回错误类型字符串
|
||||
|
||||
// 检查是否唯一约束冲突
|
||||
if (errorText.contains("重复键违反唯一约束", Qt::CaseInsensitive) ||
|
||||
errorText.contains("duplicate key", Qt::CaseInsensitive) ||
|
||||
errorText.contains("already exists", Qt::CaseInsensitive) ||
|
||||
errorText.contains("unique constraint", Qt::CaseInsensitive) ||
|
||||
error.driverText().contains("23505")) { // PostgreSQL唯一约束错误码
|
||||
|
||||
LOG_WARN("DB", QString("Duplicate image hash skipped: %1")
|
||||
.arg(QString(image.hash256.toHex())));
|
||||
continue; // 跳过这条记录,继续下一条
|
||||
} else {
|
||||
LOG_ERROR("DB", QString("Insert image failed: %1, error: %2, driver: %3")
|
||||
.arg(image.imageName, errorText, error.driverText()));
|
||||
// 非重复错误,回滚整个事务
|
||||
db.rollback();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
successCount++;
|
||||
}
|
||||
|
||||
if (successCount > 0) {
|
||||
if (!db.commit()) {
|
||||
LOG_ERROR("DB", "Commit transaction failed.");
|
||||
db.rollback();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (successCount < totalCount) {
|
||||
LOG_WARN("DB", QString("Batch insert partially completed. Success: %1, Failed: %2")
|
||||
.arg(successCount).arg(totalCount - successCount));
|
||||
}
|
||||
|
||||
LOG_INFO("DB", QString("Insert completed: %1/%2 images").arg(successCount).arg(totalCount));
|
||||
return true;
|
||||
} else {
|
||||
db.rollback();
|
||||
LOG_WARN("DB", "No records were inserted.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
LOG_ERROR("DB", QString("Batch insert HMI images failed: %1").arg(e.what()));
|
||||
db.rollback();
|
||||
LOG_ERROR("DB", QString("Insert failed with exception: %1").arg(e.what()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -3489,7 +3541,7 @@ QVector<bool> DataBase::batchCheckHMIimagesExists(const QVector<QByteArray>& has
|
|||
|
||||
for (const auto& hash : hashList) {
|
||||
placeholders.append("?");
|
||||
params.append(QString(hash.toHex())); // 转换为十六进制字符串
|
||||
params.append(hash); // 转换为十六进制字符串
|
||||
}
|
||||
|
||||
QString sql = QString("SELECT svg_hash FROM diagramui_hmi_image WHERE svg_hash IN (%1)")
|
||||
|
|
@ -3506,7 +3558,7 @@ QVector<bool> DataBase::batchCheckHMIimagesExists(const QVector<QByteArray>& has
|
|||
|
||||
// 更新存在性结果
|
||||
for (int i = 0; i < hashList.size(); ++i) {
|
||||
QString currentHash = QString(hashList[i].toHex());
|
||||
QString currentHash = QString(hashList[i]);
|
||||
if (existingHashes.contains(currentHash)) {
|
||||
existsResults[i] = true;
|
||||
}
|
||||
|
|
@ -3704,6 +3756,164 @@ bool DataBase::removeHMIRefAll(QUuid hmiId)
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool DataBase::inserHMICustomRef(QUuid hmiId,QString model,QUuid itemId,QByteArray hash256)
|
||||
{
|
||||
QString strSQL = "INSERT INTO diagramui_hmi_custom_config(hmi_uuid, model_name, item_id, svg_hash) VALUES ( ?, ?, ?, ?)";
|
||||
|
||||
QVariantList params;
|
||||
params.append(hmiId);
|
||||
params.append(model);
|
||||
params.append(itemId);
|
||||
params.append(hash256);
|
||||
|
||||
try
|
||||
{
|
||||
executeSQL(strSQL,false,params);
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOG_ERROR("DB", QString("Insert diagramui_hmi_custom_config fail"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool DataBase::insertHMICustomRefBatch(const QList<HMICustomImageRef>& refList)
|
||||
{
|
||||
if (refList.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 准备批量参数
|
||||
QStringList sqlStatements;
|
||||
QList<QVariantList> paramsList;
|
||||
|
||||
// 注意:id 是自增主键,不需要插入
|
||||
QString strSQL = "INSERT INTO diagramui_hmi_custom_config(hmi_uuid, model_name, item_id, svg_hash) VALUES ( ?, ?, ?, ?)";
|
||||
|
||||
for (const auto& ref : refList) {
|
||||
sqlStatements.append(strSQL);
|
||||
|
||||
QVariantList params;
|
||||
params.append(ref.hmiId);
|
||||
params.append(ref.model);
|
||||
params.append(ref.itemId);
|
||||
params.append(ref.hash256);
|
||||
|
||||
paramsList.append(params);
|
||||
}
|
||||
|
||||
try {
|
||||
// 使用现有批量执行函数,强制使用事务
|
||||
executeBatchSQL(sqlStatements, false, paramsList, true);
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
LOG_ERROR("DB", QString("Batch insert HMI custom refs failed: %1").arg(e.what()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QList<HMICustomImageRef> DataBase::getHMICustomRefAll(QUuid hmiId)
|
||||
{
|
||||
QList<HMICustomImageRef> lst;
|
||||
QString strSQL = "SELECT id, hmi_uuid, model_name, item_id, svg_hash FROM diagramui_hmi_custom_config WHERE hmi_uuid = ?";
|
||||
QVariantList params;
|
||||
params.append(hmiId);
|
||||
|
||||
try
|
||||
{
|
||||
QSqlQuery query = executeSQL(strSQL,false,params);
|
||||
while (query.next())
|
||||
{
|
||||
HMICustomImageRef info;
|
||||
info.id = query.value(0).toInt();
|
||||
info.hmiId = QUuid(query.value(1).toString());
|
||||
info.model = query.value(2).toString();
|
||||
info.itemId = QUuid(query.value(3).toString());
|
||||
info.hash256 = query.value(4).toByteArray();
|
||||
|
||||
lst.append(info);
|
||||
}
|
||||
query.clear();
|
||||
return lst;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
return lst;
|
||||
}
|
||||
}
|
||||
|
||||
QList<HMICustomImageRef> DataBase::getHMICustomRef(QUuid hmiId,QUuid itemId)
|
||||
{
|
||||
QList<HMICustomImageRef> lst;
|
||||
QString strSQL = "SELECT id, hmi_uuid, model_name, item_id, svg_hash FROM diagramui_hmi_custom_config WHERE hmi_uuid = ? AND item_id = ?";
|
||||
QVariantList params;
|
||||
params.append(hmiId);
|
||||
params.append(itemId);
|
||||
|
||||
try
|
||||
{
|
||||
QSqlQuery query = executeSQL(strSQL,false,params);
|
||||
while (query.next())
|
||||
{
|
||||
HMICustomImageRef info;
|
||||
info.id = query.value(0).toInt();
|
||||
info.hmiId = QUuid(query.value(1).toString());
|
||||
info.model = query.value(2).toString();
|
||||
info.itemId = QUuid(query.value(3).toString());
|
||||
info.hash256 = query.value(4).toByteArray();
|
||||
|
||||
lst.append(info);
|
||||
}
|
||||
query.clear();
|
||||
return lst;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
return lst;
|
||||
}
|
||||
}
|
||||
|
||||
bool DataBase::removeHMICustomRef(QUuid hmiId,QUuid itemId)
|
||||
{
|
||||
QString strSQL = "DELETE FROM diagramui_hmi_custom_config WHERE hmi_uuid = ? AND item_id = ?";
|
||||
QVariantList params;
|
||||
params.append(hmiId);
|
||||
params.append(itemId);
|
||||
|
||||
try
|
||||
{
|
||||
executeSQL(strSQL,false,params);
|
||||
LOG_INFO("DB", QString("Delete diagramui_hmi_custom_config success"));
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOG_ERROR("DB", QString("Delete diagramui_hmi_custom_config failed"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool DataBase::removeHMICustomRefAll(QUuid hmiId)
|
||||
{
|
||||
QString strSQL = "DELETE FROM diagramui_hmi_custom_config WHERE hmi_uuid = ?";
|
||||
QVariantList params;
|
||||
params.append(hmiId);
|
||||
|
||||
try
|
||||
{
|
||||
executeSQL(strSQL,false,params);
|
||||
LOG_INFO("DB", QString("Delete diagramui_hmi_custom_config success"));
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOG_ERROR("DB", QString("Delete diagramui_hmi_custom_config failed"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//===========================================================================
|
||||
bool DataBase::createDynamicTable(const QString &tableName, const QStringList &fields)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,12 +9,10 @@ class ConfigToolBar : public EnhancedToolBar
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ConfigToolBar(const QString &title, QWidget *parent = nullptr);
|
||||
explicit ConfigToolBar(QWidget *parent = nullptr);
|
||||
|
||||
// 从配置加载工具
|
||||
bool loadToolsFromConfig(const QString &configFile);
|
||||
|
||||
private:
|
||||
void loadDefaultTools();
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
// draggabletoolbutton.h
|
||||
#ifndef DRAGGABLETOOLBUTTON_H
|
||||
#define DRAGGABLETOOLBUTTON_H
|
||||
|
||||
#include <QToolButton>
|
||||
|
||||
class DraggableToolButton : public QToolButton
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DraggableToolButton(QWidget *parent = nullptr);
|
||||
|
||||
void setDragEnabled(bool enabled);
|
||||
bool dragEnabled() const;
|
||||
|
||||
void setToolData(const QString &data);
|
||||
QString toolData() const;
|
||||
|
||||
signals:
|
||||
void dragStarted(const QString &toolData, const QPoint &globalPos);
|
||||
void clicked(); // 自定义点击信号
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
|
||||
private:
|
||||
bool m_dragEnabled = true;
|
||||
bool m_isDragging = false;
|
||||
QPoint m_pressPos;
|
||||
QString m_toolData;
|
||||
};
|
||||
|
||||
#endif // DRAGGABLETOOLBUTTON_H
|
||||
|
|
@ -1,54 +1,45 @@
|
|||
// enhancedtoolbar.h
|
||||
#ifndef ENHANCEDTOOLBAR_H
|
||||
#define ENHANCEDTOOLBAR_H
|
||||
|
||||
#include <QToolBar>
|
||||
#include <QActionGroup>
|
||||
#include <QMap>
|
||||
|
||||
class DraggableToolButton;
|
||||
|
||||
class EnhancedToolBar : public QToolBar
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit EnhancedToolBar(const QString &title, QWidget *parent = nullptr);
|
||||
explicit EnhancedToolBar(QWidget *parent = nullptr);
|
||||
|
||||
// 工具管理接口
|
||||
// 添加工具
|
||||
void addTool(const QString &toolType, const QString &toolName,
|
||||
const QIcon &icon = QIcon());
|
||||
void removeTool(const QString &toolType);
|
||||
void setCurrentTool(const QString &toolType);
|
||||
|
||||
// 获取当前选中的工具
|
||||
QString currentTool() const;
|
||||
|
||||
// 获取工具信息
|
||||
QString toolName(const QString &toolType) const;
|
||||
QIcon toolIcon(const QString &toolType) const;
|
||||
QStringList availableTools() const;
|
||||
// 设置当前工具
|
||||
void setCurrentTool(const QString &toolType);
|
||||
|
||||
// 批量操作
|
||||
void clearTools();
|
||||
void addTools(const QList<QPair<QString, QString>> &tools);
|
||||
// 启用/禁用拖拽
|
||||
void setDragEnabled(bool enabled);
|
||||
bool dragEnabled() const;
|
||||
|
||||
signals:
|
||||
void toolSelected(const QString &toolType);
|
||||
void toolAdded(const QString &toolType);
|
||||
void toolRemoved(const QString &toolType);
|
||||
|
||||
protected:
|
||||
virtual QAction* createAction(const QString &toolType,
|
||||
const QString &toolName,
|
||||
const QIcon &icon);
|
||||
void toolDragged(const QString &toolType, const QPoint &globalPos);
|
||||
|
||||
private slots:
|
||||
void onActionTriggered(QAction *action);
|
||||
void onToolButtonClicked();
|
||||
void onToolButtonDragStarted(const QString &toolData, const QPoint &globalPos);
|
||||
void startDrag(const QString &toolType, const QPoint &globalPos);
|
||||
|
||||
private:
|
||||
void init();
|
||||
|
||||
QActionGroup *m_actionGroup;
|
||||
QMap<QString, QAction*> m_actions;
|
||||
QMap<QAction*, QString> m_actionToType; // 反向映射
|
||||
QMap<QString, DraggableToolButton*> m_buttons;
|
||||
QString m_currentTool;
|
||||
bool m_dragEnabled = true;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // ENHANCEDTOOLBAR_H
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
project(pluginManager)
|
||||
|
||||
set(PLUGINMANAGER_HEADER_FILES
|
||||
|
||||
include/pluginManager.h
|
||||
include/genericPluginAdapter.h
|
||||
../common/include/compiler.hpp
|
||||
../common/include/export.hpp
|
||||
../common/include/operatingSystem.hpp
|
||||
|
||||
../common/include/pluginCommon/iPluginAdapter.h
|
||||
../common/include/pluginCommon/iCanvasItem.h
|
||||
)
|
||||
|
||||
set(PLUGINMANAGER_SOURCE_FILES
|
||||
source/pluginManager.cpp
|
||||
source/genericPluginAdapter.cpp
|
||||
)
|
||||
|
||||
|
||||
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
|
||||
qt_add_library(pluginManager SHARED
|
||||
MANUAL_FINALIZATION
|
||||
${PLUGINMANAGER_HEADER_FILES}
|
||||
${PLUGINMANAGER_SOURCE_FILES}
|
||||
)
|
||||
else()
|
||||
add_library(pluginManager SHARED
|
||||
${PLUGINMANAGER_HEADER_FILES}
|
||||
${PLUGINMANAGER_SOURCE_FILES}
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(pluginManager PUBLIC Qt${QT_VERSION_MAJOR}::Core
|
||||
Qt${QT_VERSION_MAJOR}::Gui
|
||||
Qt${QT_VERSION_MAJOR}::Widgets)
|
||||
|
||||
target_link_libraries(pluginManager PRIVATE Qt6::Xml)
|
||||
target_link_libraries(pluginManager PRIVATE Qt6::Network)
|
||||
target_link_libraries(pluginManager PRIVATE Qt6::Sql ${PostgreSQL_LIBRARIES})
|
||||
|
||||
option(BUILD_SHARED_LIBS "Build as shared library" ON)
|
||||
|
||||
|
||||
|
||||
target_include_directories(pluginManager PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
target_compile_definitions(pluginManager
|
||||
PUBLIC
|
||||
DIAGRAM_DESIGNER_SHARED
|
||||
PRIVATE
|
||||
DIAGRAM_DESIGNER_EXPORTS
|
||||
#QT_NO_KEYWORDS
|
||||
)
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
// genericPluginAdapter.h
|
||||
#pragma once
|
||||
|
||||
#include "pluginCommon/iPluginAdapter.h"
|
||||
#include <QObject>
|
||||
|
||||
class ICanvasItem;
|
||||
|
||||
// 通用适配器实现
|
||||
class GenericPluginAdapter :public IPluginAdapter
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit GenericPluginAdapter(ICanvasItem *pluginItem, QObject *parent = nullptr);
|
||||
virtual ~GenericPluginAdapter();
|
||||
|
||||
// IPluginAdapter接口
|
||||
QString adapterType() const override { return "generic"; }
|
||||
QString pluginType() const override;
|
||||
|
||||
QRectF bounds() const override;
|
||||
void setBounds(const QRectF &bounds) override;
|
||||
|
||||
void paint(QPainter *painter, const QRectF &bounds) override;
|
||||
QPainterPath shape() const override;
|
||||
|
||||
QVariant property(const QString &key) const override;
|
||||
void setProperty(const QString &key, const QVariant &value) override;
|
||||
|
||||
void move(const QPointF &delta) override;
|
||||
void resize(const QRectF &newBounds) override;
|
||||
|
||||
bool isSelected() const override;
|
||||
void setSelected(bool selected) override;
|
||||
|
||||
QVariantMap saveState() const override;
|
||||
bool loadState(const QVariantMap &state) override;
|
||||
|
||||
// 获取原始插件项
|
||||
ICanvasItem* pluginItem() const;
|
||||
|
||||
signals:
|
||||
void boundsChanged(const QRectF &newBounds);
|
||||
void propertyChanged(const QString &key, const QVariant &value);
|
||||
void selectionChanged(bool selected);
|
||||
void adapterChanged();
|
||||
|
||||
private:
|
||||
ICanvasItem *m_pluginItem = nullptr;
|
||||
bool m_selected = false;
|
||||
QRectF m_cachedBounds;
|
||||
|
||||
void updateCache();
|
||||
void connectSignals();
|
||||
|
||||
private slots:
|
||||
void onPluginBoundsChanged(const QRectF &newBounds);
|
||||
void onPluginPropertyChanged(const QString &key, const QVariant &value);
|
||||
};
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
// pluginManager.h
|
||||
#pragma once
|
||||
|
||||
#include "export.hpp"
|
||||
#include "../common/include/pluginCommon/iCanvasItem.h"
|
||||
#include "../common/include/pluginCommon/iPlugin.h"
|
||||
#include <QObject>
|
||||
|
||||
class DIAGRAM_DESIGNER_PUBLIC PluginManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PluginManager(QObject *parent = nullptr);
|
||||
virtual ~PluginManager();
|
||||
|
||||
// 单例模式
|
||||
static PluginManager* instance();
|
||||
|
||||
// 插件管理
|
||||
bool loadPlugin(const QString &filePath);
|
||||
bool unloadPlugin(const QString &pluginId);
|
||||
void loadAllPlugins(const QString &directory);
|
||||
|
||||
// 插件目录管理
|
||||
void addPluginDirectory(const QString &dir);
|
||||
void setPluginDirectories(const QStringList &dirs);
|
||||
QStringList pluginDirectories() const;
|
||||
|
||||
// 创建原始插件项
|
||||
ICanvasItem* createItem(const QString &shapeId);
|
||||
|
||||
// 查询接口
|
||||
QStringList availableShapes() const;
|
||||
bool contains(const QString &shapeId) const;
|
||||
ShapeDescriptor shapeDescriptor(const QString &shapeId) const;
|
||||
QIcon shapeIcon(const QString &shapeId) const;
|
||||
|
||||
// 插件信息
|
||||
PluginDescriptor pluginDescriptor(const QString &pluginId) const;
|
||||
QStringList loadedPlugins() const;
|
||||
|
||||
// 内置形状注册
|
||||
void registerBuiltinShape(const QString &shapeId,
|
||||
const QString &name,
|
||||
std::function<ICanvasItem*()> creator,
|
||||
const QString &iconPath = QString());
|
||||
|
||||
signals:
|
||||
void pluginLoaded(const PluginDescriptor &descriptor);
|
||||
void pluginUnloaded(const QString &pluginId);
|
||||
void shapesChanged();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
|
@ -0,0 +1,200 @@
|
|||
// genericPluginAdapter.cpp
|
||||
#include "genericPluginAdapter.h"
|
||||
#include "pluginCommon/ICanvasItem.h"
|
||||
#include <QDebug>
|
||||
#include <QPainterPath>
|
||||
#include <QVariantMap>
|
||||
|
||||
GenericPluginAdapter::GenericPluginAdapter(ICanvasItem *pluginItem, QObject *parent)
|
||||
: IPluginAdapter(parent)
|
||||
, m_pluginItem(pluginItem)
|
||||
{
|
||||
if (!m_pluginItem) {
|
||||
qWarning() << "GenericPluginAdapter: pluginItem is null!";
|
||||
return;
|
||||
}
|
||||
|
||||
connectSignals();
|
||||
updateCache();
|
||||
|
||||
qDebug() << "GenericPluginAdapter created for plugin:" << m_pluginItem->typeId();
|
||||
}
|
||||
|
||||
GenericPluginAdapter::~GenericPluginAdapter()
|
||||
{
|
||||
if (m_pluginItem) {
|
||||
m_pluginItem->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
QString GenericPluginAdapter::pluginType() const
|
||||
{
|
||||
return m_pluginItem ? m_pluginItem->typeId() : QString();
|
||||
}
|
||||
|
||||
QRectF GenericPluginAdapter::bounds() const
|
||||
{
|
||||
return m_cachedBounds;
|
||||
}
|
||||
|
||||
void GenericPluginAdapter::setBounds(const QRectF &bounds)
|
||||
{
|
||||
if (m_pluginItem && bounds.isValid()) {
|
||||
m_pluginItem->setBounds(bounds);
|
||||
}
|
||||
}
|
||||
|
||||
void GenericPluginAdapter::paint(QPainter *painter, const QRectF &bounds)
|
||||
{
|
||||
if (m_pluginItem && painter) {
|
||||
m_pluginItem->draw(painter, bounds);
|
||||
}
|
||||
}
|
||||
|
||||
QPainterPath GenericPluginAdapter::shape() const
|
||||
{
|
||||
// 返回简单的矩形路径
|
||||
QPainterPath path;
|
||||
path.addRect(m_cachedBounds);
|
||||
return path;
|
||||
}
|
||||
|
||||
QVariant GenericPluginAdapter::property(const QString &key) const
|
||||
{
|
||||
return m_pluginItem ? m_pluginItem->property(key) : QVariant();
|
||||
}
|
||||
|
||||
void GenericPluginAdapter::setProperty(const QString &key, const QVariant &value)
|
||||
{
|
||||
if (m_pluginItem) {
|
||||
m_pluginItem->setProperty(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
void GenericPluginAdapter::move(const QPointF &delta)
|
||||
{
|
||||
if (m_pluginItem && !delta.isNull()) {
|
||||
QRectF bounds = m_pluginItem->bounds();
|
||||
bounds.translate(delta);
|
||||
m_pluginItem->setBounds(bounds);
|
||||
}
|
||||
}
|
||||
|
||||
void GenericPluginAdapter::resize(const QRectF &newBounds)
|
||||
{
|
||||
setBounds(newBounds);
|
||||
}
|
||||
|
||||
bool GenericPluginAdapter::isSelected() const
|
||||
{
|
||||
return m_selected;
|
||||
}
|
||||
|
||||
void GenericPluginAdapter::setSelected(bool selected)
|
||||
{
|
||||
if (m_selected != selected) {
|
||||
m_selected = selected;
|
||||
emit selectionChanged(selected);
|
||||
}
|
||||
}
|
||||
|
||||
QVariantMap GenericPluginAdapter::saveState() const
|
||||
{
|
||||
QVariantMap state;
|
||||
|
||||
if (!m_pluginItem) {
|
||||
return state;
|
||||
}
|
||||
|
||||
// 保存基本信息
|
||||
state["type"] = m_pluginItem->typeId();
|
||||
state["selected"] = m_selected;
|
||||
|
||||
// 保存几何信息
|
||||
QRectF bounds = m_pluginItem->bounds();
|
||||
state["x"] = bounds.x();
|
||||
state["y"] = bounds.y();
|
||||
state["width"] = bounds.width();
|
||||
state["height"] = bounds.height();
|
||||
|
||||
// 保存属性
|
||||
QVariantMap properties;
|
||||
// 这里可以保存插件的关键属性
|
||||
// 例如:properties["fillColor"] = m_pluginItem->property("fillColor");
|
||||
|
||||
state["properties"] = properties;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
bool GenericPluginAdapter::loadState(const QVariantMap &state)
|
||||
{
|
||||
if (!m_pluginItem) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 加载几何信息
|
||||
if (state.contains("x") && state.contains("y") &&
|
||||
state.contains("width") && state.contains("height")) {
|
||||
QRectF bounds(
|
||||
state["x"].toReal(),
|
||||
state["y"].toReal(),
|
||||
state["width"].toReal(),
|
||||
state["height"].toReal()
|
||||
);
|
||||
m_pluginItem->setBounds(bounds);
|
||||
}
|
||||
|
||||
// 加载选择状态
|
||||
if (state.contains("selected")) {
|
||||
setSelected(state["selected"].toBool());
|
||||
}
|
||||
|
||||
// 加载属性
|
||||
if (state.contains("properties")) {
|
||||
QVariantMap properties = state["properties"].toMap();
|
||||
for (auto it = properties.begin(); it != properties.end(); ++it) {
|
||||
m_pluginItem->setProperty(it.key(), it.value());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ICanvasItem* GenericPluginAdapter::pluginItem() const
|
||||
{
|
||||
return m_pluginItem;
|
||||
}
|
||||
|
||||
void GenericPluginAdapter::updateCache()
|
||||
{
|
||||
if (m_pluginItem) {
|
||||
m_cachedBounds = m_pluginItem->bounds();
|
||||
}
|
||||
}
|
||||
|
||||
void GenericPluginAdapter::connectSignals()
|
||||
{
|
||||
if (!m_pluginItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
connect(m_pluginItem, &ICanvasItem::boundsChanged,
|
||||
this, &GenericPluginAdapter::onPluginBoundsChanged);
|
||||
|
||||
connect(m_pluginItem, &ICanvasItem::propertyChanged,
|
||||
this, &GenericPluginAdapter::onPluginPropertyChanged);
|
||||
}
|
||||
|
||||
void GenericPluginAdapter::onPluginBoundsChanged(const QRectF &newBounds)
|
||||
{
|
||||
m_cachedBounds = newBounds;
|
||||
emit boundsChanged(newBounds);
|
||||
emit adapterChanged();
|
||||
}
|
||||
|
||||
void GenericPluginAdapter::onPluginPropertyChanged(const QString &key, const QVariant &value)
|
||||
{
|
||||
emit propertyChanged(key, value);
|
||||
emit adapterChanged();
|
||||
}
|
||||
|
|
@ -0,0 +1,388 @@
|
|||
//pluginManager.cpp
|
||||
#include "pluginManager/include/pluginManager.h"
|
||||
//#include "common/include/pluginCommon/iPlugin.h"
|
||||
#include <QPluginLoader>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QDebug>
|
||||
#include <QMutex>
|
||||
#include <QMutexLocker>
|
||||
|
||||
// 私有实现
|
||||
class PluginManager::Private
|
||||
{
|
||||
public:
|
||||
struct PluginInfo {
|
||||
QPluginLoader *loader = nullptr;
|
||||
IPlugin *plugin = nullptr;
|
||||
PluginDescriptor descriptor;
|
||||
QString filePath;
|
||||
|
||||
~PluginInfo() {
|
||||
if (plugin) {
|
||||
plugin->shutdown();
|
||||
}
|
||||
if (loader) {
|
||||
loader->unload();
|
||||
delete loader;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
QMutex mutex;
|
||||
QMap<QString, PluginInfo*> plugins; // pluginId -> PluginInfo*
|
||||
QMap<QString, QString> shapeToPlugin; // shapeId -> pluginId
|
||||
QMap<QString, ShapeDescriptor> shapeDescriptors; // shapeId -> descriptor
|
||||
|
||||
// 内置形状
|
||||
QMap<QString, std::function<ICanvasItem*()>> builtinCreators;
|
||||
QMap<QString, ShapeDescriptor> builtinDescriptors;
|
||||
|
||||
QStringList pluginDirs;
|
||||
|
||||
bool loadPluginInternal(const QString &filePath, QString *error = nullptr);
|
||||
void unloadPluginInternal(const QString &pluginId);
|
||||
};
|
||||
|
||||
PluginManager::PluginManager(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
// 注册一些内置形状
|
||||
//registerBuiltinShapes();
|
||||
}
|
||||
|
||||
PluginManager::~PluginManager()
|
||||
{
|
||||
QMutexLocker locker(&d->mutex);
|
||||
|
||||
// 卸载所有插件
|
||||
auto pluginIds = d->plugins.keys();
|
||||
for (const QString &pluginId : pluginIds) {
|
||||
d->unloadPluginInternal(pluginId);
|
||||
}
|
||||
}
|
||||
|
||||
PluginManager* PluginManager::instance()
|
||||
{
|
||||
static PluginManager instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
bool PluginManager::loadPlugin(const QString &filePath)
|
||||
{
|
||||
QMutexLocker locker(&d->mutex);
|
||||
return d->loadPluginInternal(filePath);
|
||||
}
|
||||
|
||||
bool PluginManager::unloadPlugin(const QString &pluginId)
|
||||
{
|
||||
QMutexLocker locker(&d->mutex);
|
||||
|
||||
if (!d->plugins.contains(pluginId)) {
|
||||
qWarning() << "Plugin not found:" << pluginId;
|
||||
return false;
|
||||
}
|
||||
|
||||
d->unloadPluginInternal(pluginId);
|
||||
|
||||
emit pluginUnloaded(pluginId);
|
||||
emit shapesChanged();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PluginManager::loadAllPlugins(const QString &directory)
|
||||
{
|
||||
QDir dir(directory);
|
||||
if (!dir.exists()) {
|
||||
qWarning() << "Plugin directory does not exist:" << directory;
|
||||
return;
|
||||
}
|
||||
|
||||
QStringList filters;
|
||||
#ifdef Q_OS_WIN
|
||||
filters << "*.dll";
|
||||
#elif defined(Q_OS_MAC)
|
||||
filters << "*.dylib" << "*.so";
|
||||
#else
|
||||
filters << "*.so";
|
||||
#endif
|
||||
|
||||
QStringList pluginFiles = dir.entryList(filters, QDir::Files);
|
||||
|
||||
for (const QString &file : pluginFiles) {
|
||||
QString filePath = dir.absoluteFilePath(file);
|
||||
if (!loadPlugin(filePath)) {
|
||||
qWarning() << "Failed to load plugin:" << filePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool PluginManager::Private::loadPluginInternal(const QString &filePath, QString *error)
|
||||
{
|
||||
QFileInfo fileInfo(filePath);
|
||||
if (!fileInfo.exists()) {
|
||||
if (error) *error = "File does not exist";
|
||||
return false;
|
||||
}
|
||||
|
||||
QPluginLoader *loader = new QPluginLoader(filePath);
|
||||
if (!loader->load()) {
|
||||
if (error) *error = loader->errorString();
|
||||
delete loader;
|
||||
return false;
|
||||
}
|
||||
|
||||
QObject *pluginInstance = loader->instance();
|
||||
if (!pluginInstance) {
|
||||
if (error) *error = "Failed to get plugin instance";
|
||||
loader->unload();
|
||||
delete loader;
|
||||
return false;
|
||||
}
|
||||
|
||||
IPlugin *plugin = qobject_cast<IPlugin*>(pluginInstance);
|
||||
if (!plugin) {
|
||||
if (error) *error = "Plugin does not implement IPlugin interface";
|
||||
loader->unload();
|
||||
delete loader;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!plugin->initialize()) {
|
||||
if (error) *error = "Plugin initialization failed";
|
||||
loader->unload();
|
||||
delete loader;
|
||||
return false;
|
||||
}
|
||||
|
||||
PluginDescriptor descriptor = plugin->descriptor();
|
||||
if (plugins.contains(descriptor.id)) {
|
||||
if (error) *error = "Plugin already loaded: " + descriptor.id;
|
||||
loader->unload();
|
||||
delete loader;
|
||||
return false;
|
||||
}
|
||||
|
||||
PluginInfo *info = new PluginInfo;
|
||||
info->loader = loader;
|
||||
info->plugin = plugin;
|
||||
info->descriptor = descriptor;
|
||||
info->filePath = filePath;
|
||||
|
||||
plugins[descriptor.id] = info;
|
||||
|
||||
// 注册形状
|
||||
QList<ShapeDescriptor> shapes = plugin->shapes();
|
||||
for (const ShapeDescriptor &shape : shapes) {
|
||||
shapeDescriptors[shape.id] = shape;
|
||||
shapeToPlugin[shape.id] = descriptor.id;
|
||||
}
|
||||
|
||||
qInfo() << "Plugin loaded:" << descriptor.name << "(" << descriptor.id << ")";
|
||||
return true;
|
||||
}
|
||||
|
||||
void PluginManager::Private::unloadPluginInternal(const QString &pluginId)
|
||||
{
|
||||
if (!plugins.contains(pluginId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
PluginInfo *info = plugins.take(pluginId);
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 移除关联的形状
|
||||
auto shapeIds = shapeToPlugin.keys();
|
||||
for (const QString &shapeId : shapeIds) {
|
||||
if (shapeToPlugin[shapeId] == pluginId) {
|
||||
shapeDescriptors.remove(shapeId);
|
||||
shapeToPlugin.remove(shapeId);
|
||||
}
|
||||
}
|
||||
|
||||
delete info;
|
||||
}
|
||||
|
||||
QStringList PluginManager::availableShapes() const
|
||||
{
|
||||
QMutexLocker locker(&d->mutex);
|
||||
|
||||
QStringList shapes = d->shapeDescriptors.keys();
|
||||
shapes.append(d->builtinDescriptors.keys());
|
||||
return shapes;
|
||||
}
|
||||
|
||||
bool PluginManager::contains(const QString &shapeId) const
|
||||
{
|
||||
QMutexLocker locker(&d->mutex);
|
||||
return d->shapeDescriptors.contains(shapeId) ||
|
||||
d->builtinDescriptors.contains(shapeId);
|
||||
}
|
||||
|
||||
ShapeDescriptor PluginManager::shapeDescriptor(const QString &shapeId) const
|
||||
{
|
||||
QMutexLocker locker(&d->mutex);
|
||||
|
||||
if (d->shapeDescriptors.contains(shapeId)) {
|
||||
return d->shapeDescriptors[shapeId];
|
||||
}
|
||||
|
||||
if (d->builtinDescriptors.contains(shapeId)) {
|
||||
return d->builtinDescriptors[shapeId];
|
||||
}
|
||||
|
||||
return ShapeDescriptor();
|
||||
}
|
||||
|
||||
void PluginManager::registerBuiltinShape(const QString &shapeId,
|
||||
const QString &name,
|
||||
std::function<ICanvasItem*()> creator,
|
||||
const QString &iconPath)
|
||||
{
|
||||
QMutexLocker locker(&d->mutex);
|
||||
|
||||
ShapeDescriptor desc;
|
||||
desc.id = shapeId;
|
||||
desc.name = name;
|
||||
desc.category = "内置形状";
|
||||
desc.iconPath = iconPath;
|
||||
|
||||
d->builtinDescriptors[shapeId] = desc;
|
||||
d->builtinCreators[shapeId] = creator;
|
||||
|
||||
emit shapesChanged();
|
||||
}
|
||||
|
||||
QIcon PluginManager::shapeIcon(const QString &shapeId) const
|
||||
{
|
||||
QMutexLocker locker(&d->mutex);
|
||||
|
||||
ShapeDescriptor desc = shapeDescriptor(shapeId);
|
||||
if (desc.id.isEmpty()) {
|
||||
return QIcon();
|
||||
}
|
||||
|
||||
// 首先尝试从资源文件加载
|
||||
if (desc.iconPath.startsWith(":/")) {
|
||||
if (QFile::exists(desc.iconPath)) {
|
||||
return QIcon(desc.iconPath);
|
||||
}
|
||||
}
|
||||
|
||||
// 尝试从文件系统加载
|
||||
if (QFile::exists(desc.iconPath)) {
|
||||
return QIcon(desc.iconPath);
|
||||
}
|
||||
|
||||
// 尝试从插件目录查找
|
||||
if (d->shapeToPlugin.contains(shapeId)) {
|
||||
QString pluginId = d->shapeToPlugin[shapeId];
|
||||
if (d->plugins.contains(pluginId)) {
|
||||
QString pluginDir = QFileInfo(d->plugins[pluginId]->filePath).absolutePath();
|
||||
|
||||
// 尝试相对路径
|
||||
QString relativePath = pluginDir + "/" + desc.iconPath;
|
||||
if (QFile::exists(relativePath)) {
|
||||
return QIcon(relativePath);
|
||||
}
|
||||
|
||||
// 尝试在icons子目录中查找
|
||||
QString iconName = QFileInfo(desc.iconPath).fileName();
|
||||
QString iconDirPath = pluginDir + "/icons/" + iconName;
|
||||
if (QFile::exists(iconDirPath)) {
|
||||
return QIcon(iconDirPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 返回默认图标
|
||||
return QIcon(":/shapes/default.png");
|
||||
}
|
||||
|
||||
void PluginManager::addPluginDirectory(const QString &dir)
|
||||
{
|
||||
QMutexLocker locker(&d->mutex);
|
||||
if (!d->pluginDirs.contains(dir)) {
|
||||
d->pluginDirs.append(dir);
|
||||
}
|
||||
}
|
||||
|
||||
void PluginManager::setPluginDirectories(const QStringList &dirs)
|
||||
{
|
||||
QMutexLocker locker(&d->mutex);
|
||||
d->pluginDirs = dirs;
|
||||
|
||||
// 重新扫描所有目录
|
||||
for (const QString &dir : dirs) {
|
||||
loadAllPlugins(dir);
|
||||
}
|
||||
}
|
||||
|
||||
QStringList PluginManager::pluginDirectories() const
|
||||
{
|
||||
QMutexLocker locker(&d->mutex);
|
||||
return d->pluginDirs;
|
||||
}
|
||||
|
||||
ICanvasItem* PluginManager::createItem(const QString &shapeId)
|
||||
{
|
||||
QMutexLocker locker(&d->mutex);
|
||||
|
||||
// 1. 首先检查内置形状
|
||||
if (d->builtinCreators.contains(shapeId)) {
|
||||
ICanvasItem *item = d->builtinCreators[shapeId]();
|
||||
if (item) {
|
||||
qDebug() << "Created builtin shape:" << shapeId;
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 检查插件形状
|
||||
if (!d->shapeToPlugin.contains(shapeId)) {
|
||||
qWarning() << "Shape not found:" << shapeId;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QString pluginId = d->shapeToPlugin[shapeId];
|
||||
if (!d->plugins.contains(pluginId)) {
|
||||
qWarning() << "Plugin not loaded for shape:" << shapeId;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 3. 通过插件创建形状
|
||||
IPlugin *plugin = d->plugins[pluginId]->plugin;
|
||||
if (!plugin) {
|
||||
qWarning() << "Plugin interface is null for:" << pluginId;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ICanvasItem *item = plugin->createShape(shapeId);
|
||||
if (item) {
|
||||
qDebug() << "Created plugin shape:" << shapeId << "from plugin:" << pluginId;
|
||||
} else {
|
||||
qWarning() << "Plugin failed to create shape:" << shapeId;
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
PluginDescriptor PluginManager::pluginDescriptor(const QString &pluginId) const
|
||||
{
|
||||
QMutexLocker locker(&d->mutex);
|
||||
|
||||
if (d->plugins.contains(pluginId)) {
|
||||
return d->plugins[pluginId]->descriptor;
|
||||
}
|
||||
|
||||
return PluginDescriptor();
|
||||
}
|
||||
|
||||
QStringList PluginManager::loadedPlugins() const
|
||||
{
|
||||
QMutexLocker locker(&d->mutex);
|
||||
return d->plugins.keys();
|
||||
}
|
||||
|
|
@ -2,12 +2,6 @@
|
|||
#include "configToolBar.h"
|
||||
#include <QDebug>
|
||||
|
||||
ConfigToolBar::ConfigToolBar(const QString &title, QWidget *parent)
|
||||
: EnhancedToolBar(title, parent)
|
||||
{
|
||||
loadDefaultTools();
|
||||
}
|
||||
|
||||
ConfigToolBar::ConfigToolBar(QWidget *parent)
|
||||
: EnhancedToolBar(parent)
|
||||
{
|
||||
|
|
@ -23,7 +17,7 @@ bool ConfigToolBar::loadToolsFromConfig(const QString &configFile)
|
|||
}
|
||||
|
||||
// 清空现有工具
|
||||
clearTools();
|
||||
//clearTools();
|
||||
|
||||
// 从配置添加工具
|
||||
QList<ToolInfo> tools = m_config.getAllTools();
|
||||
|
|
@ -37,8 +31,6 @@ bool ConfigToolBar::loadToolsFromConfig(const QString &configFile)
|
|||
void ConfigToolBar::loadDefaultTools()
|
||||
{
|
||||
// 添加一些基本工具
|
||||
addTool("select", "选择", QIcon(":/icons/select.png"));
|
||||
addTool("line", "直线", QIcon(":/icons/line.png"));
|
||||
addTool("rect", "矩形", QIcon(":/icons/rect.png"));
|
||||
addTool("circle", "圆形", QIcon(":/icons/circle.png"));
|
||||
addTool("image", "图像", QIcon(":/images/element/icon_image.png"));
|
||||
addTool("text", "文本", QIcon(":/images/element/icon_text.png"));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
// draggabletoolbutton.cpp
|
||||
#include "draggabletoolbutton.h"
|
||||
#include <QMouseEvent>
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
|
||||
DraggableToolButton::DraggableToolButton(QWidget *parent)
|
||||
: QToolButton(parent)
|
||||
, m_dragEnabled(true)
|
||||
, m_isDragging(false)
|
||||
{
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
void DraggableToolButton::setDragEnabled(bool enabled)
|
||||
{
|
||||
m_dragEnabled = enabled;
|
||||
}
|
||||
|
||||
bool DraggableToolButton::dragEnabled() const
|
||||
{
|
||||
return m_dragEnabled;
|
||||
}
|
||||
|
||||
void DraggableToolButton::setToolData(const QString &data)
|
||||
{
|
||||
m_toolData = data;
|
||||
}
|
||||
|
||||
QString DraggableToolButton::toolData() const
|
||||
{
|
||||
return m_toolData;
|
||||
}
|
||||
|
||||
void DraggableToolButton::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
if (event->button() == Qt::LeftButton && m_dragEnabled) {
|
||||
m_pressPos = event->pos();
|
||||
m_isDragging = false;
|
||||
}
|
||||
|
||||
// 不调用基类,完全自己处理
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void DraggableToolButton::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
if (!m_dragEnabled || !(event->buttons() & Qt::LeftButton)) {
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否达到拖拽阈值
|
||||
int moveDist = (event->pos() - m_pressPos).manhattanLength();
|
||||
if (moveDist >= QApplication::startDragDistance()) {
|
||||
if (!m_isDragging) {
|
||||
m_isDragging = true;
|
||||
emit dragStarted(m_toolData, event->globalPosition().toPoint());
|
||||
}
|
||||
}
|
||||
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void DraggableToolButton::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
if (!m_isDragging) {
|
||||
// 没有拖拽,是点击
|
||||
emit clicked();
|
||||
}
|
||||
m_isDragging = false;
|
||||
}
|
||||
|
||||
event->accept();
|
||||
}
|
||||
|
|
@ -1,108 +1,106 @@
|
|||
// EnhancedToolBar.cpp
|
||||
#include "enhancedToolBar.h"
|
||||
#include <QAction>
|
||||
#include "enhancedtoolbar.h"
|
||||
#include "draggabletoolbutton.h"
|
||||
#include <QHBoxLayout>
|
||||
#include <QMimeData>
|
||||
#include <QDrag>
|
||||
#include <QPainter>
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
|
||||
EnhancedToolBar::EnhancedToolBar(const QString &title, QWidget *parent)
|
||||
: QToolBar(title, parent)
|
||||
, m_currentTool("")
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
EnhancedToolBar::EnhancedToolBar(QWidget *parent)
|
||||
: QToolBar(parent)
|
||||
, m_currentTool("")
|
||||
, m_dragEnabled(true)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
void EnhancedToolBar::init()
|
||||
{
|
||||
// 设置工具栏属性
|
||||
setIconSize(QSize(32, 32));
|
||||
setToolButtonStyle(Qt::ToolButtonIconOnly);
|
||||
setMovable(true);
|
||||
setFloatable(true);
|
||||
setAllowedAreas(Qt::AllToolBarAreas);
|
||||
|
||||
// 创建互斥的动作组
|
||||
m_actionGroup = new QActionGroup(this);
|
||||
m_actionGroup->setExclusive(true);
|
||||
|
||||
// 连接信号
|
||||
connect(this, &QToolBar::actionTriggered,
|
||||
this, &EnhancedToolBar::onActionTriggered);
|
||||
}
|
||||
|
||||
QAction* EnhancedToolBar::createAction(const QString &toolType,
|
||||
const QString &toolName,
|
||||
const QIcon &icon)
|
||||
{
|
||||
QAction *action = new QAction(icon, toolName, this);
|
||||
action->setCheckable(true);
|
||||
action->setData(toolType);
|
||||
action->setToolTip(toolName);
|
||||
return action;
|
||||
}
|
||||
|
||||
void EnhancedToolBar::addTool(const QString &toolType, const QString &toolName,
|
||||
const QIcon &icon)
|
||||
{
|
||||
if (m_actions.contains(toolType)) {
|
||||
return; // 已存在
|
||||
if (m_buttons.contains(toolType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
QAction *action = createAction(toolType, toolName, icon);
|
||||
// 创建自定义按钮
|
||||
DraggableToolButton *button = new DraggableToolButton(this);
|
||||
button->setIcon(icon);
|
||||
button->setIconSize(iconSize());
|
||||
button->setText(toolName);
|
||||
button->setToolTip(toolName);
|
||||
button->setCheckable(true);
|
||||
button->setToolData(toolType);
|
||||
button->setDragEnabled(m_dragEnabled);
|
||||
|
||||
m_actionGroup->addAction(action);
|
||||
addAction(action);
|
||||
m_actions[toolType] = action;
|
||||
m_actionToType[action] = toolType;
|
||||
// 连接信号
|
||||
connect(button, &DraggableToolButton::clicked,
|
||||
this, &EnhancedToolBar::onToolButtonClicked);
|
||||
connect(button, &DraggableToolButton::dragStarted,
|
||||
this, &EnhancedToolBar::onToolButtonDragStarted);
|
||||
|
||||
// 如果没有当前工具,自动选择第一个工具
|
||||
// 添加到工具栏
|
||||
addWidget(button);
|
||||
m_buttons[toolType] = button;
|
||||
|
||||
// 如果没有当前工具,设置第一个为当前
|
||||
if (m_currentTool.isEmpty()) {
|
||||
setCurrentTool(toolType);
|
||||
}
|
||||
|
||||
emit toolAdded(toolType);
|
||||
}
|
||||
|
||||
void EnhancedToolBar::removeTool(const QString &toolType)
|
||||
void EnhancedToolBar::onToolButtonClicked()
|
||||
{
|
||||
if (m_actions.contains(toolType)) {
|
||||
QAction *action = m_actions[toolType];
|
||||
|
||||
removeAction(action);
|
||||
m_actionGroup->removeAction(action);
|
||||
m_actions.remove(toolType);
|
||||
m_actionToType.remove(action);
|
||||
|
||||
action->deleteLater();
|
||||
|
||||
if (m_currentTool == toolType) {
|
||||
m_currentTool = "";
|
||||
}
|
||||
|
||||
emit toolRemoved(toolType);
|
||||
DraggableToolButton *button = qobject_cast<DraggableToolButton*>(sender());
|
||||
if (button) {
|
||||
QString toolType = button->toolData();
|
||||
setCurrentTool(toolType);
|
||||
}
|
||||
}
|
||||
|
||||
void EnhancedToolBar::setCurrentTool(const QString &toolType)
|
||||
void EnhancedToolBar::onToolButtonDragStarted(const QString &toolData, const QPoint &globalPos)
|
||||
{
|
||||
if (toolType.isEmpty()) {
|
||||
// 清除当前选择
|
||||
if (m_actionGroup->checkedAction()) {
|
||||
m_actionGroup->checkedAction()->setChecked(false);
|
||||
}
|
||||
m_currentTool = "";
|
||||
emit toolSelected("");
|
||||
if (m_dragEnabled) {
|
||||
startDrag(toolData, globalPos);
|
||||
}
|
||||
else if (m_actions.contains(toolType)) {
|
||||
m_actions[toolType]->setChecked(true);
|
||||
m_currentTool = toolType;
|
||||
emit toolSelected(toolType);
|
||||
}
|
||||
|
||||
void EnhancedToolBar::startDrag(const QString &toolType, const QPoint &globalPos)
|
||||
{
|
||||
DraggableToolButton *button = m_buttons.value(toolType);
|
||||
if (!button) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString toolName = button->text();
|
||||
QIcon icon = button->icon();
|
||||
|
||||
qDebug() << "开始拖拽:" << toolType << toolName;
|
||||
|
||||
// 创建MIME数据
|
||||
QMimeData *mimeData = new QMimeData();
|
||||
mimeData->setText(toolName);
|
||||
mimeData->setData("application/x-tooltype", toolType.toUtf8());
|
||||
|
||||
// 创建拖拽对象
|
||||
QDrag *drag = new QDrag(this);
|
||||
drag->setMimeData(mimeData);
|
||||
|
||||
// 创建预览图像
|
||||
if (!icon.isNull()) {
|
||||
QPixmap pixmap = icon.pixmap(32, 32);
|
||||
drag->setPixmap(pixmap);
|
||||
drag->setHotSpot(QPoint(16, 16));
|
||||
}
|
||||
|
||||
// 发出信号
|
||||
emit toolDragged(toolType, globalPos);
|
||||
|
||||
// 执行拖拽
|
||||
Qt::DropAction result = drag->exec(Qt::CopyAction);
|
||||
|
||||
qDebug() << "拖拽完成,结果:" << result;
|
||||
}
|
||||
|
||||
QString EnhancedToolBar::currentTool() const
|
||||
|
|
@ -110,52 +108,38 @@ QString EnhancedToolBar::currentTool() const
|
|||
return m_currentTool;
|
||||
}
|
||||
|
||||
QString EnhancedToolBar::toolName(const QString &toolType) const
|
||||
void EnhancedToolBar::setCurrentTool(const QString &toolType)
|
||||
{
|
||||
if (m_actions.contains(toolType)) {
|
||||
return m_actions[toolType]->text();
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
QIcon EnhancedToolBar::toolIcon(const QString &toolType) const
|
||||
{
|
||||
if (m_actions.contains(toolType)) {
|
||||
return m_actions[toolType]->icon();
|
||||
}
|
||||
return QIcon();
|
||||
}
|
||||
|
||||
QStringList EnhancedToolBar::availableTools() const
|
||||
{
|
||||
return m_actions.keys();
|
||||
}
|
||||
|
||||
void EnhancedToolBar::clearTools()
|
||||
{
|
||||
for (auto it = m_actions.begin(); it != m_actions.end(); ++it) {
|
||||
removeAction(it.value());
|
||||
m_actionGroup->removeAction(it.value());
|
||||
it.value()->deleteLater();
|
||||
if (m_currentTool == toolType) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_actions.clear();
|
||||
m_actionToType.clear();
|
||||
m_currentTool = "";
|
||||
}
|
||||
|
||||
void EnhancedToolBar::addTools(const QList<QPair<QString, QString>> &tools)
|
||||
{
|
||||
for (const auto &tool : tools) {
|
||||
addTool(tool.first, tool.second);
|
||||
// 取消之前的选择
|
||||
if (!m_currentTool.isEmpty() && m_buttons.contains(m_currentTool)) {
|
||||
m_buttons[m_currentTool]->setChecked(false);
|
||||
}
|
||||
}
|
||||
|
||||
void EnhancedToolBar::onActionTriggered(QAction *action)
|
||||
{
|
||||
if (m_actionToType.contains(action)) {
|
||||
QString toolType = m_actionToType[action];
|
||||
// 设置新的选择
|
||||
if (m_buttons.contains(toolType)) {
|
||||
m_buttons[toolType]->setChecked(true);
|
||||
m_currentTool = toolType;
|
||||
emit toolSelected(toolType);
|
||||
} else {
|
||||
m_currentTool = "";
|
||||
}
|
||||
}
|
||||
|
||||
void EnhancedToolBar::setDragEnabled(bool enabled)
|
||||
{
|
||||
m_dragEnabled = enabled;
|
||||
|
||||
// 更新所有按钮
|
||||
for (DraggableToolButton *button : m_buttons.values()) {
|
||||
button->setDragEnabled(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
bool EnhancedToolBar::dragEnabled() const
|
||||
{
|
||||
return m_dragEnabled;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
#include "monitorPagesDlg.h"
|
||||
#include "QDetailsView.h"
|
||||
#include "baseDockWidget.h"
|
||||
#include "enhancedToolBar.h"
|
||||
#include "configToolBar.h"
|
||||
|
||||
#include "QDetailsView.h"
|
||||
|
||||
|
|
@ -83,12 +83,10 @@ void CMainWindow::moveEvent(QMoveEvent *event)
|
|||
|
||||
void CMainWindow::initializeDockUi()
|
||||
{
|
||||
EnhancedToolBar *toolBar = new EnhancedToolBar("绘图工具", this);
|
||||
ConfigToolBar* toolBar = new ConfigToolBar(this);
|
||||
addToolBar(Qt::TopToolBarArea, toolBar);
|
||||
toolBar->addTool("image", "图像", QIcon(":/images/element/icon_image.png"));
|
||||
toolBar->addTool("text", "文本", QIcon(":/images/element/icon_text.png"));
|
||||
toolBar->setIconSize(QSize(24, 24));
|
||||
toolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
|
||||
//toolBar->setIconSize(QSize(24, 24));
|
||||
//toolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
|
||||
|
||||
m_pElectricElementsBox = new ElectricElementsBox();
|
||||
/*m_pElectricElementsBox->initial();
|
||||
|
|
@ -114,21 +112,21 @@ void CMainWindow::initializeDockUi()
|
|||
diagramDock->setAllowedAreas(Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea);
|
||||
this->addDockWidget(Qt::LeftDockWidgetArea,diagramDock);
|
||||
|
||||
m_pMonitorItemsDlg = new MonitorItemsDlg(this);
|
||||
m_pMonitorItemsDock = new BaseDockWidget(QString::fromWCharArray(L"当前设备列表"),this);
|
||||
m_pMonitorItemsDock->setWidget(m_pMonitorItemsDlg);
|
||||
m_pMonitorItemsDock->setAllowedAreas(Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea);
|
||||
this->addDockWidget(Qt::RightDockWidgetArea,m_pMonitorItemsDock);
|
||||
//m_pMonitorItemsDlg = new MonitorItemsDlg(this);
|
||||
//m_pMonitorItemsDock = new BaseDockWidget(QString::fromWCharArray(L"当前设备列表"),this);
|
||||
//m_pMonitorItemsDock->setWidget(m_pMonitorItemsDlg);
|
||||
//m_pMonitorItemsDock->setAllowedAreas(Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea);
|
||||
//this->addDockWidget(Qt::RightDockWidgetArea,m_pMonitorItemsDock);
|
||||
|
||||
m_pMonitorPagesDlg = new MonitorPagesDlg(this);
|
||||
m_pMonitorPagesDock = new BaseDockWidget(QString::fromWCharArray(L"监控列表"),this);
|
||||
m_pMonitorPagesDock->setWidget(m_pMonitorPagesDlg);
|
||||
m_pMonitorPagesDock->setAllowedAreas(Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea);
|
||||
m_pMonitorPagesDock->setMinimumSize(120,550);
|
||||
this->addDockWidget(Qt::RightDockWidgetArea,m_pMonitorPagesDock);
|
||||
//m_pMonitorPagesDlg = new MonitorPagesDlg(this);
|
||||
//m_pMonitorPagesDock = new BaseDockWidget(QString::fromWCharArray(L"监控列表"),this);
|
||||
//m_pMonitorPagesDock->setWidget(m_pMonitorPagesDlg);
|
||||
//m_pMonitorPagesDock->setAllowedAreas(Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea);
|
||||
//m_pMonitorPagesDock->setMinimumSize(120,550);
|
||||
//this->addDockWidget(Qt::RightDockWidgetArea,m_pMonitorPagesDock);
|
||||
|
||||
m_pMonitorItemsDock->hide();
|
||||
m_pMonitorPagesDock->hide();
|
||||
//m_pMonitorItemsDock->hide();
|
||||
//m_pMonitorPagesDock->hide();
|
||||
|
||||
m_pDiagramCavas = new DiagramCavas(this);
|
||||
m_pDiagramCavas->initial();
|
||||
|
|
@ -186,13 +184,13 @@ void CMainWindow::initializeAction()
|
|||
connect(m_pDiagramCavas,&DiagramCavas::createHMI,m_pDiagramView,&DiagramView::onNewHMICreated);
|
||||
connect(m_pDiagramCavas,&DiagramCavas::updateHMI,m_pDiagramView,&DiagramView::onHMIUpdated);
|
||||
|
||||
connect(m_pDiagramCavas,&DiagramCavas::prepareUpdateItems,m_pMonitorItemsDlg,&MonitorItemsDlg::onUpdateItems);
|
||||
connect(m_pDiagramCavas,&DiagramCavas::prepareSelectItems,m_pMonitorItemsDlg,&MonitorItemsDlg::onSelectItems);
|
||||
connect(m_pDiagramCavas,&DiagramCavas::updateMonitorList,m_pMonitorPagesDlg,&MonitorPagesDlg::onMonitorCreated);
|
||||
//connect(m_pDiagramCavas,&DiagramCavas::prepareUpdateItems,m_pMonitorItemsDlg,&MonitorItemsDlg::onUpdateItems);
|
||||
//connect(m_pDiagramCavas,&DiagramCavas::prepareSelectItems,m_pMonitorItemsDlg,&MonitorItemsDlg::onSelectItems);
|
||||
//connect(m_pDiagramCavas,&DiagramCavas::updateMonitorList,m_pMonitorPagesDlg,&MonitorPagesDlg::onMonitorCreated);
|
||||
connect(m_pDiagramCavas,&DiagramCavas::createdMonitorItems,m_pMonitorItemsDlg,&MonitorItemsDlg::onMonitorCreated);
|
||||
connect(m_pDiagramCavas,&DiagramCavas::updateMonitorTopology,m_pTopologyView,&TopologyView::onMonitorUpdate);
|
||||
//connect(m_pDiagramCavas,&DiagramCavas::updateMonitorTopology,m_pTopologyView,&TopologyView::onMonitorUpdate);
|
||||
|
||||
connect(m_pMonitorPagesDlg,&MonitorPagesDlg::monitorSelected,m_pDiagramCavas,&DiagramCavas::onSignal_monitorSelected);
|
||||
//connect(m_pMonitorPagesDlg,&MonitorPagesDlg::monitorSelected,m_pDiagramCavas,&DiagramCavas::onSignal_monitorSelected);
|
||||
//connect(m_pMonitorPagesDlg,&MonitorPagesDlg::prepareSaveMonitor,m_pDiagramCavas,&DiagramCavas::onSignal_saveMonitor);
|
||||
|
||||
connect(ui->actionNew,&QAction::triggered,m_pDiagramCavas,&DiagramCavas::onSignal_addPage);
|
||||
|
|
@ -217,13 +215,13 @@ void CMainWindow::initializeAction()
|
|||
connect(_pActMonitor,&QAction::triggered,this,[&](){
|
||||
if(!_pActMonitor->isChecked()){
|
||||
_pActMonitor->setChecked(false);
|
||||
m_pMonitorItemsDock->hide();
|
||||
m_pMonitorPagesDock->hide();
|
||||
//m_pMonitorItemsDock->hide();
|
||||
//m_pMonitorPagesDock->hide();
|
||||
}
|
||||
else{
|
||||
_pActMonitor->setChecked(true);
|
||||
m_pMonitorItemsDock->show();
|
||||
m_pMonitorPagesDock->show();
|
||||
//m_pMonitorItemsDock->show();
|
||||
//m_pMonitorPagesDock->show();
|
||||
|
||||
if(m_pDiagramCavas)
|
||||
m_pDiagramCavas->updateMonitorListFromDB();
|
||||
|
|
|
|||
Loading…
Reference in New Issue