feat/object-selection-panels #4
|
|
@ -1,5 +1,7 @@
|
||||||
#include "WorkbenchNavController.hpp"
|
#include "WorkbenchNavController.hpp"
|
||||||
|
|
||||||
|
#include <QMetaObject>
|
||||||
|
|
||||||
#include "dto/NavDto.hpp"
|
#include "dto/NavDto.hpp"
|
||||||
|
|
||||||
namespace geopro::controller {
|
namespace geopro::controller {
|
||||||
|
|
@ -10,8 +12,8 @@ using data::Workspace;
|
||||||
WorkbenchNavController::WorkbenchNavController(data::IProjectRepository& repo, QObject* parent)
|
WorkbenchNavController::WorkbenchNavController(data::IProjectRepository& repo, QObject* parent)
|
||||||
: QObject(parent), repo_(repo) {}
|
: QObject(parent), repo_(repo) {}
|
||||||
|
|
||||||
namespace {
|
|
||||||
// RAII:进入公共导航操作时置忙(驱动等待光标),任何返回路径都复位——保证 busyChanged 配平。
|
// RAII:进入公共导航操作时置忙(驱动等待光标),任何返回路径都复位——保证 busyChanged 配平。
|
||||||
|
// 命名(非匿名)以匹配 controller 的 friend 声明,从而在析构时排空挂起的勾选请求。
|
||||||
struct BusyGuard {
|
struct BusyGuard {
|
||||||
WorkbenchNavController* self;
|
WorkbenchNavController* self;
|
||||||
bool* busy;
|
bool* busy;
|
||||||
|
|
@ -20,11 +22,16 @@ struct BusyGuard {
|
||||||
emit self->busyChanged(true);
|
emit self->busyChanged(true);
|
||||||
}
|
}
|
||||||
~BusyGuard() {
|
~BusyGuard() {
|
||||||
|
WorkbenchNavController* ctrl = self; // 取本地副本:lambda 不能捕获成员
|
||||||
*busy = false;
|
*busy = false;
|
||||||
emit self->busyChanged(false);
|
emit ctrl->busyChanged(false);
|
||||||
|
// 触发源是延迟合并发射,可能落在嵌套事件循环里:用队列调用在调用栈/嵌套循环展开后再排空,
|
||||||
|
// 那时 busy_ 已可靠为 false,重放才会真正执行(lambda 捕获的 ctrl 生命周期与应用一致,安全)。
|
||||||
|
if (ctrl->checkedTmsPending_)
|
||||||
|
QMetaObject::invokeMethod(
|
||||||
|
ctrl, [ctrl] { ctrl->drainPendingCheckedTms(); }, Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void WorkbenchNavController::start() {
|
void WorkbenchNavController::start() {
|
||||||
if (busy_) return;
|
if (busy_) return;
|
||||||
|
|
@ -51,6 +58,10 @@ void WorkbenchNavController::loadProjectsAndStructure() {
|
||||||
}
|
}
|
||||||
lastProjects_ = ps.value.rows;
|
lastProjects_ = ps.value.rows;
|
||||||
tmExceptionCache_.clear();
|
tmExceptionCache_.clear();
|
||||||
|
currentParentId_.clear(); // 切项目/工作空间重置选中态(spec §6)
|
||||||
|
currentParentConfType_ = 0;
|
||||||
|
checkedTmsPending_ = false; // 丢弃跨项目的陈旧挂起重放
|
||||||
|
pendingCheckedTms_.clear();
|
||||||
QString curP;
|
QString curP;
|
||||||
if (!ps.value.rows.empty()) {
|
if (!ps.value.rows.empty()) {
|
||||||
const auto& first = ps.value.rows.front();
|
const auto& first = ps.value.rows.front();
|
||||||
|
|
@ -107,6 +118,10 @@ void WorkbenchNavController::switchProject(const QString& projectId) {
|
||||||
}
|
}
|
||||||
lastStructNodes_ = st.value;
|
lastStructNodes_ = st.value;
|
||||||
tmExceptionCache_.clear();
|
tmExceptionCache_.clear();
|
||||||
|
currentParentId_.clear(); // 切项目/工作空间重置选中态(spec §6)
|
||||||
|
currentParentConfType_ = 0;
|
||||||
|
checkedTmsPending_ = false; // 丢弃跨项目的陈旧挂起重放
|
||||||
|
pendingCheckedTms_.clear();
|
||||||
emit structureLoaded(QString::fromStdString(currentProjectName_), st.value);
|
emit structureLoaded(QString::fromStdString(currentProjectName_), st.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -166,7 +181,11 @@ void WorkbenchNavController::loadMoreFiles() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorkbenchNavController::setCheckedTms(const QStringList& tmObjectIds) {
|
void WorkbenchNavController::setCheckedTms(const QStringList& tmObjectIds) {
|
||||||
if (busy_) return;
|
if (busy_) { // 触发源是延迟合并发射,可能落在别的同步操作的嵌套事件循环里:
|
||||||
|
pendingCheckedTms_ = tmObjectIds; // 不丢弃,记下最新一次请求,待空闲重放
|
||||||
|
checkedTmsPending_ = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
BusyGuard guard(this, &busy_);
|
BusyGuard guard(this, &busy_);
|
||||||
auto nameOf = [this](const std::string& id) -> std::string {
|
auto nameOf = [this](const std::string& id) -> std::string {
|
||||||
for (const auto& n : lastStructNodes_)
|
for (const auto& n : lastStructNodes_)
|
||||||
|
|
@ -198,6 +217,12 @@ void WorkbenchNavController::setCheckedTms(const QStringList& tmObjectIds) {
|
||||||
emit exceptionTreeLoaded(groups, total);
|
emit exceptionTreeLoaded(groups, total);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WorkbenchNavController::drainPendingCheckedTms() {
|
||||||
|
if (busy_ || !checkedTmsPending_) return;
|
||||||
|
checkedTmsPending_ = false; // 先清标志再重放,避免重入自旋
|
||||||
|
setCheckedTms(pendingCheckedTms_); // 此时 busy_=false,会正常执行
|
||||||
|
}
|
||||||
|
|
||||||
void WorkbenchNavController::selectDataset(const QString& dsObjectId) {
|
void WorkbenchNavController::selectDataset(const QString& dsObjectId) {
|
||||||
if (dsObjectId.isEmpty() || busy_) return;
|
if (dsObjectId.isEmpty() || busy_) return;
|
||||||
BusyGuard guard(this, &busy_);
|
BusyGuard guard(this, &busy_);
|
||||||
|
|
|
||||||
|
|
@ -45,10 +45,14 @@ signals:
|
||||||
void loadFailed(const QString& stage, const QString& message);
|
void loadFailed(const QString& stage, const QString& message);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend struct BusyGuard; // 允许在 guard 析构时排空挂起的勾选请求
|
||||||
void loadProjectsAndStructure(); // start + switchWorkspace 共用
|
void loadProjectsAndStructure(); // start + switchWorkspace 共用
|
||||||
|
void drainPendingCheckedTms(); // 空闲后重放最近一次被挂起的勾选集
|
||||||
|
|
||||||
data::IProjectRepository& repo_;
|
data::IProjectRepository& repo_;
|
||||||
bool busy_ = false;
|
bool busy_ = false;
|
||||||
|
bool checkedTmsPending_ = false;
|
||||||
|
QStringList pendingCheckedTms_;
|
||||||
std::vector<data::ProjectSummary> lastProjects_;
|
std::vector<data::ProjectSummary> lastProjects_;
|
||||||
std::string currentWorkspaceId_, currentProjectId_, currentProjectName_, currentCrsCode_;
|
std::string currentWorkspaceId_, currentProjectId_, currentProjectName_, currentCrsCode_;
|
||||||
std::string currentParentId_;
|
std::string currentParentId_;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue