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