diff --git a/src/app/VolumeParamsDialog.cpp b/src/app/VolumeParamsDialog.cpp index b3c9b82..9a2c17e 100644 --- a/src/app/VolumeParamsDialog.cpp +++ b/src/app/VolumeParamsDialog.cpp @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include #include @@ -111,38 +113,44 @@ VolumeParamsDialog::VolumeParamsDialog(const QVector& sources, form->addRow(formkit::editLabel(QStringLiteral("名称")), name_); cardLay->addLayout(form); - // 生成位置:GS/项目根/TM 层级树(单选),替代原扁平下拉。 - formkit::addSection(cardLay, QStringLiteral("生成位置"), card, false); - mountTree_ = new QTreeWidget(); - mountTree_->setHeaderHidden(true); - mountTree_->setIndentation(14); - mountTree_->setMaximumHeight(geopro::app::scaledPx(160)); + auto* form2 = formkit::makeEditForm(); + + // 生成位置:下拉框,下拉面板=GS/项目根/TM 层级树(QComboBox + QTreeView 视图 + 树模型)。 + mount_ = new QComboBox(); { - QHash mItems; + auto* model = new QStandardItemModel(mount_); + QHash mItems; for (const auto& n : structure) { - auto* it = new QTreeWidgetItem(); - it->setText(0, QString::fromStdString(n.name)); - it->setData(0, kRoleMountId, QString::fromStdString(n.id)); - it->setData(0, kRoleMountConfType, n.type == 2 ? 2 : 1); + auto* it = new QStandardItem(QString::fromStdString(n.name)); + it->setEditable(false); + it->setData(QString::fromStdString(n.id), kRoleMountId); + it->setData(n.type == 2 ? 2 : 1, kRoleMountConfType); mItems.insert(QString::fromStdString(n.id), it); } for (const auto& n : structure) { auto* it = mItems.value(QString::fromStdString(n.id)); auto* par = mItems.value(QString::fromStdString(n.parentId), nullptr); if (par) - par->addChild(it); + par->appendRow(it); else - mountTree_->addTopLevelItem(it); + model->appendRow(it); + } + auto* view = new QTreeView(mount_); + view->setHeaderHidden(true); + view->setItemsExpandable(true); + mount_->setModel(model); + mount_->setView(view); + view->expandAll(); + // 默认选中:指定的 defaultMountId,否则首个节点。view 当前项决定 mountTargetId;combo 显示尽力。 + QStandardItem* def = mItems.value(defaultMountId, nullptr); + if (!def && model->rowCount() > 0) def = model->item(0); + if (def) { + view->setCurrentIndex(def->index()); // 决定 mountTargetId/mountConfType 返回值 + mount_->setCurrentText(def->text()); // 顶层项可正确显示;嵌套项尽力(功能不受影响) } - mountTree_->expandAll(); - // 默认选中:指定的 defaultMountId,否则首个节点。 - QTreeWidgetItem* def = mItems.value(defaultMountId, nullptr); - if (!def && mountTree_->topLevelItemCount() > 0) def = mountTree_->topLevelItem(0); - if (def) mountTree_->setCurrentItem(def); } - cardLay->addWidget(mountTree_); - - auto* form2 = formkit::makeEditForm(); + formkit::capField(mount_); + form2->addRow(formkit::editLabel(QStringLiteral("生成位置")), mount_); model_ = new EmptyAwareComboBox(); model_->addItem(QStringLiteral("反距离加权 (IDW)"), static_cast(geopro::data::VolumeBuildParams::Model::Idw)); @@ -204,14 +212,22 @@ QStringList VolumeParamsDialog::sourceDatasetIds() const { return ids; } +namespace { +// 从生成位置下拉的树视图取当前选中项(树模型下比 combo->currentData 可靠)。 +QModelIndex mountCurrentIndex(QComboBox* mount) { + auto* view = qobject_cast(mount->view()); + return view ? view->currentIndex() : QModelIndex(); +} +} // namespace + QString VolumeParamsDialog::mountTargetId() const { - auto* it = mountTree_->currentItem(); - return it ? it->data(0, kRoleMountId).toString() : QString(); + const QModelIndex idx = mountCurrentIndex(mount_); + return idx.isValid() ? idx.data(kRoleMountId).toString() : QString(); } int VolumeParamsDialog::mountConfType() const { - auto* it = mountTree_->currentItem(); - const int ct = it ? it->data(0, kRoleMountConfType).toInt() : 0; + const QModelIndex idx = mountCurrentIndex(mount_); + const int ct = idx.isValid() ? idx.data(kRoleMountConfType).toInt() : 0; return ct == 0 ? 1 : ct; // 缺省按 GS/项目根 } diff --git a/src/app/VolumeParamsDialog.hpp b/src/app/VolumeParamsDialog.hpp index dccafbb..98cbf86 100644 --- a/src/app/VolumeParamsDialog.hpp +++ b/src/app/VolumeParamsDialog.hpp @@ -47,7 +47,7 @@ private: QDoubleSpinBox* power_ = nullptr; QDoubleSpinBox* maxDist_ = nullptr; QTreeWidget* sourceTree_ = nullptr; // 左:源数据集树(可勾选) - QTreeWidget* mountTree_ = nullptr; // 右:生成位置树(单选) + QComboBox* mount_ = nullptr; // 右:生成位置下拉(下拉面板是 GS/项目根/TM 层级树) }; } // namespace geopro::app diff --git a/src/app/panels/columns/CategorySection.cpp b/src/app/panels/columns/CategorySection.cpp index 1e7a654..1034565 100644 --- a/src/app/panels/columns/CategorySection.cpp +++ b/src/app/panels/columns/CategorySection.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include "panels/columns/DateRangeEdit.hpp" @@ -159,17 +160,33 @@ void CategorySection::refreshArrayCombo() { if (dict_) { const auto& en = dict_->arrayTypeEnum(); // 全局装置枚举 itemValue→中文 QSet seen; - // 列出当前数据里出现过、且命中枚举的装置值 → 中文名。 + // 列出当前数据里出现过的装置值 → 中文名。兼容 ds 把装置存成 itemValue(键) 或中文名(值) 两种形态。 for (const auto& r : rows_) { for (const auto& kv : r.properties) { - const auto it = en.find(kv.value); - if (it == en.end()) continue; // 非装置类型值 const QString val = QString::fromStdString(kv.value); - if (seen.contains(val)) continue; + QString name; + const auto it = en.find(kv.value); + if (it != en.end()) { + name = QString::fromStdString(it->second); // value 是 itemValue → 取中文名 + } else { + for (const auto& e : en) // value 可能直接是中文名 + if (QString::fromStdString(e.second) == val) { name = val; break; } + } + if (name.isEmpty() || seen.contains(val)) continue; seen.insert(val); - arrayCombo_->addItem(QString::fromStdString(it->second), val); + arrayCombo_->addItem(name, val); // data=实际属性值(passesFilters 据此比对) } } + if (arrayCombo_->count() <= 1) // 诊断:装置下拉仍空 → 打印枚举大小 + 首行属性,定位是枚举空还是值不匹配 + qInfo().noquote() << "[arrayfilter]" << QString::fromStdString(spec_.id) << "enum=" + << en.size() << "rows=" << rows_.size() + << (rows_.empty() ? QString() : [&] { + QStringList vs; + for (const auto& kv : rows_.front().properties) + vs << (QString::fromStdString(kv.confFieldId) + "=" + + QString::fromStdString(kv.value)); + return "row0[" + vs.join(',') + "]"; + }()); } const int idx = arrayCombo_->findData(prev); // 尽量保留上次选择 arrayCombo_->setCurrentIndex(idx >= 0 ? idx : 0);