From 50c4de4019bf4d77e27a5aade80af02e3042dea4 Mon Sep 17 00:00:00 2001 From: gaozheng Date: Mon, 8 Jun 2026 09:33:06 +0800 Subject: [PATCH] =?UTF-8?q?feat(view):=20=E5=B7=A6=E4=B8=8B=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=88=97=E8=A1=A8=20+=20=E5=AF=B9=E8=B1=A1=E6=A0=91?= =?UTF-8?q?=E6=94=B6=E5=88=B0=E6=B5=8B=E7=BA=BF=E5=B1=82(=E5=AF=B9?= =?UTF-8?q?=E9=BD=90=E5=8E=9F=E5=9E=8B,=20=E5=A2=9E=E9=87=8F2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 对象树 GS→TM(测线复选, UserRole+2=tmId); DS(采集批次)移出树, 入左下「数据真实显示栏」 (QTabWidget 数据/文件; panels/DatasetListPanel)。findTm 按 tmId 查 TM。 - 中央 rebuildCentral 改遍历勾选的测线 → 渲染其 dd_section(可多条共存)。 - 树单击测线→填数据列表; 数据列表单击采集批次→loadDataset(数据详情+异常列表+属性,抽共享 lambda)。 - 启动自动选首个含 dd_section 的测线 + 首数据集(对齐原型默认载入态)。 - structure 取一次共享; app 构建干净; 待人工登录复核。 --- docs/superpowers/STATUS.md | 5 +- .../plans/2026-06-08-m1-prototype-layout.md | 6 +- src/app/CMakeLists.txt | 3 +- src/app/main.cpp | 198 +++++++++++------- src/app/panels/DatasetListPanel.cpp | 37 ++++ src/app/panels/DatasetListPanel.hpp | 19 ++ 6 files changed, 194 insertions(+), 74 deletions(-) create mode 100644 src/app/panels/DatasetListPanel.cpp create mode 100644 src/app/panels/DatasetListPanel.hpp diff --git a/docs/superpowers/STATUS.md b/docs/superpowers/STATUS.md index 4997300..b92c36a 100644 --- a/docs/superpowers/STATUS.md +++ b/docs/superpowers/STATUS.md @@ -13,7 +13,8 @@ 桌面 app `geopro_desktop`: - **真实登录**:LoginWindow(用户名/密码/图形验证码/记住)→ `verifyCodeCheck` → RSA 加密密码 → `login2` → token → 进工作台。**真机登录成功**;输入框样式已修(三态白底深字)。 - **工作台 ADS 三区 + 数据详情**: - - **左 对象树**:GS→TM→DS,复选框勾选 → 控制中央显示哪些测线。 + - **左上 对象显示栏**:GS→TM(测线),复选框勾选测线 → 控制中央显示哪些测线的 dd_section。 + - **左下 数据真实显示栏**(对齐原型):单击测线 → 列其采集批次(数据集,tab 数据/文件);单击采集批次 → 数据详情+异常列表+属性。启动自动选首测线+首数据集。 - **中央 二维地图 / 三维视图**(两个**真内容**,非相机切换): - 二维地图 = `MapLineActor`:测线 `lat/lon` 轨迹**红线**俯视(浅底),像地图。 - 三维视图 = `CurtainActor`:沿测线的**竖直断面墙**(分段色带,z 纵向夸张×3,沿弯曲测线弯)。中央工具条**仅**「二维地图/三维视图」(对齐原型,无体素按钮)。 @@ -76,7 +77,7 @@ 9. render 仍部分内联在 main.cpp;可逐步抽到 view/controller。 10. **布局对齐原型**(权威参考 `http://prototype.geomative.cn/`;截图存 `.playwright-mcp/`)。**计划见 `plans/2026-06-08-m1-prototype-layout.md`(六面板 + view/ 抽取,增量序列)**。进度: - ✅ **增量1 右上「异常列表」**(2026-06-08,`panels/AnomalyListPanel`,与数据详情显隐联动;待人工复核)。 - - ⬜ **增量2 左下「数据列表」**+ 对象树到 TM 层(DS 移出树入数据列表)。 + - ✅ **增量2 左下「数据列表」+ 对象树到 TM 层**(2026-06-08,`panels/DatasetListPanel`;树 GS→TM 复选驱动中央, DS 移出树入数据列表 tab 数据/文件, DS 单击→详情+异常+属性, 启动自动选首测线/首数据集;待人工复核)。 - ⬜ **增量3 3D「视图详情」图层浮层**(体素的正确归宿;体素引擎已就绪,UI 待此接入)。 - ⬜ **增量4 数据详情富工具条 + 电极标记 + 数值标签**;底图影像=DEM/底图任务。 - 架构:新面板抽到 `src/app/panels/`(暂随 app 编译,如 login/),控制 main.cpp 体量;后续可升 `src/view/` 库。 diff --git a/docs/superpowers/plans/2026-06-08-m1-prototype-layout.md b/docs/superpowers/plans/2026-06-08-m1-prototype-layout.md index b38af1d..ad1b22b 100644 --- a/docs/superpowers/plans/2026-06-08-m1-prototype-layout.md +++ b/docs/superpowers/plans/2026-06-08-m1-prototype-layout.md @@ -58,7 +58,11 @@ - 放右上 dock(与"属性"分上下或 tab)。**人工复核**:单击数据集→右上列出 3 异常;眼睛切换隐藏对应虚线。 - 提交 `feat(view): 右上异常列表面板 + 与数据详情异常显隐联动`。 -### 增量 2:左下「数据列表」+ 树结构调整(树到 TM,DS 入数据列表) +### 增量 2:左下「数据列表」+ 树结构调整 ✅ 已完成(2026-06-08) +> `panels/DatasetListPanel`(populateDatasetList)。树 `populateTree` 改 GS→TM(测线复选,UserRole+2=tmId); +> `findTm` 按 tmId 查 TM。中央 rebuildCentral 改遍历勾选 TM→渲染其 dd_section。左下 dock = QTabWidget +> (数据 QListWidget / 文件占位)。树单击 TM→填数据列表;数据列表单击 DS→`loadDataset`(详情+异常+属性, +> 抽成共享 lambda)。启动自动选首含 dd_section 的测线+首数据集。app 构建净;**待人工复核**。**原计划存档**: - repo.loadStructure 改为树到 **TM** 层(GS→TM),DS 不再进树;新增 `listDatasets(tmId)` 或复用结构。 (当前样本仅 1 DS grid1 挂 ERT1;多 TM/DS 为 mock 结构,先支持单条,预留多条。) - `src/view/panels/DatasetListPanel`:tab 数据/文件;列选中 TM 的采集批次;单击 → 数据详情 + 属性。 diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 4929d5c..915d1d7 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -15,7 +15,8 @@ find_package(nlohmann_json CONFIG REQUIRED) add_executable(geopro_desktop WIN32 main.cpp login/LoginWindow.cpp - panels/AnomalyListPanel.cpp) + panels/AnomalyListPanel.cpp + panels/DatasetListPanel.cpp) target_include_directories(geopro_desktop PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/src/app/main.cpp b/src/app/main.cpp index bc18d11..c355186 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -1,5 +1,6 @@ // M1 工作台(视图重构 Task B):正确产品模型。 -// - 左 对象树:GS→TM→DS(复选框)。勾选 dd_section → 在中央当前视图显示该数据集,可多条共存。 +// - 左上 对象显示栏:GS→TM(测线,复选框)。勾选测线 → 在中央显示其 dd_section,可多条共存。 +// - 左下 数据真实显示栏:单击测线 → 列其采集批次(数据集,tab 数据/文件)。单击采集批次 → 数据详情+异常+属性。 // - 中央「二维地图 / 三维视图」:两个互斥视图(内容不同,不是同一物体换相机)。 // 二维地图 = 对每个勾选数据集 buildSurveyLine(lat/lon 红线俯视,z=0)+ applyTop2D(浅底背景)。 // 三维视图 = 对每个勾选数据集 buildCurtain(竖直断面墙),actor SetScale(1,1,3) 纵向夸张 + applyFree3D(白底)。 @@ -28,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +49,7 @@ #include "AuthService.hpp" #include "login/LoginWindow.hpp" #include "panels/AnomalyListPanel.hpp" +#include "panels/DatasetListPanel.hpp" #include "CameraPreset.hpp" #include "Scene.hpp" @@ -70,13 +73,12 @@ namespace { -// 角色:DS 项的 dd 类型存在 UserRole+1(dsId 存在 UserRole)。 -constexpr int kRoleDsId = Qt::UserRole; -constexpr int kRoleDdType = Qt::UserRole + 1; +// 角色:树 TM 项存 tmId(UserRole+2);数据列表 DS 项的 dsId/ddType 由 panels/DatasetListPanel 定义。 +constexpr int kRoleTmId = Qt::UserRole + 2; -// 从对象结构树构建 QTreeWidget:GS → TM → DS 三层。 -// DS 项可勾选(复选框):勾选驱动该测线竖直帘面在中央场景显示;UserRole 存 dsId、UserRole+1 存 ddType。 -// 网格剖面(dd_section)默认勾选,启动即显示帘面。 +// 从对象结构树构建 QTreeWidget:GS → TM 两层(对齐原型;DS=采集批次在左下「数据列表」,不进树)。 +// TM(测线) 项可勾选(复选框):勾选驱动该测线的 dd_section 在中央场景显示;UserRole+2 存 tmId。 +// 含 dd_section 的测线默认勾选,启动即显示。 void populateTree(QTreeWidget* tree, const std::vector& gss) { for (const auto& gs : gss) { @@ -85,21 +87,27 @@ void populateTree(QTreeWidget* tree, const std::vector& gs for (const auto& tm : gs.tms) { auto* tmItem = new QTreeWidgetItem(gsItem); tmItem->setText(0, QString::fromStdString(tm.name)); - for (const auto& ds : tm.dss) { - auto* dsItem = new QTreeWidgetItem(tmItem); - dsItem->setText(0, QString::fromStdString(ds.name)); - dsItem->setData(0, kRoleDsId, QString::fromStdString(ds.id)); - dsItem->setData(0, kRoleDdType, QString::fromStdString(ds.ddType)); - dsItem->setFlags(dsItem->flags() | Qt::ItemIsUserCheckable); - // 网格剖面默认勾选 → 启动即显帘面;其余默认不勾。 - dsItem->setCheckState( - 0, ds.ddType == "dd_section" ? Qt::Checked : Qt::Unchecked); - } + tmItem->setData(0, kRoleTmId, QString::fromStdString(tm.id)); + tmItem->setFlags(tmItem->flags() | Qt::ItemIsUserCheckable); + const bool hasSection = + std::any_of(tm.dss.begin(), tm.dss.end(), + [](const geopro::data::DsNode& d) { return d.ddType == "dd_section"; }); + tmItem->setCheckState(0, hasSection ? Qt::Checked : Qt::Unchecked); } } tree->expandAll(); } +// 在结构中按 tmId 查 TM;找不到返回 nullptr。 +const geopro::data::TmNode* findTm(const std::vector& gss, + const std::string& tmId) +{ + for (const auto& gs : gss) + for (const auto& tm : gs.tms) + if (tm.id == tmId) return &tm; + return nullptr; +} + // 读取 RSA 公钥 PEM 全文(登录时密码加密用)。读不到返回空串,登录将报错。 std::string readPem(const std::string& path) { @@ -225,13 +233,27 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re // 放在中央视图下方。 dockManager->addDockWidget(ads::BottomDockWidgetArea, detailDock, centerDockArea); - // 左 dock:对象树。 + // 项目结构(GS→TM→DS):取一次共享,供树/中央/数据列表查 TM 的数据集。 + auto structure = std::make_shared>(repo.loadStructure()); + + // 左上 dock:对象树(GS→TM,测线复选)。 auto* tree = new QTreeWidget(); - tree->setHeaderLabel(QStringLiteral("对象")); - populateTree(tree, repo.loadStructure()); - auto* leftDock = new ads::CDockWidget(QStringLiteral("对象列表")); + tree->setHeaderLabel(QStringLiteral("对象显示栏")); + populateTree(tree, *structure); + auto* leftDock = new ads::CDockWidget(QStringLiteral("对象显示栏")); leftDock->setWidget(tree); - dockManager->addDockWidget(ads::LeftDockWidgetArea, leftDock); + auto* leftArea = dockManager->addDockWidget(ads::LeftDockWidgetArea, leftDock); + + // 左下 dock:数据真实显示栏(选中测线后列其采集批次=数据集;tab 数据/文件)。 + auto* datasetTabs = new QTabWidget(); + auto* datasetList = new QListWidget(); + datasetList->setAlternatingRowColors(true); + datasetTabs->addTab(datasetList, QStringLiteral("数据")); + auto* fileList = new QListWidget(); // M1 文件 tab 占位 + datasetTabs->addTab(fileList, QStringLiteral("文件")); + auto* datasetDock = new ads::CDockWidget(QStringLiteral("数据真实显示栏")); + datasetDock->setWidget(datasetTabs); + dockManager->addDockWidget(ads::BottomDockWidgetArea, datasetDock, leftArea); // 右上 dock:异常列表(对齐原型;颜色块 + 名称 + 位置/深/尺寸 + 勾选显隐,与数据详情异常联动)。 auto* anomalyList = new QListWidget(); @@ -250,30 +272,19 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re dockManager->addDockWidget(ads::BottomDockWidgetArea, propDock, rightArea); // ── 中央视图重建(核心)───────────────────────────────────────────── - // 两个互斥视图按当前勾选集整体重建:scene.clear() → 对每个勾选 dd_section 加对应 actor。 + // 按勾选的测线(TM)整体重建:scene.clear() → 对每个勾选 TM 的 dd_section 加对应 actor。 // 二维地图 = buildSurveyLine(红线俯视,浅底背景)+ applyTop2D。 // 三维视图 = buildCurtain(断面墙)SetScale(1,1,kCurtainZScale) + applyFree3D(白底)。 - // frame 全局共享;切视图/勾选变化都调用此函数重建当前视图。 - auto rebuildCentral = [scene, rendererPtr, renderWindowPtr, viewMode, &repo, frame, tree]() { + // frame/structure 全局共享;切视图/勾选变化都调用此函数重建当前视图。 + auto rebuildCentral = [scene, rendererPtr, renderWindowPtr, viewMode, &repo, frame, tree, + structure]() { scene->clear(); const bool is2D = (*viewMode == ViewMode::Map2D); rendererPtr->SetBackground(is2D ? 0.96 : 1.0, is2D ? 0.97 : 1.0, is2D ? 0.99 : 1.0); - // 遍历对象树收集所有勾选的 dd_section,逐个加入当前视图内容。 - QList stack; - for (int i = 0; i < tree->topLevelItemCount(); ++i) stack.append(tree->topLevelItem(i)); - while (!stack.isEmpty()) { - QTreeWidgetItem* cur = stack.takeFirst(); - for (int i = 0; i < cur->childCount(); ++i) stack.append(cur->child(i)); - - const QString dsId = cur->data(0, kRoleDsId).toString(); - if (dsId.isEmpty()) continue; // GS/TM 节点忽略 - if (cur->checkState(0) != Qt::Checked) continue; // 仅显示勾选的 - const QString ddType = cur->data(0, kRoleDdType).toString(); - if (ddType != "dd_section") continue; // 当前仅支持剖面网格 - - const std::string id = dsId.toStdString(); + // 渲染单个 dd_section 数据集到当前视图。 + auto renderSection = [&](const std::string& id) { const auto g = repo.loadGrid(id); if (is2D) { auto line = geopro::render::buildSurveyLine(g, *frame); @@ -286,6 +297,22 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re scene->addActor(curtain); } } + }; + + // 遍历对象树收集所有勾选的测线(TM),渲染其 dd_section 数据集(可多条共存)。 + QList stack; + for (int i = 0; i < tree->topLevelItemCount(); ++i) stack.append(tree->topLevelItem(i)); + while (!stack.isEmpty()) { + QTreeWidgetItem* cur = stack.takeFirst(); + for (int i = 0; i < cur->childCount(); ++i) stack.append(cur->child(i)); + + const QString tmId = cur->data(0, kRoleTmId).toString(); + if (tmId.isEmpty()) continue; // GS 节点忽略 + if (cur->checkState(0) != Qt::Checked) continue; // 仅显示勾选的测线 + const auto* tm = findTm(*structure, tmId.toStdString()); + if (!tm) continue; + for (const auto& ds : tm->dss) + if (ds.ddType == "dd_section") renderSection(ds.id); } if (is2D) @@ -296,13 +323,22 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re renderWindowPtr->Render(); }; - // 勾选/取消某 dd_section → 重建当前视图内容(勾的才显示;可多条共存)。 + // 勾选/取消某测线(TM) → 重建当前视图内容(勾的才显示;可多条共存)。 QObject::connect(tree, &QTreeWidget::itemChanged, tree, [rebuildCentral](QTreeWidgetItem* item, int) { - if (item->data(0, kRoleDsId).toString().isEmpty()) return; // GS/TM 忽略 + if (item->data(0, kRoleTmId).toString().isEmpty()) return; // GS 忽略 rebuildCentral(); }); + // 单击测线(TM) → 左下数据列表填充其采集批次(数据集)。 + QObject::connect(tree, &QTreeWidget::itemClicked, tree, + [structure, datasetList](QTreeWidgetItem* item, int) { + const QString tmId = item->data(0, kRoleTmId).toString(); + if (tmId.isEmpty()) return; // GS 节点无数据集 + const auto* tm = findTm(*structure, tmId.toStdString()); + if (tm) geopro::app::populateDatasetList(datasetList, tm->dss); + }); + // ── 数据详情共享状态 + 重建 ────────────────────────────────────────── // 当前选中数据集 id(空=未选)与详情显示模式(反演剖面/原数据);切模式或换选中都重建。 auto currentDsId = std::make_shared(); @@ -359,37 +395,41 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re detailRenderWindowPtr->Render(); }; - // ── 单击 DS → 记选中 + 重建数据详情 + 右侧属性(与勾选区分;不改帘面可见性)── - QObject::connect( - tree, &QTreeWidget::itemClicked, tree, - [&repo, propLabel, currentDsId, rebuildDetail, anomalyList, hiddenAnoms]( - QTreeWidgetItem* item, int) { - const QString dsId = item->data(0, kRoleDsId).toString(); - if (dsId.isEmpty()) return; // GS/TM 节点无详情 - const QString ddType = item->data(0, kRoleDdType).toString(); - if (ddType != "dd_section") return; - const QString name = item->text(0); + // 加载某数据集到「数据详情 + 异常列表 + 属性」(数据列表单击与启动默认共用)。 + auto loadDataset = [&repo, propLabel, currentDsId, rebuildDetail, anomalyList, hiddenAnoms]( + const QString& dsId, const QString& name) { + if (dsId.isEmpty()) return; + *currentDsId = dsId; - *currentDsId = dsId; + // 右上异常列表:按该数据集异常重填(默认全显);先清隐藏集再填,避免重建时阻塞信号回灌。 + const auto anomalies = repo.loadAnomalies(dsId.toStdString()); + hiddenAnoms->clear(); + { + const QSignalBlocker block(anomalyList); // 重填触发 itemChanged,先屏蔽 + geopro::app::populateAnomalyList(anomalyList, anomalies); + } - // 右上异常列表:按该数据集异常重填(默认全显);先清隐藏集再填,避免重建时阻塞信号回灌。 - const auto anomalies = repo.loadAnomalies(dsId.toStdString()); - hiddenAnoms->clear(); - { - const QSignalBlocker block(anomalyList); // 重填触发 itemChanged,先屏蔽 - geopro::app::populateAnomalyList(anomalyList, anomalies); - } + rebuildDetail(); - rebuildDetail(); + // 右下属性(数据集级,与详情模式无关)。 + const auto g = repo.loadGrid(dsId.toStdString()); + propLabel->setText( + QStringLiteral("数据集: %1\n类型: 剖面网格 (dd_section)\n网格: %2 x %3\n" + "vmin / vmax: %4 / %5\n异常: %6 个") + .arg(name).arg(g.nx()).arg(g.ny()).arg(g.vmin).arg(g.vmax) + .arg(anomalies.size())); + }; - // 右下属性(数据集级,与详情模式无关)。 - const auto g = repo.loadGrid(dsId.toStdString()); - propLabel->setText( - QStringLiteral("数据集: %1\n类型: 剖面网格 (dd_section)\n网格: %2 x %3\n" - "vmin / vmax: %4 / %5\n异常: %6 个") - .arg(name).arg(g.nx()).arg(g.ny()).arg(g.vmin).arg(g.vmax) - .arg(anomalies.size())); - }); + // ── 单击左下数据列表的采集批次(DS) → 加载到数据详情/异常/属性 ── + QObject::connect(datasetList, &QListWidget::itemClicked, datasetList, + [loadDataset](QListWidgetItem* item) { + const QString dsId = item->data(geopro::app::kDsIdRole).toString(); + const QString ddType = item->data(geopro::app::kDsDdTypeRole).toString(); + if (ddType != "dd_section") return; // 仅剖面网格有详情图 + const QString name = + item->data(Qt::DisplayRole).toString().section('\n', 0, 0); + loadDataset(dsId, name); + }); // ── 异常列表勾选(显隐) → 更新隐藏集 → 重建数据详情 ── QObject::connect(anomalyList, &QListWidget::itemChanged, anomalyList, @@ -431,9 +471,27 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re rebuildCentral(); }); - // ── 启动默认:dd_section 已勾选,但 itemChanged 在 connect 之前触发故未渲染。 - // 这里 connect 之后主动按默认视图(二维地图)重建一次中央内容。 + // ── 启动默认:测线已勾选,但 itemChanged 在 connect 之前触发故未渲染;这里重建一次中央内容。 rebuildCentral(); + + // 启动默认:选第一个含 dd_section 的测线 → 填充数据列表 + 加载其首个 dd_section 详情(对齐原型)。 + for (const auto& gs : *structure) { + const geopro::data::TmNode* picked = nullptr; + for (const auto& tm : gs.tms) { + const bool hasSection = + std::any_of(tm.dss.begin(), tm.dss.end(), + [](const geopro::data::DsNode& d) { return d.ddType == "dd_section"; }); + if (hasSection) { picked = &tm; break; } + } + if (!picked) continue; + geopro::app::populateDatasetList(datasetList, picked->dss); + for (const auto& ds : picked->dss) + if (ds.ddType == "dd_section") { + loadDataset(QString::fromStdString(ds.id), QString::fromStdString(ds.name)); + break; + } + break; + } } } // namespace diff --git a/src/app/panels/DatasetListPanel.cpp b/src/app/panels/DatasetListPanel.cpp new file mode 100644 index 0000000..386137a --- /dev/null +++ b/src/app/panels/DatasetListPanel.cpp @@ -0,0 +1,37 @@ +#include "panels/DatasetListPanel.hpp" + +#include +#include +#include + +namespace geopro::app { + +namespace { + +// dd 类型 → 中文标注。 +QString ddTypeLabel(const std::string& ddType) +{ + if (ddType == "dd_section") return QStringLiteral("剖面网格"); + if (ddType == "dd_voxel") return QStringLiteral("体素"); + return QString::fromStdString(ddType); +} + +} // namespace + +void populateDatasetList(QListWidget* list, const std::vector& dss) +{ + if (!list) return; + list->clear(); + for (const auto& ds : dss) { + const QString name = QString::fromStdString(ds.name); + const QString label = ddTypeLabel(ds.ddType); + QString text = name; + if (!label.isEmpty()) text += QStringLiteral("\n%1").arg(label); + + auto* item = new QListWidgetItem(text, list); + item->setData(kDsIdRole, QString::fromStdString(ds.id)); + item->setData(kDsDdTypeRole, QString::fromStdString(ds.ddType)); + } +} + +} // namespace geopro::app diff --git a/src/app/panels/DatasetListPanel.hpp b/src/app/panels/DatasetListPanel.hpp new file mode 100644 index 0000000..f2a61e6 --- /dev/null +++ b/src/app/panels/DatasetListPanel.hpp @@ -0,0 +1,19 @@ +#pragma once +#include + +#include "repo/RepoTypes.hpp" + +class QListWidget; + +namespace geopro::app { + +// 数据列表条目角色(与 main.cpp 树一致:Qt::UserRole=dsId、+1=ddType)。 +constexpr int kDsIdRole = 0x0100; // Qt::UserRole +constexpr int kDsDdTypeRole = 0x0101; // Qt::UserRole + 1 + +// 用某测线(TM)的数据集(采集批次)填充 QListWidget(对齐原型左下「数据真实显示栏」)。 +// 每条目 = 名称 +(ddType 标注);UserRole 存 dsId、+1 存 ddType(供单击驱动数据详情)。 +// 清空旧条目后重填。 +void populateDatasetList(QListWidget* list, const std::vector& dss); + +} // namespace geopro::app