feat(app): ObjectTreePanel 被动对象树(项目→GS→TM)
This commit is contained in:
parent
6e78e50b0b
commit
c78022a6b6
|
|
@ -21,7 +21,8 @@ add_executable(geopro_desktop WIN32
|
||||||
PanelHeader.cpp
|
PanelHeader.cpp
|
||||||
login/LoginWindow.cpp
|
login/LoginWindow.cpp
|
||||||
panels/AnomalyListPanel.cpp
|
panels/AnomalyListPanel.cpp
|
||||||
panels/DatasetListPanel.cpp)
|
panels/DatasetListPanel.cpp
|
||||||
|
panels/ObjectTreePanel.cpp)
|
||||||
|
|
||||||
target_include_directories(geopro_desktop PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(geopro_desktop PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
|
|
@ -34,6 +35,7 @@ target_link_libraries(geopro_desktop PRIVATE
|
||||||
geopro_data # Phase 2:本地样本仓储(对象树 / 网格 / 色阶)
|
geopro_data # Phase 2:本地样本仓储(对象树 / 网格 / 色阶)
|
||||||
geopro_net # Phase 3:登录(验证码 + RSA + login2)
|
geopro_net # Phase 3:登录(验证码 + RSA + login2)
|
||||||
geopro_render # Phase 4:render 层(Scene / GridContourActor / 相机预设)
|
geopro_render # Phase 4:render 层(Scene / GridContourActor / 相机预设)
|
||||||
|
geopro_controller # Phase 5:导航编排(WorkbenchNavController)
|
||||||
)
|
)
|
||||||
|
|
||||||
vtk_module_autoinit(TARGETS geopro_desktop MODULES ${VTK_LIBRARIES})
|
vtk_module_autoinit(TARGETS geopro_desktop MODULES ${VTK_LIBRARIES})
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
#include "panels/ObjectTreePanel.hpp"
|
||||||
|
|
||||||
|
#include <QColor>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QSignalBlocker>
|
||||||
|
#include <QTreeWidget>
|
||||||
|
#include <QTreeWidgetItem>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
#include "Glyphs.hpp"
|
||||||
|
#include "dto/NavDto.hpp"
|
||||||
|
|
||||||
|
namespace geopro::app {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// TM 节点把 tmObjectId 存在该角色;GS/项目根节点为空。
|
||||||
|
constexpr int kRoleTmId = Qt::UserRole + 2;
|
||||||
|
|
||||||
|
void addNodes(QTreeWidgetItem* parent, const std::vector<data::dto::StructTreeNode>& nodes) {
|
||||||
|
for (const auto& n : nodes) {
|
||||||
|
auto* item = new QTreeWidgetItem(parent);
|
||||||
|
item->setText(0, QString::fromStdString(n.node.name));
|
||||||
|
if (n.isTm) {
|
||||||
|
item->setData(0, kRoleTmId, QString::fromStdString(n.node.id));
|
||||||
|
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||||
|
item->setCheckState(0, Qt::Unchecked); // 真实数据渲染下一轮接入,默认不勾
|
||||||
|
}
|
||||||
|
addNodes(item, n.children);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
ObjectTreePanel::ObjectTreePanel(QWidget* parent) : QWidget(parent) {
|
||||||
|
auto* lay = new QVBoxLayout(this);
|
||||||
|
lay->setContentsMargins(0, 0, 0, 0);
|
||||||
|
lay->setSpacing(0);
|
||||||
|
|
||||||
|
tree_ = new QTreeWidget(this);
|
||||||
|
tree_->setHeaderHidden(true);
|
||||||
|
{
|
||||||
|
const QString openArrow = writeChevronIcon(true, QColor("#8A93A3"));
|
||||||
|
const QString closedArrow = writeChevronIcon(false, QColor("#8A93A3"));
|
||||||
|
tree_->setStyleSheet(
|
||||||
|
QStringLiteral("QTreeView::branch { background: #FFFFFF; }"
|
||||||
|
"QTreeView::branch:has-children:!has-siblings:closed,"
|
||||||
|
"QTreeView::branch:closed:has-children:has-siblings { image: url(%1); }"
|
||||||
|
"QTreeView::branch:open:has-children:!has-siblings,"
|
||||||
|
"QTreeView::branch:open:has-children:has-siblings { image: url(%2); }")
|
||||||
|
.arg(closedArrow, openArrow));
|
||||||
|
}
|
||||||
|
lay->addWidget(tree_, 1);
|
||||||
|
|
||||||
|
hint_ = new QLabel(QStringLiteral("(加载中…)"), this);
|
||||||
|
hint_->setAlignment(Qt::AlignCenter);
|
||||||
|
hint_->setStyleSheet(QStringLiteral("color:#9AA6B6; padding:16px;"));
|
||||||
|
hint_->setVisible(false);
|
||||||
|
lay->addWidget(hint_);
|
||||||
|
|
||||||
|
QObject::connect(tree_, &QTreeWidget::itemClicked, this, [this](QTreeWidgetItem* item, int) {
|
||||||
|
const QString tmId = item->data(0, kRoleTmId).toString();
|
||||||
|
if (!tmId.isEmpty()) emit tmClicked(tmId);
|
||||||
|
});
|
||||||
|
QObject::connect(tree_, &QTreeWidget::itemChanged, this, [this](QTreeWidgetItem* item, int) {
|
||||||
|
const QString tmId = item->data(0, kRoleTmId).toString();
|
||||||
|
if (!tmId.isEmpty())
|
||||||
|
emit tmCheckToggled(tmId, item->checkState(0) == Qt::Checked);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjectTreePanel::setStructure(const QString& projectName,
|
||||||
|
const std::vector<data::StructNode>& nodes) {
|
||||||
|
const QSignalBlocker block(tree_); // 重建触发 itemChanged,先屏蔽
|
||||||
|
tree_->clear();
|
||||||
|
const auto roots = data::dto::buildStructTree(nodes);
|
||||||
|
if (roots.empty()) {
|
||||||
|
showMessage(projectName.isEmpty() ? QStringLiteral("(暂无项目)")
|
||||||
|
: QStringLiteral("(该项目暂无结构)"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
hint_->setVisible(false);
|
||||||
|
tree_->setVisible(true);
|
||||||
|
auto* rootItem = new QTreeWidgetItem(tree_);
|
||||||
|
rootItem->setText(0, projectName.isEmpty() ? QStringLiteral("项目") : projectName);
|
||||||
|
addNodes(rootItem, roots);
|
||||||
|
tree_->expandAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjectTreePanel::showMessage(const QString& message) {
|
||||||
|
tree_->clear();
|
||||||
|
tree_->setVisible(false);
|
||||||
|
hint_->setText(message);
|
||||||
|
hint_->setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace geopro::app
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
#pragma once
|
||||||
|
#include <QWidget>
|
||||||
|
#include <vector>
|
||||||
|
#include "repo/RepoTypes.hpp"
|
||||||
|
|
||||||
|
class QTreeWidget;
|
||||||
|
class QLabel;
|
||||||
|
|
||||||
|
namespace geopro::app {
|
||||||
|
|
||||||
|
// 被动对象树:项目根 → GS → TM(叶子=TM,可勾选)。数据来自控制器;自身不发请求。
|
||||||
|
class ObjectTreePanel : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit ObjectTreePanel(QWidget* parent = nullptr);
|
||||||
|
|
||||||
|
// 用扁平结构节点重建树(内部调 dto::buildStructTree)。
|
||||||
|
void setStructure(const QString& projectName, const std::vector<data::StructNode>& nodes);
|
||||||
|
void showMessage(const QString& message); // 错误/空状态占位
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void tmClicked(const QString& tmObjectId);
|
||||||
|
void tmCheckToggled(const QString& tmObjectId, bool checked);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QTreeWidget* tree_ = nullptr;
|
||||||
|
QLabel* hint_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace geopro::app
|
||||||
Loading…
Reference in New Issue