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