DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
MainWindow.cpp
Go to the documentation of this file.
1// DUNE DAQ modification notice:
2// This file has been modified from the original ATLAS dbe source for the DUNE DAQ project.
3// Fork baseline commit: dbe-02-12-17 (2022-05-12).
4// Renamed since fork: no.
5
6#include "dbe/MainWindow.hpp"
9#include "dbe/Command.hpp"
10#include "dbe/CommitDialog.hpp"
12#include "dbe/FileInfo.hpp"
13#include "dbe/MyApplication.hpp"
14#include "dbe/ObjectCreator.hpp"
15#include "dbe/ObjectEditor.hpp"
16#include "dbe/Preferences.hpp"
17#include "dbe/StyleUtility.hpp"
18#include "dbe/config_api.hpp"
20#include "dbe/messenger.hpp"
22#include "dbe/subtreeproxy.hpp"
23#include "dbe/treenode.hpp"
24#include "dbe/version.hpp"
25
26#include "logging/Logging.hpp"
27
28#include <QApplication>
29#include <QCloseEvent>
30#include <QDesktopServices>
31#include <QFileDialog>
32#include <QItemDelegate>
33#include <QMessageBox>
34#include <QProgressDialog>
35#include <QSettings>
36#include <QTime>
37#include <QUndoStack>
38#include <QUrl>
39#include <QWhatsThis>
40
41#include <future>
42#include <thread>
43
44#include <boost/scope_exit.hpp>
45
46namespace {
47// This allows to select data in the cells but to not modify them
48class DummyEditorDelegate : public QItemDelegate
49{
50public:
51 void setModelData(QWidget* /* editor */,
52 QAbstractItemModel* /* model */,
53 const QModelIndex& /* index */) const override
54 {
55 }
56};
57}
58
59dbe::MainWindow::MainWindow(QMap<QString, QString> const& cmdargs, QWidget* parent)
60 : QMainWindow(parent)
62 , this_files(nullptr)
63 , this_filesort(new QSortFilterProxyModel(this))
64 , this_classes(nullptr)
65 , this_treefilter(nullptr)
66 , isArchivedConf(false)
67{
68 // qRegisterMetaType<RDBMap>("RDBMap");
69
71 setupUi(this);
72
74 init();
75 init_tabs();
76 // init_rdb_menu();
77
79 attach();
80
82 QCoreApplication::setOrganizationName("dunedaq");
83 QCoreApplication::setApplicationName("dbe_main");
84 load_default_settings(); // Start with defaults in case no user setting saved
85 QSettings settings; // Then try user settings
86 apply_settings(settings);
87 argsparse(cmdargs);
88
89 if (isArchivedConf == true) {
90 OpenDB->setEnabled(false);
91 // OpenOracleDB->setEnabled(false);
92 // ConnectToRdb->setEnabled(false);
93 CreateDatabase->setEnabled(false);
94 Commit->setEnabled(false);
95
96 QMessageBox::information(this,
97 "DBE",
98 QString("The configuration is opened in archival/detached mode.")
99 .append("\nYou can browse or modify objects, but changes cannot be saved or commited."));
100 }
101
102 UndoView->show();
103}
104
105void
107{
108 tableholder->addTab(new TableTab(tableholder), "Table View");
109 tableholder->removeTab(0);
110
111 QPushButton* addtab_button = new QPushButton("+");
112 tableholder->setCornerWidget(addtab_button, Qt::TopLeftCorner);
113 connect(addtab_button, SIGNAL(clicked()), this, SLOT(slot_add_tab()));
114
115 tableholder->setTabsClosable(true);
116 connect(tableholder, SIGNAL(tabCloseRequested(int)), this, SLOT(slot_remove_tab(int)));
117}
118
119void
121{
122 tableholder->addTab(new TableTab(tableholder), "Table View");
123 tableholder->setCurrentIndex(tableholder->count() - 1);
124 tableholder->show();
125}
126
127void
129{
130 if (i == -1 || ((tableholder->count() == 1) && i == 0)) {
131 return;
132 }
133
134 QWidget* Widget = tableholder->widget(i);
135
136 tableholder->removeTab(i);
137
138 delete Widget;
139
140 Widget = nullptr;
141}
142
143void
145{
147 setWindowTitle("DUNE DAQ Configuration Database Editor (DBE)");
149 UndoView->setStack(confaccessor::get_commands().get());
150 SearchLineTable->hide();
151 SearchLineTable->setClearButtonEnabled(true);
152 SearchTreeLine->setClearButtonEnabled(true);
153 CaseSensitiveCheckBoxTable->hide();
154 tableholder->removeTab(1);
155
157 HelpMenu->setEnabled(false); // Until help is updated to be useful!!!
158
160 Commit->setEnabled(false);
161 UndoAction->setEnabled(true);
162 RedoAction->setEnabled(true);
163
165 SearchBox->setFocusPolicy(Qt::ClickFocus);
166
168 TreeView->setWhatsThis("This view shows the classes and objects of the database");
169 FileView->setWhatsThis("This view shows the file structure of the database");
170 UndoView->setWhatsThis("This view shows the commands in the Undo Command stack");
171
172 CommittedTable->setHorizontalHeaderLabels(QStringList() << "File" << "Comment" << "Date");
173 CommittedTable->setAlternatingRowColors(true);
174 CommittedTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
175 CommittedTable->horizontalHeader()->setDefaultSectionSize(250);
176 CommittedTable->setWordWrap(true);
177 CommittedTable->setTextElideMode(Qt::ElideRight);
178 CommittedTable->setItemDelegate(new DummyEditorDelegate());
179
180 // Make Files the current tab
181 InfoWidget->setCurrentIndex(0);
182}
183
184void
186{
187 connect(OpenDB, SIGNAL(triggered()), this, SLOT(slot_open_database_from_file()));
188 connect(Commit, SIGNAL(triggered()), this, SLOT(slot_commit_database()));
189 connect(Exit, SIGNAL(triggered()), this, SLOT(close()));
190 connect(actionPreferences, SIGNAL(triggered()), this, SLOT(slot_launch_preferences()));
191 connect(UndoAction, SIGNAL(triggered()), UndoView->stack(), SLOT(undo()));
192 connect(RedoAction, SIGNAL(triggered()), UndoView->stack(), SLOT(redo()));
193 connect(UndoAll, SIGNAL(triggered()), this, SLOT(slot_undo_allchanges()));
194 connect(BatchChange, SIGNAL(triggered()), this, SLOT(slot_launch_batchchange()));
195 connect(BatchChangeTable, SIGNAL(triggered()), this, SLOT(slot_launch_batchchange_on_table()));
196
197 connect(DisplayClassView, SIGNAL(triggered(bool)), TreeDockWidget, SLOT(setVisible(bool)));
198 connect(DisplayTableView, SIGNAL(triggered(bool)), TableGroupBox, SLOT(setVisible(bool)));
199 connect(DisplayMessages, SIGNAL(triggered(bool)), InfoDockWidget, SLOT(setVisible(bool)));
200 connect(DisplayToolbar, SIGNAL(triggered(bool)), MainToolBar, SLOT(setVisible(bool)));
201
202 connect(TreeDockWidget, SIGNAL(visibilityChanged(bool)), DisplayTableView, SLOT(setChecked(bool)));
203 connect(InfoDockWidget, SIGNAL(visibilityChanged(bool)), DisplayMessages, SLOT(setChecked(bool)));
204 connect(MainToolBar, SIGNAL(visibilityChanged(bool)), DisplayToolbar, SLOT(setChecked(bool)));
205
206 connect(LoadDefaultSettings, SIGNAL(triggered()), this, SLOT(reload_default_settings()));
207 connect(CreateDatabase, SIGNAL(triggered()), this, SLOT(slot_create_newdb()));
208 // connect ( OpenOracleDB, SIGNAL ( triggered() ), this, SLOT ( slot_oracle_prepare() ) );
209
210 connect(WhatThisAction, SIGNAL(triggered()), this, SLOT(slot_whatisthis()));
211 connect(UserGuide, SIGNAL(triggered()), this, SLOT(slot_show_userguide()));
212 connect(UserChanges, SIGNAL(triggered()), this, SLOT(slot_show_userchanges()));
213
214 connect(TreeView, SIGNAL(activated(QModelIndex)), this, SLOT(slot_edit_object_from_class_view(QModelIndex)));
215
216 connect(&confaccessor::ref(),
217 SIGNAL(db_committed(const std::list<std::string>&, const std::string&)),
218 this,
219 SLOT(slot_update_committed_files(const std::list<std::string>&, const std::string&)));
220
221 connect(confaccessor::gethandler().get(),
222 SIGNAL(FetchMoreData(const treenode*)),
223 this,
224 SLOT(slot_fetch_data(const treenode*)));
225
226 connect(&confaccessor::ref(), SIGNAL(object_created(QString, dref)), this, SLOT(slot_toggle_commit_button()));
227 connect(&confaccessor::ref(), SIGNAL(object_renamed(QString, dref)), this, SLOT(slot_toggle_commit_button()));
228 connect(&confaccessor::ref(), SIGNAL(object_changed(QString, dref)), this, SLOT(slot_toggle_commit_button()));
229 connect(&confaccessor::ref(), SIGNAL(object_deleted(QString, dref)), this, SLOT(slot_toggle_commit_button()));
230 connect(&confaccessor::ref(),
231 SIGNAL(db_committed(const std::list<std::string>&, const std::string&)),
232 this,
234 connect(&confaccessor::ref(), SIGNAL(IncludeFileDone()), this, SLOT(slot_toggle_commit_button()));
235 connect(&confaccessor::ref(), SIGNAL(RemoveFileDone()), this, SLOT(slot_toggle_commit_button()));
236 connect(&confaccessor::ref(), SIGNAL(ExternalChangesDetected()), this, SLOT(slot_toggle_commit_button()));
237 connect(&confaccessor::ref(), SIGNAL(ExternalChangesAccepted()), this, SLOT(slot_toggle_commit_button()));
238 connect(this,
239 SIGNAL(signal_batch_change_stopped(const QList<QPair<QString, QString>>&)),
240 this,
242
243 connect(&confaccessor::ref(), SIGNAL(IncludeFileDone()), this, SLOT(slot_model_rebuild()));
244 connect(&confaccessor::ref(), SIGNAL(RemoveFileDone()), this, SLOT(slot_model_rebuild()));
245 connect(&confaccessor::ref(), SIGNAL(ExternalChangesAccepted()), this, SLOT(slot_process_externalchanges()));
246
247 connect(SearchBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slot_filter_query()));
248 connect(SearchTreeLine, SIGNAL(textChanged(const QString&)), this, SLOT(slot_filter_textchange(const QString&)));
249 connect(SearchTreeLine, SIGNAL(textEdited(const QString&)), this, SLOT(slot_filter_query()));
250 connect(SearchTreeLine, SIGNAL(returnPressed()), this, SLOT(slot_filter_query()));
251 connect(
252 SearchLineTable, SIGNAL(textChanged(const QString&)), this, SLOT(slot_filter_table_textchange(const QString&)));
253 connect(CaseSensitiveCheckBoxTree, SIGNAL(clicked(bool)), this, SLOT(slot_toggle_casesensitive_for_treeview(bool)));
254 // connect ( ConnectToRdb, SIGNAL ( triggered ( QAction * ) ), this,
255 // SLOT ( slot_rdb_selected ( QAction * ) ) );
256
257 connect(information_about_dbe, SIGNAL(triggered()), this, SLOT(slot_show_information_about_dbe()));
258
259 // Connect to signals from the messenger system
260
262 SIGNAL(signal_debug(QString const, QString const)),
263 this,
264 SLOT(slot_information_message(QString, QString)),
265 Qt::QueuedConnection);
266
268 SIGNAL(signal_info(QString const, QString const)),
269 this,
270 SLOT(slot_information_message(QString, QString)),
271 Qt::QueuedConnection);
272
274 SIGNAL(signal_note(QString const, QString const)),
275 this,
276 SLOT(slot_information_message(QString, QString)),
277 Qt::QueuedConnection);
278
280 SIGNAL(signal_warn(QString const, QString const)),
281 this,
282 SLOT(slot_warning_message(QString, QString)),
283 Qt::QueuedConnection);
284
286 SIGNAL(signal_error(QString const, QString const)),
287 this,
288 SLOT(slot_error_message(QString, QString)),
289 Qt::QueuedConnection);
290
292 SIGNAL(signal_fail(QString const, QString const)),
293 this,
294 SLOT(slot_error_message(QString, QString)),
295 Qt::QueuedConnection);
296
297 // connect ( this, SIGNAL ( signal_rdb_found(const QString&, const RDBMap& ) ),
298 // this, SLOT ( slot_rdb_found(const QString&, const RDBMap&) ), Qt::AutoConnection );
299}
300
301void
303{
304 QStringList Headers{ "Class Name", "# Objects" };
305
306 if (this_classes != nullptr) {
307 delete this_classes;
308 delete this_treefilter;
309 }
311 this_classes = new dbe::models::tree(Headers);
314 this_treefilter->setFilterRegExp("");
315
316 connect(this_classes, SIGNAL(ObjectFile(QString)), this, SLOT(slot_loaded_db_file(QString)));
317
318 this_treefilter->setDynamicSortFilter(true);
319 this_treefilter->setSourceModel(this_classes);
321 TreeView->setModel(this_treefilter);
322 TreeView->setSortingEnabled(true);
323 TreeView->resizeColumnToContents(0);
324 TreeView->resizeColumnToContents(1);
325
326 connect(HideCheckBox, SIGNAL(toggled(bool)), this_treefilter, SLOT(ToggleEmptyClasses(bool)));
327
328 connect(ShowDerivedObjects, SIGNAL(toggled(bool)), this_classes, SLOT(ToggleAbstractClassesSelectable(bool)));
329
331}
332
333void
335{
337 SearchLineTable->clear();
338 SearchLineTable->show();
339 SearchLineTable->setProperty("placeholderText", QVariant(QString("Table Filter")));
340 CaseSensitiveCheckBoxTable->show();
341}
342
343void
344dbe::MainWindow::edit_object_at(const QModelIndex& Index)
345{
346 treenode* tree_node = this_classes->getnode(Index);
347
348 /*
349 * If an object node is linked to this index then launch the object editor
350 * else build a table for the class , showing all objects
351 */
352
353 if (dynamic_cast<ObjectNode*>(tree_node)) {
354 ObjectNode* NodeObject = dynamic_cast<ObjectNode*>(tree_node);
355 tref ObjectToBeEdited = NodeObject->GetObject();
356 slot_launch_object_editor(ObjectToBeEdited);
357 } else {
358 // Class node
359 QString const cname = tree_node->GetData(0).toString();
361
362 if (not cinfo.p_abstract or ShowDerivedObjects->isChecked()) {
363 if (TableTab* CurrentTab = dynamic_cast<TableTab*>(tableholder->currentWidget())) {
364 CurrentTab->CreateModels();
365 dbe::models::table* CurrentTabModel = CurrentTab->GetTableModel();
366 CustomDelegate* CurrentDelegate = CurrentTab->GetTableDelegate();
367 CustomTableView* CurrentView = CurrentTab->GetTableView();
368
369 connect(
370 CurrentView, SIGNAL(OpenEditor(tref)), this, SLOT(slot_launch_object_editor(tref)), Qt::UniqueConnection);
371 connect(CurrentDelegate,
372 SIGNAL(CreateObjectEditorSignal(tref)),
373 this,
375 Qt::UniqueConnection);
376
377 if (dynamic_cast<ClassNode*>(tree_node)) {
378 BOOST_SCOPE_EXIT(CurrentTabModel)
379 {
380 emit CurrentTabModel->layoutChanged();
381 }
382 BOOST_SCOPE_EXIT_END
383
384 emit CurrentTabModel->layoutAboutToBeChanged();
385
386 CurrentTabModel->BuildTableFromClass(cname, ShowDerivedObjects->isChecked());
388 tableholder->setTabText(tableholder->currentIndex(), cname);
389 CurrentTab->ResetTableView();
390 }
391
392 CurrentTab->ResizeHeaders();
393 }
394 }
395 }
396}
397
398void
400{
403
404 if (!confaccessor::db_implementation_name().contains("roksconflibs")) {
405 if (this_files != nullptr) {
406 delete this_files;
407 }
408 this_files = new FileModel();
409
410 this_filesort.setSourceModel(this_files);
411 FileView->setModel(&this_filesort);
412
413 FileView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
414 FileView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
415 FileView->horizontalHeader()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
416 FileView->horizontalHeader()->setSectionResizeMode(3, QHeaderView::ResizeToContents);
417
419 }
420}
421
422void
424{
425 if (this_classes->canFetchMore(this_classes->index(ClassNode->GetRow(), 0, QModelIndex()))) {
426 this_classes->fetchMore(this_classes->index(ClassNode->GetRow(), 0, QModelIndex()));
427 }
428}
429
430bool
432{
433 CommitDialog* SaveDialog = new CommitDialog();
434 int DialogResult = SaveDialog->exec();
435
436 if (DialogResult) {
438 for (auto file : dbe::confaccessor::uncommitted_files()) {
439 auto message = FileInfo::check_file_includes(QString::fromStdString(file));
440 if (!message.isEmpty()) {
441 QMessageBox::warning(0, "Save database", message);
442 FileInfo::show_file_info(QString::fromStdString(file));
443 return false;
444 }
445 }
446
447 QString CommitMessage = SaveDialog->GetCommitMessage();
448
449 try {
450 std::list<std::string> const& modified = confaccessor::save(CommitMessage);
452
454
455 if (not modified.empty()) {
456 std::string msg;
457
458 for (std::string const& f : modified) {
459 msg += "\n" + f;
460 }
461
462 INFO("List of modified files committed to the database ", "Program execution success", msg);
463 } else {
464 WARN("Changes where committed successfully but list of modified files could not be retrieved",
465 "Unexpected program execution");
466 }
467
468 } catch (dunedaq::conffwk::Exception const& e) {
469 WARN("The changes could not be committed", dbe::config::errors::parse(e).c_str())
470 ers::error(e);
471 return false;
472 }
473 // Gaahhh confaccessor catches dunedaq::conffwk::Exception and
474 // rethrows it as daq::dbe::CouldNotCommitChanges!!
475 catch (daq::dbe::CouldNotCommitChanges const& exc) {
476 std::string reason{ exc.what() };
477 auto cause = exc.cause();
478 while (cause != nullptr) {
479 reason = cause->what();
480 cause = cause->cause();
481 }
482 WARN("The changes could not be committed",
483 // dbe::config::errors::parse(exc).c_str(),
484 reason,
485 "\n\nTry fixing includes from File Info window")
486 ers::error(exc);
487 return false;
488 }
489 } else {
490 if (Exit) {
492 }
493 }
494 return true;
495}
496
497void
499{
500 try {
504 }
505 } catch (dunedaq::conffwk::Exception const& e) {
506 ERROR("Database changes aborted", dbe::config::errors::parse(e).c_str());
507 ers::error(e);
508 }
509}
510
511void
513{
514 try {
517 }
518 } catch (dunedaq::conffwk::Exception const& e) {
519 ERROR("External changes aborted", dbe::config::errors::parse(e).c_str());
520 ers::error(e);
521 }
522}
523
524void
526{
527 bool WidgetFound = false;
528 QString ObjectEditorName = QString("%1@%2").arg(Object.UID().c_str()).arg(Object.class_name().c_str());
529
530 for (QWidget* Editor : QApplication::allWidgets()) {
531 ObjectEditor* Widget = dynamic_cast<ObjectEditor*>(Editor);
532
533 if (Widget != nullptr) {
534 if ((Widget->objectName()).compare(ObjectEditorName) == 0) {
535 Widget->raise();
536 Widget->setVisible(true);
537 WidgetFound = true;
538 }
539 }
540 }
541
542 if (!WidgetFound) {
543 (new ObjectEditor(Object))->show();
544 }
545}
546
547void
549{
551 BatchChangeWidget* Batch = new BatchChangeWidget(nullptr);
552 Batch->setWindowModality(Qt::WindowModal);
553 Batch->show();
554 } else {
555 ERROR("Database must have been loaded", "No database loaded");
556 }
557}
558
559void
561{
563 ERROR("Database must have been loaded", "No database loaded");
564 return;
565 }
566
567 dbe::models::table* CurrentTableModel = nullptr;
568 TableTab* CurrentTab = dynamic_cast<TableTab*>(tableholder->currentWidget());
569 if (CurrentTab) {
570 CurrentTableModel = CurrentTab->GetTableModel();
571 }
572
573 std::vector<dref> TableObject;
574
575 if (!CurrentTab || !CurrentTableModel) {
576 ERROR("Table cannot be processed", "Table is empty");
577 return;
578 }
579
580 if ((*CurrentTableModel->GetTableObjects()).isEmpty()) {
581 ERROR("Table cannot be processed", "Table is empty");
582 return;
583 }
584
585 QString Filter = SearchLineTable->text();
586
587 for (dref Object : *CurrentTableModel->GetTableObjects()) {
588 if (Filter.isEmpty()) {
589 TableObject.push_back(Object);
590 } else {
591 QString ObjectString = QString::fromStdString(Object.UID());
592
593 if (ObjectString.contains(Filter, Qt::CaseInsensitive)) {
594 TableObject.push_back(Object);
595 }
596 }
597 }
598
599 BatchChangeWidget* Batch = new BatchChangeWidget(true, CurrentTableModel->get_class_name(), TableObject, nullptr);
600 Batch->setWindowModality(Qt::WindowModal);
601 Batch->show();
602}
603
604void
606{
607 QSettings settings;
608 settings.clear();
610}
611void
613{
614 QSettings defaults(":theme/DBE_Default_User_Settings.conf", QSettings::NativeFormat);
615 apply_settings(defaults);
616}
617
618QString
620{
621 if (confaccessor::dbfullname().isEmpty()) {
622 return "";
623 }
624
626 for (QString f : allFiles) {
627 for (const QString& j : incs) {
628 if (f.endsWith(j)) {
629 return f.remove(j);
630 }
631 }
632 }
633
634 return "";
635}
636
637void
639{
640
641 CreateDatabaseWidget* CreateDatabaseW = new CreateDatabaseWidget(nullptr, false, find_db_repository_dir());
642 CreateDatabaseW->show();
643 connect(CreateDatabaseW,
644 SIGNAL(CanLoadDatabase(const QString&)),
645 this,
646 SLOT(slot_load_db_from_create_widget(const QString&)));
647}
648
649void
651{
652 if (!DatabaseName.isEmpty()) {
653 QFileInfo DatabaseFile = QFileInfo(DatabaseName);
654
655 if (DatabaseFile.exists()) {
656 QString Path = QString(DatabaseFile.absoluteFilePath());
657
658 if (dbreload()) {
660
661 if (dbload()) {
662 setinternals();
664 // // build_partition_tree_model();
665 // build_resource_tree_model();
667 }
668 }
669 } else {
670 WARN("File not found during database load",
671 "File does not exist",
672 "\n\n Filename:",
673 DatabaseFile.fileName().toStdString());
674 }
675 } else {
676 ERROR("Database load error", "File was not selected");
677 }
678}
679
680bool
682{
684 QMessageBox MessageBox;
685 MessageBox.setText("Do you really wish to abandon the current database and load a new one ?");
686 MessageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
687 MessageBox.setDefaultButton(QMessageBox::Cancel);
688 int UserOption = MessageBox.exec();
689
690 switch (UserOption) {
691
692 case QMessageBox::Yes:
693 return true;
694
695 case QMessageBox::Cancel:
696 return false;
697
698 default:
699 return false;
700 }
701 } else {
702 return true;
703 }
704}
705
706bool
708{
709 // For issues related to loading the configuration in a separate thread, see ATLASDBE-229
710
711 const bool alreadyLoaded = confaccessor::is_database_loaded();
712
713 // The QueuedConnection is mandatory to let the loop receive the signal even if
714 // it is emitted before "exec" is called
715 QEventLoop loop;
716 connect(this, SIGNAL(signal_db_loaded()), &loop, SLOT(quit()), Qt::QueuedConnection);
717
718 // Make life of the progress dialog longer
719 // Show only the first time, when the configuration is not loaded
720 // In other cases, just show a busy cursor
721 std::unique_ptr<QProgressDialog> progress_bar;
722 if (!alreadyLoaded) {
723 progress_bar.reset(new QProgressDialog("Loading Configuration...", QString(), 0, 0, this));
724 progress_bar->setWindowModality(Qt::WindowModal);
725 progress_bar->show();
726 }
727
728 BOOST_SCOPE_EXIT(void)
729 {
730 QApplication::restoreOverrideCursor();
731 }
732 BOOST_SCOPE_EXIT_END
733
734 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
735
736 // Close widgets
737 for (QWidget* widget : QApplication::allWidgets()) {
738 if (dynamic_cast<ObjectEditor*>(widget)) {
739 widget->close();
740 } else if (dynamic_cast<widgets::editors::base*>(widget)) {
741 widget->close();
742 }
743 }
744
745 // Asynchronous execution only the first time the configuration is loaded
746 std::future<bool> waiter = std::async(alreadyLoaded ? std::launch::deferred : std::launch::async, [this] {
747 const bool result = confaccessor::load(!isArchivedConf);
748 emit signal_db_loaded(); // "loop.exec()" will return now
749 return result;
750 });
751
752 // Do not call "exec" if the previous call is not asynchronous
753 if (!alreadyLoaded) {
754 loop.exec(QEventLoop::ExcludeUserInputEvents);
755 }
756
757 // If "deferred", the async call is executed now and here
758 return waiter.get();
759}
760
761void
763{
765 confaccessor::gethandler()->ResetData();
767
769
770 for (int i = 0; i < tableholder->count(); i++) {
771 TableTab* CurrentTab = dynamic_cast<TableTab*>(tableholder->widget(i));
772 if (CurrentTab) {
773 CurrentTab->DisconnectView();
774 }
775 }
776
777 FileView->setModel(NULL);
778}
779
780void
782{
783 settings.beginGroup("MainWindow-layout");
784 if (settings.contains("size")) {
785 resize(settings.value("size").toSize());
786 }
787 if (settings.contains("pos")) {
788 move(settings.value("pos").toPoint());
789 }
790 if (settings.contains("TableView")) {
791 DisplayTableView->setChecked(settings.value("TableView").toBool());
792 }
793 if (settings.contains("ClassView")) {
794 DisplayClassView->setChecked(settings.value("ClassView").toBool());
795 }
796 if (settings.contains("Messages")) {
797 DisplayMessages->setChecked(settings.value("Messages").toBool());
798 }
799 if (settings.contains("geometry")) {
800 restoreGeometry(settings.value("geometry").toByteArray());
801 }
802 if (settings.contains("state")) {
803 restoreState(settings.value("state").toByteArray());
804 }
805 settings.endGroup();
806
807 settings.beginGroup("MainWindow-checkboxes");
808 if (settings.contains("tree-case-sensitive")) {
809 CaseSensitiveCheckBoxTree->setChecked(settings.value("tree-case-sensitive").toBool());
810 }
811 if (settings.contains("table-case-sensitive")) {
812 CaseSensitiveCheckBoxTable->setChecked(settings.value("table-case-sensitive").toBool());
813 }
814 settings.endGroup();
815
817}
818
819void
821{
822 QSettings Settings("dunedaq", "dbe_main");
823 Settings.beginGroup("MainWindow-layout");
824 Settings.setValue("size", size());
825 Settings.setValue("pos", pos());
826 Settings.setValue("TableView", DisplayTableView->isChecked());
827 Settings.setValue("ClassView", DisplayClassView->isChecked());
828
829 Settings.setValue("Messages", DisplayMessages->isChecked());
830 Settings.setValue("geometry", saveGeometry());
831 Settings.setValue("state", saveState());
832 Settings.endGroup();
833
834 Settings.beginGroup("MainWindow-checkboxes");
835 Settings.setValue("tree-case-sensitive", CaseSensitiveCheckBoxTree->isChecked());
836 Settings.setValue("table-case-sensitive", CaseSensitiveCheckBoxTable->isChecked());
837 Settings.endGroup();
838}
839
840void
841dbe::MainWindow::argsparse(QMap<QString, QString> const& opts)
842{
843 if (!opts.isEmpty()) {
844 dbinfo LoadConfig;
845 QString FileToLoad;
846
847 QString FileName = opts.value("f");
848 QString RdbFileName = opts.value("r");
849 QString RoksFileName = opts.value("o");
850 QString HashVersion = opts.value("v");
851
852 if (!FileName.isEmpty()) {
853 FileToLoad = FileName;
854 LoadConfig = dbinfo::oks;
855
856 if (!HashVersion.isEmpty()) {
857 ::setenv("TDAQ_DB_VERSION", QString("hash:").append(HashVersion).toStdString().c_str(), 1);
858 ::setenv("OKS_GIT_PROTOCOL", "http", 1);
859 isArchivedConf = true;
860 }
861 } else if (!RdbFileName.isEmpty()) {
862 FileToLoad = RdbFileName;
863 LoadConfig = dbinfo::rdb;
864 } else if (!RoksFileName.isEmpty()) {
865 FileToLoad = RoksFileName;
866 LoadConfig = dbinfo::roks;
867 }
868
869 if (not FileToLoad.isEmpty()) {
870 dbopen(FileToLoad, LoadConfig);
871 }
872 }
873}
874
875// /**
876// * Create Rdb menu based on the available Rdb information
877// */
878// void dbe::MainWindow::init_rdb_menu()
879// {
880// ConnectToRdb->clear();
881
882// std::list<IPCPartition> pl;
883// IPCPartition::getPartitions(pl);
884// TLOG_DEBUG(1) << "Found " << pl.size() << " partitions" ;
885
886// pl.push_front(IPCPartition("initial"));
887
888// auto f = [pl, this] () {
889// for ( auto it = pl.begin(); it != pl.end(); ++it )
890// {
891// lookForRDBServers ( *it );
892// }
893// };
894
895// std::thread t(f);
896// t.detach();
897// }
898
899// void dbe::MainWindow::slot_rdb_found(const QString& p, const RDBMap& rdbs) {
900// QMenu * part_menu = new QMenu(p);
901
902// for(auto it = rdbs.begin(); it != rdbs.end(); ++it) {
903// QAction * newAct = new QAction ( it.key(), part_menu );
904
905// QFont actFont = newAct->font();
906// if(it.value() == true) {
907// newAct->setToolTip ( QString ( "This is a Read-Only instance of the DB" ) );
908// actFont.setItalic ( true );
909// } else {
910// newAct->setToolTip ( QString ( "This is a Read/Write instance of the DB" ) );
911// actFont.setBold ( true );
912// }
913
914// newAct->setFont ( actFont );
915
916// part_menu->addAction ( newAct );
917// }
918
919// ConnectToRdb->addMenu ( part_menu );
920// }
921
922// /**
923// * Add rdb servers for each partition
924// *
925// * @param p is the partition source for which to populate with server information
926// */
927// void dbe::MainWindow::lookForRDBServers ( const IPCPartition & p )
928// {
929// TLOG_DEBUG(2) << "dbe::MainWindow::addRDBServers()" ;
930
931// if ( p.isValid() )
932// {
933// TLOG_DEBUG(2) << "Inserting partition = " << p.name() ;
934
935// RDBMap rdbs;
936
937// try
938// {
939// {
940// std::map<std::string, rdb::cursor_var> objects;
941// p.getObjects<rdb::cursor, ::ipc::use_cache, ::ipc::unchecked_narrow> ( objects );
942// std::map<std::string, rdb::cursor_var>::iterator rdb_it = objects.begin();
943
944// while ( rdb_it != objects.end() )
945// {
946// TLOG_DEBUG(2) << "Found server : " << rdb_it->first ;
947
948// rdbs.insert(QString::fromStdString(rdb_it->first), true);
949
950// ++rdb_it;
951// }
952// }
953
954// {
955// std::map<std::string, rdb::writer_var> objects;
956// p.getObjects<rdb::writer, ::ipc::use_cache, ::ipc::unchecked_narrow> ( objects );
957// std::map<std::string, rdb::writer_var>::iterator rdb_it = objects.begin();
958
959// while ( rdb_it != objects.end() )
960// {
961// TLOG_DEBUG(2) << "Found server : " << rdb_it->first ;
962
963// rdbs.insert(QString::fromStdString(rdb_it->first), false);
964
965// ++rdb_it;
966// }
967// }
968// }
969// catch ( daq::ipc::InvalidPartition& e )
970// {
971// ers::error ( e );
972// }
973
974// if(rdbs.isEmpty() == false) {
975// emit signal_rdb_found (QString::fromStdString(p.name()), rdbs);
976// }
977// }
978// }
979
980// void dbe::MainWindow::slot_rdb_selected ( QAction * action )
981// {
982// QMenu * parentMenu = qobject_cast<QMenu *> ( action->parent() );
983
984// if ( parentMenu )
985// {
986// if ( dbreload() )
987// {
988// BOOST_SCOPE_EXIT(void)
989// {
990// QApplication::restoreOverrideCursor();
991// }
992// BOOST_SCOPE_EXIT_END
993
994// QApplication::setOverrideCursor(Qt::WaitCursor);
995
996// confaccessor::setdbinfo ( action->text() + "@" + parentMenu->title(), dbinfo::rdb );
997
998// if ( dbload() )
999// {
1000// setinternals();
1001// build_class_tree_model();
1002// build_partition_tree_model();
1003// build_resource_tree_model();
1004// build_file_model();
1005// }
1006// }
1007// }
1008// }
1009
1010// void dbe::MainWindow::slot_oracle_prepare()
1011// {
1012// if ( this_oraclewidget == nullptr )
1013// {
1014// this_oraclewidget = new OracleWidget();
1015// connect ( this_oraclewidget, SIGNAL ( OpenOracleConfig ( const QString & ) ), this,
1016// SLOT ( slot_load_oracle ( const QString & ) ) );
1017// }
1018
1019// this_oraclewidget->raise();
1020// this_oraclewidget->show();
1021// }
1022
1023// void dbe::MainWindow::slot_load_oracle ( const QString & OracleDatabase )
1024// {
1025// if ( dbreload() )
1026// {
1027// confaccessor::setdblocation ( OracleDatabase );
1028
1029// if ( dbload() )
1030// {
1031// setinternals();
1032// build_class_tree_model();
1033// build_partition_tree_model();
1034// build_resource_tree_model();
1035// build_file_model();
1036// }
1037// }
1038
1039// if ( this_oraclewidget != nullptr )
1040// {
1041// this_oraclewidget->close();
1042// }
1043// }
1044
1045void
1047{
1048 QWhatsThis::enterWhatsThisMode();
1049}
1050
1051void
1053{
1054 static QString const title("About DBE");
1055 static QString const msg = QString()
1056 .append("DBE is an editor to work with OKS and RDB backends that manages most of the "
1057 "hard work for you in editing the configuration database\n")
1058 .append("\n\nMaintained :\t\tC&C Working group \n\t\t\t(atlas-tdaq-cc-wg@cern.ch)")
1059 .append("\nProgram version:\t\t")
1060 .append(dbe_compiled_version)
1061 .append("\nLibraries version:\t")
1062 .append("\n\t\t\tdbecore(")
1063 .append(dbe_lib_core_version)
1064 .append("),\n\t\t\tdbe_config_api(")
1066 .append("),\n\t\t\tdbe_structure(")
1068 .append("),\n\t\t\tdbe_internal(")
1070 .append(')')
1071 .append("\nRepo commit hash:\t")
1072 .append(dbe_compiled_commit);
1073
1074 QMessageBox::about(this, title, msg);
1075}
1076
1077void
1079{
1080 QDesktopServices::openUrl(QUrl("https://atlasdaq.cern.ch/dbe/"));
1081}
1082
1083void
1085{
1086 InfoWidget->setCurrentIndex(InfoWidget->indexOf(CommitedTab));
1087}
1088
1089void
1091{
1092 UndoView->stack()->setIndex(0);
1093}
1094
1095void
1097{
1098 if (CaseSensitiveCheckBoxTree->isChecked())
1099 this_treefilter->setFilterCaseSensitivity(Qt::CaseSensitive);
1100 else {
1101 this_treefilter->setFilterCaseSensitivity(Qt::CaseInsensitive);
1102 }
1104}
1105
1106void
1108{
1110 confaccessor::gethandler()->ResetData();
1113
1114 for (int i = 0; i < tableholder->count(); i++) {
1115 TableTab* CurrentTab = dynamic_cast<TableTab*>(tableholder->widget(i));
1116 if (CurrentTab) {
1117 CurrentTab->DisconnectView();
1118 }
1119 }
1120
1121 FileView->setModel(NULL);
1122
1125}
1126
1127void
1129{
1130 if (this_treefilter != nullptr and SearchBox->currentIndex() != 1) {
1132
1133 if (SearchBox->currentIndex() == 2) {
1134 this_treefilter->SetFilterRestrictionLevel(1000);
1135 } else {
1136 this_treefilter->SetFilterRestrictionLevel(1);
1137 }
1138
1139 this_treefilter->setFilterRegExp(FilterText);
1140 }
1141
1143}
1144
1145void
1147{
1148 if (this_treefilter == nullptr) {
1149 return;
1150 }
1151
1152 QString Tmp = SearchTreeLine->text();
1153 if (SearchBox->currentIndex() == 1) {
1155 std::vector<dbe::tref> Objects = ProcessQuery(Tmp);
1156
1157 this_treefilter->SetQueryObjects(Objects);
1158 this_treefilter->setFilterRegExp(Tmp);
1160 } else {
1161 this_treefilter->ResetQueryObjects();
1163 }
1164}
1165
1166void
1168{
1169 TableTab* CurrentTab = dynamic_cast<TableTab*>(tableholder->currentWidget());
1170
1171 if (CurrentTab) {
1172 dbe::models::tableselection* TableFilter = CurrentTab->GetTableFilter();
1173
1174 if (TableFilter == nullptr) {
1175 return;
1176 }
1177
1179
1180 if (CaseSensitiveCheckBoxTable->isChecked())
1181 TableFilter->setFilterCaseSensitivity(Qt::CaseSensitive);
1182 else {
1183 TableFilter->setFilterCaseSensitivity(Qt::CaseInsensitive);
1184 }
1185
1186 TableFilter->setFilterRegExp(FilterText);
1187 }
1188}
1189
1190void
1192{
1193 // Keep track of the selected tab
1194 int IndexOfCurrentTab = tableholder->currentIndex();
1195
1196 // Here are the all the open tabs
1197 std::vector<QModelIndex> idxs;
1198
1199 for (int i = 0; i < tableholder->count(); ++i) {
1200 TableTab* CurrentTab = dynamic_cast<TableTab*>(tableholder->widget(i));
1201 if (CurrentTab) {
1202 if (CurrentTab->GetTableModel()) {
1203 const QString& TableClassName = CurrentTab->GetTableModel()->get_class_name();
1204 if (!TableClassName.isEmpty()) {
1205 treenode* NodeClass = confaccessor::gethandler()->getnode(TableClassName);
1206 if (NodeClass != nullptr) {
1207 idxs.push_back(this_classes->getindex(NodeClass));
1208 }
1209 }
1210 }
1211 }
1212 }
1213
1214 // Remove all the tabs
1215 while (tableholder->count() != 0) {
1216 tableholder->widget(0)->deleteLater();
1217 tableholder->removeTab(0);
1218 }
1219
1220 // Disconnecting models from views
1222
1223 // Re-create all the tabs
1224 for (const auto& idx : idxs) {
1225 slot_add_tab();
1226 edit_object_at(idx);
1227 }
1228
1229 // Set the current tab
1230 tableholder->setCurrentIndex(IndexOfCurrentTab);
1231}
1232
1233void
1235{
1236 int total = 0;
1237 for (int item = 0; item < this_treefilter->rowCount(); item++) {
1238 auto index = this_treefilter->index(item, 1);
1239 auto data = this_treefilter->data(index);
1240 total += data.toInt();
1241 }
1242 TotalObjectsLabel->setText(QString("Total Objects: %1").arg(total));
1243}
1244
1245void
1247{
1248 if (isArchivedConf || check_close()) {
1249 WriteSettings();
1250
1251 foreach (QWidget* widget, QApplication::allWidgets())
1252 widget->close();
1253
1254 event->accept();
1255 } else {
1256 event->ignore();
1257 }
1258}
1259
1260std::vector<dbe::tref>
1262{
1263 if (not Tmp.isEmpty()) {
1264 QString const Query = QString("(this (object-id \".*%1.*\" ~=))").arg(Tmp);
1265
1266 try {
1267 std::vector<dbe::tref> result;
1268
1269 for (std::string const& cname : dbe::config::api::info::onclass::allnames<std::vector<std::string>>()) {
1270 std::vector<dbe::tref> class_matching_objects = inner::dbcontroller::gets(cname, Query.toStdString());
1271
1272 result.insert(result.end(), class_matching_objects.begin(), class_matching_objects.end());
1273 }
1274
1275 return result;
1276 } catch (dunedaq::conffwk::Exception const& ex) {
1277 ers::error(ex);
1278 ERROR("Query process error", dbe::config::errors::parse(ex).c_str());
1279 }
1280 }
1281
1282 return {};
1283}
1284
1285bool
1286dbe::MainWindow::eventFilter(QObject* Target, QEvent* Event)
1287{
1288 if (Target == SearchBox->lineEdit() && Event->type() == QEvent::MouseButtonRelease) {
1289 if (!SearchBox->lineEdit()->hasSelectedText()) {
1290 SearchBox->lineEdit()->selectAll();
1291 return true;
1292 }
1293 }
1294
1295 return false;
1296}
1297
1298bool
1300{
1301 bool OK = true;
1302
1303 foreach (QWidget* widget, QApplication::allWidgets()) {
1304 ObjectCreator* ObjectCreatorInstance = dynamic_cast<ObjectCreator*>(widget);
1305 ObjectEditor* ObjectEditorInstance = dynamic_cast<ObjectEditor*>(widget);
1306
1307 if (ObjectEditorInstance) {
1308 OK = ObjectEditorInstance->CanCloseWindow();
1309 }
1310
1311 if (!OK) {
1312 return false;
1313 }
1314
1315 if (ObjectCreatorInstance) {
1316 OK = ObjectCreatorInstance->CanClose();
1317 }
1318
1319 if (!OK) {
1320 return false;
1321 }
1322 }
1323
1324 {
1326
1327 if (undo_stack->isClean()) {
1328 if (undo_stack->count() == 0) {
1329 return true;
1330 } else {
1332 return true;
1333 }
1334 } else {
1335 int ret =
1336 QMessageBox::question(0,
1337 tr("DBE"),
1338 QString("There are unsaved changes.\n\nDo you want to save and commit them to the DB?\n"),
1339 QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel,
1340 QMessageBox::Save);
1341
1342 if (ret == QMessageBox::Discard) {
1344 return true;
1345 } else if (ret == QMessageBox::Save) {
1346 return slot_commit_database(true);
1347 } else if (ret == QMessageBox::Cancel) {
1348 return false;
1349 } else {
1350 return true;
1351 }
1352 }
1353 }
1354}
1355
1356void
1358{
1359 edit_object_at(this_treefilter->mapToSource(ProxyIndex));
1360}
1361
1367bool
1368dbe::MainWindow::dbopen(QString const& dbpath, dbinfo const& loadtype)
1369{
1370 if (dbreload()) {
1371 confaccessor::setdbinfo(dbpath, loadtype);
1372
1373 BOOST_SCOPE_EXIT(void)
1374 {
1375 QApplication::restoreOverrideCursor();
1376 }
1377 BOOST_SCOPE_EXIT_END
1378
1379 QApplication::setOverrideCursor(Qt::WaitCursor);
1380
1381 if (dbload()) {
1382 setinternals();
1384 // build_partition_tree_model();
1385 // build_resource_tree_model();
1387 }
1388 }
1389
1390 return true;
1391}
1392
1393void
1395{
1396 QFileDialog FileDialog(this, tr("Open File"), ".", tr("XML files (*.xml)"));
1397 FileDialog.setAcceptMode(QFileDialog::AcceptOpen);
1398 FileDialog.setFileMode(QFileDialog::ExistingFile);
1399 FileDialog.setViewMode(QFileDialog::Detail);
1400
1401 if (FileDialog.exec()) {
1402 QStringList FilesSelected = FileDialog.selectedFiles();
1403
1404 if (FilesSelected.size()) {
1405 QString DatabasePath = FilesSelected.value(0);
1406 dbopen(DatabasePath, dbinfo::oks);
1407 }
1408 }
1409}
1410
1421void
1423{
1424 auto user_confirmation = [](QString const& msg) {
1425 QMessageBox ExternalMessageBox;
1426 ExternalMessageBox.setText(msg);
1427 ExternalMessageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
1428 ExternalMessageBox.setDefaultButton(QMessageBox::Yes);
1429 return ExternalMessageBox.exec() == QMessageBox::Yes;
1430 };
1431
1433
1434 auto rewind_stack = [&undo_stack]() {
1435 std::vector<bool> commands_original_undo_state;
1436
1437 // Loop over the commands and set their undo-state to false such that when the undostack
1438 // index is rewind to zero they will not be undone. The purpose is to replay them on top of
1439 // current changes.
1440
1441 for (int i = 0; i < undo_stack->count(); ++i) {
1442 if (dbe::actions::onobject const* Command = dynamic_cast<dbe::actions::onobject const*>(undo_stack->command(i))) {
1443 commands_original_undo_state.push_back(Command->undoable());
1444 Command->setundoable(false);
1445 }
1446 }
1447
1448 // Rewind the command stack by setting the index to zero
1449 // Commands will not be replayed since we have set their state to false
1450 undo_stack->setIndex(0);
1451
1452 // Reset the state of all commands one by one
1453 {
1454 auto cmdstate = commands_original_undo_state.begin();
1455
1456 for (int i = 0; i != undo_stack->count(); ++i) {
1457 if (dbe::actions::onobject const* Command =
1458 dynamic_cast<dbe::actions::onobject const*>(undo_stack->command(i))) {
1459 Command->setundoable(*cmdstate++);
1460 }
1461 }
1462 }
1463 };
1464
1465 // Close active editor widgets before replaying changes
1466 for (QWidget* widget : QApplication::allWidgets()) {
1467 if (dynamic_cast<widgets::editors::relation*>(widget)) {
1468 widget->close();
1469 }
1470 }
1471
1472 if (undo_stack->count() != 0) {
1473 const QString msg =
1474 QString("External changes to the database have been applied. Do you want to replay your changes on top? ") +
1475 QString(" Otherwise any local change will be lost.\n");
1476 if (user_confirmation(msg)) {
1477 rewind_stack();
1478
1479 // Empty the internal stack and place the changes in a reverse order in a local stack
1480 confaccessor::t_internal_changes_stack internal_changes_reverse_copy;
1481 auto internal_changes = confaccessor::get_internal_change_stack();
1482
1483 while (not internal_changes->empty()) {
1484 internal_changes_reverse_copy.push(internal_changes->top());
1485 internal_changes->pop();
1486 }
1487
1488 // Replay the commands one by one
1489 for (int i = 0; i < undo_stack->count(); ++i) {
1490 config_internal_change Change = internal_changes_reverse_copy.top();
1491 internal_changes_reverse_copy.pop();
1492 internal_changes->push(Change);
1493
1494 try {
1495
1496 dbe::actions::onobject const* Command = dynamic_cast<dbe::actions::onobject const*>(undo_stack->command(i));
1497
1498 if (not Command->redoable()) {
1499 undo_stack->redo();
1500 } else {
1501 // If the object we are trying to make the changes to does not exist it means it was deleted
1502
1503 if ((dbe::config::api::info::has_obj(Change.classname, Change.uid) and
1507 // If in virtue of external modification the object still exists and our action was not a creation
1508 Command->reload();
1509 undo_stack->redo();
1510 } else if (not dbe::config::api::info::has_obj(Change.classname, Change.uid) and
1512 // If the external changes have removed the object and we have created it
1513 undo_stack->redo();
1514 Command->reload();
1515 } else {
1517 Command->setredoable(false);
1518 Command->setundoable(false);
1519
1520 // Advance the stack by redoing an non-redoable (i.e. the redo action has no effect) command
1521 undo_stack->redo();
1522 }
1523 }
1524
1525 } catch (dunedaq::conffwk::Exception const& e) {
1526 WARN("Object reference could not be changed",
1527 dbe::config::errors::parse(e).c_str(),
1528 "for object with UID:",
1529 Change.uid,
1530 "of class",
1531 Change.classname);
1532 } catch (...) {
1533 WARN("Unknown exception during object modification",
1534 "s",
1535 "\n\nFor object with UID:",
1536 Change.uid.c_str(),
1537 "of class:",
1538 Change.classname.c_str());
1539 }
1540 }
1541 } else {
1543 }
1544 } else {
1545 INFO("Database reloaded due external changes", "Database consistency enforcement");
1547 }
1548
1551
1552 // Emit the signal for connected listeners (e.g., the object editors)
1554}
1555
1563{
1564 QWidgetList allwidgets = QApplication::topLevelWidgets();
1565
1566 QWidgetList::iterator it = allwidgets.begin();
1567 MainWindow* main_win = qobject_cast<MainWindow*>(*it);
1568
1569 for (; it != allwidgets.end() and main_win == nullptr; ++it) {
1570 main_win = qobject_cast<MainWindow*>(*it);
1571 }
1572
1573 return main_win;
1574}
1575
1576//-----------------------------------------------------------------------------------------------------------------------------
1577
1578//-----------------------------------------------------------------------------------------------------------------------------
1586namespace {
1587const int MAX_MESSAGE_LENGTH = 500;
1588}
1589
1590void
1591dbe::MainWindow::display_message_box(const QString& title, const QString& msg, const QMessageBox::Icon& icon)
1592{
1593 QMessageBox mb(this);
1594 mb.setIcon(icon);
1595 mb.setWindowTitle(title);
1596 mb.setStandardButtons(QMessageBox::Ok);
1597 if (msg.length() > MAX_MESSAGE_LENGTH) {
1598 QString&& truncated_msg = msg.left(MAX_MESSAGE_LENGTH);
1599 truncated_msg.append("...");
1600 mb.setText(
1601 "<b>The message has been truncated because it is too long, look at the details for the full message</b>");
1602 mb.setInformativeText(truncated_msg);
1603 mb.setDetailedText(msg);
1604 } else {
1605 mb.setText(msg);
1606 }
1607
1608 mb.exec();
1609}
1610
1618void
1619dbe::MainWindow::slot_information_message(QString const title, QString const msg)
1620{
1621 display_message_box(title, msg, QMessageBox::Icon::Information);
1622}
1623
1631void
1632dbe::MainWindow::slot_error_message(QString const title, QString const msg)
1633{
1634 display_message_box(title, msg, QMessageBox::Icon::Critical);
1635}
1636
1644void
1645dbe::MainWindow::slot_warning_message(QString const title, QString const msg)
1646{
1647 display_message_box(title, msg, QMessageBox::Icon::Warning);
1648}
1649
1650//-----------------------------------------------------------------------------------------------------------------------------
1651
1654{
1655 return cptr<CustomTreeView>(TreeView);
1656}
1657
1658void
1663
1664void
1665dbe::MainWindow::slot_batch_change_stop(const QList<QPair<QString, QString>>& objs)
1666{
1667 std::vector<dbe::dref> objects;
1668 for (const auto& o : objs) {
1669 objects.push_back(inner::dbcontroller::get({ o.second.toStdString(), o.first.toStdString() }));
1670 }
1671
1672 // This allows to not reset the main tree
1673 this_classes->objectsUpdated(objects);
1674
1675 // In this case the corresponding trees are reset
1676 // In order to apply the same policy as in the class tree
1677 // the subtree_proxy class needs to be completed with proper
1678 // implementation of slots when objects are modified
1679
1680 // Proper "refresh" of table tabs
1681 for (int i = 0; i < tableholder->count(); i++) {
1682 TableTab* CurrentTab = dynamic_cast<TableTab*>(tableholder->widget(i));
1683 if (CurrentTab) {
1684 dbe::models::table* m = CurrentTab->GetTableModel();
1685 if (m) {
1686 m->objectsUpdated(objects);
1687 }
1688 }
1689 }
1690
1691 emit signal_batch_change_stopped(objs);
1692
1694}
1695
1696void
1698{
1699 if (isArchivedConf == false) {
1700 const auto& uncommittedFiles = confaccessor::uncommitted_files();
1701
1702 if (uncommittedFiles.empty() == true) {
1703 Commit->setEnabled(false);
1704 Commit->setToolTip("There is nothing to commit");
1705 } else {
1706 Commit->setEnabled(true);
1707
1708 std::string l;
1709 for (const std::string& f : uncommittedFiles) {
1710 l += " " + f + "\n";
1711 }
1712
1713 Commit->setToolTip(QString::fromStdString("Commit changes.\nHere are the uncommitted files:\n" + l));
1714 }
1715
1717
1718 } else {
1719 Commit->setEnabled(false);
1720 }
1721}
1722
1723void
1724dbe::MainWindow::slot_update_committed_files(const std::list<std::string>& files, const std::string& msg)
1725{
1726 for (const std::string& f : files) {
1727 CommittedTable->insertRow(0);
1728 CommittedTable->setItem(0, 0, new QTableWidgetItem(QString::fromStdString(f)));
1729 CommittedTable->setItem(0, 1, new QTableWidgetItem(QString::fromStdString(msg)));
1730 CommittedTable->setItem(
1731 0, 2, new QTableWidgetItem(QDate::currentDate().toString() + " " + QTime::currentTime().toString()));
1732 }
1733
1734 CommittedTable->resizeColumnsToContents();
1735}
1736
1737bool
1742
1743void
1745{
1746 allFiles.insert(file);
1747}
1748
1749void
1751{
1752 auto prefs = new Preferences();
1753 prefs->show();
1754}
char const *const dbe_lib_core_version
Including DBE.
Definition cptr.hpp:56
cptr(T *p)
Definition cptr.hpp:63
BatchChangeWidget(QWidget *parent=nullptr)
CommitDialog(QWidget *parent=0)
QString GetCommitMessage() const
CreateDatabaseWidget(QWidget *parent=nullptr, bool Include=false, const QString &CreateDir=QString())
static void parse_all_objects()
Definition FileInfo.cpp:125
static QString check_file_includes(const QString &file)
Definition FileInfo.cpp:143
static void show_file_info(const QString &filename)
Definition FileInfo.cpp:505
FileModel(QObject *parent=nullptr)
Including QT Headers.
Definition FileModel.cpp:18
void slot_fetch_data(treenode const *)
void slot_information_message(QString const, QString const)
void edit_object_at(const QModelIndex &Index)
bool dbopen(QString const &, dbinfo const &)
void slot_show_userchanges()
void slot_update_committed_files(const std::list< std::string > &, const std::string &)
void slot_warning_message(QString const, QString const)
std::atomic< bool > isArchivedConf
void slot_batch_change_start()
void slot_loaded_db_file(QString)
void slot_batch_change_stop(const QList< QPair< QString, QString > > &)
void slot_remove_tab(int i)
dbe::models::tree * this_classes
void slot_launch_object_editor(tref)
void slot_abort_changes()
void slot_process_externalchanges()
void slot_toggle_casesensitive_for_treeview(bool)
void load_default_settings()
void display_message_box(const QString &title, const QString &msg, const QMessageBox::Icon &icon)
void slot_launch_batchchange_on_table()
void build_class_tree_model()
QSet< QString > allFiles
void slot_toggle_commit_button()
void closeEvent(QCloseEvent *event)
void slot_load_db_from_create_widget(const QString &)
void build_file_model()
bool slot_commit_database(bool Exit=false)
void argsparse(QMap< QString, QString > const &)
void slot_launch_batchchange()
void apply_settings(QSettings &setting)
cptr< dbe::CustomTreeView > get_view() const
models::treeselection * this_treefilter
void slot_error_message(QString const, QString const)
bool eventFilter(QObject *Target, QEvent *Event)
void slot_open_database_from_file()
void slot_abort_external_changes()
void signal_new_file_model()
QString find_db_repository_dir()
void build_table_model()
FileModel * this_files
void slot_create_newdb()
void slot_show_userguide()
static MainWindow * findthis()
void slot_undo_allchanges()
void slot_model_rebuild()
bool m_batch_change_in_progress
void slot_edit_object_from_class_view(QModelIndex const &)
void slot_filter_table_textchange(const QString &)
void signal_db_loaded()
void slot_filter_textchange(const QString &)
void signal_externalchanges_processed()
std::vector< dbe::tref > ProcessQuery(QString const &)
void signal_batch_change_stopped(const QList< QPair< QString, QString > > &)
void update_total_objects()
void reload_default_settings()
bool check_ready() const
MainWindow(QMap< QString, QString > const &CommandLine, QWidget *parent=nullptr)
void slot_launch_preferences()
QSortFilterProxyModel this_filesort
void slot_show_information_about_dbe()
ObjectEditor(QWidget *parent=nullptr)
tref GetObject() const
Definition treenode.cpp:276
Preferences(QWidget *parent=0)
static void InitColorManagement()
TableTab(QWidget *parent=0)
Including Qt.
Definition TableTab.cpp:24
void DisconnectView()
Definition TableTab.cpp:88
dbe::models::table * GetTableModel() const
Definition TableTab.cpp:185
dbe::models::tableselection * GetTableFilter() const
Definition TableTab.cpp:191
void setundoable(bool s=true) const
Definition Command.cpp:451
void reload() const
Definition Command.cpp:493
void setredoable(bool s=true) const
Definition Command.cpp:457
bool redoable() const
Definition Command.cpp:469
static cptr< datahandler > gethandler()
static t_undo_stack_cptr get_commands()
static bool is_database_loaded()
cptr< t_undo_stack > t_undo_stack_cptr
static std::list< std::string > uncommitted_files()
std::stack< t_internal_change, std::vector< t_internal_change > > t_internal_changes_stack
static void abort()
static void set_total_objects(int const i)
static void clear_commands()
static QString dbfullname()
static t_internal_changes_stack_cptr get_internal_change_stack()
static bool load(bool subscribeToChanges=true)
static std::list< std::string > save(QString const &)
static void setdbinfo(QString const &location, dbinfo const itype=dbinfo::oks)
static confaccessor & ref()
static QString db_implementation_name()
static QStringList inclusions(QStringList const &candidates, QStringList files={})
static dunedaq::conffwk::class_t definition(std::string const &cn, bool direct_only)
static std::vector< configobject::tref > gets(std::string const &cname, std::string const &query="")
static configobject::tref get(dbe::cokey const &desc)
static messenger_proxy & ref()
QList< dbe::dref > * GetTableObjects()
Definition table.cpp:436
QString get_class_name() const
Definition table.cpp:424
bool BuildTableFromClass(const QString &ClassName, bool BuildSubClasses=false)
Definition table.cpp:252
void SetFilterType(FilterType Filter)
virtual QVariant GetData(const int Column, int role=Qt::DisplayRole) const
Definition treenode.cpp:60
int GetRow() const
Definition treenode.cpp:82
char const *const dbe_lib_internal_version
char const *const dbe_lib_config_api_version
#define ERROR(...)
Definition messenger.hpp:90
#define WARN(...)
Definition messenger.hpp:82
#define INFO(...)
Definition messenger.hpp:98
bool has_obj(std::string const &classname, std::string const &object_uid)
std::string const parse(ers::Issue const &)
inner::configobject::tref tref
Definition tref.hpp:36
dbinfo
Definition dbinfo.hpp:19
config_object_description dref
void error(const Issue &issue)
Definition ers.hpp:101
modification request
Type of modification.
std::string uid
Object Identification.
char const *const dbe_lib_structure_version
Including QT Headers.
Definition tree.cpp:17
#define dbe_compiled_version
Definition version.hpp:22
#define dbe_compiled_commit
Definition version.hpp:28