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