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