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