diff --git a/.gitignore b/.gitignore
index 21989986..5ae90f68 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,5 @@
build/
bin/
thirdparty/
+tritoin/
+QWEN.md
diff --git a/doc/dyttu.docx b/doc/dyttu.docx
new file mode 100644
index 00000000..aef5cafc
Binary files /dev/null and b/doc/dyttu.docx differ
diff --git a/doc/交互设计.md b/doc/交互设计.md
new file mode 100644
index 00000000..5ebf8dbf
--- /dev/null
+++ b/doc/交互设计.md
@@ -0,0 +1,26 @@
+# 交互设计
+## 拖拽式添加实体
+## 图表数据格式
+### WAVE图表
+按照一个文件多个曲线来,一行一个曲线
+
+
+ 曲线、曲面每一个类型一个tab页面 最大可以显示9宫格
+
+ 表格、灯 灯在上方,表格在下方(待定)
+
+ ## 菜单
+ ### 文件
+ * 新建wordspace
+ * 打开wordspace
+ * 保存wordspace
+ ----
+ * 新建曲线
+ * 新建曲面
+ * 新建表格
+ * 新建灯
+
+ ### 仿真管理
+ * 命令运行(手动编辑xml: )
+ * 参数编辑:弹出编辑框
+
diff --git a/doc/流程图.vsdx b/doc/流程图.vsdx
new file mode 100644
index 00000000..8b444531
Binary files /dev/null and b/doc/流程图.vsdx differ
diff --git a/doc/预设实体清单.txt b/doc/预设实体清单.txt
new file mode 100644
index 00000000..060cde52
--- /dev/null
+++ b/doc/预设实体清单.txt
@@ -0,0 +1,15 @@
+船:
+驱逐机(阿利伯克)、航母(尼米兹)
+
+卫星:
+高轨(静止)
+
+弹:
+高超音速弹(DF21)
+
+无源干扰:
+角反、箔条
+
+有源干扰:
+弦内、弦外
+
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 826a32ba..a8a6d2d0 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -14,8 +14,8 @@ find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Widgets LinguistTools DataVis
message("qt VERSION " ${QT_VERSION_MAJOR})
-FILE(GLOB_RECURSE HEADER_FILES ./*.h common/*.h common/*.hpp model/*.h app/*.h)
-FILE(GLOB_RECURSE CPP_FILES ./*.cpp common/*.cpp model/*.cpp app/*.cpp)
+FILE(GLOB_RECURSE HEADER_FILES ./*.h common/*.h common/*.hpp model/*.h app/*.h utils/*.h)
+FILE(GLOB_RECURSE CPP_FILES ./*.cpp common/*.cpp model/*.cpp app/*.cpp utils/*.cpp)
FILE(GLOB_RECURSE CC_FILES ./*.cc)
FILE(GLOB_RECURSE UI_FILES ./*.ui)
FILE(GLOB_RECURSE QRC_FILES ./*.qrc)
diff --git a/src/Dyt.qrc b/src/Dyt.qrc
index 53582c31..367668a1 100644
--- a/src/Dyt.qrc
+++ b/src/Dyt.qrc
@@ -1,6 +1,7 @@
res/sys_close.png
+ res/sys_float.png
res/sys_max.png
res/sys_min.png
res/sys_restore.png
@@ -11,7 +12,10 @@
res/default/menu_new_file.png
res/default/menu_open_file.png
res/default/menu_save_file.png
- res/default/menu_save_as_file.png
+ res/default/menu_wave_file.png
+ res/default/menu_light_file.png
+ res/default/menu_table_file.png
+ res/default/menu_surface_file.png
res/default/menu_save_shape_file.png
res/default/menu_save_store_file.png
res/default/menu_report_mesh.png
diff --git a/src/config/skin/default.qss b/src/config/skin/default.qss
index d4c2f311..259c2cec 100644
--- a/src/config/skin/default.qss
+++ b/src/config/skin/default.qss
@@ -72,6 +72,17 @@ QPushButton#sys_close {
padding: 0;
}
+QPushButton#sys_float {
+ max-width:48px;
+ min-width:48px;
+ max-height:28px;
+ min-height:28px;
+ border: none;
+ background: transparent;
+ image: url(:/res/sys_float.png);
+ padding: 0;
+}
+
QPushButton#sys_min {
max-width:48px;
min-width:48px;
@@ -219,6 +230,18 @@ QWidget#FileManagerMenu > QToolButton#menu_save_shape_file {
QWidget#FileManagerMenu > QToolButton#menu_save_shape_file {
qproperty-icon: url(:/res/default/menu_report_mesh.png);
}
+QWidget#FileManagerMenu > QToolButton#menu_wave_file {
+ qproperty-icon: url(:/res/default/menu_wave_file.png);
+}
+QWidget#FileManagerMenu > QToolButton#menu_surface_file {
+ qproperty-icon: url(:/res/default/menu_surface_file.png);
+}
+QWidget#FileManagerMenu > QToolButton#menu_table_file {
+ qproperty-icon: url(:/res/default/menu_table_file.png);
+}
+QWidget#FileManagerMenu > QToolButton#menu_light_file {
+ qproperty-icon: url(:/res/default/menu_light_file.png);
+}
QWidget#SystemManagerMenu > QToolButton#menu_exit {
qproperty-icon: url(:/res/default/menu_exit.png);
@@ -322,6 +345,7 @@ QMenu {
background: #212F3C;
color: #e0e0e0;
padding: 4px;
+ border-radius: 3px;
}
QMenu::item {
padding: 6px 30px 6px 20px;
@@ -340,4 +364,4 @@ QMenu::separator {
height: 1px;
background: #555;
margin: 5px 10px;
-}
+}
\ No newline at end of file
diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp
index 4f12b6cb..e91420e8 100644
--- a/src/entities/Entity.cpp
+++ b/src/entities/Entity.cpp
@@ -1,6 +1,8 @@
#include "entities/Entity.h"
#include
+// Ensure QVariant can hold and convert Entity* in signals/slots
+Q_DECLARE_METATYPE(Entity*)
#include "common/SpdLogger.h"
#include "entities/SceneComponent.h"
diff --git a/src/entities/PathComponent.cpp b/src/entities/PathComponent.cpp
index 5d675c2d..e7281a01 100644
--- a/src/entities/PathComponent.cpp
+++ b/src/entities/PathComponent.cpp
@@ -68,7 +68,7 @@ void PathComponent::Begin() {
for (int index = 0; index < num; ++index) {
const Transform& transform = transforms[index];
osg::AnimationPath::ControlPoint controlPoint(transform.GetLocation() /*+ osg::Vec3(index * 10, 0, 0)*/,
- OsgUtils::HPRToQuat(transform.GetRotation() + osg::Vec3(0, 0, -90.0)), transform.GetScale());
+ OsgUtils::HPRToQuat(transform.GetRotation()), transform.GetScale());
animationPath_->insert(steps[index], controlPoint);
}
diff --git a/src/res/default/menu_light_file.png b/src/res/default/menu_light_file.png
new file mode 100644
index 00000000..c0279ec8
Binary files /dev/null and b/src/res/default/menu_light_file.png differ
diff --git a/src/res/default/menu_surface_file.png b/src/res/default/menu_surface_file.png
new file mode 100644
index 00000000..836ed95e
Binary files /dev/null and b/src/res/default/menu_surface_file.png differ
diff --git a/src/res/default/menu_table_file.png b/src/res/default/menu_table_file.png
new file mode 100644
index 00000000..16dfbe72
Binary files /dev/null and b/src/res/default/menu_table_file.png differ
diff --git a/src/res/default/menu_wave_file.png b/src/res/default/menu_wave_file.png
new file mode 100644
index 00000000..5ae4cd95
Binary files /dev/null and b/src/res/default/menu_wave_file.png differ
diff --git a/src/res/sys_float.png b/src/res/sys_float.png
new file mode 100644
index 00000000..1ceeab87
Binary files /dev/null and b/src/res/sys_float.png differ
diff --git a/src/translations/Dyt_zh_CN.ts b/src/translations/Dyt_zh_CN.ts
index d83e8bd1..b1ba8005 100644
--- a/src/translations/Dyt_zh_CN.ts
+++ b/src/translations/Dyt_zh_CN.ts
@@ -382,30 +382,102 @@
-
+
+ new wave file
+
+
+
+
+ new surface file
+
+
+
+
+ new table file
+
+
+
+
+ new light file
+
+
+
+
Dyt (*.dyt)
-
+
open dyt file
-
+
Dyt (*.dyt);;All files (*.*)
-
+
warning
-
+
workspace is nullptr
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ prompt
+
+
+
+
+
+
+
+ please create workspace first
+
+
+
+
+
+
+
+ up to 9 files allowed for this type
+
+
+
+
+
+
+
+ file already added for this type
+
+
+
+
+
+
+
+ copy file failed
+
+
FitCurveChartView
@@ -520,127 +592,132 @@
-
+
model elements
-
+
attribte
-
+
+ Main View
+
+
+
+
Wave Curve
-
+
Speed Curve
-
+
3D Curve
-
+
Target number
-
+
Signal-to-noise ratio
-
+
Azimuth line of sight
-
+
Pitch gaze angle
-
+
azimuth
-
+
Pitch angle
-
+
attribute
-
+
Doppler
-
+
course
-
+
Speed
-
+
longitude
-
+
latitude
-
+
distance
-
+
velocity
-
+
Radial dimensions
-
+
Target RCS
-
+
Report Table
-
+
Signal Indicator Lamp
-
+
ParamSetting
-
+
bat File
@@ -711,12 +788,12 @@
OsgWidget
-
+
warning
-
+
open dyt file failed
@@ -820,22 +897,23 @@
+
WorkSpace
-
-
+
+
Entity
-
+
ModelBase
-
+
color base
@@ -893,6 +971,30 @@
altitude:
+
+
+
+ Curve[%1]
+
+
+
+
+
+ Surface[%1]
+
+
+
+
+
+ Table[%1]
+
+
+
+
+
+ Light[%1]
+
+
QtBoolEdit
@@ -913,12 +1015,12 @@
QtBoolPropertyManager
-
+
True
-
+
False
@@ -942,22 +1044,22 @@
QtColorPropertyManager
-
+
Red
-
+
Green
-
+
Blue
-
+
Alpha
@@ -965,48 +1067,48 @@
QtConeWaveComponentManager
-
-
+
+
ConeWaveComponent
-
+
Height
-
+
Radius
-
+
waveCount
-
+
waveSpeed
-
+
baseColor
-
+
waveColor
-
+
ringBrightAlpha
-
+
ringDarkAlpha
@@ -1112,28 +1214,28 @@
QtDashedLineComponentManager
-
-
+
+
DashedLineComponent
-
+
Start
-
+
End
-
+
Radius
-
+
Color
@@ -1149,17 +1251,17 @@
QtEntityPropertyManager
-
+
Name
-
+
Visible
-
+
Transform
@@ -1180,37 +1282,37 @@
QtFontPropertyManager
-
+
Family
-
+
Point Size
-
+
Bold
-
+
Italic
-
+
Underline
-
+
Strikeout
-
+
Kerning
@@ -1218,22 +1320,22 @@
QtLocalePropertyManager
-
+
<Invalid>
-
+
%1, %2
-
+
Language
-
+
Country
@@ -1241,13 +1343,13 @@
QtMeshComponetManager
-
-
+
+
MeshComponent
-
+
Mesh
@@ -1255,27 +1357,27 @@
QtModelBasePropertyManager
-
+
Name
-
+
Description
-
+
Inflow
-
+
InnerBottomElevation
-
+
Visible
@@ -1296,13 +1398,13 @@
QtPathComponentManager
-
-
+
+
PathComponent
-
+
Path
@@ -1310,17 +1412,17 @@
QtPointFPropertyManager
-
+
(%1, %2)
-
+
X
-
+
Y
@@ -1328,17 +1430,17 @@
QtPointPropertyManager
-
+
(%1, %2)
-
+
X
-
+
Y
@@ -1356,12 +1458,12 @@
-
+
[%1, %2, %3]
-
+
[%1, %2, %3] [%4, %5, %6] [%7, %8, %9]
@@ -1369,27 +1471,27 @@
QtRectFPropertyManager
-
+
[(%1, %2), %3 x %4]
-
+
X
-
+
Y
-
+
Width
-
+
Height
@@ -1397,27 +1499,27 @@
QtRectPropertyManager
-
+
[(%1, %2), %3 x %4]
-
+
X
-
+
Y
-
+
Width
-
+
Height
@@ -1425,17 +1527,17 @@
QtSizeFPropertyManager
-
+
%1 x %2
-
+
Width
-
+
Height
@@ -1443,33 +1545,33 @@
QtSizePolicyPropertyManager
-
+
<Invalid>
-
+
[%1, %2, %3, %4]
-
+
Horizontal Policy
-
+
Vertical Policy
-
+
Horizontal Stretch
-
+
Vertical Stretch
@@ -1477,17 +1579,17 @@
QtSizePropertyManager
-
+
%1 x %2
-
+
Width
-
+
Height
@@ -1503,17 +1605,17 @@
QtTransfromPropertyManager
-
+
Location
-
+
Rotation
-
+
Scale
@@ -1534,17 +1636,17 @@
QtVec3PropertyManager
-
+
X
-
+
Y
-
+
Z
@@ -1552,20 +1654,90 @@
QtWorkspacePropertyManager
-
+
Name
-
+
Description
-
+
Timestep
+
+
+ SimMatlab
+
+
+
+
+ MatlabParam
+
+
+
+
+ WavePath
+
+
+
+
+ ReportPath
+
+
+
+
+ RDPath
+
+
+
+
+ Count
+
+
+
+
+ Curve[%1]
+
+
+
+
+ Surface[%1]
+
+
+
+
+ Table[%1]
+
+
+
+
+ Light[%1]
+
+
+
+
+ Curves
+
+
+
+
+ Surfaces
+
+
+
+
+ Tables
+
+
+
+
+ Lights
+
+
SignalIndicatorLampUI
@@ -1742,21 +1914,32 @@
+
...
+ commond Path
+
+
+
+
+ select commond file path
+
+
+
+
describe
-
+
Sure
-
+
Cancel
@@ -1766,49 +1949,54 @@
-
-
-
-
-
-
+
+
+
+
+
+
warning
-
+
name or save path is empty, please check it
-
+
save current workspace?
-
+
current path is contains current folder, do you want to overwrite it?
-
+
removeRecursively failed
-
+
mkpath failed
-
+
name is exits
-
+
save spaceWork directory
+
+
+ select commond file directory
+
+
diff --git a/src/ui/DockTitleBar.cpp b/src/ui/DockTitleBar.cpp
index 1271d3d7..3f63dc78 100644
--- a/src/ui/DockTitleBar.cpp
+++ b/src/ui/DockTitleBar.cpp
@@ -14,6 +14,7 @@ DockTitleBar::DockTitleBar(QWidget* parent)
, ui(new Ui::DockTitleBar) {
ui->setupUi(this);
connect(ui->sys_close, &QPushButton::clicked, this, &DockTitleBar::signalClose);
+ connect(ui->sys_float, &QPushButton::clicked, this, &DockTitleBar::signalToggleFloating);
}
DockTitleBar::~DockTitleBar() {
diff --git a/src/ui/DockTitleBar.ui b/src/ui/DockTitleBar.ui
index 88939bf0..10d2d74f 100644
--- a/src/ui/DockTitleBar.ui
+++ b/src/ui/DockTitleBar.ui
@@ -49,6 +49,19 @@
+ -
+
+
+
+ 32
+ 32
+
+
+
+
+
+
+
-
diff --git a/src/ui/DockWidget.cpp b/src/ui/DockWidget.cpp
index 6bb51d60..69f6a2b4 100644
--- a/src/ui/DockWidget.cpp
+++ b/src/ui/DockWidget.cpp
@@ -1,6 +1,7 @@
#include "DockWidget.h"
#include
+#include
#include "ui/Menu/SystemManagerMenu.h"
#include "common/SpdLogger.h"
@@ -8,7 +9,7 @@
DockWidgetTitleBar::DockWidgetTitleBar(QWidget* parent)
- : QWidget(parent) {
+ : QWidget(parent) {
}
@@ -54,6 +55,7 @@ void DockWidget::setWindowTitle(const QString& text) {
void DockWidget::SetDockWidgetTitleBar(DockWidgetTitleBar* titleBar) {
if (nullptr != titleBar_) {
disconnect(titleBar_, &DockWidgetTitleBar::signalClose, this, &DockWidget::close);
+ disconnect(titleBar_, &DockWidgetTitleBar::signalToggleFloating, this, &DockWidget::OnToggleFloat);
}
titleBar_ = titleBar;
if (nullptr == titleBar_) {
@@ -63,6 +65,7 @@ void DockWidget::SetDockWidgetTitleBar(DockWidgetTitleBar* titleBar) {
titleBar_->SetTitle(windowTitle());
connect(titleBar_, &DockWidgetTitleBar::signalClose, this, &DockWidget::OnClose);
+ connect(titleBar_, &DockWidgetTitleBar::signalToggleFloating, this, &DockWidget::OnToggleFloat);
QDockWidget::setTitleBarWidget(titleBar_);
}
@@ -86,3 +89,12 @@ void DockWidget::OnClose() {
emit signalClose();
}
+void DockWidget::OnToggleFloat() {
+ setFloating(!isFloating());
+}
+
+void DockWidgetTitleBar::mouseDoubleClickEvent(QMouseEvent* event) {
+ QWidget::mouseDoubleClickEvent(event);
+ emit signalToggleFloating();
+}
+
diff --git a/src/ui/DockWidget.h b/src/ui/DockWidget.h
index 8a049bf4..8e878c59 100644
--- a/src/ui/DockWidget.h
+++ b/src/ui/DockWidget.h
@@ -6,7 +6,7 @@
#include
class DockWidgetTitleBar : public QWidget {
- Q_OBJECT
+ Q_OBJECT
public:
DockWidgetTitleBar(QWidget* parent);
@@ -18,9 +18,12 @@ public:
// return QSize(270, 900);
//}
//QSize minimumSizeHint() const override;
+protected:
+ void mouseDoubleClickEvent(QMouseEvent* event) override;
Q_SIGNALS:
void signalClose();
+ void signalToggleFloating();
};
class DockWidget : public QDockWidget {
@@ -45,6 +48,7 @@ protected:
private:
void OnClose();
+ void OnToggleFloat();
private:
DockWidgetTitleBar* titleBar_{ nullptr };
diff --git a/src/ui/EntityBrowser.cpp b/src/ui/EntityBrowser.cpp
new file mode 100644
index 00000000..404b8348
--- /dev/null
+++ b/src/ui/EntityBrowser.cpp
@@ -0,0 +1,48 @@
+#include "EntityBrowser.h"
+
+#include
+#include
+
+#include "DockTitleBar.h"
+#include "DockWidget.h"
+// #include "ModelBrowser/ModelTreeWidget.h"
+#include "workspace/WorkSpaceManager.h"
+
+EntityBrowser::EntityBrowser(QWidget *parent) :
+ QWidget(parent) {
+
+ InitUI();
+}
+
+EntityBrowser::~EntityBrowser() {
+
+}
+
+void EntityBrowser::AttachDock(DockWidget* dockWidget) {
+ if (nullptr == dockWidget) {
+ qDebug() << __FUNCTION__ << "dockwidget is nullptr";
+ return;
+ }
+
+ dockWidget->SetDockWidgetTitleBar(nullptr);
+ dockWidget->setWidget(this);
+
+ DockTitleBar* dockTitleBar = new DockTitleBar;
+ dockWidget->SetDockWidgetTitleBar(dockTitleBar);
+}
+
+void EntityBrowser::InitUI() {
+ // QBoxLayout* layout = new QVBoxLayout(this);
+ // layout->setContentsMargins(0, 0, 0, 0);
+
+ // treeWidget_ = new ModelTreeWidget;
+ // treeWidget_->setHeaderHidden(true);
+ // layout->addWidget(treeWidget_);
+
+ // connect(&WorkSpaceManager::Get(), &WorkSpaceManager::WorkSpaceChanged,
+ // treeWidget_, &ModelTreeWidget::OnWorkspaceChange);
+
+ // //ModelTreeWidget* treeWidget = modelBrowserPannal_->GetModelTreeWidget();
+ // connect(treeWidget_, &ModelTreeWidget::WorkSpaceChange, this, &ModelBrowser::WorkSpaceChange);
+ // connect(treeWidget_, &ModelTreeWidget::EntityChange, this, &ModelBrowser::EntityChange);
+}
diff --git a/src/ui/EntityBrowser.h b/src/ui/EntityBrowser.h
new file mode 100644
index 00000000..07412fae
--- /dev/null
+++ b/src/ui/EntityBrowser.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include
+
+class EntityBrowser : public QWidget {
+ Q_OBJECT
+
+public:
+ explicit EntityBrowser(QWidget *parent = nullptr);
+ ~EntityBrowser() override;
+
+ void AttachDock(class DockWidget* dockWidget);
+
+Q_SIGNALS:
+ void WorkSpaceChange(const QVariant& workSpace);
+ void EntityChange(const QVariant& workSpace);
+
+private:
+ void InitUI();
+
+private:
+ // class ModelTreeWidget* treeWidget_;
+};
+
diff --git a/src/ui/MainWindow.cpp b/src/ui/MainWindow.cpp
index 487e1133..de1bfdec 100644
--- a/src/ui/MainWindow.cpp
+++ b/src/ui/MainWindow.cpp
@@ -1,6 +1,7 @@
#include "MainWindow.h"
#include
+#include "utils/UiLayoutManager.h"
#include "PropertyBrowser.h"
#include "ModelBrowser.h"
@@ -28,6 +29,7 @@
#include "ui_MainWindow.h"
#include "viewer/OsgWidget.h"
+#include "DockTitleBar.h"
MainWindow::MainWindow(QWidget* parent)
: QMainWindow(parent)
@@ -43,43 +45,49 @@ MainWindow::~MainWindow() {
}
void MainWindow::InitUI() {
-
- tabWidget_ = new QTabWidget;
- tabWidget_->setTabPosition(QTabWidget::South);
- tabWidget_->tabBar()->setMinimumWidth(300);
-
- ui->viewWidget->layout()->addWidget(tabWidget_);
-
- pSettingUI = new LayoutSettingUI();
-
- const QString uiLaytouPath = RecourceHelper::Get().GetBasePath() + "/workspace/UILayout.xml";
-
- pSettingUI->InitConfig(uiLaytouPath);
- //pSettingUI->show();
-
- connect(pSettingUI, &LayoutSettingUI::signalUpdate, this, &MainWindow::InitDockLayout);
+ QWidget* centralWidget = takeCentralWidget();
+ if (nullptr != centralWidget) {
+ delete centralWidget;
+ }
+ setDockNestingEnabled(true);
setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
+ setDockOptions(QMainWindow::AllowTabbedDocks | QMainWindow::AllowNestedDocks | QMainWindow::AnimatedDocks);
DockWidget* model = new DockWidget(tr("model elements"), 0);
+ model->SetDockWidgetTitleBar(new DockTitleBar(model));
+ model->setObjectName("Dock.ModelBrowser");
// addDockWidget(pSettingUI->GetArea("ModelBrowser"), model);
modelBrowser_ = new ModelBrowser(0);
modelBrowser_->AttachDock(model);
m_mapDockWidget.insert("ModelBrowser", model);
DockWidget* attribte = new DockWidget(tr("attribte"), 0);
+ attribte->SetDockWidgetTitleBar(new DockTitleBar(attribte));
+ attribte->setObjectName("Dock.PropertyBrowser");
//addDockWidget(pSettingUI->GetArea("PropertyBrowser"), attribte);
propertyBrowser_ = new PropertyBrowser(0);
propertyBrowser_->AttachDock(attribte);
m_mapDockWidget.insert("PropertyBrowser", attribte);
+ addDockWidget(Qt::RightDockWidgetArea, attribte);
connect(modelBrowser_, &ModelBrowser::WorkSpaceChange, propertyBrowser_, &PropertyBrowser::OnWorkSpaceChange);
connect(modelBrowser_, &ModelBrowser::EntityChange, propertyBrowser_, &PropertyBrowser::OnEntityChange);
qtOsgViewWidget_ = new OsgWidget;
qtOsgViewWidget_->Initialize();
- //m_mapDockWidget.insert("PropertyBrowser", attribte);
+
+ // 主视图改为 DockWidget,支持自由停靠
+ DockWidget* viewDock = new DockWidget(tr("Main View"), 0);
+ viewDock->SetDockWidgetTitleBar(new DockTitleBar(viewDock));
+ viewDock->setObjectName("Dock.MainView");
+ viewDock->setWidget(qtOsgViewWidget_);
+ addDockWidget(Qt::LeftDockWidgetArea, viewDock);
+ m_mapDockWidget.insert("MainView", viewDock);
+
+ addDockWidget(Qt::LeftDockWidgetArea, model);
+ splitDockWidget(model, viewDock, Qt::Horizontal);
QString wavePath ="", speedPath = "", rdPath = "", matlabParam="";
if (WorkSpaceManager::Get().GetCurrent())
@@ -106,25 +114,36 @@ void MainWindow::InitUI() {
}
DockWidget* fitCurveDock = new DockWidget(tr("Wave Curve"), 0);
+ fitCurveDock->SetDockWidgetTitleBar(new DockTitleBar(fitCurveDock));
+ fitCurveDock->setObjectName("Dock.WaveCurveDialog");
fitCurveDlg_ = new FitCurveDialog(1);
fitCurveDlg_->AttachDock(fitCurveDock);
m_mapDockWidget.insert("WaveCurveDialog", fitCurveDock);
+ addDockWidget(Qt::BottomDockWidgetArea, fitCurveDock);
fitCurveDlg_->InitWaveFile(wavePath);
DockWidget* fitLgCurveDock = new DockWidget(tr("Speed Curve"), 0);
+ fitLgCurveDock->SetDockWidgetTitleBar(new DockTitleBar(fitLgCurveDock));
+ fitLgCurveDock->setObjectName("Dock.SpeedCurveDialog");
fitYLgCurveDlg_ = new FitCurveDialog(1);
fitYLgCurveDlg_->AttachDock(fitLgCurveDock);
m_mapDockWidget.insert("SpeedCurveDialog", fitLgCurveDock);
+ addDockWidget(Qt::BottomDockWidgetArea, fitLgCurveDock);
+ tabifyDockWidget(fitCurveDock, fitLgCurveDock);
fitYLgCurveDlg_->InitReportFile(speedPath);
DockWidget* surfaceCurveDock = new DockWidget(tr("3D Curve"), 0);
+ surfaceCurveDock->SetDockWidgetTitleBar(new DockTitleBar(surfaceCurveDock));
+ surfaceCurveDock->setObjectName("Dock.3DCurveDialog");
surfaceDlg_ = new SurfaceDialog();
surfaceDlg_->AttachDock(surfaceCurveDock);
m_mapDockWidget.insert("3DCurveDialog", surfaceCurveDock);
+ addDockWidget(Qt::BottomDockWidgetArea, surfaceCurveDock);
+ tabifyDockWidget(fitCurveDock, surfaceCurveDock);
surfaceDlg_->InitRD(rdPath);
@@ -146,37 +165,55 @@ void MainWindow::InitUI() {
targetUITable_->InitFile(speedPath, 50);
DockWidget* dataTableDock = new DockWidget(tr("Report Table"), 0);
+ dataTableDock->SetDockWidgetTitleBar(new DockTitleBar(dataTableDock));
+ dataTableDock->setObjectName("Dock.TargetListWgt_Table");
// addDockWidget(pSettingUI->GetArea("TargetListWgt"), dataTableDock);
targetUITable_->AttachDock(dataTableDock);
m_mapDockWidget.insert("TargetListWgt_Table", dataTableDock);
+ addDockWidget(Qt::BottomDockWidgetArea, dataTableDock);
+ tabifyDockWidget(fitCurveDock, dataTableDock);
}
const QString lampPath = RecourceHelper::Get().GetBasePath() + "/workspace/Lamp.txt";
DockWidget* signalIndicatorLampDock = new DockWidget(tr("Signal Indicator Lamp"), 0);
+ signalIndicatorLampDock->SetDockWidgetTitleBar(new DockTitleBar(signalIndicatorLampDock));
+ signalIndicatorLampDock->setObjectName("Dock.SignalIndicatorLampUI");
signalIndicatorLampUI_ = new SignalIndicatorLampUI;
signalIndicatorLampUI_->AttachDock(signalIndicatorLampDock);
signalIndicatorLampUI_->InitLamp(lampPath);
m_mapDockWidget.insert("SignalIndicatorLampUI", signalIndicatorLampDock);
+ addDockWidget(Qt::BottomDockWidgetArea, signalIndicatorLampDock);
+ tabifyDockWidget(fitCurveDock, signalIndicatorLampDock);
DockWidget* addParamSettingDock = new DockWidget(tr("ParamSetting"), 0);
+ addParamSettingDock->SetDockWidgetTitleBar(new DockTitleBar(addParamSettingDock));
+ addParamSettingDock->setObjectName("Dock.ParamSetting");
addParamDlg_ = new AddParamSetting(matlabParam);
addParamDlg_->AttachDock(addParamSettingDock);
m_mapDockWidget.insert("ParamSetting", addParamSettingDock);
+ addDockWidget(Qt::BottomDockWidgetArea, addParamSettingDock);
+ tabifyDockWidget(fitCurveDock, addParamSettingDock);
DockWidget* matlabDock = new DockWidget(tr("bat File"), 0);
+ matlabDock->SetDockWidgetTitleBar(new DockTitleBar(matlabDock));
+ matlabDock->setObjectName("Dock.Matlab");
matlabFileDlg_ = new CodeEdtUI;
matlabFileDlg_->AttachDock(matlabDock);
m_mapDockWidget.insert("Matlab", matlabDock);
+ addDockWidget(Qt::BottomDockWidgetArea, matlabDock);
+ tabifyDockWidget(fitCurveDock, matlabDock);
//ui->discript->setText(tr("name: 5year 0412"));
//ui->status->setText(tr("start: no start"));
-
- InitDockLayout();
- InitChartLayout();
+ // InitDockLayout();
+
+ // Restore previous UI layout if available
+ UiLayoutManager::Restore(this, 1);
+
//ui->viewWidget->layout()->addWidget(qtOsgViewWidget_);
qtOsgViewWidget_->LoadDefaultScene();
/*OsgViewer::Get().Initialize();
@@ -189,6 +226,8 @@ void MainWindow::InitUI() {
}
void MainWindow::UninitUI() {
+ // Save layout state before tearing down widgets
+ UiLayoutManager::Save(this, 1);
if (qtOsgViewWidget_) {
qtOsgViewWidget_->Uninitialize();
delete qtOsgViewWidget_;
@@ -196,248 +235,6 @@ void MainWindow::UninitUI() {
}
}
-void MainWindow::InitDockLayout() {
- while (tabWidget_->count() > 0) {
- tabWidget_->removeTab(0);
- }
-
- tabWidget_->tabBar()->setExpanding(true);
-
- QVariantList listTab = pSettingUI->GetAreaLayout().toList();
- for (int i = 0; i < listTab.size(); i++) {
- QVariantMap mapTab = listTab[i].toMap();
- QString strTabName = mapTab.value("Name").toString();
-
- QMainWindow* mainWindow_ = new QMainWindow;
- connect(mainWindow_, &QMainWindow::tabifiedDockWidgetActivated, this, &MainWindow::OnTabifiedDockWidgetActivated);
-
- QVariantList listDocArea = mapTab.value("Widget").toList();
-
- tabWidget_->insertTab(i, mainWindow_, strTabName);
- if (listDocArea[0].toList().size() > 0) {
- mainWindow_->setCentralWidget(qtOsgViewWidget_);
- //OsgViewer::Get().Initialize();
- //OsgViewer::Get().OnFrame();
- } else {
- mainWindow_->takeCentralWidget();
- }
-
-
- if (listDocArea.size() > 0) {
- QDockWidget* lastDock = nullptr;
-
- for (int j = 1; j < listDocArea.size(); j++) {
- Qt::DockWidgetArea dockArea;
- if (j == 1) {
- dockArea = Qt::LeftDockWidgetArea;
- } else if (j == 2) {
- dockArea = Qt::TopDockWidgetArea;
- } else if (j == 3) {
- dockArea = Qt::RightDockWidgetArea;
- } else if (j == 4) {
- dockArea = Qt::BottomDockWidgetArea;
- }
-
- QVariantList listDocAreaChild = listDocArea[j].toList();
- for (int m = 0; m < listDocAreaChild.size(); m++) {
- QVariant varWidget = listDocAreaChild[m];
-
- if (varWidget.type() == QVariant::String) {
- QDockWidget* pDock = m_mapDockWidget.value(varWidget.toString());
- if (pDock == nullptr) {
- continue;
- }
- mainWindow_->addDockWidget(dockArea, pDock);
- lastDock = pDock;
- } else {
- QVariantList listWidget = varWidget.toList();
- for (int k = 0; k < listWidget.size(); k++) {
- QDockWidget* pDock = m_mapDockWidget.value(listWidget[k].toString());
- mainWindow_->addDockWidget(dockArea, pDock);
-
- if (k == 0) {
- if (lastDock) {
- mainWindow_->splitDockWidget(lastDock, pDock, Qt::Vertical);
- }
- } else {
- mainWindow_->splitDockWidget(lastDock, pDock, Qt::Horizontal);
- }
-
- lastDock = pDock;
- }
- }
- }
- }
- }
- }
-
- tabWidget_->tabBar()->setMinimumWidth(500);
- /* AddDockArea("DockLeftArea");
- AddDockArea("DockTopArea");
- AddDockArea("DockRightArea");
- AddDockArea("DockBottomArea");*/
-}
-
-void MainWindow::AddDockArea(const QString& strArea) {
- Qt::DockWidgetArea dockArea;
- Qt::Orientation orient;
-
- if (strArea == "DockLeftArea") {
- dockArea = Qt::LeftDockWidgetArea;
- orient = Qt::Vertical;
- } else if (strArea == "DockTopArea") {
- dockArea = Qt::TopDockWidgetArea;
- orient = Qt::Horizontal;
- } else if (strArea == "DockRightArea") {
- dockArea = Qt::RightDockWidgetArea;
- orient = Qt::Vertical;
- } else if (strArea == "DockBottomArea") {
- dockArea = Qt::BottomDockWidgetArea;
- orient = Qt::Horizontal;
- } else {
- return;
- }
-
- QList listAdd;
-
- QVariant varArea = pSettingUI->GetAreaLayout();
- if (varArea.isValid()) {
- QVariantList listWidget = varArea.toList();
- for each(QVariant varWidget in listWidget) {
- if (varWidget.type() == QVariant::String) {
- QDockWidget* pDock = m_mapDockWidget.value(varWidget.toString());
- addDockWidget(dockArea, pDock);
-
- listAdd.push_back(pDock);
- } else {
- QDockWidget* pLastDock = nullptr;
- QVariantList listTab = varWidget.toList();
- for each(QVariant tabChild in listTab) {
- QDockWidget* pDock = m_mapDockWidget.value(tabChild.toString());
- addDockWidget(dockArea, pDock);
-
- if (pLastDock) {
- //tabifyDockWidget(pLastDock, pDock);
- splitDockWidget(pLastDock, pDock, Qt::Horizontal);
- }
-
- listAdd.push_back(pDock);
-
- pLastDock = pDock;
- }
- }
- }
- }
- QList listSpliter;
- for (size_t i = 0; i < listAdd.size(); i++) {
- listSpliter.push_back(1);
- }
-
- resizeDocks(listAdd, listSpliter, orient);
-}
-
-void MainWindow::InitChartLayout()
-{
- QString strChart = RecourceHelper::Get().GetBasePath() + "/workspace/Chart.xml";
- m_mgrChart.Load(strChart);
-
- QVariantList varList = m_mgrChart.GetChartWgt();
- for (int nI = 0; nI < varList.size(); nI++)
- {
- QVariantMap mapWgt = varList.at(nI).toMap();
- QString strWgt = mapWgt.begin().key();
- QVariantList listChart = mapWgt.begin().value().toList();
-
- QMainWindow* mainWindow_ = new QMainWindow;
- connect(mainWindow_, &QMainWindow::tabifiedDockWidgetActivated, this, &MainWindow::OnTabifiedDockWidgetActivated);
-
- int nCount = tabWidget_->count();
- tabWidget_->insertTab(nCount, mainWindow_, strWgt);
-
- QVariantMap varRows;
- for (int nJ = 0; nJ < listChart.size(); nJ++)
- {
- QVariantMap mapChart = listChart.at(nJ).toMap();
- int nRow = mapChart.value("row").toInt();
- int nCol = mapChart.value("column").toInt();
- QString strKey = QString::number(nRow) + "-" + QString::number(nCol);
- varRows.insert(strKey, mapChart);
- }
-
- QDockWidget* lastRowDock = nullptr;
- QDockWidget* lastColDock = nullptr;
- int lastRow = -1;
- int lastCol = -1;
- for (QVariantMap::Iterator ite = varRows.begin(); ite != varRows.end(); ++ite)
- {
- QVariantMap mapChart = ite.value().toMap();
- int nRow = mapChart.value("row").toInt();
- int nCol = mapChart.value("column").toInt();
- QString strName = mapChart.value("Name").toString();
- QString xTitle = mapChart.value("xTitle").toString();
- QString yTitle = mapChart.value("yTitle").toString();
- float xMin = mapChart.value("xMin").toFloat();
- float xMax = mapChart.value("xMax").toFloat();
- int xCount = mapChart.value("xCount").toInt();
- float yMin = mapChart.value("yMin").toFloat();
- float yMax = mapChart.value("yMax").toFloat();
-
- DockWidget* pDock = new DockWidget(strName, 0);
- fitCurveDlg_ = new FitCurveDialog(1);
- fitCurveDlg_->AttachDock(pDock);
- fitCurveDlg_->updateTitle(xTitle, yTitle);
- fitCurveDlg_->updateMinMaxX(xMin, xMax, xCount);
- fitCurveDlg_->updateMinMaxY(yMin, yMax);
-
- mainWindow_->addDockWidget(Qt::LeftDockWidgetArea, pDock);
-
- if (lastRow > -1)
- {
- if (lastRow == nRow)
- {
- if (lastCol > -1)
- {
- if (lastCol != nCol)
- {
- mainWindow_->splitDockWidget(lastColDock, pDock, Qt::Horizontal);
- }
- lastColDock = pDock;
- }
- else
- {
- lastColDock = pDock;
- }
- }
- else
- {
- //mainWindow_->splitDockWidget(lastRowDock, pDock, Qt::Vertical);
-
- lastRowDock = pDock;
- }
- }
- else
- {
- lastRowDock = pDock;
- lastColDock = pDock;
- }
-
- lastRow = nRow;
- lastCol = nCol;
- }
- }
-}
-
-void MainWindow::OnTabifiedDockWidgetActivated(QDockWidget* dockWidget) {
- //if (dockWidget) {
- // QMainWindow* mainWindow = qobject_cast(dockWidget->parentWidget());
- // if (mainWindow) {
- // mainWindow->removeDockWidget(dockWidget);
- // }
-
- // // tabWidget_->setCurrentWidget(dockWidget->parentWidget());
- //}
-}
-
void MainWindow::slotShowUISetting() {
pSettingUI->show();
}
diff --git a/src/ui/MainWindow.h b/src/ui/MainWindow.h
index adb9d0f8..8b77370b 100644
--- a/src/ui/MainWindow.h
+++ b/src/ui/MainWindow.h
@@ -46,14 +46,6 @@ private:
void InitUI();
void UninitUI();
- void InitDockLayout();
- void AddDockArea(const QString& strArea);
-
- void InitChartLayout();
-
-protected:
- void OnTabifiedDockWidgetActivated(QDockWidget* dockWidget);
-
private:
Ui::MainWindow* ui;
diff --git a/src/ui/MainWindow.ui b/src/ui/MainWindow.ui
index 61c17f6e..63d92d14 100644
--- a/src/ui/MainWindow.ui
+++ b/src/ui/MainWindow.ui
@@ -1,131 +1,20 @@
- MainWindow
-
-
-
- 0
- 0
- 800
- 658
-
-
-
- MainWindow
-
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
-
- 19
-
-
- 19
-
-
- 19
-
-
- 19
-
-
-
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
- 0
- 20
-
-
-
-
- 16777215
- 30
-
-
-
-
- 0
-
-
- 0
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 767
- 20
-
-
-
-
-
-
-
-
-
-
-
-
+ MainWindow
+
+
+
+ 0
+ 0
+ 1223
+ 950
+
+
+
+ MainWindow
+
+
+
+
+
diff --git a/src/ui/Menu/FileManagerMenu.cpp b/src/ui/Menu/FileManagerMenu.cpp
index aff15399..653ea602 100644
--- a/src/ui/Menu/FileManagerMenu.cpp
+++ b/src/ui/Menu/FileManagerMenu.cpp
@@ -12,6 +12,7 @@
#include "common/SpdLogger.h"
#include "workspace/WorkSpace.h"
#include "workspace/WorkSpaceManager.h"
+#include "workspace/FileEntry.h"
#include "utils/FileUtils.h"
#include "ui_FileManagerMenu.h"
@@ -32,6 +33,12 @@ void FileManagerMenu::InitConnect() {
connect(ui->menu_new_file, &QToolButton::clicked, this, &FileManagerMenu::NewWorkSpace);
connect(ui->menu_open_file, &QToolButton::clicked, this, &FileManagerMenu::OpenWorkSpace);
connect(ui->menu_save_file, &QToolButton::clicked, this, &FileManagerMenu::SaveWorkSpace);
+
+ // add file entity buttons
+ connect(ui->menu_wave_file, &QToolButton::clicked, this, &FileManagerMenu::AddWaveFile);
+ connect(ui->menu_surface_file, &QToolButton::clicked, this, &FileManagerMenu::AddSurfaceFile);
+ connect(ui->menu_table_file, &QToolButton::clicked, this, &FileManagerMenu::AddTableFile);
+ connect(ui->menu_light_file, &QToolButton::clicked, this, &FileManagerMenu::AddLightFile);
}
void FileManagerMenu::NewWorkSpace() {
@@ -70,19 +77,94 @@ void FileManagerMenu::SaveWorkSpace() {
QString dytFile = workspace->GetPath();
LOG_INFO("save {} dyt file: {}", name.toLocal8Bit().constData(),
dytFile.toLocal8Bit().constData());
- /* if (!FileUtils::IsExist(dytFile)) {
- QString selfilter = tr("Dyt (*.dyt)");
- const QString workspacePath = Application::GetWorkSpacePath();
- dytFile = QFileDialog::getSaveFileName(&MainFrame::Get(), tr("save dyt file"), workspacePath,
- tr("Dyt (*.dyt);;All files (*.*)"),
- &selfilter);
- LOG_INFO("user select file: {}", dytFile.toLocal8Bit().constData());
- if (dytFile.isEmpty()) {
- return;
- }
-
- }*/
bool success = workspace->Save(dytFile);
LOG_INFO("save dyt: {}", success);
}
+
+void FileManagerMenu::AddWaveFile() {
+ auto current = WorkSpaceManager::Get().GetCurrent();
+ if (nullptr == current) {
+ QMessageBox::information(&MainFrame::Get(), tr("prompt"), tr("please create workspace first"));
+ return;
+ }
+
+ switch (current->CreateFileEntry(FileEntryType::Curve)) {
+ case WorkSpace::FileEntryResult::Ok:
+ break;
+ case WorkSpace::FileEntryResult::LimitExceeded:
+ QMessageBox::information(&MainFrame::Get(), tr("prompt"), tr("up to 9 files allowed for this type"));
+ break;
+ case WorkSpace::FileEntryResult::Duplicate:
+ QMessageBox::information(&MainFrame::Get(), tr("prompt"), tr("file already added for this type"));
+ break;
+ case WorkSpace::FileEntryResult::CopyFailed:
+ QMessageBox::information(&MainFrame::Get(), tr("prompt"), tr("copy file failed"));
+ break;
+ }
+}
+
+void FileManagerMenu::AddSurfaceFile() {
+ auto current = WorkSpaceManager::Get().GetCurrent();
+ if (nullptr == current) {
+ QMessageBox::information(&MainFrame::Get(), tr("prompt"), tr("please create workspace first"));
+ return;
+ }
+
+ switch (current->CreateFileEntry(FileEntryType::Surface)) {
+ case WorkSpace::FileEntryResult::Ok:
+ break;
+ case WorkSpace::FileEntryResult::LimitExceeded:
+ QMessageBox::information(&MainFrame::Get(), tr("prompt"), tr("up to 9 files allowed for this type"));
+ break;
+ case WorkSpace::FileEntryResult::Duplicate:
+ QMessageBox::information(&MainFrame::Get(), tr("prompt"), tr("file already added for this type"));
+ break;
+ case WorkSpace::FileEntryResult::CopyFailed:
+ QMessageBox::information(&MainFrame::Get(), tr("prompt"), tr("copy file failed"));
+ break;
+ }
+}
+
+void FileManagerMenu::AddTableFile() {
+ auto current = WorkSpaceManager::Get().GetCurrent();
+ if (nullptr == current) {
+ QMessageBox::information(&MainFrame::Get(), tr("prompt"), tr("please create workspace first"));
+ return;
+ }
+ switch (current->CreateFileEntry(FileEntryType::Table)) {
+ case WorkSpace::FileEntryResult::Ok:
+ break;
+ case WorkSpace::FileEntryResult::LimitExceeded:
+ QMessageBox::information(&MainFrame::Get(), tr("prompt"), tr("up to 9 files allowed for this type"));
+ break;
+ case WorkSpace::FileEntryResult::Duplicate:
+ QMessageBox::information(&MainFrame::Get(), tr("prompt"), tr("file already added for this type"));
+ break;
+ case WorkSpace::FileEntryResult::CopyFailed:
+ QMessageBox::information(&MainFrame::Get(), tr("prompt"), tr("copy file failed"));
+ break;
+ }
+}
+
+void FileManagerMenu::AddLightFile() {
+ auto current = WorkSpaceManager::Get().GetCurrent();
+ if (nullptr == current) {
+ QMessageBox::information(&MainFrame::Get(), tr("prompt"), tr("please create workspace first"));
+ return;
+ }
+
+ switch (current->CreateFileEntry(FileEntryType::Light)) {
+ case WorkSpace::FileEntryResult::Ok:
+ break;
+ case WorkSpace::FileEntryResult::LimitExceeded:
+ QMessageBox::information(&MainFrame::Get(), tr("prompt"), tr("up to 9 files allowed for this type"));
+ break;
+ case WorkSpace::FileEntryResult::Duplicate:
+ QMessageBox::information(&MainFrame::Get(), tr("prompt"), tr("file already added for this type"));
+ break;
+ case WorkSpace::FileEntryResult::CopyFailed:
+ QMessageBox::information(&MainFrame::Get(), tr("prompt"), tr("copy file failed"));
+ break;
+ }
+}
diff --git a/src/ui/Menu/FileManagerMenu.h b/src/ui/Menu/FileManagerMenu.h
index d0948b5a..ff93612e 100644
--- a/src/ui/Menu/FileManagerMenu.h
+++ b/src/ui/Menu/FileManagerMenu.h
@@ -24,6 +24,11 @@ private:
void OpenWorkSpace();
void SaveWorkSpace();
+ void AddWaveFile();
+ void AddSurfaceFile();
+ void AddTableFile();
+ void AddLightFile();
+
private:
Ui::FileManagerMenu* ui;
};
\ No newline at end of file
diff --git a/src/ui/Menu/FileManagerMenu.ui b/src/ui/Menu/FileManagerMenu.ui
index d356a9e2..0aa0b80b 100644
--- a/src/ui/Menu/FileManagerMenu.ui
+++ b/src/ui/Menu/FileManagerMenu.ui
@@ -54,6 +54,46 @@
+ -
+
+
+ new wave file
+
+
+
+
+
+
+ -
+
+
+ new surface file
+
+
+
+
+
+
+ -
+
+
+ new table file
+
+
+
+
+
+
+ -
+
+
+ new light file
+
+
+
+
+
+
-
diff --git a/src/ui/PropertyBrowser.cpp b/src/ui/PropertyBrowser.cpp
index db566930..2c53dbd0 100644
--- a/src/ui/PropertyBrowser.cpp
+++ b/src/ui/PropertyBrowser.cpp
@@ -56,6 +56,14 @@ void PropertyBrowser::OnWorkSpaceChange(const QVariant& value) {
QWorkspaceAttribute worksapceAttribute(workspace);
workSpaceManager_->setValue(property, worksapceAttribute);
addProperty(property, tr("WorkSpace"));
+
+ // Track and react to runtime workspace changes
+ if (currentWorkspace_) {
+ QObject::disconnect(currentWorkspace_, nullptr, this, nullptr);
+ }
+ currentWorkspace_ = workspace;
+ QObject::connect(currentWorkspace_, &WorkSpace::FilesChanged,
+ this, &PropertyBrowser::OnWorkspaceFilesChanged);
}
void PropertyBrowser::OnEntityChange(const QVariant& value) {
@@ -152,6 +160,8 @@ void PropertyBrowser::InitPropertyManager() {
browser_->setFactoryForManager(sizeManager_->subIntPropertyManager(), spinBoxFactory);
browser_->setFactoryForManager(workSpaceManager_->subStringProperyManager(), lineEditFactory);
browser_->setFactoryForManager(workSpaceManager_->subFilesProperyManager(), filePathFactory);
+ // Enable editing for grouped file entry counts
+ browser_->setFactoryForManager(workSpaceManager_->subIntProperyManager(), spinBoxFactory);
browser_->setFactoryForManager(entityManager_->subStringProperyManager(), lineEditFactory);
browser_->setFactoryForManager(entityManager_->subBoolProperyManager(), checkBoxFactory);
browser_->setFactoryForManager(
@@ -165,6 +175,16 @@ void PropertyBrowser::InitPropertyManager() {
doubleSpinBoxFactory);
}
+void PropertyBrowser::OnWorkspaceFilesChanged(FileEntryType /*type*/) {
+ if (!currentWorkspace_) return;
+ auto it = idToProperty_.find(tr("WorkSpace"));
+ if (it == idToProperty_.end()) return;
+ QtProperty* property = it.value();
+ QWorkspaceAttribute worksapceAttribute(currentWorkspace_);
+ // Refresh the full workspace property tree to reflect new counts/paths
+ workSpaceManager_->setValue(property, worksapceAttribute);
+}
+
void PropertyBrowser::InitComponentPropertyManager() {
QtDoubleSpinBoxFactory* doubleSpinBoxFactory = new QtDoubleSpinBoxFactory(this);
QtCheckBoxFactory* checkBoxFactory = new QtCheckBoxFactory(this);
diff --git a/src/ui/PropertyBrowser.h b/src/ui/PropertyBrowser.h
index 770529c2..9effc06c 100644
--- a/src/ui/PropertyBrowser.h
+++ b/src/ui/PropertyBrowser.h
@@ -2,6 +2,7 @@
#include
#include
+#include "workspace/FileEntry.h"
class QtProperty;
@@ -17,6 +18,7 @@ public:
void OnWorkSpaceChange(const QVariant& value);
void OnEntityChange(const QVariant& value);
+ void OnWorkspaceFilesChanged(enum class FileEntryType type);
void Test();
@@ -49,5 +51,8 @@ private:
QMap idToExpanded_;
QMap componetManager_;
+
+ // Track current workspace for real-time refresh
+ class WorkSpace* currentWorkspace_{ nullptr };
};
diff --git a/src/ui/PropertyBrowser/qtpropertymanager.cpp b/src/ui/PropertyBrowser/qtpropertymanager.cpp
index 7c6ca7cf..0de1686e 100644
--- a/src/ui/PropertyBrowser/qtpropertymanager.cpp
+++ b/src/ui/PropertyBrowser/qtpropertymanager.cpp
@@ -42,6 +42,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -7893,35 +7894,84 @@ void QtModelBasePropertyManager::uninitializeProperty(QtProperty* property) {
#pragma region QtWorkspacePropertyManager
class QtWorkspacePropertyManagerPrivate {
- QtWorkspacePropertyManager* q_ptr;
- Q_DECLARE_PUBLIC(QtWorkspacePropertyManager)
+ QtWorkspacePropertyManager* q_ptr;
+ Q_DECLARE_PUBLIC(QtWorkspacePropertyManager)
public:
- void slotStringChanged(QtProperty* property, QString value);
+ void slotStringChanged(QtProperty* property, QString value);
+ void slotIntChanged(QtProperty* property, int value);
- void slotPropertyDestroyed(QtProperty* property);
+ void slotPropertyDestroyed(QtProperty* property);
- typedef QMap PropertyValueMap;
- PropertyValueMap m_values;
+ typedef QMap PropertyValueMap;
+ PropertyValueMap m_values;
- QtStringPropertyManager* m_stringProperyManager;
- QtFilesPropertyManager* m_filesProperyManager;
+ QtStringPropertyManager* m_stringProperyManager;
+ QtFilesPropertyManager* m_filesProperyManager;
+ QtIntPropertyManager* m_intProperyManager{ nullptr };
+ QtGroupPropertyManager* m_groupProperyManager{ nullptr };
- QMap m_properyToName;
- QMap m_properyToDescription;
- QMap m_properyToTimestep;
+ QMap m_properyToName;
+ QMap m_properyToDescription;
+ QMap m_properyToTimestep;
+ QMap m_properyToSimMatlab;
+ QMap m_properyToMatlabParam;
+ QMap m_properyToWavePath;
+ QMap m_properyToReportPath;
+ QMap m_properyToRDPath;
- QMap m_nameToPropery;
- QMap m_descriptionToPropery;
- QMap m_timestepToPropery;
+ QMap m_nameToPropery;
+ QMap m_descriptionToPropery;
+ QMap m_timestepToPropery;
+ QMap m_simMatlabToPropery;
+ QMap m_matlabParamToPropery;
+ QMap m_wavePathToPropery;
+ QMap m_reportPathToPropery;
+ QMap m_rdPathToPropery;
+
+ // Grouped file entries: Curve
+ QMap m_properyToCurveGroup;
+ QMap m_curveGroupToPropery;
+ QMap m_properyToCurveCount;
+ QMap m_curveCountToPropery;
+ QMap> m_properyToCurvePaths;
+ QMap m_curvePathToPropery;
+ QMap m_curvePathIndex;
+
+ // Surface
+ QMap m_properyToSurfaceGroup;
+ QMap m_surfaceGroupToPropery;
+ QMap m_properyToSurfaceCount;
+ QMap m_surfaceCountToPropery;
+ QMap> m_properyToSurfacePaths;
+ QMap m_surfacePathToPropery;
+ QMap m_surfacePathIndex;
+
+ // Table
+ QMap m_properyToTableGroup;
+ QMap m_tableGroupToPropery;
+ QMap m_properyToTableCount;
+ QMap m_tableCountToPropery;
+ QMap> m_properyToTablePaths;
+ QMap m_tablePathToPropery;
+ QMap m_tablePathIndex;
+
+ // Light
+ QMap m_properyToLightGroup;
+ QMap m_lightGroupToPropery;
+ QMap m_properyToLightCount;
+ QMap m_lightCountToPropery;
+ QMap> m_properyToLightPaths;
+ QMap m_lightPathToPropery;
+ QMap m_lightPathIndex;
};
void QtWorkspacePropertyManagerPrivate::slotStringChanged(QtProperty* property, QString value) {
- if (QtProperty* prop = m_nameToPropery.value(property, 0)) {
- QWorkspaceAttribute c = m_values[prop];
- c.SetName(value);
- q_ptr->setValue(prop, c);
+ if (QtProperty* prop = m_nameToPropery.value(property, 0)) {
+ QWorkspaceAttribute c = m_values[prop];
+ c.SetName(value);
+ q_ptr->setValue(prop, c);
} else if (QtProperty* prop = m_descriptionToPropery.value(property, 0)) {
QWorkspaceAttribute c = m_values[prop];
c.SetDescription(value);
@@ -7930,9 +7980,102 @@ void QtWorkspacePropertyManagerPrivate::slotStringChanged(QtProperty* property,
QWorkspaceAttribute c = m_values[prop];
c.SetTimeStep(value);
q_ptr->setValue(prop, c);
+ } else if (QtProperty* prop = m_simMatlabToPropery.value(property, 0)) {
+ QWorkspaceAttribute c = m_values[prop];
+ c.SetSimMatlab(value);
+ q_ptr->setValue(prop, c);
+ } else if (QtProperty* prop = m_matlabParamToPropery.value(property, 0)) {
+ QWorkspaceAttribute c = m_values[prop];
+ c.SetMatlabParam(value);
+ q_ptr->setValue(prop, c);
+ } else if (QtProperty* prop = m_wavePathToPropery.value(property, 0)) {
+ QWorkspaceAttribute c = m_values[prop];
+ c.SetWavePath(value);
+ q_ptr->setValue(prop, c);
+ } else if (QtProperty* prop = m_reportPathToPropery.value(property, 0)) {
+ QWorkspaceAttribute c = m_values[prop];
+ c.SetReportPath(value);
+ q_ptr->setValue(prop, c);
+ } else if (QtProperty* prop = m_rdPathToPropery.value(property, 0)) {
+ QWorkspaceAttribute c = m_values[prop];
+ c.SetRDPath(value);
+ q_ptr->setValue(prop, c);
+ } else if (QtProperty* prop = m_curvePathToPropery.value(property, 0)) {
+ QWorkspaceAttribute c = m_values[prop];
+ int idx = m_curvePathIndex.value(property, 0);
+ c.SetFileEntryPath(FileEntryType::Curve, idx, value);
+ q_ptr->setValue(prop, c);
+ } else if (QtProperty* prop = m_surfacePathToPropery.value(property, 0)) {
+ QWorkspaceAttribute c = m_values[prop];
+ int idx = m_surfacePathIndex.value(property, 0);
+ c.SetFileEntryPath(FileEntryType::Surface, idx, value);
+ q_ptr->setValue(prop, c);
+ } else if (QtProperty* prop = m_tablePathToPropery.value(property, 0)) {
+ QWorkspaceAttribute c = m_values[prop];
+ int idx = m_tablePathIndex.value(property, 0);
+ c.SetFileEntryPath(FileEntryType::Table, idx, value);
+ q_ptr->setValue(prop, c);
+ } else if (QtProperty* prop = m_lightPathToPropery.value(property, 0)) {
+ QWorkspaceAttribute c = m_values[prop];
+ int idx = m_lightPathIndex.value(property, 0);
+ c.SetFileEntryPath(FileEntryType::Light, idx, value);
+ q_ptr->setValue(prop, c);
}
}
+void QtWorkspacePropertyManagerPrivate::slotIntChanged(QtProperty* property, int value) {
+ // Determine which type this count property belongs to
+ auto handleType = [&](FileEntryType type,
+ QMap& countToProp,
+ QMap>& propToPaths,
+ QMap& pathToProp,
+ QMap& pathIndex,
+ QMap& propToGroup) {
+ if (QtProperty* root = countToProp.value(property, nullptr)) {
+ // Adjust UI path properties to match new count
+ QVector& paths = propToPaths[root];
+ int current = paths.size();
+ // Add new path properties
+ if (value > current) {
+ QtProperty* group = propToGroup.value(root, nullptr);
+ for (int i = current; i < value; ++i) {
+ QtProperty* p = m_filesProperyManager->addProperty();
+ QString title;
+ switch (type) {
+ case FileEntryType::Curve: title = QObject::tr("Curve[%1]").arg(i + 1); break;
+ case FileEntryType::Surface: title = QObject::tr("Surface[%1]").arg(i + 1); break;
+ case FileEntryType::Table: title = QObject::tr("Table[%1]").arg(i + 1); break;
+ case FileEntryType::Light: title = QObject::tr("Light[%1]").arg(i + 1); break;
+ }
+ p->setPropertyName(title);
+ group->addSubProperty(p);
+ paths.append(p);
+ pathToProp[p] = root;
+ pathIndex[p] = i;
+ }
+ } else if (value < current) {
+ // Remove excess path properties
+ for (int i = current - 1; i >= value; --i) {
+ QtProperty* p = paths.at(i);
+ pathIndex.remove(p);
+ pathToProp.remove(p);
+ paths.remove(i);
+ delete p;
+ }
+ }
+ // Update underlying model count
+ QWorkspaceAttribute c = m_values[root];
+ c.SetFileEntryCount(type, value);
+ q_ptr->setValue(root, c);
+ }
+ };
+
+ handleType(FileEntryType::Curve, m_curveCountToPropery, m_properyToCurvePaths, m_curvePathToPropery, m_curvePathIndex, m_properyToCurveGroup);
+ handleType(FileEntryType::Surface, m_surfaceCountToPropery, m_properyToSurfacePaths, m_surfacePathToPropery, m_surfacePathIndex, m_properyToSurfaceGroup);
+ handleType(FileEntryType::Table, m_tableCountToPropery, m_properyToTablePaths, m_tablePathToPropery, m_tablePathIndex, m_properyToTableGroup);
+ handleType(FileEntryType::Light, m_lightCountToPropery, m_properyToLightPaths, m_lightPathToPropery, m_lightPathIndex, m_properyToLightGroup);
+}
+
void QtWorkspacePropertyManagerPrivate::slotPropertyDestroyed(QtProperty* property) {
if (QtProperty* subProp = m_nameToPropery.value(property, nullptr)) {
m_nameToPropery[subProp] = 0;
@@ -7943,23 +8086,48 @@ void QtWorkspacePropertyManagerPrivate::slotPropertyDestroyed(QtProperty* proper
m_descriptionToPropery[subProp] = 0;
m_descriptionToPropery.remove(property);
}
-
- if (QtProperty* subProp = m_timestepToPropery.value(property, nullptr)) {
- m_timestepToPropery[subProp] = 0;
- m_timestepToPropery.remove(property);
- }
+
+ if (QtProperty* subProp = m_timestepToPropery.value(property, nullptr)) {
+ m_timestepToPropery[subProp] = 0;
+ m_timestepToPropery.remove(property);
+ }
+
+ if (QtProperty* subProp = m_simMatlabToPropery.value(property, nullptr)) {
+ m_simMatlabToPropery[subProp] = 0;
+ m_simMatlabToPropery.remove(property);
+ }
+ if (QtProperty* subProp = m_matlabParamToPropery.value(property, nullptr)) {
+ m_matlabParamToPropery[subProp] = 0;
+ m_matlabParamToPropery.remove(property);
+ }
+ if (QtProperty* subProp = m_wavePathToPropery.value(property, nullptr)) {
+ m_wavePathToPropery[subProp] = 0;
+ m_wavePathToPropery.remove(property);
+ }
+ if (QtProperty* subProp = m_reportPathToPropery.value(property, nullptr)) {
+ m_reportPathToPropery[subProp] = 0;
+ m_reportPathToPropery.remove(property);
+ }
+ if (QtProperty* subProp = m_rdPathToPropery.value(property, nullptr)) {
+ m_rdPathToPropery[subProp] = 0;
+ m_rdPathToPropery.remove(property);
+ }
}
QtWorkspacePropertyManager::QtWorkspacePropertyManager(QObject* parent)
- : QtAbstractPropertyManager(parent), d_ptr(new QtWorkspacePropertyManagerPrivate) {
- d_ptr->q_ptr = this;
+ : QtAbstractPropertyManager(parent), d_ptr(new QtWorkspacePropertyManagerPrivate) {
+ d_ptr->q_ptr = this;
- d_ptr->m_stringProperyManager = new QtStringPropertyManager(this);
- connect(d_ptr->m_stringProperyManager, SIGNAL(valueChanged(QtProperty*, QString)),
- this, SLOT(slotStringChanged(QtProperty*, QString)));
+ d_ptr->m_stringProperyManager = new QtStringPropertyManager(this);
+ connect(d_ptr->m_stringProperyManager, SIGNAL(valueChanged(QtProperty*, QString)),
+ this, SLOT(slotStringChanged(QtProperty*, QString)));
d_ptr->m_filesProperyManager = new QtFilesPropertyManager(this);
connect(d_ptr->m_filesProperyManager, SIGNAL(valueChanged(QtProperty*, QString)),
this, SLOT(slotStringChanged(QtProperty*, QString)));
+ d_ptr->m_intProperyManager = new QtIntPropertyManager(this);
+ connect(d_ptr->m_intProperyManager, SIGNAL(valueChanged(QtProperty*, int)),
+ this, SLOT(slotIntChanged(QtProperty*, int)));
+ d_ptr->m_groupProperyManager = new QtGroupPropertyManager(this);
}
/*!
@@ -7982,11 +8150,19 @@ QWorkspaceAttribute QtWorkspacePropertyManager::value(const QtProperty* property
}
QtStringPropertyManager* QtWorkspacePropertyManager::subStringProperyManager() const {
- return d_ptr->m_stringProperyManager;
+ return d_ptr->m_stringProperyManager;
}
QtFilesPropertyManager* QtWorkspacePropertyManager::subFilesProperyManager() const {
- return d_ptr->m_filesProperyManager;
+ return d_ptr->m_filesProperyManager;
+}
+
+QtIntPropertyManager* QtWorkspacePropertyManager::subIntProperyManager() const {
+ return d_ptr->m_intProperyManager;
+}
+
+QtGroupPropertyManager* QtWorkspacePropertyManager::subGroupProperyManager() const {
+ return d_ptr->m_groupProperyManager;
}
/*!
@@ -8019,30 +8195,88 @@ QIcon QtWorkspacePropertyManager::valueIcon(const QtProperty* property) const {
\sa value(), valueChanged()
*/
void QtWorkspacePropertyManager::setValue(QtProperty* property, const QWorkspaceAttribute& value) {
- const QtWorkspacePropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property);
- if (it == d_ptr->m_values.end())
- return;
+ const QtWorkspacePropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property);
+ if (it == d_ptr->m_values.end())
+ return;
- if (it.value() == value)
- return;
+ if (it.value() == value)
+ return;
- it.value() = value;
+ it.value() = value;
- d_ptr->m_stringProperyManager->setValue(d_ptr->m_properyToName[property], value.GetName());
- d_ptr->m_stringProperyManager->setValue(d_ptr->m_properyToDescription[property], value.GetDescription());
- d_ptr->m_filesProperyManager->setValue(d_ptr->m_properyToTimestep[property], value.GetTimeStep());
+ d_ptr->m_stringProperyManager->setValue(d_ptr->m_properyToName[property], value.GetName());
+ d_ptr->m_stringProperyManager->setValue(d_ptr->m_properyToDescription[property], value.GetDescription());
+ d_ptr->m_filesProperyManager->setValue(d_ptr->m_properyToTimestep[property], value.GetTimeStep());
+ d_ptr->m_filesProperyManager->setValue(d_ptr->m_properyToSimMatlab[property], value.GetSimMatlab());
+ d_ptr->m_filesProperyManager->setValue(d_ptr->m_properyToMatlabParam[property], value.GetMatlabParam());
+ d_ptr->m_filesProperyManager->setValue(d_ptr->m_properyToWavePath[property], value.GetWavePath());
+ d_ptr->m_filesProperyManager->setValue(d_ptr->m_properyToReportPath[property], value.GetReportPath());
+ d_ptr->m_filesProperyManager->setValue(d_ptr->m_properyToRDPath[property], value.GetRDPath());
- emit propertyChanged(property);
- emit valueChanged(property, value);
+ auto syncGroup = [&](FileEntryType type,
+ QMap& propToGroup,
+ QMap& propToCount,
+ QMap>& propToPaths,
+ QMap& pathToProp,
+ QMap& pathIndex) {
+ QtProperty* group = propToGroup.value(property, nullptr);
+ if (!group) return;
+ auto entries = value.GetFileEntries(type);
+ int count = static_cast(entries.size());
+ // update count without triggering slot
+ QtProperty* countProp = propToCount.value(property, nullptr);
+ if (countProp) d_ptr->m_intProperyManager->setValueOnly(countProp, count);
+ QVector& paths = propToPaths[property];
+ int current = paths.size();
+ // expand
+ if (count > current) {
+ for (int i = current; i < count; ++i) {
+ QtProperty* p = d_ptr->m_filesProperyManager->addProperty();
+ QString title;
+ switch (type) {
+ case FileEntryType::Curve: title = QObject::tr("Curve[%1]").arg(i + 1); break;
+ case FileEntryType::Surface: title = QObject::tr("Surface[%1]").arg(i + 1); break;
+ case FileEntryType::Table: title = QObject::tr("Table[%1]").arg(i + 1); break;
+ case FileEntryType::Light: title = QObject::tr("Light[%1]").arg(i + 1); break;
+ }
+ p->setPropertyName(title);
+ group->addSubProperty(p);
+ paths.append(p);
+ pathToProp[p] = property;
+ pathIndex[p] = i;
+ }
+ } else if (count < current) {
+ for (int i = current - 1; i >= count; --i) {
+ QtProperty* p = paths.at(i);
+ pathIndex.remove(p);
+ pathToProp.remove(p);
+ paths.remove(i);
+ delete p;
+ }
+ }
+ // set values
+ for (int i = 0; i < count; ++i) {
+ const QString absPath = value.GetFileEntryAbsPath(type, i);
+ d_ptr->m_filesProperyManager->setValueOnly(paths.at(i), absPath);
+ }
+ };
+
+ syncGroup(FileEntryType::Curve, d_ptr->m_properyToCurveGroup, d_ptr->m_properyToCurveCount, d_ptr->m_properyToCurvePaths, d_ptr->m_curvePathToPropery, d_ptr->m_curvePathIndex);
+ syncGroup(FileEntryType::Surface, d_ptr->m_properyToSurfaceGroup, d_ptr->m_properyToSurfaceCount, d_ptr->m_properyToSurfacePaths, d_ptr->m_surfacePathToPropery, d_ptr->m_surfacePathIndex);
+ syncGroup(FileEntryType::Table, d_ptr->m_properyToTableGroup, d_ptr->m_properyToTableCount, d_ptr->m_properyToTablePaths, d_ptr->m_tablePathToPropery, d_ptr->m_tablePathIndex);
+ syncGroup(FileEntryType::Light, d_ptr->m_properyToLightGroup, d_ptr->m_properyToLightCount, d_ptr->m_properyToLightPaths, d_ptr->m_lightPathToPropery, d_ptr->m_lightPathIndex);
+
+ emit propertyChanged(property);
+ emit valueChanged(property, value);
}
/*!
\reimp
*/
void QtWorkspacePropertyManager::initializeProperty(QtProperty* property) {
- QWorkspaceAttribute val;
- d_ptr->m_values[property] = val;
+ QWorkspaceAttribute val;
+ d_ptr->m_values[property] = val;
QtProperty* prop = d_ptr->m_stringProperyManager->addProperty();
prop->setPropertyName(tr("Name"));
@@ -8064,18 +8298,113 @@ void QtWorkspacePropertyManager::initializeProperty(QtProperty* property) {
d_ptr->m_properyToTimestep[property] = prop;
d_ptr->m_timestepToPropery[prop] = property;
property->addSubProperty(prop);
+
+ prop = d_ptr->m_filesProperyManager->addProperty();
+ prop->setPropertyName(tr("SimMatlab"));
+ d_ptr->m_filesProperyManager->setValueOnly(prop, val.GetSimMatlab());
+ d_ptr->m_properyToSimMatlab[property] = prop;
+ d_ptr->m_simMatlabToPropery[prop] = property;
+ property->addSubProperty(prop);
+
+ prop = d_ptr->m_filesProperyManager->addProperty();
+ prop->setPropertyName(tr("MatlabParam"));
+ d_ptr->m_filesProperyManager->setValueOnly(prop, val.GetMatlabParam());
+ d_ptr->m_properyToMatlabParam[property] = prop;
+ d_ptr->m_matlabParamToPropery[prop] = property;
+ property->addSubProperty(prop);
+
+ prop = d_ptr->m_filesProperyManager->addProperty();
+ prop->setPropertyName(tr("WavePath"));
+ d_ptr->m_filesProperyManager->setValueOnly(prop, val.GetWavePath());
+ d_ptr->m_properyToWavePath[property] = prop;
+ d_ptr->m_wavePathToPropery[prop] = property;
+ property->addSubProperty(prop);
+
+ prop = d_ptr->m_filesProperyManager->addProperty();
+ prop->setPropertyName(tr("ReportPath"));
+ d_ptr->m_filesProperyManager->setValueOnly(prop, val.GetReportPath());
+ d_ptr->m_properyToReportPath[property] = prop;
+ d_ptr->m_reportPathToPropery[prop] = property;
+ property->addSubProperty(prop);
+
+ prop = d_ptr->m_filesProperyManager->addProperty();
+ prop->setPropertyName(tr("RDPath"));
+ d_ptr->m_filesProperyManager->setValueOnly(prop, val.GetRDPath());
+ d_ptr->m_properyToRDPath[property] = prop;
+ d_ptr->m_rdPathToPropery[prop] = property;
+ property->addSubProperty(prop);
+
+ // Add grouped file sections
+ auto addGroup = [&](FileEntryType type, const QString& groupName,
+ QMap& propToGroup,
+ QMap& groupToProp,
+ QMap& propToCount,
+ QMap& countToProp,
+ QMap>& propToPaths,
+ QMap& pathToProp,
+ QMap& pathIndex) {
+ QtProperty* group = d_ptr->m_groupProperyManager->addProperty();
+ group->setPropertyName(groupName);
+ property->addSubProperty(group);
+ propToGroup[property] = group;
+ groupToProp[group] = property;
+
+ // Count property
+ QtProperty* countProp = d_ptr->m_intProperyManager->addProperty();
+ countProp->setPropertyName(tr("Count"));
+ d_ptr->m_intProperyManager->setRange(countProp, 0, 1024);
+ // initial count from workspace
+ int initialCount = static_cast(val.GetFileEntries(type).size());
+ d_ptr->m_intProperyManager->setValueOnly(countProp, initialCount);
+ propToCount[property] = countProp;
+ countToProp[countProp] = property;
+ group->addSubProperty(countProp);
+
+ // initial paths
+ auto entries = val.GetFileEntries(type);
+ QVector& paths = propToPaths[property];
+ for (int i = 0; i < static_cast(entries.size()); ++i) {
+ QtProperty* p = d_ptr->m_filesProperyManager->addProperty();
+ QString title;
+ switch (type) {
+ case FileEntryType::Curve: title = tr("Curve[%1]").arg(i + 1); break;
+ case FileEntryType::Surface: title = tr("Surface[%1]").arg(i + 1); break;
+ case FileEntryType::Table: title = tr("Table[%1]").arg(i + 1); break;
+ case FileEntryType::Light: title = tr("Light[%1]").arg(i + 1); break;
+ }
+ p->setPropertyName(title);
+ d_ptr->m_filesProperyManager->setValueOnly(p, val.GetFileEntryAbsPath(type, i));
+ group->addSubProperty(p);
+ paths.append(p);
+ pathToProp[p] = property;
+ pathIndex[p] = i;
+ }
+ };
+
+ addGroup(FileEntryType::Curve, tr("Curves"), d_ptr->m_properyToCurveGroup, d_ptr->m_curveGroupToPropery,
+ d_ptr->m_properyToCurveCount, d_ptr->m_curveCountToPropery,
+ d_ptr->m_properyToCurvePaths, d_ptr->m_curvePathToPropery, d_ptr->m_curvePathIndex);
+ addGroup(FileEntryType::Surface, tr("Surfaces"), d_ptr->m_properyToSurfaceGroup, d_ptr->m_surfaceGroupToPropery,
+ d_ptr->m_properyToSurfaceCount, d_ptr->m_surfaceCountToPropery,
+ d_ptr->m_properyToSurfacePaths, d_ptr->m_surfacePathToPropery, d_ptr->m_surfacePathIndex);
+ addGroup(FileEntryType::Table, tr("Tables"), d_ptr->m_properyToTableGroup, d_ptr->m_tableGroupToPropery,
+ d_ptr->m_properyToTableCount, d_ptr->m_tableCountToPropery,
+ d_ptr->m_properyToTablePaths, d_ptr->m_tablePathToPropery, d_ptr->m_tablePathIndex);
+ addGroup(FileEntryType::Light, tr("Lights"), d_ptr->m_properyToLightGroup, d_ptr->m_lightGroupToPropery,
+ d_ptr->m_properyToLightCount, d_ptr->m_lightCountToPropery,
+ d_ptr->m_properyToLightPaths, d_ptr->m_lightPathToPropery, d_ptr->m_lightPathIndex);
}
/*!
\reimp
*/
void QtWorkspacePropertyManager::uninitializeProperty(QtProperty* property) {
- QtProperty* prop = d_ptr->m_nameToPropery[property];
- if (prop) {
- d_ptr->m_nameToPropery.remove(prop);
- delete prop;
- }
- d_ptr->m_properyToName.remove(property);
+ QtProperty* prop = d_ptr->m_nameToPropery[property];
+ if (prop) {
+ d_ptr->m_nameToPropery.remove(prop);
+ delete prop;
+ }
+ d_ptr->m_properyToName.remove(property);
prop = d_ptr->m_descriptionToPropery[property];
if (prop) {
@@ -8090,6 +8419,84 @@ void QtWorkspacePropertyManager::uninitializeProperty(QtProperty* property) {
delete prop;
}
d_ptr->m_properyToTimestep.remove(property);
+
+ prop = d_ptr->m_simMatlabToPropery[property];
+ if (prop) {
+ d_ptr->m_simMatlabToPropery.remove(prop);
+ delete prop;
+ }
+ d_ptr->m_properyToSimMatlab.remove(property);
+
+ prop = d_ptr->m_matlabParamToPropery[property];
+ if (prop) {
+ d_ptr->m_matlabParamToPropery.remove(prop);
+ delete prop;
+ }
+ d_ptr->m_properyToMatlabParam.remove(property);
+
+ prop = d_ptr->m_wavePathToPropery[property];
+ if (prop) {
+ d_ptr->m_wavePathToPropery.remove(prop);
+ delete prop;
+ }
+ d_ptr->m_properyToWavePath.remove(property);
+
+ prop = d_ptr->m_reportPathToPropery[property];
+ if (prop) {
+ d_ptr->m_reportPathToPropery.remove(prop);
+ delete prop;
+ }
+ d_ptr->m_properyToReportPath.remove(property);
+
+ prop = d_ptr->m_rdPathToPropery[property];
+ if (prop) {
+ d_ptr->m_rdPathToPropery.remove(prop);
+ delete prop;
+ }
+ d_ptr->m_properyToRDPath.remove(property);
+
+ // Cleanup grouped file properties
+ auto cleanupGroup = [&](QMap& propToGroup,
+ QMap& groupToProp,
+ QMap& propToCount,
+ QMap& countToProp,
+ QMap>& propToPaths,
+ QMap& pathToProp,
+ QMap& pathIndex) {
+ QtProperty* group = propToGroup.value(property, nullptr);
+ if (group) {
+ propToGroup.remove(property);
+ groupToProp.remove(group);
+ }
+ QtProperty* countProp = propToCount.value(property, nullptr);
+ if (countProp) {
+ countToProp.remove(countProp);
+ propToCount.remove(property);
+ delete countProp;
+ }
+ QVector& paths = propToPaths[property];
+ for (QtProperty* p : paths) {
+ pathIndex.remove(p);
+ pathToProp.remove(p);
+ delete p;
+ }
+ paths.clear();
+ propToPaths.remove(property);
+ if (group) delete group;
+ };
+
+ cleanupGroup(d_ptr->m_properyToCurveGroup, d_ptr->m_curveGroupToPropery,
+ d_ptr->m_properyToCurveCount, d_ptr->m_curveCountToPropery,
+ d_ptr->m_properyToCurvePaths, d_ptr->m_curvePathToPropery, d_ptr->m_curvePathIndex);
+ cleanupGroup(d_ptr->m_properyToSurfaceGroup, d_ptr->m_surfaceGroupToPropery,
+ d_ptr->m_properyToSurfaceCount, d_ptr->m_surfaceCountToPropery,
+ d_ptr->m_properyToSurfacePaths, d_ptr->m_surfacePathToPropery, d_ptr->m_surfacePathIndex);
+ cleanupGroup(d_ptr->m_properyToTableGroup, d_ptr->m_tableGroupToPropery,
+ d_ptr->m_properyToTableCount, d_ptr->m_tableCountToPropery,
+ d_ptr->m_properyToTablePaths, d_ptr->m_tablePathToPropery, d_ptr->m_tablePathIndex);
+ cleanupGroup(d_ptr->m_properyToLightGroup, d_ptr->m_lightGroupToPropery,
+ d_ptr->m_properyToLightCount, d_ptr->m_lightCountToPropery,
+ d_ptr->m_properyToLightPaths, d_ptr->m_lightPathToPropery, d_ptr->m_lightPathIndex);
}
#pragma endregion
diff --git a/src/ui/PropertyBrowser/qtpropertymanager.h b/src/ui/PropertyBrowser/qtpropertymanager.h
index 1c9edfee..c1fabc4e 100644
--- a/src/ui/PropertyBrowser/qtpropertymanager.h
+++ b/src/ui/PropertyBrowser/qtpropertymanager.h
@@ -1027,6 +1027,8 @@ public:
QtStringPropertyManager* subStringProperyManager() const;
QtFilesPropertyManager* subFilesProperyManager() const;
+ QtIntPropertyManager* subIntProperyManager() const;
+ QtGroupPropertyManager* subGroupProperyManager() const;
public Q_SLOTS:
void setValue(QtProperty* property, const QWorkspaceAttribute& val);
@@ -1042,6 +1044,7 @@ private:
Q_DECLARE_PRIVATE(QtWorkspacePropertyManager)
Q_DISABLE_COPY_MOVE(QtWorkspacePropertyManager)
Q_PRIVATE_SLOT(d_func(), void slotStringChanged(QtProperty*, QString))
+ Q_PRIVATE_SLOT(d_func(), void slotIntChanged(QtProperty*, int))
};
#pragma endregion
diff --git a/src/ui/PropertyBrowser/qtworkspaceattribute.cpp b/src/ui/PropertyBrowser/qtworkspaceattribute.cpp
index 1b1ddc29..d4b7f89f 100644
--- a/src/ui/PropertyBrowser/qtworkspaceattribute.cpp
+++ b/src/ui/PropertyBrowser/qtworkspaceattribute.cpp
@@ -14,15 +14,18 @@
QWorkspaceAttribute::QWorkspaceAttribute(class WorkSpace* workspace)
: workspace_(workspace) {
-
+ if (workspace_) {
+ filesSeq_ = workspace_->GetFilesSeq();
+ }
}
bool QWorkspaceAttribute::operator==(const QWorkspaceAttribute& other) {
- return workspace_ == other.workspace_;
+ return workspace_ == other.workspace_ && filesSeq_ == other.filesSeq_;
}
QWorkspaceAttribute& QWorkspaceAttribute::operator=(const QWorkspaceAttribute& other) {
workspace_ = other.workspace_;
+ filesSeq_ = other.filesSeq_;
return *this;
}
@@ -163,7 +166,7 @@ void QWorkspaceAttribute::SetRDPath(const QString& path)
workspace_->SetRDPath(path);
}
-const QString QWorkspaceAttribute::GetRDPath() const
+const QString QWorkspaceAttribute::GetRDPath() const
{
if (nullptr == workspace_) {
return "";
@@ -171,6 +174,34 @@ const QString QWorkspaceAttribute::GetRDPath() const
return workspace_->GetRDPath();
}
+std::vector QWorkspaceAttribute::GetFileEntries(FileEntryType type) const {
+ if (nullptr == workspace_) {
+ return {};
+ }
+ return workspace_->GetFileEntries(type);
+}
+
+void QWorkspaceAttribute::SetFileEntryCount(FileEntryType type, int count) {
+ if (nullptr == workspace_) {
+ return;
+ }
+ workspace_->SetFileEntryCount(type, count);
+}
+
+void QWorkspaceAttribute::SetFileEntryPath(FileEntryType type, int index, const QString& path) {
+ if (nullptr == workspace_) {
+ return;
+ }
+ workspace_->SetFileEntryPath(type, index, path);
+}
+
+QString QWorkspaceAttribute::GetFileEntryAbsPath(FileEntryType type, int index) const {
+ if (nullptr == workspace_) {
+ return QString();
+ }
+ return workspace_->GetFileEntryAbsPath(type, index);
+}
+
QTransformAttribute::QTransformAttribute(class Transform* obj)
: object_(obj) {
diff --git a/src/ui/PropertyBrowser/qtworkspaceattribute.h b/src/ui/PropertyBrowser/qtworkspaceattribute.h
index 7cd45748..397a3ccc 100644
--- a/src/ui/PropertyBrowser/qtworkspaceattribute.h
+++ b/src/ui/PropertyBrowser/qtworkspaceattribute.h
@@ -43,6 +43,9 @@
#include
#include
#include
+#include "workspace/FileEntry.h"
+#include
+#include
class QWorkspaceAttribute {
public:
@@ -76,8 +79,16 @@ public:
void SetRDPath(const QString& path);
const QString GetRDPath() const;
+
+ // Grouped files API
+ std::vector GetFileEntries(FileEntryType type) const;
+ void SetFileEntryCount(FileEntryType type, int count);
+ void SetFileEntryPath(FileEntryType type, int index, const QString& path);
+ QString GetFileEntryAbsPath(FileEntryType type, int index) const;
private:
class WorkSpace* workspace_{ nullptr };
+ // Snapshot of workspace files change sequence to detect mutations
+ std::uint64_t filesSeq_{ 0 };
};
diff --git a/src/ui/WorkSpace/WorkSpaceDlg.cpp b/src/ui/WorkSpace/WorkSpaceDlg.cpp
index 4918bb9e..1460c7e2 100644
--- a/src/ui/WorkSpace/WorkSpaceDlg.cpp
+++ b/src/ui/WorkSpace/WorkSpaceDlg.cpp
@@ -33,6 +33,7 @@ void WorkSpaceDlg::InitConnect() {
connect(ui->pbSure, &QPushButton::clicked, this, &WorkSpaceDlg::OnSure);
connect(ui->pbCancel, &QPushButton::clicked, this, &WorkSpaceDlg::reject);
connect(ui->tbPath, &QPushButton::clicked, this, &WorkSpaceDlg::OnSelectSavePath);
+ connect(ui->tbCommondPath, &QPushButton::clicked, this, &WorkSpaceDlg::OnSelectCommondPath);
connect(ui->leName, &QLineEdit::textChanged, [this](const QString& txt) {
QString path = QString("%1/%2").arg(path_).arg(txt);
ui->lePath->setText(path);
@@ -93,6 +94,9 @@ void WorkSpaceDlg::OnSure() {
workspacePath += QString("/%1.dyt").arg(name);
WorkSpace* workSpace = WorkSpaceManager::Get().GetOrCreate(workspacePath, name);
workSpace->SetDescribe(ui->etDescribe->toPlainText());
+ workSpace->SetCommondFilePath(commondPath_);
+ // Execute commands configured for onCreate right after workspace is set up
+ workSpace->ExecuteCommands(WorkSpace::CommandWhen::OnCreate);
WorkSpaceManager::Get().SetCurrent(workSpace);
accept();
@@ -110,23 +114,20 @@ void WorkSpaceDlg::OnSelectSavePath() {
ui->lePath->setText(QString("%1/%2").arg(path_).arg(ui->leName->text()));
LOG_INFO("save path: {}", path_.toLocal8Bit().constData());
}
-//
-//void WorkSpaceDlg::InitFrame() {
-// FrameTitleBar* titleBar = new FrameTitleBar(this);
-// titleBar->SetMainWidget(this);
-//
-// titleBar->SetSysButton(FrameTitleBar::FTB_ICON | FrameTitleBar::FTB_CLOSE);
-//
-// QVBoxLayout* layout = new QVBoxLayout(this);
-// layout->setContentsMargins(0, 0, 0, 0);
-// layout->setSpacing(0);
-//
-// layout->setStretch(0, 0);
-// layout->setStretch(1, 1);
-// layout->setAlignment(Qt::AlignLeft | Qt::AlignTop);
-// SetTitleBar(titleBar);
-//
-// QWidget* mainDilag_ = new QWidget(this);
-// layout->addWidget(mainDilag_, 1);
-// ui->setupUi(mainDilag_);
-//}
+
+void WorkSpaceDlg::OnSelectCommondPath() {
+ const QString workspacePath = Application::GetWorkSpacePath();
+ const QString xmlPath = QFileDialog::getOpenFileName(
+ this,
+ tr("select command xml file"),
+ workspacePath,
+ tr("XML files (*.xml);;All files (*.*)"));
+ if (xmlPath.isEmpty()) {
+ LOG_WARN("command xml file is empty");
+ return;
+ }
+ commondPath_ = xmlPath;
+ ui->leCommondPath->setText(commondPath_);
+ LOG_INFO("select command xml: {}", commondPath_.toLocal8Bit().constData());
+}
+
diff --git a/src/ui/WorkSpace/WorkSpaceDlg.h b/src/ui/WorkSpace/WorkSpaceDlg.h
index 1719ae5f..5f5dd525 100644
--- a/src/ui/WorkSpace/WorkSpaceDlg.h
+++ b/src/ui/WorkSpace/WorkSpaceDlg.h
@@ -18,10 +18,12 @@ protected:
void OnSure();
void OnSelectSavePath();
+ void OnSelectCommondPath();
//void InitFrame();
private:
Ui::WorkSpaceDlg* ui;
QString path_;
+ QString commondPath_;
};
\ No newline at end of file
diff --git a/src/ui/WorkSpace/WorkSpaceDlg.ui b/src/ui/WorkSpace/WorkSpaceDlg.ui
index cc58cbd1..ed2de71d 100644
--- a/src/ui/WorkSpace/WorkSpaceDlg.ui
+++ b/src/ui/WorkSpace/WorkSpaceDlg.ui
@@ -6,8 +6,8 @@
0
0
- 345
- 243
+ 528
+ 418
@@ -66,6 +66,37 @@
+ -
+
+
-
+
+
+ commond Path
+
+
+
+ -
+
+
+
+
+
+ true
+
+
+ select commond file path
+
+
+
+ -
+
+
+ ...
+
+
+
+
+
-
-
@@ -113,8 +144,6 @@
-
-
-
+
diff --git a/src/utils/UiLayoutManager.cpp b/src/utils/UiLayoutManager.cpp
new file mode 100644
index 00000000..db35dd40
--- /dev/null
+++ b/src/utils/UiLayoutManager.cpp
@@ -0,0 +1,38 @@
+#include "UiLayoutManager.h"
+
+#include
+#include
+#include
+
+#include "common/RecourceHelper.h"
+
+namespace {
+static inline QString layoutIniPath() {
+ return RecourceHelper::Get().GetBasePath() + "/config/UIState.ini";
+}
+}
+
+void UiLayoutManager::Save(QMainWindow* mainWindow, int version) {
+ if (!mainWindow) return;
+ const QString iniPath = layoutIniPath();
+ QSettings settings(iniPath, QSettings::IniFormat);
+ settings.setValue("MainWindow/geometry", mainWindow->saveGeometry());
+ settings.setValue("MainWindow/state", mainWindow->saveState(version));
+}
+
+void UiLayoutManager::Restore(QMainWindow* mainWindow, int version) {
+ if (!mainWindow) return;
+ const QString iniPath = layoutIniPath();
+ if (!QFile::exists(iniPath)) {
+ return;
+ }
+ QSettings settings(iniPath, QSettings::IniFormat);
+ const QByteArray geometry = settings.value("MainWindow/geometry").toByteArray();
+ if (!geometry.isEmpty()) {
+ mainWindow->restoreGeometry(geometry);
+ }
+ const QByteArray state = settings.value("MainWindow/state").toByteArray();
+ if (!state.isEmpty()) {
+ mainWindow->restoreState(state, version);
+ }
+}
\ No newline at end of file
diff --git a/src/utils/UiLayoutManager.h b/src/utils/UiLayoutManager.h
new file mode 100644
index 00000000..4d1796e7
--- /dev/null
+++ b/src/utils/UiLayoutManager.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include
+class QMainWindow;
+
+class UiLayoutManager {
+public:
+ // 保存主窗口布局到 workspace/UIState.ini
+ static void Save(QMainWindow* mainWindow, int version = 1);
+
+ // 从 workspace/UIState.ini 恢复布局
+ static void Restore(QMainWindow* mainWindow, int version = 1);
+};
\ No newline at end of file
diff --git a/src/viewer/OsgWidget.cpp b/src/viewer/OsgWidget.cpp
index c2902f79..2e484e25 100644
--- a/src/viewer/OsgWidget.cpp
+++ b/src/viewer/OsgWidget.cpp
@@ -46,6 +46,8 @@ OsgWidget::OsgWidget(QWidget* parent, Qt::WindowFlags f)
connect( &timer_, SIGNAL(timeout()), this, SLOT(update()) );
timer_.start( 10 );
+
+ setMinimumSize(100, 100);
LOG_INFO("OsgWidget::OsgWidget");
}
diff --git a/src/workspace/CommandExecutor.cpp b/src/workspace/CommandExecutor.cpp
new file mode 100644
index 00000000..d8d34db5
--- /dev/null
+++ b/src/workspace/CommandExecutor.cpp
@@ -0,0 +1,68 @@
+#include "workspace/CommandExecutor.h"
+
+#include
+#include
+#include
+
+#include "common/SpdLogger.h"
+
+void CommandExecutor::Execute(WorkSpace* ws, WorkSpace::CommandWhen when) {
+ if (!ws) return;
+ if (!cmd_.enabled) return;
+
+ const QString whenStr = (when == WorkSpace::CommandWhen::OnCreate) ? QStringLiteral("oncreate") : QStringLiteral("onload");
+
+ // Build final arguments (already prepared by manager but honor rawArgs if provided)
+ QStringList argsList = cmd_.args;
+ auto pushArgs = [&argsList](const QString& s) {
+ if (!s.isEmpty()) {
+ for (const auto& part : s.split(' ', Qt::SkipEmptyParts)) {
+ argsList << part;
+ }
+ }
+ };
+ if (!cmd_.rawArgs.isEmpty()) {
+ pushArgs(cmd_.rawArgs);
+ }
+
+ const QString programLower = cmd_.program.toLower();
+ if (!cmd_.path.isEmpty()) {
+ if (programLower.endsWith("cmd.exe")) {
+ argsList << "/c" << cmd_.path;
+ } else if (programLower.endsWith("powershell.exe")) {
+ argsList << "-NoProfile" << "-ExecutionPolicy" << "Bypass" << "-File" << cmd_.path;
+ } else {
+ argsList << cmd_.path;
+ }
+ }
+
+ QProcess proc;
+ // Apply environment if provided
+ if (!cmd_.env.empty()) {
+ QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+ for (auto it = cmd_.env.begin(); it != cmd_.env.end(); ++it) {
+ env.insert(it.key(), it.value());
+ }
+ proc.setProcessEnvironment(env);
+ }
+
+ proc.setProgram(cmd_.program);
+ proc.setArguments(argsList);
+ proc.setWorkingDirectory(cmd_.workingDir.isEmpty() ? ws->GetDir() : cmd_.workingDir);
+ LOG_INFO("run command: name={} prog={} args={} cwd={} when={} desc={}",
+ cmd_.name.toLocal8Bit().constData(),
+ cmd_.program.toLocal8Bit().constData(),
+ argsList.join(' ').toLocal8Bit().constData(),
+ proc.workingDirectory().toLocal8Bit().constData(),
+ whenStr.toLocal8Bit().constData(),
+ cmd_.descript.toLocal8Bit().constData());
+ proc.start();
+ if (!proc.waitForStarted()) {
+ LOG_WARN("command failed to start: {}", cmd_.program.toLocal8Bit().constData());
+ return;
+ }
+ proc.waitForFinished(cmd_.timeoutMs);
+ const QByteArray out = proc.readAllStandardOutput();
+ const QByteArray err = proc.readAllStandardError();
+ LOG_INFO("command '{}' exitCode={} stdout={} stderr={}", cmd_.name.toLocal8Bit().constData(), proc.exitCode(), out.constData(), err.constData());
+}
\ No newline at end of file
diff --git a/src/workspace/CommandExecutor.h b/src/workspace/CommandExecutor.h
new file mode 100644
index 00000000..14a03bc9
--- /dev/null
+++ b/src/workspace/CommandExecutor.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include
+#include
+#include
+
+#include "workspace/WorkSpace.h"
+
+// Merge Command model into this header to reduce files
+struct Command {
+ QString name;
+ QString program;
+ QStringList args; // final argument list to pass to QProcess
+ QString rawArgs; // original args string from XML (optional)
+ QString path; // script or executable path
+ QString workingDir; // working directory
+ bool enabled{true};
+ QMap env; // environment key/value pairs
+ QString descript; // description
+ int timeoutMs{30000}; // default 30s
+};
+
+class CommandExecutor {
+public:
+ explicit CommandExecutor(const Command& cmd) : cmd_(cmd) {}
+ void Execute(WorkSpace* ws, WorkSpace::CommandWhen when);
+
+ const Command& Get() const { return cmd_; }
+
+private:
+ Command cmd_;
+};
\ No newline at end of file
diff --git a/src/workspace/CommandManager.cpp b/src/workspace/CommandManager.cpp
new file mode 100644
index 00000000..f5313b9d
--- /dev/null
+++ b/src/workspace/CommandManager.cpp
@@ -0,0 +1,117 @@
+#include "workspace/CommandManager.h"
+
+#include
+
+#include "xml/tinyxml2.h"
+#include "common/SpdLogger.h"
+
+static QMap parseEnvAttr(const QString& envAttr) {
+ QMap env;
+ if (envAttr.isEmpty()) return env;
+ const auto pairs = envAttr.split(';', Qt::SkipEmptyParts);
+ for (const auto& p : pairs) {
+ const auto kv = p.split('=', Qt::KeepEmptyParts);
+ if (kv.size() >= 2) env.insert(kv[0].trimmed(), kv[1].trimmed());
+ }
+ return env;
+}
+
+void CommandManager::Reload(WorkSpace* ws) {
+ onCreate_.clear();
+ onLoad_.clear();
+ if (!ws) return;
+
+ const QString cmdPath = ws->GetCommondFilePath();
+ if (cmdPath.isEmpty()) {
+ LOG_INFO("no command xml configured");
+ return;
+ }
+ QFileInfo fi(cmdPath);
+ if (!fi.exists() || !fi.isFile()) {
+ LOG_WARN("command xml not found: {}", cmdPath.toLocal8Bit().constData());
+ return;
+ }
+
+ tinyxml2::XMLDocument doc;
+ auto rc = doc.LoadFile(cmdPath.toLocal8Bit().constData());
+ if (rc != tinyxml2::XML_SUCCESS) {
+ LOG_WARN("load command xml failed: {} rc:{}", cmdPath.toLocal8Bit().constData(), static_cast(rc));
+ return;
+ }
+ auto* root = doc.RootElement();
+ if (!root) {
+ LOG_WARN("command xml has no root: {}", cmdPath.toLocal8Bit().constData());
+ return;
+ }
+
+ for (auto* node = root->FirstChildElement(); node; node = node->NextSiblingElement()) {
+ const char* tag = node->Name();
+ if (!tag) continue;
+ QString tagQ = QString::fromUtf8(tag).toLower();
+ if (tagQ != QLatin1String("commond") && tagQ != QLatin1String("command")) continue;
+
+ Command cmd;
+ if (const char* nameAttr = node->Attribute("name")) cmd.name = QString::fromUtf8(nameAttr);
+ if (const char* exeAttr = node->Attribute("exe")) cmd.program = QString::fromUtf8(exeAttr);
+ if (cmd.program.isEmpty()) {
+ if (const char* programAttr = node->Attribute("program")) cmd.program = QString::fromUtf8(programAttr);
+ }
+ if (const char* pathAttr = node->Attribute("path")) cmd.path = QString::fromUtf8(pathAttr);
+ if (cmd.path.isEmpty()) {
+ if (const char* pathTypo = node->Attribute("paht")) cmd.path = QString::fromUtf8(pathTypo);
+ }
+ if (const char* argsAttr = node->Attribute("args")) cmd.rawArgs = QString::fromUtf8(argsAttr);
+ if (const char* cwdAttr = node->Attribute("workingDir")) cmd.workingDir = QString::fromUtf8(cwdAttr);
+ if (cmd.workingDir.isEmpty()) {
+ if (const char* cwdAttr2 = node->Attribute("cwd")) cmd.workingDir = QString::fromUtf8(cwdAttr2);
+ }
+ if (const char* enabledAttr = node->Attribute("enabled")) {
+ QString en = QString::fromUtf8(enabledAttr).toLower();
+ cmd.enabled = !(en == QLatin1String("false") || en == QLatin1String("0"));
+ }
+ if (const char* descAttr = node->Attribute("descript")) cmd.descript = QString::fromUtf8(descAttr);
+ if (cmd.descript.isEmpty()) {
+ if (const char* desc2 = node->Attribute("description")) cmd.descript = QString::fromUtf8(desc2);
+ }
+ if (const char* timeoutAttr = node->Attribute("timeoutSec")) {
+ bool ok = false; int v = QString::fromUtf8(timeoutAttr).toInt(&ok);
+ if (ok && v > 0) cmd.timeoutMs = v * 1000;
+ }
+ // env: either attribute env="KEY=VAL;K2=V2" or child elements
+ if (const char* envAttr = node->Attribute("env")) {
+ cmd.env = parseEnvAttr(QString::fromUtf8(envAttr));
+ }
+ for (auto* envNode = node->FirstChildElement("env"); envNode; envNode = envNode->NextSiblingElement("env")) {
+ const char* k = envNode->Attribute("key");
+ const char* v = envNode->Attribute("value");
+ if (k && v) cmd.env.insert(QString::fromUtf8(k), QString::fromUtf8(v));
+ }
+
+ // Pre-build args list from rawArgs (actual insertion of path happens in executor)
+ if (!cmd.rawArgs.isEmpty()) {
+ for (const auto& part : cmd.rawArgs.split(' ', Qt::SkipEmptyParts)) {
+ cmd.args << part;
+ }
+ }
+
+ // when routing
+ WorkSpace::CommandWhen target = WorkSpace::CommandWhen::OnCreate; // default
+ if (const char* whenAttr = node->Attribute("when")) {
+ QString wa = QString::fromUtf8(whenAttr).toLower();
+ if (wa == QLatin1String("onload")) target = WorkSpace::CommandWhen::OnLoad;
+ }
+
+ auto exec = std::make_unique(cmd);
+ if (target == WorkSpace::CommandWhen::OnCreate) onCreate_.push_back(std::move(exec));
+ else onLoad_.push_back(std::move(exec));
+ }
+}
+
+void CommandManager::Execute(WorkSpace* ws, WorkSpace::CommandWhen when) {
+ // Reload each time to reflect latest XML
+ Reload(ws);
+ auto& list = (when == WorkSpace::CommandWhen::OnCreate) ? onCreate_ : onLoad_;
+ for (auto& exec : list) {
+ exec->Execute(ws, when);
+ }
+}
\ No newline at end of file
diff --git a/src/workspace/CommandManager.h b/src/workspace/CommandManager.h
new file mode 100644
index 00000000..178f2fa3
--- /dev/null
+++ b/src/workspace/CommandManager.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include
+#include
+
+#include "workspace/WorkSpace.h"
+#include "workspace/CommandExecutor.h"
+
+class CommandManager {
+public:
+ void Reload(WorkSpace* ws);
+ void Execute(WorkSpace* ws, WorkSpace::CommandWhen when);
+
+private:
+ std::vector> onCreate_;
+ std::vector> onLoad_;
+};
\ No newline at end of file
diff --git a/src/workspace/FileEntry.h b/src/workspace/FileEntry.h
new file mode 100644
index 00000000..51495ff6
--- /dev/null
+++ b/src/workspace/FileEntry.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include
+
+enum class FileEntryType {
+ Curve,
+ Surface,
+ Table,
+ Light
+};
+
+struct FileEntry {
+ FileEntryType type;
+ QString fileName; // relative file name under workspace dir; may be empty
+};
+
+inline const char* FileEntryTypeToString(FileEntryType t) {
+ switch (t) {
+ case FileEntryType::Curve: return "curve";
+ case FileEntryType::Surface: return "surface";
+ case FileEntryType::Table: return "table";
+ case FileEntryType::Light: return "light";
+ }
+ return "unknown";
+}
+
+inline bool FileEntryTypeFromString(const char* s, FileEntryType& out) {
+ if (!s) return false;
+ if (0 == strcmp(s, "curve")) { out = FileEntryType::Curve; return true; }
+ if (0 == strcmp(s, "surface")) { out = FileEntryType::Surface; return true; }
+ if (0 == strcmp(s, "table")) { out = FileEntryType::Table; return true; }
+ if (0 == strcmp(s, "light")) { out = FileEntryType::Light; return true; }
+ return false;
+}
\ No newline at end of file
diff --git a/src/workspace/WorkSpace.cpp b/src/workspace/WorkSpace.cpp
index 9836479f..b971b926 100644
--- a/src/workspace/WorkSpace.cpp
+++ b/src/workspace/WorkSpace.cpp
@@ -6,6 +6,7 @@
#include "workspace/WorkSpaceXMLParse.h"
#include "workspace/WorkSpaceXMLWrite.h"
+#include "workspace/CommandManager.h"
#include "workspace/WorkSpaceItem.h"
#include "workspace/Timestep.h"
@@ -15,6 +16,7 @@
#include "common/SpdLogger.h"
#include "entities/Entity.h"
#include "utils/FileUtils.h"
+#include
//#include "workspace/WorkSpaceItemGroup.h"
//#include "workspace/WorkSpaceRiverGroup.h"
//#include "workspace/WorkSpaceRiverNetGroup.h"
@@ -25,6 +27,7 @@ WorkSpace::WorkSpace(QObject* parent) noexcept
: QObject(parent) {
uuid_ = QUuid::createUuid().toString();
homeViewpoint_ = osgEarth::Viewpoint("home", 120.000000, 25.000000, 100.000000, -2.500000, -90.000000, 8200000.000000);
+ cmdMgr_ = std::make_unique();
}
WorkSpace::WorkSpace(const QString& path, QObject* parent)
@@ -32,6 +35,7 @@ WorkSpace::WorkSpace(const QString& path, QObject* parent)
, path_(path){
uuid_ = QUuid::createUuid().toString();
homeViewpoint_ = osgEarth::Viewpoint("home", 120.000000, 25.000000, 100.000000, -2.500000, -90.000000, 8200000.000000);
+ cmdMgr_ = std::make_unique();
}
const QString WorkSpace::GetDir() const {
@@ -39,6 +43,22 @@ const QString WorkSpace::GetDir() const {
return info.absolutePath();
}
+void WorkSpace::SetCommondFilePath(const QString& path) {
+ QFileInfo fileInfo(path);
+ QString dirPath = QString("%1/%2").arg(GetDir(), fileInfo.fileName());
+ bool sucess = FileUtils::CopyFileToPath(path, dirPath, true);
+ LOG_INFO("copy commond file {}: {} to {}",
+ path.toLocal8Bit().data(),
+ dirPath.toLocal8Bit().data(),
+ sucess);
+ commondPath_ = fileInfo.fileName();
+}
+
+const QString WorkSpace::GetCommondFilePath() const {
+ QString path = QString("%1/%2").arg(GetDir(), commondPath_);
+ return path;
+}
+
void WorkSpace::SetSimMatlab(const QString& path) {
QFileInfo fileInfo(path);
QString dirPath = QString("%1/%2").arg(GetDir(), fileInfo.fileName());
@@ -103,6 +123,87 @@ void WorkSpace::SetRDPath(const QString& path)
rdFile_ = fileInfo.fileName();
}
+std::vector WorkSpace::GetFileEntries(FileEntryType type) const {
+ auto it = files_.find(type);
+ if (it == files_.end()) {
+ return {};
+ }
+ return it->second;
+}
+
+WorkSpace::FileEntryResult WorkSpace::CreateFileEntry(FileEntryType type) {
+ auto& vec = files_[type];
+ if (vec.size() >= 9) {
+ return FileEntryResult::LimitExceeded;
+ }
+ // push a placeholder; actual filename may be set elsewhere via SetWavePath/SetRDPath/etc
+ vec.push_back(FileEntry{ type, QString() });
+ ++filesSeq_;
+ // Notify listeners (e.g., PropertyBrowser) to refresh workspace properties
+ emit FilesChanged(type);
+ return FileEntryResult::Ok;
+}
+
+bool WorkSpace::SetFileEntryCount(FileEntryType type, int count) {
+ if (count < 0) count = 0;
+ if (count > 9) count = 9;
+ auto& vec = files_[type];
+ if (static_cast(vec.size()) == count) {
+ return true;
+ }
+ if (static_cast(vec.size()) < count) {
+ int toAdd = count - static_cast(vec.size());
+ for (int i = 0; i < toAdd; ++i) {
+ vec.push_back(FileEntry{ type, QString() });
+ }
+ } else {
+ vec.resize(count);
+ }
+ ++filesSeq_;
+ emit FilesChanged(type);
+ return true;
+}
+
+bool WorkSpace::SetFileEntryPath(FileEntryType type, int index, const QString& path) {
+ auto& vec = files_[type];
+ if (index < 0 || index >= static_cast(vec.size())) {
+ return false;
+ }
+ QFileInfo fileInfo(path);
+ if (!fileInfo.exists()) {
+ return false;
+ }
+ QString dirPath = QString("%1/%2").arg(GetDir(), fileInfo.fileName());
+ bool sucess = FileUtils::CopyFileToPath(path, dirPath, true);
+ LOG_INFO("copy grouped file {}: {} to {}",
+ path.toLocal8Bit().data(),
+ dirPath.toLocal8Bit().data(),
+ sucess);
+ if (!sucess) {
+ return false;
+ }
+ vec[index].fileName = fileInfo.fileName();
+ ++filesSeq_;
+ emit FilesChanged(type);
+ return true;
+}
+
+QString WorkSpace::GetFileEntryAbsPath(FileEntryType type, int index) const {
+ auto it = files_.find(type);
+ if (it == files_.end()) {
+ return QString();
+ }
+ const auto& vec = it->second;
+ if (index < 0 || index >= static_cast(vec.size())) {
+ return QString();
+ }
+ const QString& name = vec[index].fileName;
+ if (name.isEmpty()) {
+ return QString();
+ }
+ return QString("%1/%2").arg(GetDir(), name);
+}
+
const QString WorkSpace::GetRDPath() const
{
QString path = QString("%1/%2").arg(GetDir(), rdFile_);
@@ -282,4 +383,13 @@ void WorkSpace::OnLoaded() {
if (nullptr != timestep_) {
emit TimestepChanged(timestep_);
}
+ // Execute commands configured for onLoad
+ ExecuteCommands(CommandWhen::OnLoad);
+}
+
+void WorkSpace::ExecuteCommands(CommandWhen when) {
+ if (!cmdMgr_) {
+ cmdMgr_ = std::make_unique();
+ }
+ cmdMgr_->Execute(this, when);
}
diff --git a/src/workspace/WorkSpace.h b/src/workspace/WorkSpace.h
index b5b44259..e649b2ba 100644
--- a/src/workspace/WorkSpace.h
+++ b/src/workspace/WorkSpace.h
@@ -1,6 +1,8 @@
#pragma once
#include