diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 4d43f4e..bbe0e46 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -82,6 +82,7 @@ add_executable(geopro_desktop WIN32 panels/columns/Column3DDataset.cpp panels/columns/Column3DAnalysis.cpp panels/columns/CategorySection.cpp + panels/columns/CategoryAnalysisTab.cpp panels/columns/ColumnDrawer.cpp panels/AnomalyTablePanel.cpp panels/LoadingOverlay.cpp diff --git a/src/app/panels/columns/CategoryAnalysisTab.cpp b/src/app/panels/columns/CategoryAnalysisTab.cpp new file mode 100644 index 0000000..f719751 --- /dev/null +++ b/src/app/panels/columns/CategoryAnalysisTab.cpp @@ -0,0 +1,67 @@ +#include "panels/columns/CategoryAnalysisTab.hpp" + +#include +#include + +#include "Theme.hpp" +#include "panels/columns/CategorySection.hpp" + +namespace geopro::app { + +CategoryAnalysisTab::CategoryAnalysisTab(geopro::data::DatasetFieldDictionary* dict, QWidget* parent) + : QWidget(parent) { + auto* outer = new QVBoxLayout(this); + outer->setContentsMargins(0, 0, 0, 0); + outer->setSpacing(0); + + auto* scroll = new QScrollArea(this); + scroll->setWidgetResizable(true); + scroll->setFrameShape(QFrame::NoFrame); + outer->addWidget(scroll, 1); + + auto* content = new QWidget(scroll); + auto* col = new QVBoxLayout(content); + col->setContentsMargins(0, 0, 0, 0); + col->setSpacing(space::kSm); + + for (const CategorySpec& spec : categoryConfigs()) { + auto* sec = new CategorySection(spec, dict, content); + sections_[spec.id] = sec; + const std::string segId = spec.id; + connect(sec, &CategorySection::checkedDatasetsChanged, this, + [this, segId](const QStringList& ids) { + checkedBySeg_[segId] = ids; + recomputeCheckedUnion(); + }); + connect(sec, &CategorySection::generateVolumeRequested, this, + &CategoryAnalysisTab::generateVolumeRequested); + connect(sec, &CategorySection::detailRequested, this, &CategoryAnalysisTab::detailRequested); + col->addWidget(sec); + } + col->addStretch(1); + scroll->setWidget(content); +} + +void CategoryAnalysisTab::setBuckets(const CategoryBuckets& b) { + const auto& cfg = categoryConfigs(); + for (std::size_t i = 0; i < cfg.size() && i < b.segments.size(); ++i) { + if (auto* sec = section(cfg[i].id)) sec->setDatasets(b.segments[i]); + } +} + +void CategoryAnalysisTab::setStructure(const std::vector& nodes) { + for (auto& [id, sec] : sections_) sec->setStructure(nodes); +} + +CategorySection* CategoryAnalysisTab::section(const std::string& id) const { + const auto it = sections_.find(id); + return it != sections_.end() ? it->second : nullptr; +} + +void CategoryAnalysisTab::recomputeCheckedUnion() { + QStringList all; // ds 归属唯一段,跨段不重复,直接拼接 + for (const auto& [id, ids] : checkedBySeg_) all += ids; + emit checkedDatasetsChanged(all); +} + +} // namespace geopro::app diff --git a/src/app/panels/columns/CategoryAnalysisTab.hpp b/src/app/panels/columns/CategoryAnalysisTab.hpp new file mode 100644 index 0000000..967a337 --- /dev/null +++ b/src/app/panels/columns/CategoryAnalysisTab.hpp @@ -0,0 +1,41 @@ +#pragma once +#include +#include +#include +#include +#include +#include "DatasetCategory.hpp" // CategoryBuckets +#include "repo/RepoTypes.hpp" + +namespace geopro::data { +class DatasetFieldDictionary; +} + +namespace geopro::app { + +class CategorySection; + +// 「三维分析」tab:QScrollArea 竖向堆叠 5 个数据类型大类段(spec §4)。 +// 各段勾选合并为并集上抛;生成/详情请求透传。 +class CategoryAnalysisTab : public QWidget { + Q_OBJECT +public: + explicit CategoryAnalysisTab(geopro::data::DatasetFieldDictionary* dict, QWidget* parent = nullptr); + + void setBuckets(const CategoryBuckets& b); // 分发到 5 段(与 categoryConfigs 同序) + void setStructure(const std::vector& nodes); // 转发各段 + CategorySection* section(const std::string& id) const; // 按 CategorySpec.id 取段 + +signals: + void checkedDatasetsChanged(const QStringList& dsIds); // 5 段勾选并集 + void generateVolumeRequested(const QString& dsTypeCode, const QStringList& sourceDsIds); + void detailRequested(const QString& dsId, const QString& ddCode, const QString& name); + +private: + void recomputeCheckedUnion(); + + std::map sections_; + std::map checkedBySeg_; // 各段当前勾选(合并成并集) +}; + +} // namespace geopro::app diff --git a/src/app/panels/columns/ColumnDrawer.cpp b/src/app/panels/columns/ColumnDrawer.cpp index 9a62f65..4e25e17 100644 --- a/src/app/panels/columns/ColumnDrawer.cpp +++ b/src/app/panels/columns/ColumnDrawer.cpp @@ -2,6 +2,7 @@ #include "panels/columns/Column3DDataset.hpp" #include "panels/columns/Column2DDataset.hpp" #include "panels/columns/Column3DAnalysis.hpp" +#include "panels/columns/CategoryAnalysisTab.hpp" #include "Glyphs.hpp" #include "Theme.hpp" #include @@ -10,20 +11,22 @@ namespace geopro::app { -ColumnDrawer::ColumnDrawer(QWidget* parent) +ColumnDrawer::ColumnDrawer(QWidget* parent, geopro::data::DatasetFieldDictionary* dict) : QWidget(parent) { - // 创建三个栏 - col3D_ = new Column3DDataset(this); - col2D_ = new Column2DDataset(this); + col2D_ = new Column2DDataset(this); + analysisTab_ = new CategoryAnalysisTab(dict, this); + // 过渡:旧三维数据集/三维分析栏仍实例化以兼容 main 现有接线,但隐藏、不入 tab(Task 12 退役)。 + col3D_ = new Column3DDataset(this); colAnalysis_ = new Column3DAnalysis(this); + col3D_->hide(); + colAnalysis_->hide(); - // Tab 容器(body_) + // Tab 容器(body_):两 tab(三维分析[分段] / 二维分析)。 auto* tabs = new QTabWidget(this); body_ = tabs; - tabs->addTab(col3D_, QStringLiteral("三维数据集")); - tabs->addTab(col2D_, QStringLiteral("二维数据集")); - tabs->addTab(colAnalysis_, QStringLiteral("三维分析")); + tabs->addTab(analysisTab_, QStringLiteral("三维分析")); + tabs->addTab(col2D_, QStringLiteral("二维分析")); // 折叠按钮:固定宽 18px,垂直拉伸。 // 用 SVG 图标(makeGlyph)而非 ◀/▶ 文字——三角符(U+25C0/25B6)不在 YaHei,作按钮文字会触发 diff --git a/src/app/panels/columns/ColumnDrawer.hpp b/src/app/panels/columns/ColumnDrawer.hpp index 500e88f..ce60442 100644 --- a/src/app/panels/columns/ColumnDrawer.hpp +++ b/src/app/panels/columns/ColumnDrawer.hpp @@ -3,30 +3,39 @@ class QPushButton; +namespace geopro::data { +class DatasetFieldDictionary; +} + namespace geopro::app { class Column3DDataset; class Column2DDataset; class Column3DAnalysis; +class CategoryAnalysisTab; -// VTK视图左侧内嵌抽屉:三 tab(三维数据集/二维数据集/三维分析) + 折叠开关。 +// VTK视图左侧内嵌抽屉:两 tab(三维分析[按数据类型分段]/二维分析) + 折叠开关。 +// 旧 col3D_/colAnalysis_ 仍实例化但隐藏(不入 tab),保留访问器供 main 现有接线过渡,Task 12 退役。 class ColumnDrawer : public QWidget { Q_OBJECT public: - explicit ColumnDrawer(QWidget* parent = nullptr); + explicit ColumnDrawer(QWidget* parent = nullptr, + geopro::data::DatasetFieldDictionary* dict = nullptr); - Column3DDataset* col3D() const { return col3D_; } + Column3DDataset* col3D() const { return col3D_; } // 【过渡,Task 12 删】 Column2DDataset* col2D() const { return col2D_; } - Column3DAnalysis* colAnalysis() const { return colAnalysis_; } + Column3DAnalysis* colAnalysis() const { return colAnalysis_; } // 【过渡,Task 12 删】 + CategoryAnalysisTab* analysisTab() const { return analysisTab_; } public slots: void toggleCollapsed(); void expand(); // 强制展开(进入全屏时确保三栏可见) private: - Column3DDataset* col3D_ = nullptr; + Column3DDataset* col3D_ = nullptr; // 【过渡,隐藏不入 tab,Task 12 删】 Column2DDataset* col2D_ = nullptr; - Column3DAnalysis* colAnalysis_ = nullptr; + Column3DAnalysis* colAnalysis_ = nullptr; // 【过渡,隐藏不入 tab,Task 12 删】 + CategoryAnalysisTab* analysisTab_ = nullptr; QWidget* body_ = nullptr; // QTabWidget,折叠时隐藏 QPushButton* toggleBtn_ = nullptr; bool collapsed_ = false;