no more blocker

This commit is contained in:
2026-07-07 20:22:12 +08:00
parent e356329dc9
commit 47da444d74
4 changed files with 88 additions and 199 deletions

View File

@@ -398,9 +398,6 @@ QString SceneGraphTools::listScenegraphNodes() const
}
// --- SG node selection ---
// TODO: all code below is disabled until the selection-sync / sub-model-population
// bug is fixed. See PLAN.md "Known issues / Blocked" section.
#if 0
QModelIndex SceneGraphTools::findNodeByAddress(QAbstractItemModel *m, const QString &address) const
{
@@ -466,10 +463,11 @@ QString SceneGraphTools::ensureNodeSelected(const QString &address) const
QStringLiteral("node %1 not found in scene graph tree (still loading?)").arg(address)))
.toJson(QJsonDocument::Compact));
// Create the selection model client BEFORE selecting. This:
// 1. Sends ObjectMonitored to the server, activating the ServerProxyModel
// 2. Starts the 125ms default-selection timer
// 3. Enables echo-back from the server's SelectionModelServer
auto *selModel = m_session->selectionModel(sgModel);
if (!selModel)
return QString::fromUtf8(QJsonDocument(errorJson(
QStringLiteral("selection model not available"))).toJson(QJsonDocument::Compact));
// CRITICAL: Create sub-model RemoteModels BEFORE sending the selection.
// The probe populates and resets sub-models (vertex, adjacency, shader,
@@ -491,62 +489,22 @@ QString SceneGraphTools::ensureNodeSelected(const QString &address) const
QString::fromUtf8(kQuickInspectorIface),
"setSlowMode", QVariantList{ false });
// Wait long enough for:
// 1. ObjectMonitored messages to reach the server and start monitoring
// 2. SelectionModelStateRequest (125ms timer from SelectionModelClient ctor)
// to be sent and the server's response (default selection) to arrive
// 3. Any SG model updates from setSlowMode(false) to settle
// Wait for the SelectionModelClient's 125ms default-selection timer to fire
// and settle before our override, so they don't race.
QEventLoop loop;
settle(loop, 2000);
settle(loop, 300);
// Now send the selection. The server should now be in a stable state with
// the default selection already processed. Our selection will override it.
selModel->select(idx, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows | QItemSelectionModel::Current);
m_selectedAddress = address;
// Also manually construct and send a SelectionModelSelect message directly
// to the server's selection model address, bypassing SelectionModelClient.
// This eliminates any issues with SelectionModelClient state.
{
const auto selAddr = GammaRay::Endpoint::instance()->objectAddress(
QStringLiteral("%1.selection").arg(QString::fromUtf8(kQuickSceneGraphModel)));
if (selAddr != GammaRay::Protocol::InvalidObjectAddress) {
// Check the path length
const auto mi = GammaRay::Protocol::fromQModelIndex(idx);
int pathLen = mi.size();
// Log the path for debugging
QString pathStr;
for (int i = 0; i < mi.size(); ++i)
pathStr += QStringLiteral("(%1,%2) ").arg(mi[i].row).arg(mi[i].column);
GammaRay::Message msg(selAddr, GammaRay::Protocol::SelectionModelSelect);
msg << qint32(1); // 1 range
msg << mi << mi; // topLeft, bottomRight
msg << (QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows | QItemSelectionModel::Current);
GammaRay::Endpoint::send(msg);
// Store path info for diagnostics
m_lastSelectPath = QStringLiteral("len=%1 %2").arg(pathLen).arg(pathStr);
}
}
// Select the node via client-side selection model. This sends a
// SelectionModelSelect message to the server, which processes it and
// triggers sgSelectionChanged -> PropertyController::setObject(),
// populating the sub-models with the selected node's data.
if (selModel && idx.isValid())
selModel->select(idx, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows | QItemSelectionModel::Current);
// Wait for the selection to be processed and sub-model data to arrive.
settle(loop, 2000);
// Re-send via direct message to ensure it sticks.
{
const auto selAddr = GammaRay::Endpoint::instance()->objectAddress(
QStringLiteral("%1.selection").arg(QString::fromUtf8(kQuickSceneGraphModel)));
if (selAddr != GammaRay::Protocol::InvalidObjectAddress) {
GammaRay::Message msg(selAddr, GammaRay::Protocol::SelectionModelSelect);
const auto mi = GammaRay::Protocol::fromQModelIndex(idx);
msg << qint32(1);
msg << mi << mi;
msg << (QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows | QItemSelectionModel::Current);
GammaRay::Endpoint::send(msg);
}
}
settle(loop, 2000);
m_selectedAddress = address;
// Prime sub-models to fetch their row/column counts and cell data.
if (vModel) { vModel->rowCount(); primeAndWait(vModel, 4, 300, 500, 1500); }
@@ -572,64 +530,20 @@ QString SceneGraphTools::selectScenegraphNode(const QString &address) const
type = sgModel->data(typeIdx, Qt::DisplayRole).toString();
}
// Check selection state and sub-model row counts
auto *sgModel2 = m_session->model(QString::fromUtf8(kQuickSceneGraphModel));
auto *selModel = m_session->selectionModel(sgModel2);
// Check sub-model row counts
auto *vModel = m_session->model(QStringLiteral("%1.sgGeometryVertexModel").arg(QString::fromUtf8(kBaseName)));
auto *aModel = m_session->model(QStringLiteral("%1.sgGeometryAdjacencyModel").arg(QString::fromUtf8(kBaseName)));
auto *sModel = m_session->model(QStringLiteral("%1.shaderModel").arg(QString::fromUtf8(kBaseName)));
auto *mModel = m_session->model(QStringLiteral("%1.materialPropertyModel").arg(QString::fromUtf8(kBaseName)));
// Diagnostic: check if models are registered on the probe (have valid addresses)
auto *ep = GammaRay::Endpoint::instance();
const auto vAddr = ep ? ep->objectAddress(QStringLiteral("%1.sgGeometryVertexModel").arg(QString::fromUtf8(kBaseName))) : 0;
const auto aAddr = ep ? ep->objectAddress(QStringLiteral("%1.sgGeometryAdjacencyModel").arg(QString::fromUtf8(kBaseName))) : 0;
const auto sAddr = ep ? ep->objectAddress(QStringLiteral("%1.shaderModel").arg(QString::fromUtf8(kBaseName))) : 0;
const auto mAddr = ep ? ep->objectAddress(QStringLiteral("%1.materialPropertyModel").arg(QString::fromUtf8(kBaseName))) : 0;
const auto selAddr = ep ? ep->objectAddress(QStringLiteral("%1.selection").arg(QString::fromUtf8(kQuickSceneGraphModel))) : 0;
// Also check the wrong name (in case source model name mismatch)
const auto dotSelAddr = ep ? ep->objectAddress(QStringLiteral(".selection")) : 0;
// Check what the selected index looks like
QString selIdxInfo;
if (selModel && selModel->hasSelection()) {
auto rows = selModel->selectedRows();
if (rows.isEmpty()) {
selIdxInfo = QStringLiteral("hasSelection=true but selectedRows() empty");
} else {
// Walk the parent chain to get the full path
QStringList pathParts;
QModelIndex cur = rows.first();
while (cur.isValid()) {
QString addr = cur.data(Qt::DisplayRole).toString();
pathParts.prepend(QStringLiteral("r%1:%2").arg(cur.row()).arg(addr));
cur = cur.parent();
}
selIdxInfo = pathParts.join(" -> ");
}
} else {
selIdxInfo = QStringLiteral("no selection");
}
QJsonObject out = {
{ QStringLiteral("address"), address },
{ QStringLiteral("type"), type },
{ QStringLiteral("hasGeometry"), vModel && vModel->rowCount() > 0 },
{ QStringLiteral("hasMaterial"), sModel && sModel->rowCount() > 0 },
{ QStringLiteral("_diag_epConnected"), ep ? ep->isConnected() : false },
{ QStringLiteral("_diag_selModelAddr"), qint64(selAddr) },
{ QStringLiteral("_diag_selHasSelection"), selModel ? selModel->hasSelection() : false },
{ QStringLiteral("_diag_selIdxInfo"), selIdxInfo },
{ QStringLiteral("_diag_vertexModelAddr"), qint64(vAddr) },
{ QStringLiteral("_diag_adjacencyModelAddr"), qint64(aAddr) },
{ QStringLiteral("_diag_shaderModelAddr"), qint64(sAddr) },
{ QStringLiteral("_diag_materialPropModelAddr"), qint64(mAddr) },
{ QStringLiteral("_diag_vertexRowCount"), vModel ? vModel->rowCount() : -1 },
{ QStringLiteral("_diag_adjacencyRowCount"), aModel ? aModel->rowCount() : -1 },
{ QStringLiteral("_diag_shaderRowCount"), sModel ? sModel->rowCount() : -1 },
{ QStringLiteral("_diag_materialPropRowCount"), mModel ? mModel->rowCount() : -1 },
{ QStringLiteral("_diag_vertexColCount"), vModel ? vModel->columnCount() : -1 },
{ QStringLiteral("_diag_vertexData00"), vModel && vModel->rowCount() > 0 && vModel->columnCount() > 0 ? vModel->data(vModel->index(0, 0)).toString() : QString() },
{ QStringLiteral("vertexCount"), vModel ? vModel->rowCount() : 0 },
{ QStringLiteral("shaderCount"), sModel ? sModel->rowCount() : 0 },
{ QStringLiteral("propertyCount"), mModel ? mModel->rowCount() : 0 },
};
return QString::fromUtf8(QJsonDocument(out).toJson(QJsonDocument::Compact));
}
@@ -818,8 +732,6 @@ QString SceneGraphTools::getMaterialProperties(const QString &address) const
return QString::fromUtf8(QJsonDocument(out).toJson(QJsonDocument::Compact));
}
#endif // disabled until selection-sync bug is fixed
// --- Rendering visualization ---
QString SceneGraphTools::setRenderMode(const QString &mode) const