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

This commit is contained in:
pimin 2025-11-09 17:17:34 +08:00
commit 69c24cb780
21 changed files with 859 additions and 65 deletions

View File

@ -109,6 +109,25 @@ Entity* EntitiesManager::CreateMesh(const QString& mesh) {
SceneComponent* conponent = ComponentFactory::Create("MeshComponent", nullptr);
conponent->SetAttribute("mesh", mesh.toStdString().c_str());
conponent->AttachEntity(entity);
// Also add PathComponent so the entity has a path attribute by default
SceneComponent* rootComponent = entity->GetRootComponent();
if (rootComponent) {
SceneComponent* pathComponent = ComponentFactory::Create("PathComponent", rootComponent);
if (pathComponent) {
pathComponent->AttachTo(rootComponent);
LOG_INFO("EntitiesManager::CreateMesh - Added PathComponent");
} else {
LOG_WARN("EntitiesManager::CreateMesh - Failed to create PathComponent");
}
} else {
SceneComponent* pathComponent = ComponentFactory::Create("PathComponent", nullptr);
if (pathComponent) {
pathComponent->AttachEntity(entity);
LOG_INFO("EntitiesManager::CreateMesh - Added PathComponent with no root");
} else {
LOG_WARN("EntitiesManager::CreateMesh - Failed to create PathComponent with no root");
}
}
return entity;
}

View File

@ -66,6 +66,28 @@ Entity* EntityFactory::CreateEntityWithComponents(const QString& type, const QSt
}
}
// Always add PathComponent so entity has path attribute editable in PropertyBrowser
{
SceneComponent* rootComponent = entity->GetRootComponent();
if (nullptr == rootComponent) {
SceneComponent* pathComponent = ComponentFactory::Create("PathComponent", nullptr);
if (pathComponent) {
pathComponent->AttachEntity(entity);
LOG_INFO("EntityFactory::CreateEntityWithComponents - Added PathComponent");
} else {
LOG_WARN("EntityFactory::CreateEntityWithComponents - Failed to create PathComponent");
}
} else {
SceneComponent* pathComponent = ComponentFactory::Create("PathComponent", rootComponent);
if (pathComponent) {
pathComponent->AttachTo(rootComponent);
LOG_INFO("EntityFactory::CreateEntityWithComponents - Added PathComponent");
} else {
LOG_WARN("EntityFactory::CreateEntityWithComponents - Failed to create PathComponent");
}
}
}
// Add required components
QStringList requiredComponents = it->second->GetRequiredComponents();
SceneComponent* rootComponent = entity->GetRootComponent();

View File

@ -25,7 +25,7 @@ DockWidget::DockWidget(const QString& title, QWidget* parent)
if (nullptr != windowManagerMenu) {
windowManagerMenu->AddDockWidget(this);
}
// 同步到可视的 WindowManagerMenu 列表(如果存在)
// Also register with visible WindowManagerMenu list if available
if (auto* listMenu = MainFrame::Get().GetMenuManager<WindowManagerMenu>("window_manager")) {
listMenu->AddDockWidget(this);
}
@ -41,7 +41,7 @@ DockWidget::DockWidget(QWidget* parent)
if (nullptr != windowManagerMenu) {
windowManagerMenu->AddDockWidget(this);
}
// 同步到可视的 WindowManagerMenu 列表(如果存在)
// Also register with visible WindowManagerMenu list if available
if (auto* listMenu = MainFrame::Get().GetMenuManager<WindowManagerMenu>("window_manager")) {
listMenu->AddDockWidget(this);
}

View File

@ -104,6 +104,7 @@ void MainWindow::InitUI() {
connect(modelBrowser_, &ModelBrowser::WorkSpaceChange, propertyBrowser_, &PropertyBrowser::OnWorkSpaceChange);
connect(modelBrowser_, &ModelBrowser::EntityChange, propertyBrowser_, &PropertyBrowser::OnEntityChange);
connect(modelBrowser_, &ModelBrowser::FileEntryChange, propertyBrowser_, &PropertyBrowser::OnFileEntryChange);
connect(modelBrowser_, &ModelBrowser::GroupChange, propertyBrowser_, &PropertyBrowser::OnGroupChange);
qtOsgViewWidget_ = new OsgWidget;
qtOsgViewWidget_->Initialize();

View File

@ -52,12 +52,28 @@ void FileManagerMenu::NewWorkSpace() {
}
void FileManagerMenu::OpenWorkSpace() {
// Select workspace file first
QString fileName = QFileDialog::getOpenFileName(&MainFrame::Get(),
QObject::tr("Open Workspace"), Application::GetWorkSpacePath(), QObject::tr("Dyt Files (*.dyt)"));
if (fileName.isEmpty()) {
return;
}
// After a valid file path is selected, prompt to save/unload current workspace
auto* current = WorkSpaceManager::Get().GetCurrent();
if (current) {
QMessageBox::StandardButton ret = QMessageBox::question(
&MainFrame::Get(), QObject::tr("warning"), QObject::tr("save current workspace?"),
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
if (ret == QMessageBox::Cancel) {
return;
}
if (ret == QMessageBox::Yes) {
SaveWorkSpace();
}
current->Unlaod();
}
LOG_INFO("open workspace: {}", fileName.toLocal8Bit().constData());
emit LoadDyt(fileName);
}

View File

@ -37,16 +37,22 @@ SimuRunMenu::~SimuRunMenu() {
}
void SimuRunMenu::OnWorkspaceChanged(WorkSpace* ws) {
Q_UNUSED(ws);
// Reconnect to workspace commands change to refresh buttons when path changes
if (wsCmdConn_) {
QObject::disconnect(wsCmdConn_);
}
if (ws) {
wsCmdConn_ = connect(ws, &WorkSpace::CommandsChanged, this, &SimuRunMenu::RefreshButtons);
}
RefreshButtons();
}
void SimuRunMenu::RefreshButtons() {
// Clear existing buttons
ClearAllBtn();
ClearAllBtn();
CreateMatlabParam();
CreateLine();
CreateMatlabParam();
CreateLine();
auto* ws = WorkSpaceManager::Get().GetCurrent();
if (!ws)
@ -122,21 +128,22 @@ void SimuRunMenu::CreateGroup(const QString& title,
void SimuRunMenu::CreateMatlabParam()
{
QHBoxLayout* layout = qobject_cast<QHBoxLayout*>(this->layout());
if (!layout)
return;
QHBoxLayout* layout = qobject_cast<QHBoxLayout*>(this->layout());
if (!layout)
return;
QToolButton *pBtn = new QToolButton();
pBtn->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
pBtn->setText(QString::fromLocal8Bit("参数设置"));
pBtn->setText(tr("setting param"));
pBtn->setIcon(QIcon(":/res/default/menu_setting_restore.png"));
pBtn->setToolTip(QString::fromLocal8Bit("设置Matlab的输入参数"));
pBtn->setToolTip(QString::fromLocal8Bit("set Matlab param"));
connect(pBtn, SIGNAL(clicked()), this, SLOT(slotHandleMatlabParam()));
layout->addWidget(pBtn);
layout->addWidget(pBtn);
}
void SimuRunMenu::CreateLine()
{
QHBoxLayout* layout = qobject_cast<QHBoxLayout*>(this->layout());
@ -182,18 +189,18 @@ void SimuRunMenu::ClearAllBtn()
void SimuRunMenu::slotHandleMatlabParam()
{
if (WorkSpaceManager::Get().GetCurrent())
{
if (!m_pParam)
{
m_pParam = new DockWidget(m_mainWindow);
m_pParam->setAllowedAreas(Qt::NoDockWidgetArea);
if (WorkSpaceManager::Get().GetCurrent())
{
if (!m_pParam)
{
m_pParam = new DockWidget(m_mainWindow);
m_pParam->setAllowedAreas(Qt::NoDockWidgetArea);
DockTitleBar* titleBar = new DockTitleBar(m_pParam);
titleBar->SetFloatVisible(false);
titleBar->SetMaxVisible(false);
m_pParam->SetDockWidgetTitleBar(titleBar);
m_pParam->setWindowTitle(QString::fromLocal8Bit("参数设置"));
m_pParam->setWindowTitle(tr("set param"));
QString strDir = WorkSpaceManager::Get().GetCurrent()->GetDir();
AddParamSetting *pParam = new AddParamSetting(strDir);
@ -204,10 +211,10 @@ void SimuRunMenu::slotHandleMatlabParam()
m_pParam->setFloating(true);
m_pParam->show();
}
}
}
void SimuRunMenu::SetMainWindow(MainWindow* mainWindow)
{
m_mainWindow = mainWindow;
m_mainWindow = mainWindow;
}

View File

@ -32,6 +32,9 @@ private:
void ClearAllBtn();
private:
QMetaObject::Connection wsCmdConn_;
private:
DockWidget *m_pParam;
MainWindow* m_mainWindow;

View File

@ -31,26 +31,44 @@ void SystemManagerMenu::AddDockWidget(class DockWidget* dockWidget) {
}
);
action->setCheckable(true);
// 勾选状态应与可见状态一致
// Keep action checked state consistent with dock visibility
action->setChecked(dockWidget->isVisible());
// 绑定 dock 到 action便于打开菜单时同步状态
// Bind dock widget to action via data for state sync
action->setData(QVariant::fromValue(dockWidget));
connect(action, &QAction::triggered, [dockWidget, action]() {
dockWidget->setVisible(action->isChecked());
}
);
// 同步可见性变化到勾选状态
// Sync visibility changes to action checked state
connect(dockWidget, &DockWidget::visibilityChanged, [action](bool visible) {
action->setChecked(visible);
});
connect(dockWidget, &DockWidget::signalClose, [action]() {
action->setChecked(false);
});
// Remove action when associated DockWidget is destroyed
connect(dockWidget, &QObject::destroyed, this, [this, dockWidget]() {
RemoveDockWidget(dockWidget);
});
windowManagerMenu_->addAction(action);
}
void SystemManagerMenu::RemoveDockWidget(class DockWidget* dockWidget) {
if (!windowManagerMenu_) {
return;
}
const auto actions = windowManagerMenu_->actions();
for (QAction* act : actions) {
QVariant v = act->data();
if (v.isValid()) {
DockWidget* dock = v.value<DockWidget*>();
if (dock == dockWidget) {
windowManagerMenu_->removeAction(act);
act->deleteLater();
break;
}
}
}
}
void SystemManagerMenu::InitConnect() {
@ -71,9 +89,9 @@ void SystemManagerMenu::OnExit() {
}
void SystemManagerMenu::OnWindowManagerMenu() {
// <EFBFBD><EFBFBD><EFBFBD>Ӵ<EFBFBD><EFBFBD>ڹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>˵<EFBFBD>
// Add window manager menu
LOG_INFO("add window manager menu");
// 打开菜单前,同步所有条目的勾选状态与当前 dock 可见性
// Before opening, sync action checked state with current dock visibility
for (QAction* act : windowManagerMenu_->actions()) {
QVariant v = act->data();
if (v.isValid()) {

View File

@ -14,8 +14,7 @@ WindowManagerMenu::WindowManagerMenu(QWidget* parent)
: QWidget(parent)
, ui(new Ui::WindowManagerMenu) {
ui->setupUi(this);
connect(ui->listWidget, &QListWidget::itemClicked, this, &WindowManagerMenu::OnItemClicked);
}
WindowManagerMenu::~WindowManagerMenu() {
@ -33,24 +32,43 @@ void WindowManagerMenu::AddDockWidget(DockWidget* dockWidget) {
item->setText(title);
}
);
// 初始勾选状态与 dock 的可见性同步
// Initialize check state to match dock visibility
item->setCheckState(dockWidget->isVisible() ? Qt::Checked : Qt::Unchecked);
connect(ui->listWidget, &QListWidget::itemClicked, [](QListWidgetItem* item) {
bool checked = !(item->checkState() == Qt::Checked);
item->setCheckState(checked ? Qt::Checked : Qt::Unchecked);
item->data(DockWidgetRole).value<DockWidget*>()->setVisible(checked);
});
item->setData(DockWidgetRole, QVariant::fromValue(dockWidget));
// 同步 dock 可见性变化到勾选状态
// Sync dock visibility changes to check state
connect(dockWidget, &DockWidget::visibilityChanged, [item](bool visible) {
item->setCheckState(visible ? Qt::Checked : Qt::Unchecked);
});
connect(dockWidget, &DockWidget::signalClose, [this, item]() {
item->setCheckState(Qt::Unchecked);
});
// Remove the corresponding item when the DockWidget is destroyed
connect(dockWidget, &QObject::destroyed, this, [this, dockWidget]() {
RemoveDockWidget(dockWidget);
});
ui->listWidget->addItem(item);
}
void WindowManagerMenu::RemoveDockWidget(class DockWidget* dockWidget) {
if (!ui || !ui->listWidget) {
return;
}
for (int i = 0; i < ui->listWidget->count(); ++i) {
QListWidgetItem* item = ui->listWidget->item(i);
DockWidget* dock = item->data(DockWidgetRole).value<DockWidget*>();
if (dock == dockWidget) {
// Remove and delete the list item
delete ui->listWidget->takeItem(i);
break;
}
}
}
void WindowManagerMenu::OnItemClicked(QListWidgetItem* item) {
bool checked = !(item->checkState() == Qt::Checked);
item->setCheckState(checked ? Qt::Checked : Qt::Unchecked);
DockWidget* dock = item->data(DockWidgetRole).value<DockWidget*>();
if (dock) {
dock->setVisible(checked);
}
}

View File

@ -8,6 +8,8 @@ namespace Ui {
class WindowManagerMenu;
}
class QListWidgetItem;
class WindowManagerMenu : public QWidget {
Q_OBJECT
@ -23,4 +25,6 @@ protected:
private:
Ui::WindowManagerMenu* ui;
private slots:
void OnItemClicked(QListWidgetItem* item);
};

View File

@ -47,4 +47,5 @@ void ModelBrowser::InitUI() {
connect(treeWidget_, &ModelTreeWidget::WorkSpaceChange, this, &ModelBrowser::WorkSpaceChange);
connect(treeWidget_, &ModelTreeWidget::EntityChange, this, &ModelBrowser::EntityChange);
connect(treeWidget_, &ModelTreeWidget::FileEntryChange, this, &ModelBrowser::FileEntryChange);
connect(treeWidget_, &ModelTreeWidget::GroupChange, this, &ModelBrowser::FileEntryChange);
}

View File

@ -15,6 +15,7 @@ Q_SIGNALS:
void WorkSpaceChange(const QVariant& workSpace);
void EntityChange(const QVariant& workSpace);
void FileEntryChange(const QVariant& fileEntry);
void GroupChange(const QVariant& group);
private:
void InitUI();

View File

@ -6,5 +6,6 @@ enum ItemRol {
E_Workspace = Qt::ItemDataRole::UserRole + 1,
E_Entity,
E_UUid,
E_FileEntry
E_FileEntry,
E_Group
};

View File

@ -4,6 +4,7 @@
#include <QUuid>
#include <QVariant>
#include <QMenu>
#include <QMessageBox>
#include <osgEarthUtil/EarthManipulator>
@ -61,8 +62,52 @@ void ModelTreeWidget::OnWorkspaceChange(WorkSpace* workSpace) {
// Create and populate curve entries branch
curvesRoot_ = new QTreeWidgetItem(root_);
curvesRoot_->setText(0, tr("Curves"));
QVariant vCurves;
vCurves.setValue(QString("Curves"));
curvesRoot_->setData(0, E_Group, vCurves);
curvesRoot_->setData(0, E_UUid, QString("CurvesRoot"));
PopulateCurveEntries();
// Create and populate other file type branches
surfacesRoot_ = new QTreeWidgetItem(root_);
surfacesRoot_->setText(0, tr("Surfaces"));
QVariant vSurfaces;
vSurfaces.setValue(QString("Surfaces"));
curvesRoot_->setData(0, E_Group, vSurfaces);
surfacesRoot_->setData(0, E_UUid, QString("SurfacesRoot"));
PopulateSurfaceEntries();
tablesRoot_ = new QTreeWidgetItem(root_);
tablesRoot_->setText(0, tr("Tables"));
QVariant vTables;
vTables.setValue(QString("Tables"));
tablesRoot_->setData(0, E_Group, vTables);
tablesRoot_->setData(0, E_UUid, QString("TablesRoot"));
PopulateTableEntries();
lightsRoot_ = new QTreeWidgetItem(root_);
lightsRoot_->setText(0, tr("Lights"));
QVariant vLights;
vLights.setValue(QString("Lights"));
lightsRoot_->setData(0, E_Group, vLights);
lightsRoot_->setData(0, E_UUid, QString("LightsRoot"));
PopulateLightEntries();
polarsRoot_ = new QTreeWidgetItem(root_);
polarsRoot_->setText(0, tr("Polars"));
QVariant vPolars;
vPolars.setValue(QString("Lights"));
polarsRoot_->setData(0, E_Group, vPolars);
polarsRoot_->setData(0, E_UUid, QString("PolarsRoot"));
PopulatePolarEntries();
imagesRoot_ = new QTreeWidgetItem(root_);
imagesRoot_->setText(0, tr("Images"));
QVariant vImages;
vImages.setValue(QString("Images"));
imagesRoot_->setData(0, E_Group, vImages);
imagesRoot_->setData(0, E_UUid, QString("PolarsRoot"));
PopulateImageEntries();
}
void ModelTreeWidget::OnEntityAdded(Entity* entity) {
@ -100,14 +145,30 @@ void ModelTreeWidget::OnEntityRemoved(Entity* entity) {
void ModelTreeWidget::contextMenuEvent(QContextMenuEvent* event) {
QTreeWidgetItem* item = itemAt(event->pos());
if (nullptr != item) {
QVariant value = item->data(0, E_Entity);
if (!value.isValid()) {
LOG_WARN("unknown data E_Entity");
// Try entity menu first
QVariant valueEntity = item->data(0, E_Entity);
if (valueEntity.isValid()) {
Entity* entity = valueEntity.value<Entity*>();
PopupEntityMenu(event, entity);
return;
}
Entity* entity = value.value<Entity*>();
PopupEntityMenu(event, entity);
// Then file entry menu
QVariant valueEntry = item->data(0, E_FileEntry);
if (valueEntry.isValid()) {
auto* entry = valueEntry.value<FileEntry*>();
QMenu menu(this);
QAction* deleteAction = new QAction(tr("Delete File"), this);
menu.addAction(deleteAction);
connect(deleteAction, &QAction::triggered, [this, entry]() {
OnDeleteFileEntry(entry);
});
menu.exec(event->globalPos());
return;
}
// Otherwise, show nothing for group/root
return;
} else {
return;
QMenu menu(this);
@ -154,7 +215,6 @@ void ModelTreeWidget::contextMenuEvent(QContextMenuEvent* event) {
);
menu.addAction(addEntiy);
// <20><>ʾ<EFBFBD>˵<EFBFBD>
menu.exec(event->globalPos());
}
@ -172,13 +232,28 @@ void ModelTreeWidget::OnWorkItemChanged(WorkSpaceItem* item) {
void ModelTreeWidget::OnWorkItemCliecked(QTreeWidgetItem* item, int column) {
// Prefer entity, then file entry, then workspace
QVariant value = item->data(column, E_Entity);
if (value.isValid()) { emit EntityChange(value); return; }
if (value.isValid()) {
emit EntityChange(value);
return;
}
value = item->data(column, E_FileEntry);
if (value.isValid()) { emit FileEntryChange(value); return; }
if (value.isValid()) {
emit FileEntryChange(value);
return;
}
value = item->data(column, E_Workspace);
if (value.isValid()) { emit WorkSpaceChange(value); return; }
if (value.isValid()) {
emit WorkSpaceChange(value);
return;
}
value = item->data(column, E_Group);
if (value.isValid()) {
emit GroupChange(value);
return;
}
LOG_WARN("unknown data rol");
}
@ -243,6 +318,37 @@ void ModelTreeWidget::OnDeleteEntity(Entity* entity) {
entity->Destory();
}
void ModelTreeWidget::OnDeleteFileEntry(FileEntry* entry) {
if (!entry) {
LOG_WARN("OnDeleteFileEntry: entry is nullptr");
return;
}
auto workspace = WorkSpaceManager::Get().GetCurrent();
if (!workspace) {
LOG_WARN("OnDeleteFileEntry: workspace is nullptr");
return;
}
// Confirm deletion of the workspace-managed item (non-destructive to physical file)
auto res = QMessageBox::question(this, tr("Confirm"), tr("Delete this file entry from workspace?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
if (res != QMessageBox::Yes) {
return;
}
bool ok = workspace->RemoveFileEntry(entry->GetType(), entry);
if (!ok) {
QMessageBox::warning(this, tr("Prompt"), tr("Delete failed"));
return;
}
// Clear property panel to avoid showing stale info of deleted item
QVariant v;
v.setValue(workspace);
emit WorkSpaceChange(v);
}
void ModelTreeWidget::PopupEntityMenu(QContextMenuEvent* event, Entity* entity) {
QMenu menu(this);
@ -419,8 +525,124 @@ void ModelTreeWidget::PopulateCurveEntries() {
}
}
void ModelTreeWidget::OnWorkspaceFilesChanged(FileEntryType type, std::shared_ptr<FileEntry> /*fileEntry*/) {
if (type == FileEntryType::Curve) {
PopulateCurveEntries();
void ModelTreeWidget::PopulateSurfaceEntries() {
if (!currentWorkSpace_ || !surfacesRoot_) return;
while (surfacesRoot_->childCount() > 0) {
QTreeWidgetItem* child = surfacesRoot_->child(0);
surfacesRoot_->removeChild(child);
delete child;
}
const auto entries = currentWorkSpace_->GetFileEntries(FileEntryType::Surface);
for (const auto& entry : entries) {
if (!entry) continue;
QTreeWidgetItem* item = new QTreeWidgetItem;
item->setText(0, entry->GetName());
QVariant v;
v.setValue(entry.get());
item->setData(0, E_FileEntry, v);
item->setData(0, E_UUid, QString("Surface:%1").arg(entry->GetFileName()));
surfacesRoot_->addChild(item);
}
}
void ModelTreeWidget::PopulateTableEntries() {
if (!currentWorkSpace_ || !tablesRoot_) return;
while (tablesRoot_->childCount() > 0) {
QTreeWidgetItem* child = tablesRoot_->child(0);
tablesRoot_->removeChild(child);
delete child;
}
const auto entries = currentWorkSpace_->GetFileEntries(FileEntryType::Table);
for (const auto& entry : entries) {
if (!entry) continue;
QTreeWidgetItem* item = new QTreeWidgetItem;
item->setText(0, entry->GetName());
QVariant v;
v.setValue(entry.get());
item->setData(0, E_FileEntry, v);
item->setData(0, E_UUid, QString("Table:%1").arg(entry->GetFileName()));
tablesRoot_->addChild(item);
}
}
void ModelTreeWidget::PopulateLightEntries() {
if (!currentWorkSpace_ || !lightsRoot_) return;
while (lightsRoot_->childCount() > 0) {
QTreeWidgetItem* child = lightsRoot_->child(0);
lightsRoot_->removeChild(child);
delete child;
}
const auto entries = currentWorkSpace_->GetFileEntries(FileEntryType::Light);
for (const auto& entry : entries) {
if (!entry) continue;
QTreeWidgetItem* item = new QTreeWidgetItem;
item->setText(0, entry->GetName());
QVariant v;
v.setValue(entry.get());
item->setData(0, E_FileEntry, v);
item->setData(0, E_UUid, QString("Light:%1").arg(entry->GetFileName()));
lightsRoot_->addChild(item);
}
}
void ModelTreeWidget::PopulatePolarEntries() {
if (!currentWorkSpace_ || !polarsRoot_) return;
while (polarsRoot_->childCount() > 0) {
QTreeWidgetItem* child = polarsRoot_->child(0);
polarsRoot_->removeChild(child);
delete child;
}
const auto entries = currentWorkSpace_->GetFileEntries(FileEntryType::Polar);
for (const auto& entry : entries) {
if (!entry) continue;
QTreeWidgetItem* item = new QTreeWidgetItem;
item->setText(0, entry->GetName());
QVariant v;
v.setValue(entry.get());
item->setData(0, E_FileEntry, v);
item->setData(0, E_UUid, QString("Polar:%1").arg(entry->GetFileName()));
polarsRoot_->addChild(item);
}
}
void ModelTreeWidget::PopulateImageEntries() {
if (!currentWorkSpace_ || !imagesRoot_) return;
while (imagesRoot_->childCount() > 0) {
QTreeWidgetItem* child = imagesRoot_->child(0);
imagesRoot_->removeChild(child);
delete child;
}
const auto entries = currentWorkSpace_->GetFileEntries(FileEntryType::Image);
for (const auto& entry : entries) {
if (!entry) continue;
QTreeWidgetItem* item = new QTreeWidgetItem;
item->setText(0, entry->GetName());
QVariant v;
v.setValue(entry.get());
item->setData(0, E_FileEntry, v);
item->setData(0, E_UUid, QString("Image:%1").arg(entry->GetFileName()));
imagesRoot_->addChild(item);
}
}
void ModelTreeWidget::OnWorkspaceFilesChanged(FileEntryType type, std::shared_ptr<FileEntry> /*fileEntry*/) {
switch (type) {
case FileEntryType::Curve: PopulateCurveEntries(); break;
case FileEntryType::Surface: PopulateSurfaceEntries(); break;
case FileEntryType::Table: PopulateTableEntries(); break;
case FileEntryType::Light: PopulateLightEntries(); break;
case FileEntryType::Polar: PopulatePolarEntries(); break;
case FileEntryType::Image: PopulateImageEntries(); break;
default: break;
}
}

View File

@ -24,6 +24,7 @@ Q_SIGNALS:
void WorkSpaceChange(const QVariant& workSpace);
void EntityChange(const QVariant& entity);
void FileEntryChange(const QVariant& fileEntry);
void GroupChange(const QVariant& group);
protected:
void contextMenuEvent(QContextMenuEvent* event) override;
@ -38,6 +39,7 @@ protected:
class SceneComponent* OnAddComponent(const QString& typeName, class Entity* entity);
void OnDeleteEntity(class Entity* entity);
void OnDeleteFileEntry(class FileEntry* entry);
void PopupEntityMenu(QContextMenuEvent* event, class Entity* entity);
@ -52,9 +54,19 @@ private:
//void initUI();
void AddEntity(class QTreeWidgetItem* parent, Entity* entity);
void PopulateCurveEntries();
void PopulateSurfaceEntries();
void PopulateTableEntries();
void PopulateLightEntries();
void PopulatePolarEntries();
void PopulateImageEntries();
private:
WorkSpace* currentWorkSpace_{ nullptr };
QTreeWidgetItem* root_{ nullptr };
QTreeWidgetItem* curvesRoot_{ nullptr };
QTreeWidgetItem* surfacesRoot_{ nullptr };
QTreeWidgetItem* tablesRoot_{ nullptr };
QTreeWidgetItem* lightsRoot_{ nullptr };
QTreeWidgetItem* polarsRoot_{ nullptr };
QTreeWidgetItem* imagesRoot_{ nullptr };
};

View File

@ -11,6 +11,7 @@
#include "DockTitleBar.h"
#include "DockWidget.h"
#include "workspace/WorkSpace.h"
#include "workspace/WorkSpaceManager.h"
#include "entities/Entity.h"
#include "entities/MeshComponent.h"
@ -47,14 +48,21 @@ void PropertyBrowser::OnWorkSpaceChange(const QVariant& value) {
WorkSpace* workspace = value.value<WorkSpace*>();
if (nullptr == workspace) {
LOG_WARN("workspace is nullptr");
// 如果没有属性对象,清空属性面板
browser_->clear();
propertyToId_.clear();
idToProperty_.clear();
idToExpanded_.clear();
colorSetters_.clear();
return;
}
// 点击根项目需要清空属性面板,不展示工作区属性
browser_->clear();
// Reset local mappings when workspace changes
propertyToId_.clear();
idToProperty_.clear();
idToExpanded_.clear();
colorSetters_.clear();
QtProperty* property;
@ -63,7 +71,7 @@ void PropertyBrowser::OnWorkSpaceChange(const QVariant& value) {
workSpaceManager_->setValue(property, worksapceAttribute);
addProperty(property, tr("WorkSpace"));
// Track and react to runtime workspace changes
// 保持对运行时工作区变更的监听(树刷新所需),但属性面板保持清空
if (currentWorkspace_) {
QObject::disconnect(currentWorkspace_, nullptr, this, nullptr);
}
@ -71,7 +79,7 @@ void PropertyBrowser::OnWorkSpaceChange(const QVariant& value) {
QObject::connect(currentWorkspace_, &WorkSpace::FilesChanged,
this, &PropertyBrowser::OnWorkspaceFilesChanged);
// No longer mount file entries under workspace; file entries are handled separately
// 属性面板清空,文件项属性由 FileEntry 点击时单独处理
}
void PropertyBrowser::OnEntityChange(const QVariant& value) {
@ -79,6 +87,12 @@ void PropertyBrowser::OnEntityChange(const QVariant& value) {
Entity* entity = value.value<Entity*>();
if (nullptr == entity) {
LOG_WARN("engity is nullptr");
// 如果没有属性对象,清空属性面板
browser_->clear();
propertyToId_.clear();
idToProperty_.clear();
idToExpanded_.clear();
colorSetters_.clear();
return;
}
@ -127,6 +141,13 @@ void PropertyBrowser::OnFileEntryChange(const QVariant& value) {
FileEntry* entry = value.value<FileEntry*>();
if (!entry) {
LOG_WARN("file entry is nullptr");
// 如果没有属性对象,清空属性面板
inFileEntryView_ = false;
browser_->clear();
propertyToId_.clear();
idToProperty_.clear();
idToExpanded_.clear();
colorSetters_.clear();
return;
}
@ -142,6 +163,345 @@ void PropertyBrowser::OnFileEntryChange(const QVariant& value) {
auto curve = entry->AsCurve();
if (!curve) {
LOG_WARN("file entry not a curve: %s", entry->GetFileName().toStdString().c_str());
// 基础信息组
const QString idBasic = QString("FileEntry:%1").arg(entry->GetFileName());
const QString titleBasic = QString("File Entry - %1").arg(entry->GetName());
QtProperty* groupBasic = groupManager_->addProperty(titleBasic);
QtProperty* typeProp = stringManager_->addProperty(tr("Type"));
stringManager_->setValue(typeProp, QString::fromStdString(FileEntryTypeToString(entry->GetType())));
groupBasic->addSubProperty(typeProp);
QtProperty* nameProp = stringManager_->addProperty(tr("Name"));
stringManager_->setValue(nameProp, entry->GetName());
groupBasic->addSubProperty(nameProp);
QtProperty* fileProp = stringManager_->addProperty(tr("FileName"));
stringManager_->setValue(fileProp, entry->GetFileName());
groupBasic->addSubProperty(fileProp);
QtProperty* pathProp = stringManager_->addProperty(tr("Path"));
stringManager_->setValue(pathProp, entry->GetPath());
groupBasic->addSubProperty(pathProp);
addProperty(groupBasic, idBasic);
// 类型专属属性显示
switch (entry->GetType()) {
case FileEntryType::Surface: {
auto surf = entry->AsSurface();
if (surf) {
const QString idChart = QString("SurfaceChart:%1").arg(entry->GetFileName());
const QString idItems = QString("SurfaceItems:%1").arg(entry->GetFileName());
const QString titleChart = QString("Surface Chart - %1").arg(entry->GetName());
const QString titleItems = QString("Surfaces - %1").arg(entry->GetName());
// Chart 属性
QtProperty* chartGroup = groupManager_->addProperty(titleChart);
const auto& chart = surf->GetChartProperties();
QtProperty* xCountProp = intManager_->addProperty(tr("xCount"));
intManager_->setValue(xCountProp, chart.xCount);
chartGroup->addSubProperty(xCountProp);
QtProperty* yCountProp = intManager_->addProperty(tr("yCount"));
intManager_->setValue(yCountProp, chart.yCount);
chartGroup->addSubProperty(yCountProp);
QtProperty* zCountProp = intManager_->addProperty(tr("zCount"));
intManager_->setValue(zCountProp, chart.zCount);
chartGroup->addSubProperty(zCountProp);
QtProperty* xTitleProp = stringManager_->addProperty(tr("xTitle"));
stringManager_->setValue(xTitleProp, chart.xTitle);
chartGroup->addSubProperty(xTitleProp);
QtProperty* yTitleProp = stringManager_->addProperty(tr("yTitle"));
stringManager_->setValue(yTitleProp, chart.yTitle);
chartGroup->addSubProperty(yTitleProp);
QtProperty* zTitleProp = stringManager_->addProperty(tr("zTitle"));
stringManager_->setValue(zTitleProp, chart.zTitle);
chartGroup->addSubProperty(zTitleProp);
QtProperty* xMinProp = doubleManager_->addProperty(tr("xMin"));
doubleManager_->setValue(xMinProp, chart.xMin);
chartGroup->addSubProperty(xMinProp);
QtProperty* xMaxProp = doubleManager_->addProperty(tr("xMax"));
doubleManager_->setValue(xMaxProp, chart.xMax);
chartGroup->addSubProperty(xMaxProp);
QtProperty* yMinProp = doubleManager_->addProperty(tr("yMin"));
doubleManager_->setValue(yMinProp, chart.yMin);
chartGroup->addSubProperty(yMinProp);
QtProperty* yMaxProp = doubleManager_->addProperty(tr("yMax"));
doubleManager_->setValue(yMaxProp, chart.yMax);
chartGroup->addSubProperty(yMaxProp);
QtProperty* zMinProp = doubleManager_->addProperty(tr("zMin"));
doubleManager_->setValue(zMinProp, chart.zMin);
chartGroup->addSubProperty(zMinProp);
QtProperty* zMaxProp = doubleManager_->addProperty(tr("zMax"));
doubleManager_->setValue(zMaxProp, chart.zMax);
chartGroup->addSubProperty(zMaxProp);
QtProperty* tProp = doubleManager_->addProperty(tr("timeParam"));
doubleManager_->setValue(tProp, chart.timeParam);
chartGroup->addSubProperty(tProp);
addProperty(chartGroup, idChart);
// Surface 列表
QtProperty* itemsGroup = groupManager_->addProperty(titleItems);
const auto& items = surf->GetSurfaceProperties();
for (int i = 0; i < items.size(); ++i) {
const auto& s = items[i];
QtProperty* itemGroup = groupManager_->addProperty(QString("Surface[%1]").arg(i));
QtProperty* nm = stringManager_->addProperty(tr("name"));
stringManager_->setValue(nm, s.name);
itemGroup->addSubProperty(nm);
QtProperty* col = colorManager_->addProperty(tr("color"));
colorManager_->setValue(col, s.color);
itemGroup->addSubProperty(col);
// 写回 Surface 条目颜色
colorSetters_[col] = [surf, entry, i](const QColor& c){
auto props = surf->GetSurfaceProperties();
if (i >= 0 && i < props.size()) {
auto item = props[i];
item.color = c;
surf->SetSurfaceProperty(i, item);
if (auto ws = WorkSpaceManager::Get().GetCurrent()) ws->NotifyFileEntryUpdated(entry->GetType());
}
};
QtProperty* st = intManager_->addProperty(tr("start"));
intManager_->setValue(st, s.start);
itemGroup->addSubProperty(st);
QtProperty* sp = intManager_->addProperty(tr("stop"));
intManager_->setValue(sp, s.stop);
itemGroup->addSubProperty(sp);
QtProperty* x = stringManager_->addProperty(tr("x"));
stringManager_->setValue(x, s.x);
itemGroup->addSubProperty(x);
QtProperty* y = stringManager_->addProperty(tr("y"));
stringManager_->setValue(y, s.y);
itemGroup->addSubProperty(y);
QtProperty* z = stringManager_->addProperty(tr("z"));
stringManager_->setValue(z, s.z);
itemGroup->addSubProperty(z);
itemsGroup->addSubProperty(itemGroup);
}
addProperty(itemsGroup, idItems);
}
break;
}
case FileEntryType::Table: {
auto tbl = entry->AsTable();
if (tbl) {
const QString idChart = QString("TableChart:%1").arg(entry->GetFileName());
const QString idItems = QString("TableItems:%1").arg(entry->GetFileName());
const QString titleChart = QString("Table Chart - %1").arg(entry->GetName());
const QString titleItems = QString("Tables - %1").arg(entry->GetName());
QtProperty* chartGroup = groupManager_->addProperty(titleChart);
const auto& chart = tbl->GetChartProperties();
QtProperty* headerProp = stringManager_->addProperty(tr("headerString"));
stringManager_->setValue(headerProp, chart.headerString);
chartGroup->addSubProperty(headerProp);
QtProperty* tProp = doubleManager_->addProperty(tr("timeParam"));
doubleManager_->setValue(tProp, chart.timeParam);
chartGroup->addSubProperty(tProp);
addProperty(chartGroup, idChart);
QtProperty* itemsGroup = groupManager_->addProperty(titleItems);
const auto& items = tbl->GetTableProperties();
for (int i = 0; i < items.size(); ++i) {
const auto& t = items[i];
QtProperty* itemGroup = groupManager_->addProperty(QString("Table[%1]").arg(i));
QtProperty* nm = stringManager_->addProperty(tr("name"));
stringManager_->setValue(nm, t.name);
itemGroup->addSubProperty(nm);
QtProperty* col = colorManager_->addProperty(tr("color"));
colorManager_->setValue(col, t.color);
itemGroup->addSubProperty(col);
// 写回 Table 条目颜色
colorSetters_[col] = [tbl, entry, i](const QColor& c){
auto props = tbl->GetTableProperties();
if (i >= 0 && i < props.size()) {
auto item = props[i];
item.color = c;
tbl->SetTableProperty(i, item);
if (auto ws = WorkSpaceManager::Get().GetCurrent()) ws->NotifyFileEntryUpdated(entry->GetType());
}
};
// datas 展示为拼接字符串
QStringList values;
for (const auto& v : t.datas) values << QString::number(v);
QtProperty* ds = stringManager_->addProperty(tr("datas"));
stringManager_->setValue(ds, values.join(", "));
itemGroup->addSubProperty(ds);
itemsGroup->addSubProperty(itemGroup);
}
addProperty(itemsGroup, idItems);
}
break;
}
case FileEntryType::Light: {
auto lt = entry->AsLight();
if (lt) {
const QString idColor = QString("LightColors:%1").arg(entry->GetFileName());
const QString idRows = QString("LightRows:%1").arg(entry->GetFileName());
const QString titleColor = QString("Light Colors - %1").arg(entry->GetName());
const QString titleRows = QString("Light Rows - %1").arg(entry->GetName());
// 颜色与时间
QtProperty* colorGroup = groupManager_->addProperty(titleColor);
const auto& colorProps = lt->GetColorProperties();
QtProperty* oc = colorManager_->addProperty(tr("openColor"));
colorManager_->setValue(oc, colorProps.openColor);
colorGroup->addSubProperty(oc);
QtProperty* cc = colorManager_->addProperty(tr("closeColor"));
colorManager_->setValue(cc, colorProps.closeColor);
colorGroup->addSubProperty(cc);
QtProperty* tProp = doubleManager_->addProperty(tr("timeParam"));
doubleManager_->setValue(tProp, colorProps.timeParam);
colorGroup->addSubProperty(tProp);
addProperty(colorGroup, idColor);
// 写回处理:颜色变化更新到 FileEntryLight 并通知 Workspace
colorSetters_[oc] = [lt, entry](const QColor& c){
auto props = lt->GetColorProperties();
props.openColor = c;
lt->SetColorProperties(props);
if (auto ws = WorkSpaceManager::Get().GetCurrent()) ws->NotifyFileEntryUpdated(entry->GetType());
};
colorSetters_[cc] = [lt, entry](const QColor& c){
auto props = lt->GetColorProperties();
props.closeColor = c;
lt->SetColorProperties(props);
if (auto ws = WorkSpaceManager::Get().GetCurrent()) ws->NotifyFileEntryUpdated(entry->GetType());
};
// 行数据
QtProperty* rowsGroup = groupManager_->addProperty(titleRows);
const auto& rows = lt->GetLightProperties();
for (int i = 0; i < rows.size(); ++i) {
const auto& r = rows[i];
QtProperty* row = groupManager_->addProperty(QString("Row[%1]").arg(i));
QtProperty* names = stringManager_->addProperty(tr("names"));
stringManager_->setValue(names, r.name.join(", "));
row->addSubProperty(names);
QStringList values;
for (const auto& v : r.data) values << QString::number(v);
QtProperty* ds = stringManager_->addProperty(tr("data"));
stringManager_->setValue(ds, values.join(", "));
row->addSubProperty(ds);
rowsGroup->addSubProperty(row);
}
addProperty(rowsGroup, idRows);
}
break;
}
case FileEntryType::Polar: {
auto pl = entry->AsPolar();
if (pl) {
const QString idChart = QString("PolarChart:%1").arg(entry->GetFileName());
const QString idLines = QString("PolarLines:%1").arg(entry->GetFileName());
const QString titleChart = QString("Polar Chart - %1").arg(entry->GetName());
const QString titleLines = QString("Lines - %1").arg(entry->GetName());
QtProperty* chartGroup = groupManager_->addProperty(titleChart);
const auto& chart = pl->GetChartProperties();
auto addInt = [&](const QString& label, int v){ QtProperty* p=intManager_->addProperty(label); intManager_->setValue(p, v); chartGroup->addSubProperty(p); };
auto addStr = [&](const QString& label, const QString& v){ QtProperty* p=stringManager_->addProperty(label); stringManager_->setValue(p, v); chartGroup->addSubProperty(p); };
auto addDbl = [&](const QString& label, double v){ QtProperty* p=doubleManager_->addProperty(label); doubleManager_->setValue(p, v); chartGroup->addSubProperty(p); };
addInt(tr("AngularCount"), chart.AngularCount);
addInt(tr("RadialCount"), chart.RadialCount);
addStr(tr("AngularTitle"), chart.AngularTitle);
addStr(tr("RadialTitle"), chart.RadialTitle);
addDbl(tr("AngularMin"), chart.AngularMin);
addDbl(tr("AngularMax"), chart.AngularMax);
addDbl(tr("RadialMin"), chart.RadialMin);
addDbl(tr("RadialMax"), chart.RadialMax);
addStr(tr("AngularUnit"), chart.AngularUnit);
addStr(tr("RadialUnit"), chart.RadialUnit);
addDbl(tr("timeParam"), chart.timeParam);
addProperty(chartGroup, idChart);
QtProperty* linesGroup = groupManager_->addProperty(titleLines);
const auto& lines = pl->GetLineProperties();
for (int i = 0; i < lines.size(); ++i) {
const auto& ln = lines[i];
QtProperty* line = groupManager_->addProperty(QString("Line[%1]").arg(i));
QtProperty* nm = stringManager_->addProperty(tr("name"));
stringManager_->setValue(nm, ln.name);
line->addSubProperty(nm);
QtProperty* col = colorManager_->addProperty(tr("color"));
colorManager_->setValue(col, ln.color);
line->addSubProperty(col);
// 写回 Polar 线颜色
colorSetters_[col] = [pl, entry, i](const QColor& c){
auto props = pl->GetLineProperties();
if (i >= 0 && i < props.size()) {
auto item = props[i];
item.color = c;
pl->SetLineProperty(i, item);
if (auto ws = WorkSpaceManager::Get().GetCurrent()) ws->NotifyFileEntryUpdated(entry->GetType());
}
};
QtProperty* ag = intManager_->addProperty(tr("Angular"));
intManager_->setValue(ag, ln.Angular);
line->addSubProperty(ag);
QtProperty* rd = intManager_->addProperty(tr("Radial"));
intManager_->setValue(rd, ln.Radial);
line->addSubProperty(rd);
linesGroup->addSubProperty(line);
}
addProperty(linesGroup, idLines);
}
break;
}
case FileEntryType::Image: {
auto img = entry->AsImage();
if (img) {
const QString idChart = QString("ImageChart:%1").arg(entry->GetFileName());
const QString idItems = QString("Images:%1").arg(entry->GetFileName());
const QString titleChart = QString("Image Chart - %1").arg(entry->GetName());
const QString titleItems = QString("Image Set - %1").arg(entry->GetName());
QtProperty* chartGroup = groupManager_->addProperty(titleChart);
const auto& chart = img->GetChartProperties();
QtProperty* tProp = doubleManager_->addProperty(tr("timeParam"));
doubleManager_->setValue(tProp, chart.timeParam);
chartGroup->addSubProperty(tProp);
addProperty(chartGroup, idChart);
QtProperty* itemsGroup = groupManager_->addProperty(titleItems);
const auto& items = img->GetImageProperties();
for (int i = 0; i < items.size(); ++i) {
const auto& im = items[i];
QtProperty* item = groupManager_->addProperty(QString("Image[%1]").arg(i));
QtProperty* names = stringManager_->addProperty(tr("names"));
names->setToolTip(tr("File name list"));
stringManager_->setValue(names, im.names.join(", "));
item->addSubProperty(names);
QStringList values;
for (const auto& v : im.datas) values << QString::number(v);
QtProperty* ds = stringManager_->addProperty(tr("datas"));
ds->setToolTip(tr("Image data per file"));
stringManager_->setValue(ds, values.join(", "));
item->addSubProperty(ds);
QtProperty* pth = stringManager_->addProperty(tr("path"));
stringManager_->setValue(pth, im.path);
item->addSubProperty(pth);
QtProperty* sfx = stringManager_->addProperty(tr("suffix"));
stringManager_->setValue(sfx, im.suffix);
item->addSubProperty(sfx);
itemsGroup->addSubProperty(item);
}
addProperty(itemsGroup, idItems);
}
break;
}
default:
break;
}
// 聚焦基础信息组
if (groupBasic) {
QtBrowserItem* item = browser_->topLevelItem(groupBasic);
if (item) {
browser_->setExpanded(item, true);
browser_->setCurrentItem(item);
}
}
return;
}
const QString title = QString("CurveEntry - %1").arg(entry->GetName());
@ -160,6 +520,10 @@ void PropertyBrowser::OnFileEntryChange(const QVariant& value) {
}
}
void PropertyBrowser::OnGroupChange(const QVariant& value) {
browser_->clear();
}
void PropertyBrowser::InitUI() {
QBoxLayout* layout = new QVBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
@ -186,6 +550,7 @@ void PropertyBrowser::InitPropertyManager() {
workSpaceManager_ = new QtWorkspacePropertyManager(this);
entityManager_ = new QtEntityPropertyManager(this);
curveEntryManager_ = new QtCurveEntryPropertyManager(this);
groupManager_ = new QtGroupPropertyManager(this);
QtDoubleSpinBoxFactory* doubleSpinBoxFactory = new QtDoubleSpinBoxFactory(this);
QtCheckBoxFactory* checkBoxFactory = new QtCheckBoxFactory(this);
@ -200,6 +565,8 @@ void PropertyBrowser::InitPropertyManager() {
browser_->setFactoryForManager(boolManager_, checkBoxFactory);
browser_->setFactoryForManager(doubleManager_, doubleSpinBoxFactory);
browser_->setFactoryForManager(stringManager_, lineEditFactory);
// Color properties: use a color dialog editor for the top-level color, keep sub-channel ints editable
browser_->setFactoryForManager(colorManager_, colorFactory);
browser_->setFactoryForManager(colorManager_->subIntPropertyManager(), spinBoxFactory);
browser_->setFactoryForManager(fontManager_->subIntPropertyManager(), spinBoxFactory);
browser_->setFactoryForManager(fontManager_->subBoolPropertyManager(), checkBoxFactory);
@ -228,6 +595,14 @@ void PropertyBrowser::InitPropertyManager() {
browser_->setFactoryForManager(curveEntryManager_->subIntProperyManager(), spinBoxFactory);
browser_->setFactoryForManager(curveEntryManager_->subDoubleProperyManager(), doubleSpinBoxFactory);
browser_->setFactoryForManager(curveEntryManager_->subColorProperyManager(), colorFactory);
// 颜色属性变更信号:触发对应写回处理器
connect(colorManager_, &QtColorPropertyManager::valueChanged, this,
[this](QtProperty* prop, const QColor& color){
if (colorSetters_.contains(prop)) {
colorSetters_[prop](color);
}
});
}
void PropertyBrowser::OnWorkspaceFilesChanged(FileEntryType type, std::shared_ptr<FileEntry> fileEntry) {

View File

@ -2,6 +2,8 @@
#include <QWidget>
#include <QMap>
#include <QColor>
#include <functional>
#include "workspace/FileEntry.h"
class QtProperty;
@ -19,6 +21,7 @@ public:
void OnWorkSpaceChange(const QVariant& value);
void OnEntityChange(const QVariant& value);
void OnFileEntryChange(const QVariant& value);
void OnGroupChange(const QVariant& value);
void OnWorkspaceFilesChanged(enum class FileEntryType type, std::shared_ptr<FileEntry> fileEntry);
void Test();
@ -47,6 +50,7 @@ private:
class QtWorkspacePropertyManager* workSpaceManager_{ nullptr };
class QtEntityPropertyManager* entityManager_{ nullptr };
class QtCurveEntryPropertyManager* curveEntryManager_{ nullptr };
class QtGroupPropertyManager* groupManager_{ nullptr };
QMap<QtProperty*, QString> propertyToId_;
QMap<QString, QtProperty*> idToProperty_;
@ -59,5 +63,8 @@ private:
// When true, we are showing a single FileEntry view (not workspace-wide groups)
bool inFileEntryView_{ false };
// Write-back hooks for color properties
QMap<class QtProperty*, std::function<void(const QColor&)>> colorSetters_;
};

View File

@ -9308,7 +9308,7 @@ void QtMeshComponetManager::SetPropertyValue(QtProperty* property, SceneComponen
}
QString QtMeshComponetManager::GetPropertyId() const {
return tr("MeshComponent");
return QStringLiteral("MeshComponent");
}
/*!
@ -9467,9 +9467,8 @@ void QtPathComponentManager::SetPropertyValue(QtProperty* property, SceneCompone
}
QString QtPathComponentManager::GetPropertyId() const {
return tr("PathComponent");
return QStringLiteral("PathComponent");
}
/*!
Returns the given \a property's value.
@ -9732,7 +9731,7 @@ void QtConeWaveComponentManager::SetPropertyValue(QtProperty* property, SceneCom
}
QString QtConeWaveComponentManager::GetPropertyId() const {
return tr("ConeWaveComponent");
return QStringLiteral("ConeWaveComponent");
}
/*!
@ -10073,7 +10072,7 @@ void QtDashedLineComponentManager::SetPropertyValue(QtProperty* property, SceneC
}
QString QtDashedLineComponentManager::GetPropertyId() const {
return tr("DashedLineComponent");
return QStringLiteral("DashedLineComponent");
}
QDashedLineComponentAttribute QtDashedLineComponentManager::value(const QtProperty* property) const {

View File

@ -53,6 +53,7 @@ void WorkSpace::SetCommondFilePath(const QString& path) {
dirPath.toLocal8Bit().data(),
sucess);
commondPath_ = fileInfo.fileName();
emit CommandsChanged();
}
// Deprecated path APIs removed
@ -147,14 +148,10 @@ bool WorkSpace::SetFileEntryCount(FileEntryType type, int count) {
fileEntry = std::make_shared<FileEntryCurve>();
break;
case FileEntryType::Surface:
// TODO: Create FileEntrySurface when implemented
fileEntry = std::make_shared<FileEntry>();
fileEntry->SetType(FileEntryType::Surface);
fileEntry = std::make_shared<FileEntrySurface>();
break;
case FileEntryType::Table:
// TODO: Create FileEntryTable when implemented
fileEntry = std::make_shared<FileEntry>();
fileEntry->SetType(FileEntryType::Table);
fileEntry = std::make_shared<FileEntryTable>();
break;
case FileEntryType::Light:
fileEntry = std::make_shared<FileEntryLight>();
@ -385,3 +382,66 @@ void WorkSpace::NotifyFileEntryUpdated(FileEntryType type, std::shared_ptr<FileE
++filesSeq_;
emit FilesChanged(type, fileEntry);
}
// 删除指定指针的文件条目(不删除物理文件,仅移出工作空间管理)
bool WorkSpace::RemoveFileEntry(FileEntryType type, FileEntry* entry) {
if (!entry) {
LOG_WARN("RemoveFileEntry: entry is nullptr");
return false;
}
auto it = files_.find(type);
if (it == files_.end()) {
LOG_WARN("RemoveFileEntry: type not found: {}", FileEntryTypeToString(type));
return false;
}
auto& vec = it->second;
auto pos = std::find_if(vec.begin(), vec.end(), [entry](const std::shared_ptr<FileEntry>& sp){ return sp.get() == entry; });
if (pos == vec.end()) {
LOG_WARN("RemoveFileEntry: entry not found in type: {}", FileEntryTypeToString(type));
return false;
}
vec.erase(pos);
++filesSeq_;
emit FilesChanged(type, nullptr);
LOG_INFO("Removed file entry of type: {}", FileEntryTypeToString(type));
return true;
}
// 按索引删除文件条目
bool WorkSpace::RemoveFileEntryAt(FileEntryType type, int index) {
auto it = files_.find(type);
if (it == files_.end()) {
LOG_WARN("RemoveFileEntryAt: type not found: {}", FileEntryTypeToString(type));
return false;
}
auto& vec = it->second;
if (index < 0 || index >= static_cast<int>(vec.size())) {
LOG_WARN("RemoveFileEntryAt: invalid index {} for type {}", index, FileEntryTypeToString(type));
return false;
}
vec.erase(vec.begin() + index);
++filesSeq_;
emit FilesChanged(type, nullptr);
LOG_INFO("Removed file entry at index {} for type {}", index, FileEntryTypeToString(type));
return true;
}
// 按文件名删除文件条目(匹配工作空间内记录的文件名)
bool WorkSpace::RemoveFileEntryByName(FileEntryType type, const QString& fileName) {
auto it = files_.find(type);
if (it == files_.end()) {
LOG_WARN("RemoveFileEntryByName: type not found: {}", FileEntryTypeToString(type));
return false;
}
auto& vec = it->second;
auto pos = std::find_if(vec.begin(), vec.end(), [&fileName](const std::shared_ptr<FileEntry>& sp){ return sp && sp->GetFileName() == fileName; });
if (pos == vec.end()) {
LOG_WARN("RemoveFileEntryByName: file not found: {}", fileName.toUtf8().constData());
return false;
}
vec.erase(pos);
++filesSeq_;
emit FilesChanged(type, nullptr);
LOG_INFO("Removed file entry by name: {} for type {}", fileName.toUtf8().constData(), FileEntryTypeToString(type));
return true;
}

View File

@ -68,12 +68,17 @@ public:
// New unified file entry management
FileEntryResult SetFileEntry(std::shared_ptr<FileEntry> fileEntry, bool is_copy = true);
std::vector<std::shared_ptr<FileEntry>> GetFileEntries(FileEntryType type) const;
std::vector<std::shared_ptr<FileEntry>> GetFileEntries(FileEntryType type) const;
// Manage grouped file entries
bool SetFileEntryCount(FileEntryType type, int count);
QString GetFileEntryAbsPath(FileEntryType type, int index) const;
// Remove file entries
bool RemoveFileEntry(FileEntryType type, class FileEntry* entry);
bool RemoveFileEntryAt(FileEntryType type, int index);
bool RemoveFileEntryByName(FileEntryType type, const QString& fileName);
inline void SetHomeViewpoint(const osgEarth::Viewpoint& viewpoint) {
homeViewpoint_ = viewpoint;
homeViewpoint_.setHeading(0.0); // Ensure heading is set to 0.0
@ -136,6 +141,7 @@ Q_SIGNALS:
void TimestepChanged(class Timestep* timestep);
void LampStatusChanged(class LampStatus* lampStatus);
void FilesChanged(FileEntryType type, std::shared_ptr<FileEntry> fileEntry);
void CommandsChanged();
private:
QString name_;

View File

@ -161,7 +161,9 @@ void WorkSpaceManager::SetCurrent(WorkSpace* workspace) {
}
if (nullptr != current_) {
// Ensure previous workspace is properly ended and unloaded
current_->End();
current_->Unlaod();
}
current_ = workspace;
workspace->SetActiveScene(scene_);