dbselect
Loading...
Searching...
No Matches
dbselectView.cc
Go to the documentation of this file.
1// dbselect
2#include "dbselectView.h"
3#include "dbselect_options.h"
4
5// gemc
7
8// qt
9#include <QHBoxLayout>
10#include <QStandardItemModel>
11#include <QHeaderView>
12#include <QStringList>
13#include <QTimer>
14
15// c++
16#include <sstream>
17
18
19// Implementation notes:
20// - Doxygen documentation is authoritative in dbselectView.h.
21// - This file uses short non-Doxygen comments to explain local implementation decisions.
22
23DBSelectView::DBSelectView(const std::shared_ptr<GOptions>& gopts, GDetectorConstruction* dc, QWidget* parent)
24 : QWidget(parent),
25 GBase(gopts, DBSELECT_LOGGER),
26 db(nullptr),
27 gDetectorConstruction(dc),
28 gopt(gopts) {
29
30 // Read database path/key and default experiment from options.
31 dbhost = gopts->getRequiredScalarString("sql");
32 experiment = gopts->getRequiredScalarString("experiment");
33
34 // Search order for locating the database file:
35 // 1) current directory
36 // 2) GEMC installation root
37 // 3) GEMC examples directory
38 std::vector<std::string> dirs = {
39 ".",
40 gutilities::gemc_root().string(),
41 (gutilities::gemc_root() / "examples").string()
42 };
43
44 auto dbPath = gutilities::searchForFileInLocations(dirs, dbhost);
45 if (!dbPath) {
46 log->warning("Failed to find database file <%1>. Setup tab will start empty.", dbhost);
47 setupUI();
48 experimentModel->blockSignals(true);
49 experimentModel->setHorizontalHeaderLabels(
50 QStringList() << tr("exp/system") << tr("volumes") << tr("variation") << tr("run"));
51 experimentModel->blockSignals(false);
52 modified = false;
53 updateModifiedUI();
54 experimentHeaderLabel->setText(tr("Database \"%1\" was not found.").arg(QString::fromStdString(dbhost)));
55 return;
56 }
57
58 // Open read-only and ensure the expected table exists and is non-empty.
59 if (sqlite3_open_v2(dbPath.value().c_str(), &db, SQLITE_OPEN_READONLY, nullptr) != SQLITE_OK || !isGeometryTableValid()) {
60 sqlite3_close(db);
61 db = nullptr;
62 log->warning("Failed to open or validate database <%1>. Setup tab will start empty.", dbhost);
63 setupUI();
64 experimentModel->blockSignals(true);
65 experimentModel->setHorizontalHeaderLabels(
66 QStringList() << tr("exp/system") << tr("volumes") << tr("variation") << tr("run"));
67 experimentModel->blockSignals(false);
68 modified = false;
69 updateModifiedUI();
70 experimentHeaderLabel->setText(
71 tr("Database \"%1\" could not be opened or validated.").arg(QString::fromStdString(dbhost)));
72 return;
73 }
74
75 log->info(1, "Opened database: %1 found at %2", dbhost, dbPath.value());
76
77 // Create UI widgets and model.
78 setupUI();
79
80 // During initial population we block itemChanged notifications to prevent
81 // the model initialization from marking the view as user-modified.
82 experimentModel->blockSignals(true);
83 loadExperiments();
84
85 // Verify that the default experiment exists and pre-check it.
86 bool expFound = false;
87 for (int i = 0; i < experimentModel->rowCount(); ++i) {
88 QStandardItem* expItem = experimentModel->item(i, 0);
89 if (expItem && expItem->text() == QString::fromStdString(experiment)) {
90 expItem->setCheckState(Qt::Checked);
91 expFound = true;
92 break;
93 }
94 }
95 if (!expFound) {
96 log->error(gsystem::ERR_EXPERIMENTNOTFOUND, "%1 not found in database.%2", experiment, dbhost);
97 }
98
99 // Apply selections from configured GSystem objects (if any).
100 applyGSystemSelections();
101
102 // Update system appearances initially so “volumes” and availability icons are correct.
103 for (int i = 0; i < experimentModel->rowCount(); ++i) {
104 QStandardItem* expItem = experimentModel->item(i, 0);
105 for (int j = 0; j < expItem->rowCount(); ++j) {
106 QStandardItem* sysItem = expItem->child(j, 0);
107 updateSystemItemAppearance(sysItem);
108 }
109 }
110
111 // Initialization complete: restore signals.
112 experimentModel->blockSignals(false);
113
114 // Ensure the view starts unmodified.
115 modified = false;
116 updateModifiedUI();
117 QTimer::singleShot(0, this, &DBSelectView::resizeExperimentColumns);
118}
119
120bool DBSelectView::isGeometryTableValid() const {
121 if (!db)
122 return false;
123
124 sqlite3_stmt* stmt = nullptr;
125 const char* sql_query = "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='geometry'";
126
127 // First check: table existence.
128 if (sqlite3_prepare_v2(db, sql_query, -1, &stmt, nullptr) != SQLITE_OK) {
129 log->error(
130 gsystem::ERR_GSQLITEERROR, "SQL Error: Failed to check geometry table existence:%1",
131 sqlite3_errmsg(db));
132 }
133
134 bool tableExists = false;
135 if (sqlite3_step(stmt) == SQLITE_ROW) {
136 tableExists = sqlite3_column_int(stmt, 0) > 0;
137 }
138 sqlite3_finalize(stmt);
139
140 if (!tableExists)
141 return false;
142
143 // Second check: table contains data.
144 sql_query = "SELECT COUNT(*) FROM geometry";
145 if (sqlite3_prepare_v2(db, sql_query, -1, &stmt, nullptr) != SQLITE_OK) {
146 log->error(
147 gsystem::ERR_GSQLITEERROR, "SQL Error: Failed to count rows in geometry table:%1",
148 sqlite3_errmsg(db));
149 }
150
151 bool hasData = false;
152 if (sqlite3_step(stmt) == SQLITE_ROW) {
153 hasData = sqlite3_column_int(stmt, 0) > 0;
154 }
155 sqlite3_finalize(stmt);
156
157 return hasData;
158}
159
160void DBSelectView::applyGSystemSelections() {
161 // Pull the current system selection from configuration and mirror it into the UI model.
162 auto gsystems = gsystem::getSystems(gopt);
163
164 for (int i = 0; i < experimentModel->rowCount(); ++i) {
165 QStandardItem* expItem = experimentModel->item(i, 0);
166 if (!expItem)
167 continue;
168
169 // Mark the default experiment as checked if it matches.
170 if (expItem->text() == QString::fromStdString(experiment)) {
171 expItem->setCheckState(Qt::Checked);
172 }
173
174 // Process each child system row under this experiment.
175 for (int j = 0; j < expItem->rowCount(); ++j) {
176 QStandardItem* sysItem = expItem->child(j, 0);
177 QStandardItem* varItem = expItem->child(j, 2);
178 QStandardItem* runItem = expItem->child(j, 3);
179 if (!sysItem || !varItem || !runItem)
180 continue;
181
182 std::string sysName = sysItem->text().toStdString();
183 std::string rowVariation = varItem->data(Qt::EditRole).toString().toStdString();
184 bool systemFound = false;
185
186 for (auto const& gsys : gsystems) {
187 if (gsys->getName() == sysName && gsys->getVariation() == rowVariation) {
188 systemFound = true;
189 sysItem->setCheckState(Qt::Checked);
190
191 // Runs: select configured value if present, otherwise default to first.
192 QStringList availableRuns = getAvailableRuns(sysName, rowVariation);
193 QString selectedRun = QString::number(gsys->getRunno());
194 if (availableRuns.contains(selectedRun))
195 runItem->setData(selectedRun, Qt::EditRole);
196 else if (!availableRuns.isEmpty())
197 runItem->setData(availableRuns.first(), Qt::EditRole);
198 runItem->setData(availableRuns, Qt::UserRole);
199
200 updateSystemItemAppearance(sysItem);
201 break;
202 }
203 }
204
205 // If no configured system matches, keep it unchecked.
206 if (!systemFound) {
207 sysItem->setCheckState(Qt::Unchecked);
208 }
209 }
210 }
211}
212
213void DBSelectView::setupUI() {
214 auto mainLayout = new QVBoxLayout(this);
215 mainLayout->setContentsMargins(10, 10, 10, 10);
216 mainLayout->setSpacing(10);
217
218 // Header: title + experiment summary on the left, reload button on the right.
219 auto headerLayout = new QHBoxLayout();
220
221 auto labelLayout = new QVBoxLayout();
222 titleLabel = new QLabel(tr("Experiment Selection"), this);
223 QFont titleFont("Avenir", 20, QFont::Bold);
224 titleLabel->setFont(titleFont);
225 titleLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
226 labelLayout->addWidget(titleLabel);
227
228 experimentHeaderLabel = new QLabel("", this);
229 experimentHeaderLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
230 experimentHeaderLabel->setWordWrap(true);
231 experimentHeaderLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
232 labelLayout->addWidget(experimentHeaderLabel);
233
234 headerLayout->addLayout(labelLayout);
235 headerLayout->addStretch();
236 reloadButton = new QPushButton(tr("Reload"), this);
237 reloadButton->setEnabled(false);
238 headerLayout->addWidget(reloadButton);
239 connect(reloadButton, &QPushButton::pressed, this, &DBSelectView::reload_geometry);
240
241 mainLayout->addLayout(headerLayout);
242
243 // Tree view and model.
244 experimentTree = new QTreeView(this);
245 experimentTree->setAlternatingRowColors(true);
246 experimentTree->setSelectionMode(QAbstractItemView::SingleSelection);
247 experimentTree->setSelectionBehavior(QAbstractItemView::SelectRows);
248 experimentTree->header()->show();
249
250 experimentModel = new QStandardItemModel(this);
251 experimentModel->setHorizontalHeaderLabels(
252 QStringList() << tr("exp/system") << tr("volumes") << tr("variation") << tr("run"));
253 experimentTree->setModel(experimentModel);
254
255 // Run values are edited via a drop-down.
256 experimentTree->setItemDelegateForColumn(3, new ComboDelegate(this));
257
258 mainLayout->addWidget(experimentTree);
259
260 connect(experimentModel, &QStandardItemModel::itemChanged,
261 this, &DBSelectView::onItemChanged);
262}
263
264void DBSelectView::loadExperiments() {
265 experimentModel->clear();
266 if (!db) { return; }
267
268 const std::string configuredExperiment = experiment;
269 sqlite3_stmt* stmt = nullptr;
270 const char* sql_query = "SELECT DISTINCT experiment FROM geometry";
271
272 int rc = sqlite3_prepare_v2(db, sql_query, -1, &stmt, nullptr);
273 if (rc != SQLITE_OK) {
274 log->error(gsystem::ERR_GSQLITEERROR, "Failed to prepare experiment query:%1", sqlite3_errmsg(db));
275 }
276
277 // Populate one top-level item per experiment.
278 while (sqlite3_step(stmt) == SQLITE_ROW) {
279 const char* expText = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
280 if (expText) {
281 QString expName = QString::fromUtf8(expText);
282
283 // Note: this assigns the member used by loadSystemsForExperiment().
284 experiment = expName.toStdString();
285
286 auto* expItem = new QStandardItem(expName);
287 expItem->setFlags(expItem->flags() & ~Qt::ItemIsEditable);
288 expItem->setCheckable(true);
289 expItem->setCheckState(Qt::Unchecked);
290
291 // Dummy columns for the experiment row; only column 0 is meaningful.
292 auto* dummyEntries = new QStandardItem("");
293 auto* dummyVar = new QStandardItem("");
294 auto* dummyRun = new QStandardItem("");
295
296 loadSystemsForExperiment(expItem);
297
298 experimentModel->appendRow(QList<QStandardItem*>() << expItem << dummyEntries << dummyVar << dummyRun);
299 }
300 }
301
302 sqlite3_finalize(stmt);
303 experiment = configuredExperiment;
304}
305
306void DBSelectView::loadSystemsForExperiment(QStandardItem* experimentItem) {
307 sqlite3_stmt* stmt = nullptr;
308 const char* sql_query = "SELECT DISTINCT system, variation FROM geometry WHERE experiment = ? ORDER BY system, variation";
309
310 if (sqlite3_prepare_v2(db, sql_query, -1, &stmt, nullptr) == SQLITE_OK) {
311 // Bind current experiment selection (member variable).
312 sqlite3_bind_text(stmt, 1, experiment.c_str(), -1, SQLITE_TRANSIENT);
313
314 while (sqlite3_step(stmt) == SQLITE_ROW) {
315 const char* sysText = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
316 const char* varText = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
317 if (sysText && varText) {
318 auto* sysItem = new QStandardItem(QString::fromUtf8(sysText));
319 sysItem->setFlags(sysItem->flags() & ~Qt::ItemIsEditable);
320 sysItem->setCheckable(true);
321 sysItem->setCheckState(Qt::Unchecked);
322
323 // Column 1: count of matching geometry entries (set later).
324 auto* entriesItem = new QStandardItem("");
325
326 // Column 2: variation represented by this row.
327 auto* varItem = new QStandardItem();
328 QString variation = QString::fromUtf8(varText);
329 QStringList varList{variation};
330 varItem->setData(variation, Qt::EditRole);
331 varItem->setData(varList, Qt::UserRole);
332 varItem->setFlags(varItem->flags() & ~Qt::ItemIsEditable);
333
334 // Column 3: run (editable, backed by UserRole list).
335 auto* runItem = new QStandardItem();
336 QStringList runList = getAvailableRuns(sysText, varText);
337 if (!runList.isEmpty())
338 runItem->setData(runList.first(), Qt::EditRole);
339 else
340 runItem->setData("", Qt::EditRole);
341 runItem->setData(runList, Qt::UserRole);
342
343 QList<QStandardItem*> rowItems;
344 rowItems << sysItem << entriesItem << varItem << runItem;
345 experimentItem->appendRow(rowItems);
346 }
347 }
348 }
349
350 sqlite3_finalize(stmt);
351}
352
353int DBSelectView::getGeometryCount(const std::string& system, const std::string& variation, int run) const {
354 if (!db) { return 0; }
355
356 int count = 0;
357 std::string query = "SELECT COUNT(*) FROM geometry WHERE experiment = ? AND system = ? AND variation = ? AND run = ?";
358
359 sqlite3_stmt* stmt = nullptr;
360 if (sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
361 sqlite3_bind_text(stmt, 1, experiment.c_str(), -1, SQLITE_TRANSIENT);
362 sqlite3_bind_text(stmt, 2, system.c_str(), -1, SQLITE_TRANSIENT);
363 sqlite3_bind_text(stmt, 3, variation.c_str(), -1, SQLITE_TRANSIENT);
364 sqlite3_bind_int(stmt, 4, run);
365
366 if (sqlite3_step(stmt) == SQLITE_ROW) {
367 count = sqlite3_column_int(stmt, 0);
368 }
369 }
370 else {
371 log->error(gsystem::ERR_GSQLITEERROR, "SQL Error: Failed togetGeometryCounte:%1", sqlite3_errmsg(db));
372 }
373
374 sqlite3_finalize(stmt);
375 return count;
376}
377
378QStringList DBSelectView::getAvailableRuns(const std::string& system, const std::string& variation) const {
379 QStringList runList;
380 if (!db) { return runList; }
381
382 sqlite3_stmt* stmt = nullptr;
383 const char* sql_query = "SELECT DISTINCT run FROM geometry WHERE experiment = ? AND system = ? AND variation = ? ORDER BY run";
384
385 if (sqlite3_prepare_v2(db, sql_query, -1, &stmt, nullptr) == SQLITE_OK) {
386 sqlite3_bind_text(stmt, 1, experiment.c_str(), -1, SQLITE_TRANSIENT);
387 sqlite3_bind_text(stmt, 2, system.c_str(), -1, SQLITE_TRANSIENT);
388 sqlite3_bind_text(stmt, 3, variation.c_str(), -1, SQLITE_TRANSIENT);
389
390 while (sqlite3_step(stmt) == SQLITE_ROW) {
391 int runVal = sqlite3_column_int(stmt, 0);
392 runList << QString::number(runVal);
393 }
394 }
395
396 sqlite3_finalize(stmt);
397 return runList;
398}
399
400bool DBSelectView::systemAvailable(const std::string& system, const std::string& variation, int run) {
401 if (!db) { return false; }
402
403 std::string query = "SELECT COUNT(*) FROM geometry WHERE system = ? AND variation = ? AND run = ?";
404 sqlite3_stmt* stmt = nullptr;
405
406 if (sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) != SQLITE_OK) {
407 log->error(
408 gsystem::ERR_GSQLITEERROR, "SQL Error:systemAvailable: prepare failed:e:%1", sqlite3_errmsg(db));
409 }
410
411 sqlite3_bind_text(stmt, 1, system.c_str(), -1, SQLITE_TRANSIENT);
412 sqlite3_bind_text(stmt, 2, variation.c_str(), -1, SQLITE_TRANSIENT);
413 sqlite3_bind_int(stmt, 3, run);
414
415 bool available = false;
416 if (sqlite3_step(stmt) == SQLITE_ROW) {
417 int count = sqlite3_column_int(stmt, 0);
418 available = (count > 0);
419 }
420
421 sqlite3_finalize(stmt);
422 return available;
423}
424
425QIcon DBSelectView::createStatusIcon(const QColor& color) {
426 QPixmap pixmap(12, 12);
427 pixmap.fill(color);
428 return QIcon(pixmap);
429}
430
431void DBSelectView::updateSystemItemAppearance(QStandardItem* systemItem) {
432 QStandardItem* parentItem = systemItem->parent();
433 if (!parentItem)
434 return;
435
436 // Determine selection tuple from row state.
437 int row = systemItem->row();
438 QStandardItem* varItem = parentItem->child(row, 2);
439 QStandardItem* runItem = parentItem->child(row, 3);
440
441 QString varStr = varItem ? varItem->data(Qt::EditRole).toString() : "";
442 QString runStr = runItem ? runItem->data(Qt::EditRole).toString() : "";
443
444 int run = runStr.toInt();
445 QString expStr = parentItem->text();
446
447 // Note: the member is updated so subsequent queries use the selected experiment.
448 experiment = expStr.toStdString();
449
450 std::string systemName = systemItem->text().toStdString();
451 std::string variation = varStr.toStdString();
452
453 int count = getGeometryCount(systemName, variation, run);
454
455 // Column 1 is the per-row entry count (“volumes”).
456 QStandardItem* entriesItem = parentItem->child(row, 1);
457 if (entriesItem) {
458 entriesItem->setText(QString::number(count));
459 }
460
461 // Update availability icon based on whether any matching geometry entries exist.
462 bool available = (count > 0);
463 QColor statusColor = available ? QColor("green") : QColor("red");
464 systemItem->setIcon(createStatusIcon(statusColor));
465
466 // Keep the system item readable regardless of icon state.
467 systemItem->setData(QVariant(), Qt::BackgroundRole);
468 systemItem->setData(QVariant(), Qt::ForegroundRole);
469}
470
471void DBSelectView::updateExperimentHeader() {
472 QStandardItem* selectedExp = nullptr;
473
474 // Find the single checked top-level experiment.
475 for (int i = 0; i < experimentModel->rowCount(); ++i) {
476 QStandardItem* expItem = experimentModel->item(i, 0);
477 if (expItem && expItem->checkState() == Qt::Checked) {
478 selectedExp = expItem;
479 break;
480 }
481 }
482
483 if (selectedExp) {
484 int totalSystems = selectedExp->rowCount();
485 experimentHeaderLabel->setText(tr("Total systems for experiment \"%1\": %2")
486 .arg(selectedExp->text()).arg(totalSystems));
487 }
488 else {
489 experimentHeaderLabel->setText("");
490 }
491
492 // Ensure headers remain visible after model clear/reset patterns.
493 experimentModel->setHorizontalHeaderLabels(
494 QStringList() << tr("exp/system") << tr("volumes") << tr("variation") << tr("run"));
495}
496
497void DBSelectView::onItemChanged(QStandardItem* item) {
498 if (m_ignoreItemChange || !item)
499 return;
500
501 // Guard against recursive updates while changing check states programmatically.
502 m_ignoreItemChange = true;
503
504 // Top-level item: experiment selection.
505 if (!item->parent()) {
506 if (item->checkState() == Qt::Checked) {
507 // Enforce only one experiment checked at a time.
508 for (int i = 0; i < experimentModel->rowCount(); ++i) {
509 QStandardItem* expItem = experimentModel->item(i, 0);
510 if (expItem != item)
511 expItem->setCheckState(Qt::Unchecked);
512 }
513 updateExperimentHeader();
514 }
515 else {
516 // If experiment unchecked, also uncheck its systems.
517 for (int i = 0; i < item->rowCount(); ++i) {
518 QStandardItem* sysItem = item->child(i, 0);
519 if (sysItem)
520 sysItem->setCheckState(Qt::Unchecked);
521 }
522 updateExperimentHeader();
523 }
524 }
525 else {
526 // Child item: system row change.
527 if (item->column() == 0) {
528 if (item->checkState() == Qt::Checked) {
529 for (int i = 0; i < item->parent()->rowCount(); ++i) {
530 QStandardItem* sibling = item->parent()->child(i, 0);
531 if (sibling && sibling != item && sibling->text() == item->text()) {
532 sibling->setCheckState(Qt::Unchecked);
533 }
534 }
535 }
536 updateSystemItemAppearance(item);
537 }
538 else if (item->column() == 2 || item->column() == 3) {
539 QStandardItem* sysItem = item->parent()->child(item->row(), 0);
540 updateSystemItemAppearance(sysItem);
541 }
542 }
543
544 m_ignoreItemChange = false;
545
546 // Mark the view as modified and reflect the state in the header/title and reload button.
547 if (!modified) {
548 modified = true;
549 }
550 updateModifiedUI();
551}
552
554 SystemList updatedSystems;
555
556 // Walk the model and build one GSystem per checked system row.
557 for (int i = 0; i < experimentModel->rowCount(); i++) {
558 QStandardItem* expItem = experimentModel->item(i, 0);
559 if (!expItem)
560 continue;
561
562 for (int j = 0; j < expItem->rowCount(); j++) {
563 QStandardItem* sysItem = expItem->child(j, 0);
564 QStandardItem* varItem = expItem->child(j, 2);
565 QStandardItem* runItem = expItem->child(j, 3);
566
567 if (!sysItem || !varItem || !runItem)
568 continue;
569
570 if (sysItem->checkState() == Qt::Checked) {
571 std::string systemName = sysItem->text().toStdString();
572 std::string variation = varItem->data(Qt::EditRole).toString().toStdString();
573 int run = runItem->data(Qt::EditRole).toInt();
574 std::string expName = expItem->text().toStdString();
575
576 log->info(
577 2, "%1: adding systemName: %2 , variation: %3, for run:%4", SFUNCTION_NAME, systemName,
578 variation, run);
579
580 updatedSystems.emplace_back(
581 std::make_shared<GSystem>(
582 gopt,
583 dbhost,
584 systemName,
586 expName,
587 run,
588 variation
589 ));
590 }
591 }
592 }
593
594 return updatedSystems;
595}
596
597void DBSelectView::updateModifiedUI() {
598 // Keep header text and layout in sync with model state.
599 updateExperimentHeader();
600
601 if (modified)
602 titleLabel->setText(tr("Experiment Selection* (modified)"));
603 else
604 titleLabel->setText(tr("Experiment Selection"));
605 reloadButton->setEnabled(modified);
606
607 // Column sizing and tree expansion provide a readable default view after changes.
608 resizeExperimentColumns();
609}
610
611void DBSelectView::resizeExperimentColumns() {
612 if (!experimentTree) { return; }
613
614 experimentTree->resizeColumnToContents(0);
615 experimentTree->setColumnWidth(1, 100);
616 experimentTree->setColumnWidth(2, 150);
617 experimentTree->setColumnWidth(3, 150);
618 experimentTree->header()->setStretchLastSection(false);
619 experimentTree->expandAll();
620}
621
623 log->info(0, "%1: Reloading geometry...", SFUNCTION_NAME);
624
625 // Extract selection into a SystemList and provide visibility into what is being reloaded.
626 auto reloaded_system = get_gsystems();
627 if (!reloaded_system.empty()) {
628 std::ostringstream gsystemYaml;
629 gsystemYaml << "[";
630 for (size_t i = 0; i < reloaded_system.size(); ++i) {
631 const auto& gsys = reloaded_system[i];
632 if (i > 0) { gsystemYaml << ", "; }
633 gsystemYaml << "{name: " << gsys->getName()
634 << ", factory: " << gsys->getFactoryName()
635 << ", variation: " << gsys->getVariation();
636 if (gsys->getAnnotations()) {
637 gsystemYaml << ", annotations: " << *gsys->getAnnotations();
638 }
639 gsystemYaml << "}";
640 }
641 gsystemYaml << "]";
642 gopt->setOptionValueFromString("gsystem", gsystemYaml.str());
643 gopt->setOptionValueFromString("runno", std::to_string(reloaded_system.front()->getRunno()));
644 }
645 for (auto& gsys : reloaded_system) {
646 log->info(2, "%1: reloaded system: %2", SFUNCTION_NAME, gsys->getName());
647 }
648
650
651 // Delegate the actual reload to detector construction.
652 gDetectorConstruction->reload_geometry(reloaded_system);
653
654 // Reload completes the edit cycle: clear modified state.
655 modified = false;
656 updateModifiedUI();
657 emit geometryReloaded();
658}
void geometryReloaded()
Emitted after detector construction has reloaded geometry from the selected systems.
SystemList get_gsystems()
Build and return the list of selected systems as a SystemList.
void geometryAboutToReload()
Emitted immediately before detector construction replaces the current geometry.
DBSelectView(const std::shared_ptr< GOptions > &gopts, GDetectorConstruction *dc, QWidget *parent=nullptr)
Construct the view and populate the experiment/system model from the database.
void reload_geometry()
Slot invoked by the Reload button to reload geometry based on current selections.
GBase(const std::shared_ptr< GOptions > &gopt, std::string logger_name="")
std::shared_ptr< GLogger > log
constexpr const char * DBSELECT_LOGGER
Logger name used by the dbselect module.
run
#define SFUNCTION_NAME
std::vector< SystemPtr > SystemList
constexpr int ERR_EXPERIMENTNOTFOUND
constexpr char GSYSTEMSQLITETFACTORYLABEL[]
constexpr int ERR_GSQLITEERROR
SystemList getSystems(const std::shared_ptr< GOptions > &gopts)
std::filesystem::path gemc_root()
std::optional< std::string > searchForFileInLocations(const std::vector< std::string > &locations, std::string_view filename)