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