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