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