| 1365 | } |
| 1366 | |
| 1367 | void PlotWidget::reconnectDataSignals() { |
| 1368 | if (samples_ingested_connection_) { |
| 1369 | disconnect(samples_ingested_connection_); |
| 1370 | } |
| 1371 | if (dataset_replace_connection_) { |
| 1372 | disconnect(dataset_replace_connection_); |
| 1373 | } |
| 1374 | if (display_offset_connection_) { |
| 1375 | disconnect(display_offset_connection_); |
| 1376 | } |
| 1377 | if (display_offset_dataset_connection_) { |
| 1378 | disconnect(display_offset_dataset_connection_); |
| 1379 | } |
| 1380 | if (session_ == nullptr) { |
| 1381 | return; |
| 1382 | } |
| 1383 | |
| 1384 | samples_ingested_connection_ = |
| 1385 | connect(session_, &SessionManager::samplesIngested, this, [this](const QVector<TopicId>& ids, bool live) { |
| 1386 | bool changed = false; |
| 1387 | for (auto& info : curveList()) { |
| 1388 | auto* adapter = dynamic_cast<DatastoreCurveAdapter*>(info.curve->data()); |
| 1389 | if (adapter != nullptr) { |
| 1390 | if (std::find(ids.begin(), ids.end(), adapter->source().topic_id) != ids.end()) { |
| 1391 | adapter->onTopicCommitted(); |
| 1392 | changed = true; |
| 1393 | } |
| 1394 | continue; |
| 1395 | } |
| 1396 | |
| 1397 | auto* xy_series = dynamic_cast<PointSeriesXY*>(info.curve->data()); |
| 1398 | if (xy_series == nullptr) { |
| 1399 | continue; |
| 1400 | } |
| 1401 | if (std::find(ids.begin(), ids.end(), xy_series->xSource().topic_id) != ids.end() || |
| 1402 | std::find(ids.begin(), ids.end(), xy_series->ySource().topic_id) != ids.end()) { |
| 1403 | xy_series->onTopicCommitted(); |
| 1404 | changed = true; |
| 1405 | } |
| 1406 | } |
| 1407 | if (!changed) { |
| 1408 | return; |
| 1409 | } |
| 1410 | if (live) { |
| 1411 | // Follow-live: re-fit axes so streaming samples beyond the initial |
| 1412 | // drop-time range become visible. resetZoom subsumes |
| 1413 | // updateMaximumZoomArea + replot. |
| 1414 | resetZoom(); |
| 1415 | } else { |
| 1416 | // One-shot writers (file load) stay zoomed where the user left them. |
| 1417 | updateMaximumZoomArea(); |
| 1418 | replot(); |
| 1419 | } |
| 1420 | }); |
| 1421 | |
| 1422 | // In-place reload swaps a dataset's chunks under our adapters, freeing the raw |
| 1423 | // TopicChunk* they cache (sample_index_ / xy index). Drop those caches |
| 1424 | // synchronously BEFORE the swap to avoid a UAF; bindings (DatasetId/TopicIds) |
nothing calls this directly
no test coverage detected