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