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