Merge branch 'new_osg' of http://brigecode.icu:16623/PM/DYTSrouce into new_osg

This commit is contained in:
pimin 2025-10-13 14:06:26 +08:00
commit 387792620a
51 changed files with 1831 additions and 643 deletions

2
.gitignore vendored
View File

@ -2,3 +2,5 @@
build/ build/
bin/ bin/
thirdparty/ thirdparty/
tritoin/
QWEN.md

BIN
doc/dyttu.docx Normal file

Binary file not shown.

26
doc/交互设计.md Normal file
View File

@ -0,0 +1,26 @@
# 交互设计
## 拖拽式添加实体
## 图表数据格式
### WAVE图表
按照一个文件多个曲线来,一行一个曲线
曲线、曲面每一个类型一个tab页面 最大可以显示9宫格
表格、灯 灯在上方,表格在下方(待定)
## 菜单
### 文件
* 新建wordspace
* 打开wordspace
* 保存wordspace
----
* 新建曲线
* 新建曲面
* 新建表格
* 新建灯
### 仿真管理
* 命令运行手动编辑xml: <commond "delfeile" exe="cmd.exe" path="d:/1.bat"/>
* 参数编辑:弹出编辑框

BIN
doc/流程图.vsdx Normal file

Binary file not shown.

View File

@ -0,0 +1,15 @@
船:
驱逐机(阿利伯克)、航母(尼米兹)
卫星:
高轨(静止)
弹:
高超音速弹DF21
无源干扰:
角反、箔条
有源干扰:
弦内、弦外

View File

@ -14,8 +14,8 @@ find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Widgets LinguistTools DataVis
message("qt VERSION " ${QT_VERSION_MAJOR}) message("qt VERSION " ${QT_VERSION_MAJOR})
FILE(GLOB_RECURSE HEADER_FILES ./*.h common/*.h common/*.hpp model/*.h app/*.h) 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) FILE(GLOB_RECURSE CPP_FILES ./*.cpp common/*.cpp model/*.cpp app/*.cpp utils/*.cpp)
FILE(GLOB_RECURSE CC_FILES ./*.cc) FILE(GLOB_RECURSE CC_FILES ./*.cc)
FILE(GLOB_RECURSE UI_FILES ./*.ui) FILE(GLOB_RECURSE UI_FILES ./*.ui)
FILE(GLOB_RECURSE QRC_FILES ./*.qrc) FILE(GLOB_RECURSE QRC_FILES ./*.qrc)

View File

@ -1,6 +1,7 @@
<RCC> <RCC>
<qresource prefix="/"> <qresource prefix="/">
<file>res/sys_close.png</file> <file>res/sys_close.png</file>
<file>res/sys_float.png</file>
<file>res/sys_max.png</file> <file>res/sys_max.png</file>
<file>res/sys_min.png</file> <file>res/sys_min.png</file>
<file>res/sys_restore.png</file> <file>res/sys_restore.png</file>
@ -11,7 +12,10 @@
<file>res/default/menu_new_file.png</file> <file>res/default/menu_new_file.png</file>
<file>res/default/menu_open_file.png</file> <file>res/default/menu_open_file.png</file>
<file>res/default/menu_save_file.png</file> <file>res/default/menu_save_file.png</file>
<file>res/default/menu_save_as_file.png</file> <file>res/default/menu_wave_file.png</file>
<file>res/default/menu_light_file.png</file>
<file>res/default/menu_table_file.png</file>
<file>res/default/menu_surface_file.png</file>
<file>res/default/menu_save_shape_file.png</file> <file>res/default/menu_save_shape_file.png</file>
<file>res/default/menu_save_store_file.png</file> <file>res/default/menu_save_store_file.png</file>
<file>res/default/menu_report_mesh.png</file> <file>res/default/menu_report_mesh.png</file>

View File

@ -72,6 +72,17 @@ QPushButton#sys_close {
padding: 0; 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 { QPushButton#sys_min {
max-width:48px; max-width:48px;
min-width:48px; min-width:48px;
@ -219,6 +230,18 @@ QWidget#FileManagerMenu > QToolButton#menu_save_shape_file {
QWidget#FileManagerMenu > QToolButton#menu_save_shape_file { QWidget#FileManagerMenu > QToolButton#menu_save_shape_file {
qproperty-icon: url(:/res/default/menu_report_mesh.png); 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 { QWidget#SystemManagerMenu > QToolButton#menu_exit {
qproperty-icon: url(:/res/default/menu_exit.png); qproperty-icon: url(:/res/default/menu_exit.png);
@ -322,6 +345,7 @@ QMenu {
background: #212F3C; background: #212F3C;
color: #e0e0e0; color: #e0e0e0;
padding: 4px; padding: 4px;
border-radius: 3px;
} }
QMenu::item { QMenu::item {
padding: 6px 30px 6px 20px; padding: 6px 30px 6px 20px;
@ -340,4 +364,4 @@ QMenu::separator {
height: 1px; height: 1px;
background: #555; background: #555;
margin: 5px 10px; margin: 5px 10px;
} }

View File

@ -1,6 +1,8 @@
#include "entities/Entity.h" #include "entities/Entity.h"
#include <QUuid> #include <QUuid>
// Ensure QVariant can hold and convert Entity* in signals/slots
Q_DECLARE_METATYPE(Entity*)
#include "common/SpdLogger.h" #include "common/SpdLogger.h"
#include "entities/SceneComponent.h" #include "entities/SceneComponent.h"

View File

@ -68,7 +68,7 @@ void PathComponent::Begin() {
for (int index = 0; index < num; ++index) { for (int index = 0; index < num; ++index) {
const Transform& transform = transforms[index]; const Transform& transform = transforms[index];
osg::AnimationPath::ControlPoint controlPoint(transform.GetLocation() /*+ osg::Vec3(index * 10, 0, 0)*/, 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); animationPath_->insert(steps[index], controlPoint);
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 973 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 662 B

BIN
src/res/sys_float.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

File diff suppressed because it is too large Load Diff

View File

@ -14,6 +14,7 @@ DockTitleBar::DockTitleBar(QWidget* parent)
, ui(new Ui::DockTitleBar) { , ui(new Ui::DockTitleBar) {
ui->setupUi(this); ui->setupUi(this);
connect(ui->sys_close, &QPushButton::clicked, this, &DockTitleBar::signalClose); connect(ui->sys_close, &QPushButton::clicked, this, &DockTitleBar::signalClose);
connect(ui->sys_float, &QPushButton::clicked, this, &DockTitleBar::signalToggleFloating);
} }
DockTitleBar::~DockTitleBar() { DockTitleBar::~DockTitleBar() {

View File

@ -49,6 +49,19 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item>
<widget class="QPushButton" name="sys_float">
<property name="maximumSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item> <item>
<widget class="QPushButton" name="sys_close"> <widget class="QPushButton" name="sys_close">
<property name="maximumSize"> <property name="maximumSize">

View File

@ -1,6 +1,7 @@
#include "DockWidget.h" #include "DockWidget.h"
#include <QStyleOptionDockWidget> #include <QStyleOptionDockWidget>
#include <QMouseEvent>
#include "ui/Menu/SystemManagerMenu.h" #include "ui/Menu/SystemManagerMenu.h"
#include "common/SpdLogger.h" #include "common/SpdLogger.h"
@ -8,7 +9,7 @@
DockWidgetTitleBar::DockWidgetTitleBar(QWidget* parent) DockWidgetTitleBar::DockWidgetTitleBar(QWidget* parent)
: QWidget(parent) { : QWidget(parent) {
} }
@ -54,6 +55,7 @@ void DockWidget::setWindowTitle(const QString& text) {
void DockWidget::SetDockWidgetTitleBar(DockWidgetTitleBar* titleBar) { void DockWidget::SetDockWidgetTitleBar(DockWidgetTitleBar* titleBar) {
if (nullptr != titleBar_) { if (nullptr != titleBar_) {
disconnect(titleBar_, &DockWidgetTitleBar::signalClose, this, &DockWidget::close); disconnect(titleBar_, &DockWidgetTitleBar::signalClose, this, &DockWidget::close);
disconnect(titleBar_, &DockWidgetTitleBar::signalToggleFloating, this, &DockWidget::OnToggleFloat);
} }
titleBar_ = titleBar; titleBar_ = titleBar;
if (nullptr == titleBar_) { if (nullptr == titleBar_) {
@ -63,6 +65,7 @@ void DockWidget::SetDockWidgetTitleBar(DockWidgetTitleBar* titleBar) {
titleBar_->SetTitle(windowTitle()); titleBar_->SetTitle(windowTitle());
connect(titleBar_, &DockWidgetTitleBar::signalClose, this, &DockWidget::OnClose); connect(titleBar_, &DockWidgetTitleBar::signalClose, this, &DockWidget::OnClose);
connect(titleBar_, &DockWidgetTitleBar::signalToggleFloating, this, &DockWidget::OnToggleFloat);
QDockWidget::setTitleBarWidget(titleBar_); QDockWidget::setTitleBarWidget(titleBar_);
} }
@ -86,3 +89,12 @@ void DockWidget::OnClose() {
emit signalClose(); emit signalClose();
} }
void DockWidget::OnToggleFloat() {
setFloating(!isFloating());
}
void DockWidgetTitleBar::mouseDoubleClickEvent(QMouseEvent* event) {
QWidget::mouseDoubleClickEvent(event);
emit signalToggleFloating();
}

View File

@ -6,7 +6,7 @@
#include <QTimer> #include <QTimer>
class DockWidgetTitleBar : public QWidget { class DockWidgetTitleBar : public QWidget {
Q_OBJECT Q_OBJECT
public: public:
DockWidgetTitleBar(QWidget* parent); DockWidgetTitleBar(QWidget* parent);
@ -18,9 +18,12 @@ public:
// return QSize(270, 900); // return QSize(270, 900);
//} //}
//QSize minimumSizeHint() const override; //QSize minimumSizeHint() const override;
protected:
void mouseDoubleClickEvent(QMouseEvent* event) override;
Q_SIGNALS: Q_SIGNALS:
void signalClose(); void signalClose();
void signalToggleFloating();
}; };
class DockWidget : public QDockWidget { class DockWidget : public QDockWidget {
@ -45,6 +48,7 @@ protected:
private: private:
void OnClose(); void OnClose();
void OnToggleFloat();
private: private:
DockWidgetTitleBar* titleBar_{ nullptr }; DockWidgetTitleBar* titleBar_{ nullptr };

48
src/ui/EntityBrowser.cpp Normal file
View File

@ -0,0 +1,48 @@
#include "EntityBrowser.h"
#include <QBoxLayout>
#include <QDebug>
#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);
}

24
src/ui/EntityBrowser.h Normal file
View File

@ -0,0 +1,24 @@
#pragma once
#include <QWidget>
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_;
};

View File

@ -1,6 +1,7 @@
#include "MainWindow.h" #include "MainWindow.h"
#include <qtabwidget.h> #include <qtabwidget.h>
#include "utils/UiLayoutManager.h"
#include "PropertyBrowser.h" #include "PropertyBrowser.h"
#include "ModelBrowser.h" #include "ModelBrowser.h"
@ -28,6 +29,7 @@
#include "ui_MainWindow.h" #include "ui_MainWindow.h"
#include "viewer/OsgWidget.h" #include "viewer/OsgWidget.h"
#include "DockTitleBar.h"
MainWindow::MainWindow(QWidget* parent) MainWindow::MainWindow(QWidget* parent)
: QMainWindow(parent) : QMainWindow(parent)
@ -43,43 +45,49 @@ MainWindow::~MainWindow() {
} }
void MainWindow::InitUI() { void MainWindow::InitUI() {
QWidget* centralWidget = takeCentralWidget();
tabWidget_ = new QTabWidget; if (nullptr != centralWidget) {
tabWidget_->setTabPosition(QTabWidget::South); delete centralWidget;
tabWidget_->tabBar()->setMinimumWidth(300); }
setDockNestingEnabled(true);
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);
setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea); setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea); setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
setDockOptions(QMainWindow::AllowTabbedDocks | QMainWindow::AllowNestedDocks | QMainWindow::AnimatedDocks);
DockWidget* model = new DockWidget(tr("model elements"), 0); DockWidget* model = new DockWidget(tr("model elements"), 0);
model->SetDockWidgetTitleBar(new DockTitleBar(model));
model->setObjectName("Dock.ModelBrowser");
// addDockWidget(pSettingUI->GetArea("ModelBrowser"), model); // addDockWidget(pSettingUI->GetArea("ModelBrowser"), model);
modelBrowser_ = new ModelBrowser(0); modelBrowser_ = new ModelBrowser(0);
modelBrowser_->AttachDock(model); modelBrowser_->AttachDock(model);
m_mapDockWidget.insert("ModelBrowser", model); m_mapDockWidget.insert("ModelBrowser", model);
DockWidget* attribte = new DockWidget(tr("attribte"), 0); DockWidget* attribte = new DockWidget(tr("attribte"), 0);
attribte->SetDockWidgetTitleBar(new DockTitleBar(attribte));
attribte->setObjectName("Dock.PropertyBrowser");
//addDockWidget(pSettingUI->GetArea("PropertyBrowser"), attribte); //addDockWidget(pSettingUI->GetArea("PropertyBrowser"), attribte);
propertyBrowser_ = new PropertyBrowser(0); propertyBrowser_ = new PropertyBrowser(0);
propertyBrowser_->AttachDock(attribte); propertyBrowser_->AttachDock(attribte);
m_mapDockWidget.insert("PropertyBrowser", attribte); m_mapDockWidget.insert("PropertyBrowser", attribte);
addDockWidget(Qt::RightDockWidgetArea, attribte);
connect(modelBrowser_, &ModelBrowser::WorkSpaceChange, propertyBrowser_, &PropertyBrowser::OnWorkSpaceChange); connect(modelBrowser_, &ModelBrowser::WorkSpaceChange, propertyBrowser_, &PropertyBrowser::OnWorkSpaceChange);
connect(modelBrowser_, &ModelBrowser::EntityChange, propertyBrowser_, &PropertyBrowser::OnEntityChange); connect(modelBrowser_, &ModelBrowser::EntityChange, propertyBrowser_, &PropertyBrowser::OnEntityChange);
qtOsgViewWidget_ = new OsgWidget; qtOsgViewWidget_ = new OsgWidget;
qtOsgViewWidget_->Initialize(); 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=""; QString wavePath ="", speedPath = "", rdPath = "", matlabParam="";
if (WorkSpaceManager::Get().GetCurrent()) if (WorkSpaceManager::Get().GetCurrent())
@ -106,25 +114,36 @@ void MainWindow::InitUI() {
} }
DockWidget* fitCurveDock = new DockWidget(tr("Wave Curve"), 0); DockWidget* fitCurveDock = new DockWidget(tr("Wave Curve"), 0);
fitCurveDock->SetDockWidgetTitleBar(new DockTitleBar(fitCurveDock));
fitCurveDock->setObjectName("Dock.WaveCurveDialog");
fitCurveDlg_ = new FitCurveDialog(1); fitCurveDlg_ = new FitCurveDialog(1);
fitCurveDlg_->AttachDock(fitCurveDock); fitCurveDlg_->AttachDock(fitCurveDock);
m_mapDockWidget.insert("WaveCurveDialog", fitCurveDock); m_mapDockWidget.insert("WaveCurveDialog", fitCurveDock);
addDockWidget(Qt::BottomDockWidgetArea, fitCurveDock);
fitCurveDlg_->InitWaveFile(wavePath); fitCurveDlg_->InitWaveFile(wavePath);
DockWidget* fitLgCurveDock = new DockWidget(tr("Speed Curve"), 0); DockWidget* fitLgCurveDock = new DockWidget(tr("Speed Curve"), 0);
fitLgCurveDock->SetDockWidgetTitleBar(new DockTitleBar(fitLgCurveDock));
fitLgCurveDock->setObjectName("Dock.SpeedCurveDialog");
fitYLgCurveDlg_ = new FitCurveDialog(1); fitYLgCurveDlg_ = new FitCurveDialog(1);
fitYLgCurveDlg_->AttachDock(fitLgCurveDock); fitYLgCurveDlg_->AttachDock(fitLgCurveDock);
m_mapDockWidget.insert("SpeedCurveDialog", fitLgCurveDock); m_mapDockWidget.insert("SpeedCurveDialog", fitLgCurveDock);
addDockWidget(Qt::BottomDockWidgetArea, fitLgCurveDock);
tabifyDockWidget(fitCurveDock, fitLgCurveDock);
fitYLgCurveDlg_->InitReportFile(speedPath); fitYLgCurveDlg_->InitReportFile(speedPath);
DockWidget* surfaceCurveDock = new DockWidget(tr("3D Curve"), 0); DockWidget* surfaceCurveDock = new DockWidget(tr("3D Curve"), 0);
surfaceCurveDock->SetDockWidgetTitleBar(new DockTitleBar(surfaceCurveDock));
surfaceCurveDock->setObjectName("Dock.3DCurveDialog");
surfaceDlg_ = new SurfaceDialog(); surfaceDlg_ = new SurfaceDialog();
surfaceDlg_->AttachDock(surfaceCurveDock); surfaceDlg_->AttachDock(surfaceCurveDock);
m_mapDockWidget.insert("3DCurveDialog", surfaceCurveDock); m_mapDockWidget.insert("3DCurveDialog", surfaceCurveDock);
addDockWidget(Qt::BottomDockWidgetArea, surfaceCurveDock);
tabifyDockWidget(fitCurveDock, surfaceCurveDock);
surfaceDlg_->InitRD(rdPath); surfaceDlg_->InitRD(rdPath);
@ -146,37 +165,55 @@ void MainWindow::InitUI() {
targetUITable_->InitFile(speedPath, 50); targetUITable_->InitFile(speedPath, 50);
DockWidget* dataTableDock = new DockWidget(tr("Report Table"), 0); DockWidget* dataTableDock = new DockWidget(tr("Report Table"), 0);
dataTableDock->SetDockWidgetTitleBar(new DockTitleBar(dataTableDock));
dataTableDock->setObjectName("Dock.TargetListWgt_Table");
// addDockWidget(pSettingUI->GetArea("TargetListWgt"), dataTableDock); // addDockWidget(pSettingUI->GetArea("TargetListWgt"), dataTableDock);
targetUITable_->AttachDock(dataTableDock); targetUITable_->AttachDock(dataTableDock);
m_mapDockWidget.insert("TargetListWgt_Table", dataTableDock); m_mapDockWidget.insert("TargetListWgt_Table", dataTableDock);
addDockWidget(Qt::BottomDockWidgetArea, dataTableDock);
tabifyDockWidget(fitCurveDock, dataTableDock);
} }
const QString lampPath = RecourceHelper::Get().GetBasePath() + "/workspace/Lamp.txt"; const QString lampPath = RecourceHelper::Get().GetBasePath() + "/workspace/Lamp.txt";
DockWidget* signalIndicatorLampDock = new DockWidget(tr("Signal Indicator Lamp"), 0); DockWidget* signalIndicatorLampDock = new DockWidget(tr("Signal Indicator Lamp"), 0);
signalIndicatorLampDock->SetDockWidgetTitleBar(new DockTitleBar(signalIndicatorLampDock));
signalIndicatorLampDock->setObjectName("Dock.SignalIndicatorLampUI");
signalIndicatorLampUI_ = new SignalIndicatorLampUI; signalIndicatorLampUI_ = new SignalIndicatorLampUI;
signalIndicatorLampUI_->AttachDock(signalIndicatorLampDock); signalIndicatorLampUI_->AttachDock(signalIndicatorLampDock);
signalIndicatorLampUI_->InitLamp(lampPath); signalIndicatorLampUI_->InitLamp(lampPath);
m_mapDockWidget.insert("SignalIndicatorLampUI", signalIndicatorLampDock); m_mapDockWidget.insert("SignalIndicatorLampUI", signalIndicatorLampDock);
addDockWidget(Qt::BottomDockWidgetArea, signalIndicatorLampDock);
tabifyDockWidget(fitCurveDock, signalIndicatorLampDock);
DockWidget* addParamSettingDock = new DockWidget(tr("ParamSetting"), 0); DockWidget* addParamSettingDock = new DockWidget(tr("ParamSetting"), 0);
addParamSettingDock->SetDockWidgetTitleBar(new DockTitleBar(addParamSettingDock));
addParamSettingDock->setObjectName("Dock.ParamSetting");
addParamDlg_ = new AddParamSetting(matlabParam); addParamDlg_ = new AddParamSetting(matlabParam);
addParamDlg_->AttachDock(addParamSettingDock); addParamDlg_->AttachDock(addParamSettingDock);
m_mapDockWidget.insert("ParamSetting", addParamSettingDock); m_mapDockWidget.insert("ParamSetting", addParamSettingDock);
addDockWidget(Qt::BottomDockWidgetArea, addParamSettingDock);
tabifyDockWidget(fitCurveDock, addParamSettingDock);
DockWidget* matlabDock = new DockWidget(tr("bat File"), 0); DockWidget* matlabDock = new DockWidget(tr("bat File"), 0);
matlabDock->SetDockWidgetTitleBar(new DockTitleBar(matlabDock));
matlabDock->setObjectName("Dock.Matlab");
matlabFileDlg_ = new CodeEdtUI; matlabFileDlg_ = new CodeEdtUI;
matlabFileDlg_->AttachDock(matlabDock); matlabFileDlg_->AttachDock(matlabDock);
m_mapDockWidget.insert("Matlab", matlabDock); m_mapDockWidget.insert("Matlab", matlabDock);
addDockWidget(Qt::BottomDockWidgetArea, matlabDock);
tabifyDockWidget(fitCurveDock, matlabDock);
//ui->discript->setText(tr("name: 5year 0412")); //ui->discript->setText(tr("name: 5year 0412"));
//ui->status->setText(tr("start: no start")); //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_); //ui->viewWidget->layout()->addWidget(qtOsgViewWidget_);
qtOsgViewWidget_->LoadDefaultScene(); qtOsgViewWidget_->LoadDefaultScene();
/*OsgViewer::Get().Initialize(); /*OsgViewer::Get().Initialize();
@ -189,6 +226,8 @@ void MainWindow::InitUI() {
} }
void MainWindow::UninitUI() { void MainWindow::UninitUI() {
// Save layout state before tearing down widgets
UiLayoutManager::Save(this, 1);
if (qtOsgViewWidget_) { if (qtOsgViewWidget_) {
qtOsgViewWidget_->Uninitialize(); qtOsgViewWidget_->Uninitialize();
delete qtOsgViewWidget_; 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<QDockWidget*> 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<int> 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<QMainWindow*>(dockWidget->parentWidget());
// if (mainWindow) {
// mainWindow->removeDockWidget(dockWidget);
// }
// // tabWidget_->setCurrentWidget(dockWidget->parentWidget());
//}
}
void MainWindow::slotShowUISetting() { void MainWindow::slotShowUISetting() {
pSettingUI->show(); pSettingUI->show();
} }

View File

@ -46,14 +46,6 @@ private:
void InitUI(); void InitUI();
void UninitUI(); void UninitUI();
void InitDockLayout();
void AddDockArea(const QString& strArea);
void InitChartLayout();
protected:
void OnTabifiedDockWidgetActivated(QDockWidget* dockWidget);
private: private:
Ui::MainWindow* ui; Ui::MainWindow* ui;

View File

@ -1,131 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"> <ui version="4.0">
<class>MainWindow</class> <class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow"> <widget class="QMainWindow" name="MainWindow">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>800</width> <width>1223</width>
<height>658</height> <height>950</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>MainWindow</string> <string>MainWindow</string>
</property> </property>
<widget class="QWidget" name="centralwidget"> <widget class="QWidget" name="centralwidget"/>
<layout class="QVBoxLayout" name="verticalLayout"> </widget>
<property name="spacing"> <resources/>
<number>0</number> <connections/>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QWidget" name="viewDisplay" native="true">
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>19</number>
</property>
<property name="topMargin">
<number>19</number>
</property>
<property name="rightMargin">
<number>19</number>
</property>
<property name="bottomMargin">
<number>19</number>
</property>
<item>
<widget class="QWidget" name="viewWidget" native="true">
<layout class="QGridLayout" name="gridLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout"/>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="statusWidget" native="true">
<property name="minimumSize">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>30</height>
</size>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="topMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="discript">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="status">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>767</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui> </ui>

View File

@ -12,6 +12,7 @@
#include "common/SpdLogger.h" #include "common/SpdLogger.h"
#include "workspace/WorkSpace.h" #include "workspace/WorkSpace.h"
#include "workspace/WorkSpaceManager.h" #include "workspace/WorkSpaceManager.h"
#include "workspace/FileEntry.h"
#include "utils/FileUtils.h" #include "utils/FileUtils.h"
#include "ui_FileManagerMenu.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_new_file, &QToolButton::clicked, this, &FileManagerMenu::NewWorkSpace);
connect(ui->menu_open_file, &QToolButton::clicked, this, &FileManagerMenu::OpenWorkSpace); connect(ui->menu_open_file, &QToolButton::clicked, this, &FileManagerMenu::OpenWorkSpace);
connect(ui->menu_save_file, &QToolButton::clicked, this, &FileManagerMenu::SaveWorkSpace); 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() { void FileManagerMenu::NewWorkSpace() {
@ -70,19 +77,94 @@ void FileManagerMenu::SaveWorkSpace() {
QString dytFile = workspace->GetPath(); QString dytFile = workspace->GetPath();
LOG_INFO("save {} dyt file: {}", name.toLocal8Bit().constData(), LOG_INFO("save {} dyt file: {}", name.toLocal8Bit().constData(),
dytFile.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); bool success = workspace->Save(dytFile);
LOG_INFO("save dyt: {}", success); 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;
}
}

View File

@ -24,6 +24,11 @@ private:
void OpenWorkSpace(); void OpenWorkSpace();
void SaveWorkSpace(); void SaveWorkSpace();
void AddWaveFile();
void AddSurfaceFile();
void AddTableFile();
void AddLightFile();
private: private:
Ui::FileManagerMenu* ui; Ui::FileManagerMenu* ui;
}; };

View File

@ -54,6 +54,46 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QToolButton" name="menu_wave_file">
<property name="toolTip">
<string>new wave file</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="menu_surface_file">
<property name="toolTip">
<string>new surface file</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="menu_table_file">
<property name="toolTip">
<string>new table file</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="menu_light_file">
<property name="toolTip">
<string>new light file</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item> <item>
<spacer name="horizontalSpacer"> <spacer name="horizontalSpacer">
<property name="orientation"> <property name="orientation">

View File

@ -56,6 +56,14 @@ void PropertyBrowser::OnWorkSpaceChange(const QVariant& value) {
QWorkspaceAttribute worksapceAttribute(workspace); QWorkspaceAttribute worksapceAttribute(workspace);
workSpaceManager_->setValue(property, worksapceAttribute); workSpaceManager_->setValue(property, worksapceAttribute);
addProperty(property, tr("WorkSpace")); 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) { void PropertyBrowser::OnEntityChange(const QVariant& value) {
@ -152,6 +160,8 @@ void PropertyBrowser::InitPropertyManager() {
browser_->setFactoryForManager(sizeManager_->subIntPropertyManager(), spinBoxFactory); browser_->setFactoryForManager(sizeManager_->subIntPropertyManager(), spinBoxFactory);
browser_->setFactoryForManager(workSpaceManager_->subStringProperyManager(), lineEditFactory); browser_->setFactoryForManager(workSpaceManager_->subStringProperyManager(), lineEditFactory);
browser_->setFactoryForManager(workSpaceManager_->subFilesProperyManager(), filePathFactory); 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_->subStringProperyManager(), lineEditFactory);
browser_->setFactoryForManager(entityManager_->subBoolProperyManager(), checkBoxFactory); browser_->setFactoryForManager(entityManager_->subBoolProperyManager(), checkBoxFactory);
browser_->setFactoryForManager( browser_->setFactoryForManager(
@ -165,6 +175,16 @@ void PropertyBrowser::InitPropertyManager() {
doubleSpinBoxFactory); 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() { void PropertyBrowser::InitComponentPropertyManager() {
QtDoubleSpinBoxFactory* doubleSpinBoxFactory = new QtDoubleSpinBoxFactory(this); QtDoubleSpinBoxFactory* doubleSpinBoxFactory = new QtDoubleSpinBoxFactory(this);
QtCheckBoxFactory* checkBoxFactory = new QtCheckBoxFactory(this); QtCheckBoxFactory* checkBoxFactory = new QtCheckBoxFactory(this);

View File

@ -2,6 +2,7 @@
#include <QWidget> #include <QWidget>
#include <QMap> #include <QMap>
#include "workspace/FileEntry.h"
class QtProperty; class QtProperty;
@ -17,6 +18,7 @@ public:
void OnWorkSpaceChange(const QVariant& value); void OnWorkSpaceChange(const QVariant& value);
void OnEntityChange(const QVariant& value); void OnEntityChange(const QVariant& value);
void OnWorkspaceFilesChanged(enum class FileEntryType type);
void Test(); void Test();
@ -49,5 +51,8 @@ private:
QMap<QString, bool> idToExpanded_; QMap<QString, bool> idToExpanded_;
QMap<QString, class QtComponentPropertyManager*> componetManager_; QMap<QString, class QtComponentPropertyManager*> componetManager_;
// Track current workspace for real-time refresh
class WorkSpace* currentWorkspace_{ nullptr };
}; };

View File

@ -42,6 +42,7 @@
#include <QtCore/QDateTime> #include <QtCore/QDateTime>
#include <QtCore/QLocale> #include <QtCore/QLocale>
#include <QtCore/QMap> #include <QtCore/QMap>
#include <QtCore/QVector>
#include <QtCore/QTimer> #include <QtCore/QTimer>
#include <QtCore/QRegularExpression> #include <QtCore/QRegularExpression>
#include <QtGui/QIcon> #include <QtGui/QIcon>
@ -7893,35 +7894,84 @@ void QtModelBasePropertyManager::uninitializeProperty(QtProperty* property) {
#pragma region QtWorkspacePropertyManager #pragma region QtWorkspacePropertyManager
class QtWorkspacePropertyManagerPrivate { class QtWorkspacePropertyManagerPrivate {
QtWorkspacePropertyManager* q_ptr; QtWorkspacePropertyManager* q_ptr;
Q_DECLARE_PUBLIC(QtWorkspacePropertyManager) Q_DECLARE_PUBLIC(QtWorkspacePropertyManager)
public: 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<const QtProperty*, QWorkspaceAttribute> PropertyValueMap; typedef QMap<const QtProperty*, QWorkspaceAttribute> PropertyValueMap;
PropertyValueMap m_values; PropertyValueMap m_values;
QtStringPropertyManager* m_stringProperyManager; QtStringPropertyManager* m_stringProperyManager;
QtFilesPropertyManager* m_filesProperyManager; QtFilesPropertyManager* m_filesProperyManager;
QtIntPropertyManager* m_intProperyManager{ nullptr };
QtGroupPropertyManager* m_groupProperyManager{ nullptr };
QMap<const QtProperty*, QtProperty*> m_properyToName; QMap<const QtProperty*, QtProperty*> m_properyToName;
QMap<const QtProperty*, QtProperty*> m_properyToDescription; QMap<const QtProperty*, QtProperty*> m_properyToDescription;
QMap<const QtProperty*, QtProperty*> m_properyToTimestep; QMap<const QtProperty*, QtProperty*> m_properyToTimestep;
QMap<const QtProperty*, QtProperty*> m_properyToSimMatlab;
QMap<const QtProperty*, QtProperty*> m_properyToMatlabParam;
QMap<const QtProperty*, QtProperty*> m_properyToWavePath;
QMap<const QtProperty*, QtProperty*> m_properyToReportPath;
QMap<const QtProperty*, QtProperty*> m_properyToRDPath;
QMap<const QtProperty*, QtProperty*> m_nameToPropery; QMap<const QtProperty*, QtProperty*> m_nameToPropery;
QMap<const QtProperty*, QtProperty*> m_descriptionToPropery; QMap<const QtProperty*, QtProperty*> m_descriptionToPropery;
QMap<const QtProperty*, QtProperty*> m_timestepToPropery; QMap<const QtProperty*, QtProperty*> m_timestepToPropery;
QMap<const QtProperty*, QtProperty*> m_simMatlabToPropery;
QMap<const QtProperty*, QtProperty*> m_matlabParamToPropery;
QMap<const QtProperty*, QtProperty*> m_wavePathToPropery;
QMap<const QtProperty*, QtProperty*> m_reportPathToPropery;
QMap<const QtProperty*, QtProperty*> m_rdPathToPropery;
// Grouped file entries: Curve
QMap<const QtProperty*, QtProperty*> m_properyToCurveGroup;
QMap<const QtProperty*, QtProperty*> m_curveGroupToPropery;
QMap<const QtProperty*, QtProperty*> m_properyToCurveCount;
QMap<const QtProperty*, QtProperty*> m_curveCountToPropery;
QMap<const QtProperty*, QVector<QtProperty*>> m_properyToCurvePaths;
QMap<const QtProperty*, QtProperty*> m_curvePathToPropery;
QMap<const QtProperty*, int> m_curvePathIndex;
// Surface
QMap<const QtProperty*, QtProperty*> m_properyToSurfaceGroup;
QMap<const QtProperty*, QtProperty*> m_surfaceGroupToPropery;
QMap<const QtProperty*, QtProperty*> m_properyToSurfaceCount;
QMap<const QtProperty*, QtProperty*> m_surfaceCountToPropery;
QMap<const QtProperty*, QVector<QtProperty*>> m_properyToSurfacePaths;
QMap<const QtProperty*, QtProperty*> m_surfacePathToPropery;
QMap<const QtProperty*, int> m_surfacePathIndex;
// Table
QMap<const QtProperty*, QtProperty*> m_properyToTableGroup;
QMap<const QtProperty*, QtProperty*> m_tableGroupToPropery;
QMap<const QtProperty*, QtProperty*> m_properyToTableCount;
QMap<const QtProperty*, QtProperty*> m_tableCountToPropery;
QMap<const QtProperty*, QVector<QtProperty*>> m_properyToTablePaths;
QMap<const QtProperty*, QtProperty*> m_tablePathToPropery;
QMap<const QtProperty*, int> m_tablePathIndex;
// Light
QMap<const QtProperty*, QtProperty*> m_properyToLightGroup;
QMap<const QtProperty*, QtProperty*> m_lightGroupToPropery;
QMap<const QtProperty*, QtProperty*> m_properyToLightCount;
QMap<const QtProperty*, QtProperty*> m_lightCountToPropery;
QMap<const QtProperty*, QVector<QtProperty*>> m_properyToLightPaths;
QMap<const QtProperty*, QtProperty*> m_lightPathToPropery;
QMap<const QtProperty*, int> m_lightPathIndex;
}; };
void QtWorkspacePropertyManagerPrivate::slotStringChanged(QtProperty* property, QString value) { void QtWorkspacePropertyManagerPrivate::slotStringChanged(QtProperty* property, QString value) {
if (QtProperty* prop = m_nameToPropery.value(property, 0)) { if (QtProperty* prop = m_nameToPropery.value(property, 0)) {
QWorkspaceAttribute c = m_values[prop]; QWorkspaceAttribute c = m_values[prop];
c.SetName(value); c.SetName(value);
q_ptr->setValue(prop, c); q_ptr->setValue(prop, c);
} else if (QtProperty* prop = m_descriptionToPropery.value(property, 0)) { } else if (QtProperty* prop = m_descriptionToPropery.value(property, 0)) {
QWorkspaceAttribute c = m_values[prop]; QWorkspaceAttribute c = m_values[prop];
c.SetDescription(value); c.SetDescription(value);
@ -7930,9 +7980,102 @@ void QtWorkspacePropertyManagerPrivate::slotStringChanged(QtProperty* property,
QWorkspaceAttribute c = m_values[prop]; QWorkspaceAttribute c = m_values[prop];
c.SetTimeStep(value); c.SetTimeStep(value);
q_ptr->setValue(prop, c); 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<const QtProperty*, QtProperty*>& countToProp,
QMap<const QtProperty*, QVector<QtProperty*>>& propToPaths,
QMap<const QtProperty*, QtProperty*>& pathToProp,
QMap<const QtProperty*, int>& pathIndex,
QMap<const QtProperty*, QtProperty*>& propToGroup) {
if (QtProperty* root = countToProp.value(property, nullptr)) {
// Adjust UI path properties to match new count
QVector<QtProperty*>& 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) { void QtWorkspacePropertyManagerPrivate::slotPropertyDestroyed(QtProperty* property) {
if (QtProperty* subProp = m_nameToPropery.value(property, nullptr)) { if (QtProperty* subProp = m_nameToPropery.value(property, nullptr)) {
m_nameToPropery[subProp] = 0; m_nameToPropery[subProp] = 0;
@ -7943,23 +8086,48 @@ void QtWorkspacePropertyManagerPrivate::slotPropertyDestroyed(QtProperty* proper
m_descriptionToPropery[subProp] = 0; m_descriptionToPropery[subProp] = 0;
m_descriptionToPropery.remove(property); m_descriptionToPropery.remove(property);
} }
if (QtProperty* subProp = m_timestepToPropery.value(property, nullptr)) { if (QtProperty* subProp = m_timestepToPropery.value(property, nullptr)) {
m_timestepToPropery[subProp] = 0; m_timestepToPropery[subProp] = 0;
m_timestepToPropery.remove(property); 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) QtWorkspacePropertyManager::QtWorkspacePropertyManager(QObject* parent)
: QtAbstractPropertyManager(parent), d_ptr(new QtWorkspacePropertyManagerPrivate) { : QtAbstractPropertyManager(parent), d_ptr(new QtWorkspacePropertyManagerPrivate) {
d_ptr->q_ptr = this; d_ptr->q_ptr = this;
d_ptr->m_stringProperyManager = new QtStringPropertyManager(this); d_ptr->m_stringProperyManager = new QtStringPropertyManager(this);
connect(d_ptr->m_stringProperyManager, SIGNAL(valueChanged(QtProperty*, QString)), connect(d_ptr->m_stringProperyManager, SIGNAL(valueChanged(QtProperty*, QString)),
this, SLOT(slotStringChanged(QtProperty*, QString))); this, SLOT(slotStringChanged(QtProperty*, QString)));
d_ptr->m_filesProperyManager = new QtFilesPropertyManager(this); d_ptr->m_filesProperyManager = new QtFilesPropertyManager(this);
connect(d_ptr->m_filesProperyManager, SIGNAL(valueChanged(QtProperty*, QString)), connect(d_ptr->m_filesProperyManager, SIGNAL(valueChanged(QtProperty*, QString)),
this, SLOT(slotStringChanged(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 { QtStringPropertyManager* QtWorkspacePropertyManager::subStringProperyManager() const {
return d_ptr->m_stringProperyManager; return d_ptr->m_stringProperyManager;
} }
QtFilesPropertyManager* QtWorkspacePropertyManager::subFilesProperyManager() const { 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() \sa value(), valueChanged()
*/ */
void QtWorkspacePropertyManager::setValue(QtProperty* property, const QWorkspaceAttribute& value) { void QtWorkspacePropertyManager::setValue(QtProperty* property, const QWorkspaceAttribute& value) {
const QtWorkspacePropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); const QtWorkspacePropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property);
if (it == d_ptr->m_values.end()) if (it == d_ptr->m_values.end())
return; return;
if (it.value() == value) if (it.value() == value)
return; 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_properyToName[property], value.GetName());
d_ptr->m_stringProperyManager->setValue(d_ptr->m_properyToDescription[property], value.GetDescription()); 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_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); auto syncGroup = [&](FileEntryType type,
emit valueChanged(property, value); QMap<const QtProperty*, QtProperty*>& propToGroup,
QMap<const QtProperty*, QtProperty*>& propToCount,
QMap<const QtProperty*, QVector<QtProperty*>>& propToPaths,
QMap<const QtProperty*, QtProperty*>& pathToProp,
QMap<const QtProperty*, int>& pathIndex) {
QtProperty* group = propToGroup.value(property, nullptr);
if (!group) return;
auto entries = value.GetFileEntries(type);
int count = static_cast<int>(entries.size());
// update count without triggering slot
QtProperty* countProp = propToCount.value(property, nullptr);
if (countProp) d_ptr->m_intProperyManager->setValueOnly(countProp, count);
QVector<QtProperty*>& 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 \reimp
*/ */
void QtWorkspacePropertyManager::initializeProperty(QtProperty* property) { void QtWorkspacePropertyManager::initializeProperty(QtProperty* property) {
QWorkspaceAttribute val; QWorkspaceAttribute val;
d_ptr->m_values[property] = val; d_ptr->m_values[property] = val;
QtProperty* prop = d_ptr->m_stringProperyManager->addProperty(); QtProperty* prop = d_ptr->m_stringProperyManager->addProperty();
prop->setPropertyName(tr("Name")); prop->setPropertyName(tr("Name"));
@ -8064,18 +8298,113 @@ void QtWorkspacePropertyManager::initializeProperty(QtProperty* property) {
d_ptr->m_properyToTimestep[property] = prop; d_ptr->m_properyToTimestep[property] = prop;
d_ptr->m_timestepToPropery[prop] = property; d_ptr->m_timestepToPropery[prop] = property;
property->addSubProperty(prop); 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<const QtProperty*, QtProperty*>& propToGroup,
QMap<const QtProperty*, QtProperty*>& groupToProp,
QMap<const QtProperty*, QtProperty*>& propToCount,
QMap<const QtProperty*, QtProperty*>& countToProp,
QMap<const QtProperty*, QVector<QtProperty*>>& propToPaths,
QMap<const QtProperty*, QtProperty*>& pathToProp,
QMap<const QtProperty*, int>& 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<int>(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<QtProperty*>& paths = propToPaths[property];
for (int i = 0; i < static_cast<int>(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 \reimp
*/ */
void QtWorkspacePropertyManager::uninitializeProperty(QtProperty* property) { void QtWorkspacePropertyManager::uninitializeProperty(QtProperty* property) {
QtProperty* prop = d_ptr->m_nameToPropery[property]; QtProperty* prop = d_ptr->m_nameToPropery[property];
if (prop) { if (prop) {
d_ptr->m_nameToPropery.remove(prop); d_ptr->m_nameToPropery.remove(prop);
delete prop; delete prop;
} }
d_ptr->m_properyToName.remove(property); d_ptr->m_properyToName.remove(property);
prop = d_ptr->m_descriptionToPropery[property]; prop = d_ptr->m_descriptionToPropery[property];
if (prop) { if (prop) {
@ -8090,6 +8419,84 @@ void QtWorkspacePropertyManager::uninitializeProperty(QtProperty* property) {
delete prop; delete prop;
} }
d_ptr->m_properyToTimestep.remove(property); 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<const QtProperty*, QtProperty*>& propToGroup,
QMap<const QtProperty*, QtProperty*>& groupToProp,
QMap<const QtProperty*, QtProperty*>& propToCount,
QMap<const QtProperty*, QtProperty*>& countToProp,
QMap<const QtProperty*, QVector<QtProperty*>>& propToPaths,
QMap<const QtProperty*, QtProperty*>& pathToProp,
QMap<const QtProperty*, int>& 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<QtProperty*>& 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 #pragma endregion

View File

@ -1027,6 +1027,8 @@ public:
QtStringPropertyManager* subStringProperyManager() const; QtStringPropertyManager* subStringProperyManager() const;
QtFilesPropertyManager* subFilesProperyManager() const; QtFilesPropertyManager* subFilesProperyManager() const;
QtIntPropertyManager* subIntProperyManager() const;
QtGroupPropertyManager* subGroupProperyManager() const;
public Q_SLOTS: public Q_SLOTS:
void setValue(QtProperty* property, const QWorkspaceAttribute& val); void setValue(QtProperty* property, const QWorkspaceAttribute& val);
@ -1042,6 +1044,7 @@ private:
Q_DECLARE_PRIVATE(QtWorkspacePropertyManager) Q_DECLARE_PRIVATE(QtWorkspacePropertyManager)
Q_DISABLE_COPY_MOVE(QtWorkspacePropertyManager) Q_DISABLE_COPY_MOVE(QtWorkspacePropertyManager)
Q_PRIVATE_SLOT(d_func(), void slotStringChanged(QtProperty*, QString)) Q_PRIVATE_SLOT(d_func(), void slotStringChanged(QtProperty*, QString))
Q_PRIVATE_SLOT(d_func(), void slotIntChanged(QtProperty*, int))
}; };
#pragma endregion #pragma endregion

View File

@ -14,15 +14,18 @@
QWorkspaceAttribute::QWorkspaceAttribute(class WorkSpace* workspace) QWorkspaceAttribute::QWorkspaceAttribute(class WorkSpace* workspace)
: workspace_(workspace) { : workspace_(workspace) {
if (workspace_) {
filesSeq_ = workspace_->GetFilesSeq();
}
} }
bool QWorkspaceAttribute::operator==(const QWorkspaceAttribute& other) { bool QWorkspaceAttribute::operator==(const QWorkspaceAttribute& other) {
return workspace_ == other.workspace_; return workspace_ == other.workspace_ && filesSeq_ == other.filesSeq_;
} }
QWorkspaceAttribute& QWorkspaceAttribute::operator=(const QWorkspaceAttribute& other) { QWorkspaceAttribute& QWorkspaceAttribute::operator=(const QWorkspaceAttribute& other) {
workspace_ = other.workspace_; workspace_ = other.workspace_;
filesSeq_ = other.filesSeq_;
return *this; return *this;
} }
@ -163,7 +166,7 @@ void QWorkspaceAttribute::SetRDPath(const QString& path)
workspace_->SetRDPath(path); workspace_->SetRDPath(path);
} }
const QString QWorkspaceAttribute::GetRDPath() const const QString QWorkspaceAttribute::GetRDPath() const
{ {
if (nullptr == workspace_) { if (nullptr == workspace_) {
return ""; return "";
@ -171,6 +174,34 @@ const QString QWorkspaceAttribute::GetRDPath() const
return workspace_->GetRDPath(); return workspace_->GetRDPath();
} }
std::vector<FileEntry> 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) QTransformAttribute::QTransformAttribute(class Transform* obj)
: object_(obj) { : object_(obj) {

View File

@ -43,6 +43,9 @@
#include <QString> #include <QString>
#include <QColor> #include <QColor>
#include <osg/Vec3> #include <osg/Vec3>
#include "workspace/FileEntry.h"
#include <vector>
#include <cstdint>
class QWorkspaceAttribute { class QWorkspaceAttribute {
public: public:
@ -76,8 +79,16 @@ public:
void SetRDPath(const QString& path); void SetRDPath(const QString& path);
const QString GetRDPath() const; const QString GetRDPath() const;
// Grouped files API
std::vector<FileEntry> 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: private:
class WorkSpace* workspace_{ nullptr }; class WorkSpace* workspace_{ nullptr };
// Snapshot of workspace files change sequence to detect mutations
std::uint64_t filesSeq_{ 0 };
}; };

View File

@ -33,6 +33,7 @@ void WorkSpaceDlg::InitConnect() {
connect(ui->pbSure, &QPushButton::clicked, this, &WorkSpaceDlg::OnSure); connect(ui->pbSure, &QPushButton::clicked, this, &WorkSpaceDlg::OnSure);
connect(ui->pbCancel, &QPushButton::clicked, this, &WorkSpaceDlg::reject); connect(ui->pbCancel, &QPushButton::clicked, this, &WorkSpaceDlg::reject);
connect(ui->tbPath, &QPushButton::clicked, this, &WorkSpaceDlg::OnSelectSavePath); 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) { connect(ui->leName, &QLineEdit::textChanged, [this](const QString& txt) {
QString path = QString("%1/%2").arg(path_).arg(txt); QString path = QString("%1/%2").arg(path_).arg(txt);
ui->lePath->setText(path); ui->lePath->setText(path);
@ -93,6 +94,9 @@ void WorkSpaceDlg::OnSure() {
workspacePath += QString("/%1.dyt").arg(name); workspacePath += QString("/%1.dyt").arg(name);
WorkSpace* workSpace = WorkSpaceManager::Get().GetOrCreate(workspacePath, name); WorkSpace* workSpace = WorkSpaceManager::Get().GetOrCreate(workspacePath, name);
workSpace->SetDescribe(ui->etDescribe->toPlainText()); 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); WorkSpaceManager::Get().SetCurrent(workSpace);
accept(); accept();
@ -110,23 +114,20 @@ void WorkSpaceDlg::OnSelectSavePath() {
ui->lePath->setText(QString("%1/%2").arg(path_).arg(ui->leName->text())); ui->lePath->setText(QString("%1/%2").arg(path_).arg(ui->leName->text()));
LOG_INFO("save path: {}", path_.toLocal8Bit().constData()); LOG_INFO("save path: {}", path_.toLocal8Bit().constData());
} }
//
//void WorkSpaceDlg::InitFrame() { void WorkSpaceDlg::OnSelectCommondPath() {
// FrameTitleBar* titleBar = new FrameTitleBar(this); const QString workspacePath = Application::GetWorkSpacePath();
// titleBar->SetMainWidget(this); const QString xmlPath = QFileDialog::getOpenFileName(
// this,
// titleBar->SetSysButton(FrameTitleBar::FTB_ICON | FrameTitleBar::FTB_CLOSE); tr("select command xml file"),
// workspacePath,
// QVBoxLayout* layout = new QVBoxLayout(this); tr("XML files (*.xml);;All files (*.*)"));
// layout->setContentsMargins(0, 0, 0, 0); if (xmlPath.isEmpty()) {
// layout->setSpacing(0); LOG_WARN("command xml file is empty");
// return;
// layout->setStretch(0, 0); }
// layout->setStretch(1, 1); commondPath_ = xmlPath;
// layout->setAlignment(Qt::AlignLeft | Qt::AlignTop); ui->leCommondPath->setText(commondPath_);
// SetTitleBar(titleBar); LOG_INFO("select command xml: {}", commondPath_.toLocal8Bit().constData());
// }
// QWidget* mainDilag_ = new QWidget(this);
// layout->addWidget(mainDilag_, 1);
// ui->setupUi(mainDilag_);
//}

View File

@ -18,10 +18,12 @@ protected:
void OnSure(); void OnSure();
void OnSelectSavePath(); void OnSelectSavePath();
void OnSelectCommondPath();
//void InitFrame(); //void InitFrame();
private: private:
Ui::WorkSpaceDlg* ui; Ui::WorkSpaceDlg* ui;
QString path_; QString path_;
QString commondPath_;
}; };

View File

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>345</width> <width>528</width>
<height>243</height> <height>418</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -66,6 +66,37 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>commond Path</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="leCommondPath">
<property name="text">
<string/>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="placeholderText">
<string>select commond file path</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="tbCommondPath">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
<item> <item>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
@ -113,8 +144,6 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<resources> <resources/>
<include location="../Hydro.qrc"/>
</resources>
<connections/> <connections/>
</ui> </ui>

View File

@ -0,0 +1,38 @@
#include "UiLayoutManager.h"
#include <QSettings>
#include <QFile>
#include <QMainWindow>
#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);
}
}

View File

@ -0,0 +1,13 @@
#pragma once
#include <QString>
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);
};

View File

@ -46,6 +46,8 @@ OsgWidget::OsgWidget(QWidget* parent, Qt::WindowFlags f)
connect( &timer_, SIGNAL(timeout()), this, SLOT(update()) ); connect( &timer_, SIGNAL(timeout()), this, SLOT(update()) );
timer_.start( 10 ); timer_.start( 10 );
setMinimumSize(100, 100);
LOG_INFO("OsgWidget::OsgWidget"); LOG_INFO("OsgWidget::OsgWidget");
} }

View File

@ -0,0 +1,68 @@
#include "workspace/CommandExecutor.h"
#include <QFileInfo>
#include <QProcess>
#include <QProcessEnvironment>
#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());
}

View File

@ -0,0 +1,32 @@
#pragma once
#include <QString>
#include <QStringList>
#include <QMap>
#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<QString, QString> 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_;
};

View File

@ -0,0 +1,117 @@
#include "workspace/CommandManager.h"
#include <QFileInfo>
#include "xml/tinyxml2.h"
#include "common/SpdLogger.h"
static QMap<QString, QString> parseEnvAttr(const QString& envAttr) {
QMap<QString, QString> 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<int>(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 <env key="" value=""/>
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<CommandExecutor>(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);
}
}

View File

@ -0,0 +1,17 @@
#pragma once
#include <memory>
#include <vector>
#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<std::unique_ptr<CommandExecutor>> onCreate_;
std::vector<std::unique_ptr<CommandExecutor>> onLoad_;
};

34
src/workspace/FileEntry.h Normal file
View File

@ -0,0 +1,34 @@
#pragma once
#include <QString>
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;
}

View File

@ -6,6 +6,7 @@
#include "workspace/WorkSpaceXMLParse.h" #include "workspace/WorkSpaceXMLParse.h"
#include "workspace/WorkSpaceXMLWrite.h" #include "workspace/WorkSpaceXMLWrite.h"
#include "workspace/CommandManager.h"
#include "workspace/WorkSpaceItem.h" #include "workspace/WorkSpaceItem.h"
#include "workspace/Timestep.h" #include "workspace/Timestep.h"
@ -15,6 +16,7 @@
#include "common/SpdLogger.h" #include "common/SpdLogger.h"
#include "entities/Entity.h" #include "entities/Entity.h"
#include "utils/FileUtils.h" #include "utils/FileUtils.h"
#include <QProcess>
//#include "workspace/WorkSpaceItemGroup.h" //#include "workspace/WorkSpaceItemGroup.h"
//#include "workspace/WorkSpaceRiverGroup.h" //#include "workspace/WorkSpaceRiverGroup.h"
//#include "workspace/WorkSpaceRiverNetGroup.h" //#include "workspace/WorkSpaceRiverNetGroup.h"
@ -25,6 +27,7 @@ WorkSpace::WorkSpace(QObject* parent) noexcept
: QObject(parent) { : QObject(parent) {
uuid_ = QUuid::createUuid().toString(); uuid_ = QUuid::createUuid().toString();
homeViewpoint_ = osgEarth::Viewpoint("home", 120.000000, 25.000000, 100.000000, -2.500000, -90.000000, 8200000.000000); homeViewpoint_ = osgEarth::Viewpoint("home", 120.000000, 25.000000, 100.000000, -2.500000, -90.000000, 8200000.000000);
cmdMgr_ = std::make_unique<CommandManager>();
} }
WorkSpace::WorkSpace(const QString& path, QObject* parent) WorkSpace::WorkSpace(const QString& path, QObject* parent)
@ -32,6 +35,7 @@ WorkSpace::WorkSpace(const QString& path, QObject* parent)
, path_(path){ , path_(path){
uuid_ = QUuid::createUuid().toString(); uuid_ = QUuid::createUuid().toString();
homeViewpoint_ = osgEarth::Viewpoint("home", 120.000000, 25.000000, 100.000000, -2.500000, -90.000000, 8200000.000000); homeViewpoint_ = osgEarth::Viewpoint("home", 120.000000, 25.000000, 100.000000, -2.500000, -90.000000, 8200000.000000);
cmdMgr_ = std::make_unique<CommandManager>();
} }
const QString WorkSpace::GetDir() const { const QString WorkSpace::GetDir() const {
@ -39,6 +43,22 @@ const QString WorkSpace::GetDir() const {
return info.absolutePath(); 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) { void WorkSpace::SetSimMatlab(const QString& path) {
QFileInfo fileInfo(path); QFileInfo fileInfo(path);
QString dirPath = QString("%1/%2").arg(GetDir(), fileInfo.fileName()); QString dirPath = QString("%1/%2").arg(GetDir(), fileInfo.fileName());
@ -103,6 +123,87 @@ void WorkSpace::SetRDPath(const QString& path)
rdFile_ = fileInfo.fileName(); rdFile_ = fileInfo.fileName();
} }
std::vector<FileEntry> 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<int>(vec.size()) == count) {
return true;
}
if (static_cast<int>(vec.size()) < count) {
int toAdd = count - static_cast<int>(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<int>(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<int>(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 const QString WorkSpace::GetRDPath() const
{ {
QString path = QString("%1/%2").arg(GetDir(), rdFile_); QString path = QString("%1/%2").arg(GetDir(), rdFile_);
@ -282,4 +383,13 @@ void WorkSpace::OnLoaded() {
if (nullptr != timestep_) { if (nullptr != timestep_) {
emit TimestepChanged(timestep_); emit TimestepChanged(timestep_);
} }
// Execute commands configured for onLoad
ExecuteCommands(CommandWhen::OnLoad);
}
void WorkSpace::ExecuteCommands(CommandWhen when) {
if (!cmdMgr_) {
cmdMgr_ = std::make_unique<CommandManager>();
}
cmdMgr_->Execute(this, when);
} }

View File

@ -1,6 +1,8 @@
#pragma once #pragma once
#include <map> #include <map>
#include <memory>
#include <cstdint>
#include <QObject> #include <QObject>
#include <osgEarth/Viewpoint> #include <osgEarth/Viewpoint>
@ -9,10 +11,12 @@
#include "scene/OEScene.h" #include "scene/OEScene.h"
#include "config.h" #include "config.h"
#include "common/SpdLogger.h" #include "common/SpdLogger.h"
#include "workspace/FileEntry.h"
//#include "../ui/chartPlot/DYTChart.h" //#include "../ui/chartPlot/DYTChart.h"
class WorkSpaceItem; class WorkSpaceItem;
class CommandManager;
class WorkSpace : public QObject { class WorkSpace : public QObject {
Q_OBJECT Q_OBJECT
@ -46,6 +50,14 @@ public:
inline const QString& GetDescribe() const { inline const QString& GetDescribe() const {
return describe_; return describe_;
} }
void SetCommondFilePath(const QString& path);
const QString GetCommondFilePath() const;
// Execute command xml according to trigger
enum class CommandWhen { OnCreate, OnLoad };
void ExecuteCommands(CommandWhen when);
void SetSimMatlab(const QString& path); void SetSimMatlab(const QString& path);
const QString GetSimMatlab() const; const QString GetSimMatlab() const;
@ -65,6 +77,16 @@ public:
void SetRDPath(const QString& path); void SetRDPath(const QString& path);
const QString GetRDPath() const; const QString GetRDPath() const;
// Files list API (per-type, max 9 per type)
enum class FileEntryResult { Ok, LimitExceeded, Duplicate, CopyFailed };
FileEntryResult CreateFileEntry(FileEntryType type);
std::vector<FileEntry> GetFileEntries(FileEntryType type) const;
// Manage grouped file entries
bool SetFileEntryCount(FileEntryType type, int count);
bool SetFileEntryPath(FileEntryType type, int index, const QString& path);
QString GetFileEntryAbsPath(FileEntryType type, int index) const;
inline void SetHomeViewpoint(const osgEarth::Viewpoint& viewpoint) { inline void SetHomeViewpoint(const osgEarth::Viewpoint& viewpoint) {
homeViewpoint_ = viewpoint; homeViewpoint_ = viewpoint;
homeViewpoint_.setHeading(0.0); // Ensure heading is set to 0.0 homeViewpoint_.setHeading(0.0); // Ensure heading is set to 0.0
@ -119,10 +141,12 @@ public:
void OnLoaded(); void OnLoaded();
Q_SIGNALS: Q_SIGNALS:
void EntityAdded(class Entity* entity); void EntityAdded(class Entity* entity);
void EntityRemoved(class Entity* entity); void EntityRemoved(class Entity* entity);
void TimestepChanged(class Timestep* timestep); void TimestepChanged(class Timestep* timestep);
void LampStatusChanged(class LampStatus* lampStatus); void LampStatusChanged(class LampStatus* lampStatus);
// Emitted when grouped file entries change (count or path or creation)
void FilesChanged(FileEntryType type);
protected: protected:
const QString& GetSimMatlabName() const { const QString& GetSimMatlabName() const {
@ -134,6 +158,7 @@ private:
QString uuid_; QString uuid_;
QString describe_; QString describe_;
QString path_; QString path_;
QString commondPath_;
QString simMatlabPath_; QString simMatlabPath_;
QString waveFile_; QString waveFile_;
@ -144,11 +169,19 @@ private:
osgEarth::Viewpoint homeViewpoint_; osgEarth::Viewpoint homeViewpoint_;
bool leaded_{ false }; bool leaded_{ false };
std::vector<class Entity*> entities_; std::vector<class Entity*> entities_;
OEScene* scene_{ nullptr }; OEScene* scene_{ nullptr };
class Timestep* timestep_{ nullptr }; class Timestep* timestep_{ nullptr };
class LampStatus* lampStatus_{ nullptr }; class LampStatus* lampStatus_{ nullptr };
class Entity* trackedEntity_{ nullptr }; class Entity* trackedEntity_{ nullptr };
// Stored as file entries under workspace dir, keyed by type
std::map<FileEntryType, std::vector<FileEntry>> files_;
// Monotonic sequence for file entries changes, used to trigger UI refresh
std::uint64_t filesSeq_{ 0 };
// Executor for command XML actions
std::unique_ptr<CommandManager> cmdMgr_;
public:
std::uint64_t GetFilesSeq() const { return filesSeq_; }
friend class WorkSpaceXMLWrite; friend class WorkSpaceXMLWrite;
}; };

View File

@ -84,6 +84,30 @@ bool WorkSpaceXMLParse::ParseLamp(const tinyxml2::XMLElement* element) {
return workSpace_->SetLampPath(path); return workSpace_->SetLampPath(path);
} }
bool WorkSpaceXMLParse::ParseFiles(const tinyxml2::XMLElement* element) {
if (nullptr == element) {
LOG_WARN("element is nullptr");
return false;
}
const tinyxml2::XMLElement* typeElement = element->FirstChildElement("type");
while (nullptr != typeElement) {
const char* name = typeElement->Attribute("name");
int count = 0;
typeElement->QueryIntAttribute("count", &count);
if (nullptr != name && count > 0) {
FileEntryType enumType;
if (FileEntryTypeFromString(name, enumType)) {
for (int i = 0; i < count; ++i) {
workSpace_->CreateFileEntry(enumType);
}
}
}
typeElement = typeElement->NextSiblingElement("type");
}
return true;
}
bool WorkSpaceXMLParse::ParseEntities(const tinyxml2::XMLElement* element) { bool WorkSpaceXMLParse::ParseEntities(const tinyxml2::XMLElement* element) {
if (nullptr == element) { if (nullptr == element) {
LOG_WARN("element is nullptr"); LOG_WARN("element is nullptr");
@ -238,6 +262,9 @@ bool WorkSpaceXMLParse::Load(const QString& dyt) {
else if (0 == strcmp(name, "SimMatlab")) { else if (0 == strcmp(name, "SimMatlab")) {
ParseSimMatlab(xmlElement); ParseSimMatlab(xmlElement);
} }
else if (0 == strcmp(name, "files")) {
ParseFiles(xmlElement);
}
xmlElement = xmlElement->NextSiblingElement(); xmlElement = xmlElement->NextSiblingElement();
} }

View File

@ -35,6 +35,7 @@ private:
bool ParseChart(const tinyxml2::XMLElement* element); bool ParseChart(const tinyxml2::XMLElement* element);
bool ParseReport(const tinyxml2::XMLElement* element); bool ParseReport(const tinyxml2::XMLElement* element);
bool ParseSimMatlab(const tinyxml2::XMLElement* element); bool ParseSimMatlab(const tinyxml2::XMLElement* element);
bool ParseFiles(const tinyxml2::XMLElement* element);
private: private:
QString name_; QString name_;

View File

@ -10,6 +10,7 @@
#include "utils/StringUtils.h" #include "utils/StringUtils.h"
#include "workspace/WorkSpaceManager.h" #include "workspace/WorkSpaceManager.h"
#include "workspace/FileEntry.h"
WorkSpaceXMLWrite::WorkSpaceXMLWrite(WorkSpace* workspace, QObject* parent) noexcept WorkSpaceXMLWrite::WorkSpaceXMLWrite(WorkSpace* workspace, QObject* parent) noexcept
: QObject(parent) : QObject(parent)
@ -35,6 +36,7 @@ bool WorkSpaceXMLWrite::Save(const QString& path) {
SaveChart(scene, &doc); SaveChart(scene, &doc);
SaveTimeStep(scene); SaveTimeStep(scene);
SaveLamp(scene); SaveLamp(scene);
SaveFiles(scene, &doc);
tinyxml2::XMLElement* entitiesXml = scene->InsertNewChildElement("entities"); tinyxml2::XMLElement* entitiesXml = scene->InsertNewChildElement("entities");
std::vector<Entity*>& entities = workSpace_->GetEntities(); std::vector<Entity*>& entities = workSpace_->GetEntities();
@ -120,3 +122,19 @@ bool WorkSpaceXMLWrite::SaveChart(tinyxml2::XMLElement* scene, tinyxml2::XMLDocu
return true; return true;
} }
bool WorkSpaceXMLWrite::SaveFiles(tinyxml2::XMLElement* scene, tinyxml2::XMLDocument* doc) {
// Persist multi-file entries per type as counts
tinyxml2::XMLElement* files = doc->NewElement("files");
scene->LinkEndChild(files);
for (const auto& kv : workSpace_->files_) {
const FileEntryType type = kv.first;
const auto& vec = kv.second;
tinyxml2::XMLElement* typeElem = doc->NewElement("type");
typeElem->SetAttribute("name", FileEntryTypeToString(type));
typeElem->SetAttribute("count", static_cast<int>(vec.size()));
files->LinkEndChild(typeElem);
}
return true;
}

View File

@ -16,11 +16,12 @@ public:
bool Save(const QString& path); bool Save(const QString& path);
protected: protected:
bool SaveScene(tinyxml2::XMLElement* scene); bool SaveScene(tinyxml2::XMLElement* scene);
bool SaveTimeStep(tinyxml2::XMLElement* scene); bool SaveTimeStep(tinyxml2::XMLElement* scene);
bool SaveLamp(tinyxml2::XMLElement* scene); bool SaveLamp(tinyxml2::XMLElement* scene);
bool SaveEntities(tinyxml2::XMLElement* scene, tinyxml2::XMLDocument* doc); bool SaveEntities(tinyxml2::XMLElement* scene, tinyxml2::XMLDocument* doc);
bool SaveChart(tinyxml2::XMLElement* scene, tinyxml2::XMLDocument* doc); bool SaveChart(tinyxml2::XMLElement* scene, tinyxml2::XMLDocument* doc);
bool SaveFiles(tinyxml2::XMLElement* scene, tinyxml2::XMLDocument* doc);
private: private:
WorkSpace* workSpace_; WorkSpace* workSpace_;