LCOV - code coverage report
Current view: top level - dbe/src/structure - FileInfo.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 0.0 % 324 0
Test Date: 2026-03-29 15:29:34 Functions: 0.0 % 32 0

            Line data    Source code
       1              : #include "dbe/confaccessor.hpp"
       2              : #include "dbe/config_api.hpp"
       3              : #include "dbe/config_api_commands.hpp"
       4              : #include "dbe/FileInfo.hpp"
       5              : #include "dbe/MainWindow.hpp"
       6              : #include "dbe/ObjectEditor.hpp"
       7              : #include "dbe/StyleUtility.hpp"
       8              : 
       9              : #include "ui_FileInfo.h"
      10              : 
      11              : #include <QFileDialog>
      12              : #include <QInputDialog>
      13              : #include <QListWidgetItem>
      14              : #include <QString>
      15              : #include <QWidget>
      16              : 
      17              : namespace dbegraph = dbe::config::api::graph;
      18              : 
      19              : namespace dbe {
      20              : 
      21              : QString FileInfo::s_schema_path{"."};
      22              : QString FileInfo::s_data_path{"."};
      23              : QStringList FileInfo::s_path_list{};
      24              : QList<QUrl> FileInfo::s_path_urls{};
      25              : std::map<QString, std::map<QString, const tref>> FileInfo::s_obj_map{};
      26              : 
      27            0 : void FileInfo::setup_paths() {
      28            0 :   QString DUNEDAQ_DB_PATH = getenv ( "DUNEDAQ_DB_PATH" );
      29            0 :   s_path_list.clear();
      30            0 :   s_path_urls.clear();
      31            0 :   auto path_list = DUNEDAQ_DB_PATH.split (QLatin1Char(':'), Qt::SkipEmptyParts );
      32            0 :   for ( QString & path : path_list ) {
      33            0 :     char* rpath =  realpath(path.toStdString().c_str(), NULL);
      34            0 :     path = QString(rpath);
      35            0 :     free(rpath);
      36              : 
      37            0 :     if (! path.isEmpty()) {
      38            0 :       if ( !path.endsWith ( "/" ) ) {
      39            0 :         path.append ( "/" );
      40              :       }
      41            0 :       s_path_urls.append(QUrl::fromLocalFile(path));
      42            0 :       s_path_list.append(path);
      43              :     }
      44              :   }
      45            0 : }
      46              : 
      47            0 : QString FileInfo::prune_path(QString file) {
      48            0 :   if (s_path_list.isEmpty()) {
      49            0 :     setup_paths();
      50              :   }
      51            0 :   for (const QString& element : s_path_list) {
      52            0 :     if (file.startsWith(element)) {
      53            0 :       file.remove(element);
      54              :       break;
      55              :     }
      56              :   }
      57            0 :   return file;
      58              : }
      59              : 
      60            0 : bool FileInfo::match_path(QString& file, QStringList& includes) {
      61            0 :   if (s_path_list.isEmpty()) {
      62            0 :     setup_paths();
      63              :   }
      64              : 
      65            0 :   QStringList candidates{file};
      66              :   // element is a copy here, not a reference
      67            0 :   for (const QString element : s_path_list) {
      68            0 :     if (file.startsWith(element)) {
      69            0 :       candidates.append(file.remove(element));
      70              :     }
      71            0 :   }
      72              : 
      73            0 :   for (auto cand : candidates) {
      74            0 :     if (includes.contains(cand)) {
      75            0 :       return true;
      76              :     }
      77            0 :   }
      78            0 :   return false;
      79            0 : }
      80              : 
      81            0 : QList<QUrl>  FileInfo::get_path_urls(){
      82            0 :   if (s_path_urls.isEmpty()) {
      83            0 :     setup_paths();
      84              :   }
      85            0 :   return s_path_urls;
      86              : }
      87            0 : QStringList FileInfo::get_path_list(){
      88            0 :   if (s_path_list.isEmpty()) {
      89            0 :     setup_paths();
      90              :   }
      91            0 :   return s_path_list;
      92              : }
      93              : 
      94            0 : void FileInfo::parse_all_objects() {
      95            0 :   s_obj_map.clear();
      96            0 :   for (auto const& class_name :
      97            0 :          config::api::info::onclass::allnames <std::vector<std::string>>()) {
      98            0 :     for (auto obj : config::api::info::onclass::objects(class_name, false)) {
      99            0 :       auto file = prune_path(QString::fromStdString(obj.contained_in()));
     100            0 :       auto name = QString::fromStdString(obj.full_name());
     101            0 :       if (!s_obj_map.contains(file)) {
     102            0 :         s_obj_map.insert({file,{}});
     103              :       }
     104            0 :       s_obj_map.at(file).insert({name, obj});
     105            0 :     }
     106            0 :   }
     107            0 : }
     108              : 
     109            0 : QString FileInfo::check_file_includes(const QString& filename) {
     110            0 :   QString message{};
     111              : 
     112            0 :   QStringList includes(config::api::get::file::inclusions_singlefile (
     113            0 :                          filename));
     114            0 :   if (s_obj_map.contains(prune_path(filename))) {
     115            0 :     for (auto [id, obj] : s_obj_map.at(prune_path(filename))) {
     116            0 :       dunedaq::conffwk::class_t const & classdef =
     117            0 :         dbe::config::api::info::onclass::definition (obj.class_name(), false);
     118              : 
     119            0 :       auto schema_file = QString::fromStdString(classdef.p_schema_path);
     120            0 :       if (!match_path(schema_file, includes)) {
     121            0 :         message += QString("Object <i>" + id + "</i> is of class <i>"
     122            0 :                            + QString::fromStdString(obj.class_name())
     123            0 :                            + "</i> defined in file <b>" + schema_file
     124            0 :                            + "</b> which is not included<br>");
     125              :       }
     126            0 :       std::vector<tref> relobjs;
     127            0 :       for (auto rel: classdef.p_relationships) {
     128            0 :         if (config::api::info::relation::is_simple(rel)) {
     129            0 :           try {
     130            0 :             relobjs.push_back(dbegraph::linked::through::relation<tref> (obj, rel));
     131              :           }
     132            0 :           catch ( daq::dbe::config_object_retrieval_result_is_null const & e ) {
     133              :             // nothing needs be done to handle cases that a relation has not been set
     134            0 :           }
     135              :         }
     136              :         else {
     137            0 :           relobjs = dbegraph::linked::through::relation<std::vector<tref>> (obj, rel);
     138              :         }
     139              : 
     140            0 :         includes.append(prune_path(filename));
     141            0 :         for (auto relobj : relobjs) {
     142            0 :           auto file = QString::fromStdString(relobj.contained_in());
     143            0 :           if (!(match_path(file, includes))) {
     144            0 :             message += QString("Object <i>" + id + "</i> has relationship to <i>"
     145            0 :                                + QString::fromStdString(relobj.full_name())
     146            0 :                                + "</i> in file <b>" + file
     147            0 :                                + "</b> which is not included<br>");
     148              :           }
     149            0 :         }
     150            0 :       }
     151            0 :     }
     152              :   }
     153            0 :   return message;
     154            0 : }
     155              : 
     156              : 
     157            0 : FileInfo::FileInfo(QString filename, QWidget* /*parent*/)
     158            0 :   : m_ui(new Ui::FileInfo), m_filename(filename), m_uuid(QUuid::createUuid()) {
     159              : 
     160            0 :   QWidget::setAttribute(Qt::WA_DeleteOnClose);
     161              : 
     162            0 :   m_ui->setupUi(this);
     163            0 :   m_ui->filename->setText(filename);
     164            0 :   if (confaccessor::check_file_rw(filename)) {
     165            0 :     m_ui->rstatus->setText(QString("RW"));
     166            0 :     m_readonly = false;
     167              :   }
     168              :   else {
     169            0 :     m_ui->rstatus->setText(QString("RO"));
     170            0 :     m_readonly = true;
     171              :   }
     172              : 
     173            0 :   setObjectName(filename);
     174            0 :   setWindowTitle("File:  " + filename.section('/',-1));
     175              : 
     176            0 :   setup_paths();
     177            0 :   parse_includes();
     178            0 :   parse_objects();
     179              : 
     180            0 :   m_ui->schema_list->setContextMenuPolicy ( Qt::ContextMenuPolicy::CustomContextMenu );
     181            0 :   m_ui->data_list->setContextMenuPolicy ( Qt::ContextMenuPolicy::CustomContextMenu );
     182            0 :   m_ui->object_list->setContextMenuPolicy ( Qt::ContextMenuPolicy::CustomContextMenu );
     183              : 
     184            0 :   connect (m_ui->add_schema, SIGNAL(pressed()), this, SLOT (add_schemafile()));
     185            0 :   connect (m_ui->add_data, SIGNAL(pressed()), this, SLOT (add_datafile()));
     186              : 
     187            0 :   connect (m_ui->schema_list, SIGNAL (customContextMenuRequested(QPoint)),
     188              :            this, SLOT (activate_schema_context_menu(QPoint)));
     189              : 
     190            0 :   connect (m_ui->data_list, SIGNAL (customContextMenuRequested(QPoint)),
     191              :            this, SLOT (activate_data_context_menu(QPoint)));
     192            0 :   connect (m_ui->data_list, SIGNAL (itemActivated(QListWidgetItem*)),
     193              :            this, SLOT (file_info_slot(QListWidgetItem*)) );
     194              : 
     195            0 :   connect (m_ui->object_list, SIGNAL (itemActivated(QListWidgetItem*)),
     196              :            this, SLOT (edit_object_slot(QListWidgetItem*)) );
     197            0 :   connect (m_ui->object_list, SIGNAL (customContextMenuRequested(QPoint)),
     198              :            this, SLOT (activate_object_context_menu(QPoint)));
     199              : 
     200            0 :   connect (MainWindow::findthis(), SIGNAL(signal_new_file_model()),
     201              :            this, SLOT (filemodel_updated()));
     202            0 : }
     203              : 
     204            0 : void FileInfo::filemodel_updated() {
     205            0 :   parse_includes();
     206            0 :   parse_objects();
     207            0 : }
     208              : 
     209              : 
     210              : 
     211            0 : void FileInfo::parse_objects() {
     212            0 :   parse_all_objects();
     213            0 :   m_ui->object_list->clear();
     214            0 :   if (s_obj_map.contains(prune_path(m_filename))) {
     215            0 :     auto& omap = s_obj_map.at(prune_path(m_filename));
     216            0 :     for (auto const& [obj_name, obj_ref] : omap) {
     217            0 :       auto item = new QListWidgetItem(obj_name);
     218            0 :       m_ui->object_list->addItem(item);
     219              :     }
     220              :   }
     221            0 :   m_ui->object_list->update();
     222              : 
     223            0 :   m_ui->warningBox->setVisible(!check_includes());
     224            0 : }
     225              : 
     226              : 
     227            0 : bool FileInfo::check_includes() {
     228            0 :   QString message = check_file_includes(m_filename);
     229            0 :   m_ui->message->setText(message);
     230            0 :   return message.isEmpty();
     231            0 : }
     232              : 
     233            0 : void FileInfo::parse_includes() {
     234            0 :   QStringList includes(config::api::get::file::inclusions_singlefile (
     235            0 :                          m_filename));
     236            0 :   m_ui->schema_list->clear();
     237            0 :   m_ui->data_list->clear();
     238            0 :   for (auto inc: includes) {
     239            0 :     auto item = new QListWidgetItem(inc);
     240            0 :     if (!confaccessor::check_file_rw(inc)) {
     241            0 :       item->setForeground(QBrush(StyleUtility::FileReadOnlyForeground));
     242            0 :       item->setBackground(QBrush(StyleUtility::FileReadOnlyBackground));
     243              :     }
     244            0 :     if (inc.endsWith(".schema.xml")) {
     245            0 :       m_ui->schema_list->addItem(item);
     246              :     }
     247            0 :     if (inc.endsWith(".data.xml")) {
     248            0 :       m_ui->data_list->addItem(item);
     249              :       
     250              :     }
     251            0 :   }
     252            0 :   m_ui->schema_list->update();
     253            0 :   m_ui->data_list->update();
     254            0 : }
     255              : 
     256            0 : void FileInfo::keyPressEvent(QKeyEvent* event) {
     257            0 :   if (event->key() == Qt::Key_Escape) {
     258            0 :     close();
     259              :   }
     260            0 :   QWidget::keyPressEvent(event);
     261            0 : }
     262              : 
     263            0 : void FileInfo::accept() {
     264            0 :   close();
     265            0 : }
     266            0 : void FileInfo::reject() {
     267            0 :   close();
     268            0 : }
     269              : 
     270            0 : void FileInfo::edit_object_slot() {
     271            0 :   auto item = m_ui->object_list->currentItem();
     272            0 :   edit_object_slot(item);
     273            0 : }
     274              : 
     275            0 : void FileInfo::edit_object_slot(QListWidgetItem* item) {
     276            0 :   auto name = item->text();
     277            0 :   if (s_obj_map.at(prune_path(m_filename)).contains(name)) {
     278            0 :     for ( QWidget * widget : QApplication::allWidgets() ) {
     279            0 :       auto oe = dynamic_cast<ObjectEditor*> ( widget );
     280            0 :       if ( oe != nullptr ) {
     281            0 :         if (oe->objectName() == name) {
     282            0 :           oe->raise();
     283            0 :           oe->setVisible ( true );
     284            0 :           oe->activateWindow();
     285            0 :           return;
     286              :         }
     287              :       }
     288            0 :     }
     289              : 
     290            0 :     auto obj = s_obj_map.at(prune_path(m_filename)).at(name);
     291            0 :     auto oe = new ObjectEditor(obj);
     292            0 :     oe->show();
     293            0 :   }
     294            0 : }
     295              : 
     296            0 : void FileInfo::delete_object_slot() {
     297            0 :   auto name = m_ui->object_list->currentItem()->text();
     298            0 :   auto file = prune_path(m_filename);
     299            0 :   if (s_obj_map.at(file).contains(name)) {
     300            0 :     config::api::commands::delobj(s_obj_map.at(file).at(name), m_uuid);
     301              :   }
     302            0 :   parse_objects();
     303            0 : }
     304              : 
     305            0 : void FileInfo::rename_object_slot() {
     306            0 :   auto name = m_ui->object_list->currentItem()->text();
     307            0 :   auto file = prune_path(m_filename);
     308            0 :   if (s_obj_map.at(file).contains(name)) {
     309            0 :     QInputDialog dia(this);
     310            0 :     dia.setLabelText("Enter new name for " + name);
     311            0 :     auto code = dia.exec();
     312            0 :     if (code == QDialog::Accepted) {
     313            0 :       std::string new_name = dia.textValue().toStdString();
     314            0 :       config::api::commands::renobj(s_obj_map.at(file).at(name), new_name, m_uuid);
     315            0 :     }
     316            0 :   }
     317            0 :   parse_objects();
     318            0 : }
     319              : 
     320            0 : void FileInfo::add_datafile() {
     321            0 :   if (s_data_path == ".") {
     322            0 :     s_data_path = s_schema_path;
     323              :   }
     324            0 :   auto fd = new QFileDialog ( this, tr ( "Open Data File" ), s_data_path,
     325            0 :                               tr ( "XML data files (*.data.xml)" ) );
     326            0 :   add_includefile(fd);
     327            0 :   if (fd->result() == QDialog::Accepted) {
     328            0 :     s_data_path = fd->directory().path();
     329              :   }
     330            0 : }
     331            0 : void FileInfo::add_schemafile() {
     332            0 :   if (s_schema_path == ".") {
     333            0 :     s_schema_path = s_data_path;
     334              :   }
     335            0 :   auto fd = new QFileDialog ( this, tr ( "Open Schema File" ), s_schema_path,
     336            0 :                               tr ( "XML schema files (*.schema.xml)" ) );
     337            0 :   add_includefile(fd);
     338            0 :   if (fd->result() == QDialog::Accepted) {
     339            0 :     s_schema_path = fd->directory().path();
     340              :   }
     341            0 : }
     342            0 : void FileInfo::add_includefile(QFileDialog* fd) {
     343            0 :   fd->setFileMode ( QFileDialog::ExistingFiles );
     344            0 :   fd->setViewMode ( QFileDialog::Detail );
     345            0 :   fd->setAcceptMode ( QFileDialog::AcceptOpen );
     346            0 :   fd->setSidebarUrls(s_path_urls);
     347            0 :   if (fd->exec() == QDialog::Accepted) {
     348            0 :     auto files = fd->selectedFiles();
     349            0 :     for (auto file: files) {
     350            0 :       file = prune_path(file);
     351            0 :       config::api::commands::file::add(m_filename, file);
     352            0 :     }
     353            0 :     parse_includes();
     354            0 :     parse_objects();
     355            0 :   }
     356            0 : }
     357              : 
     358            0 : void FileInfo::remove_schemafile_slot() {
     359            0 :   remove_includefile(m_ui->schema_list->currentItem()->text());
     360            0 : }
     361            0 : void FileInfo::remove_datafile_slot() {
     362            0 :   remove_includefile(m_ui->data_list->currentItem()->text());
     363            0 : }
     364            0 : void FileInfo::remove_includefile(const QString& file) {
     365            0 :   config::api::commands::file::remove(m_filename, file);
     366            0 :   parse_includes();
     367            0 :   parse_objects();
     368            0 : }
     369              : 
     370              : 
     371            0 : void FileInfo::file_info_slot() {
     372            0 :   show_file_info(m_ui->data_list->currentItem()->text());
     373            0 : }
     374              : 
     375            0 : void FileInfo::file_info_slot(QListWidgetItem* item) {
     376            0 :   show_file_info(item->text());
     377            0 : }
     378              : 
     379            0 : void FileInfo::file_info_slot(const QString& filename) {
     380            0 :   show_file_info(filename);
     381            0 : }
     382              : 
     383            0 : void FileInfo::show_file_info(const QString& filename) {
     384            0 :   for ( QWidget * widget : QApplication::allWidgets() ) {
     385            0 :     auto fi = dynamic_cast<FileInfo *> ( widget );
     386            0 :     if ( fi != nullptr ) {
     387            0 :       if (fi->objectName() == filename) {
     388            0 :         fi->raise();
     389            0 :         fi->setVisible ( true );
     390            0 :         fi->activateWindow();
     391            0 :         return;
     392              :       }
     393              :     }
     394            0 :   }
     395              : 
     396            0 :   auto fi = new FileInfo(filename);
     397            0 :   fi->show();
     398              : }
     399              : 
     400            0 : void FileInfo::activate_schema_context_menu (QPoint pos) {
     401            0 :   if (m_schema_menu == nullptr) {
     402            0 :     m_schema_menu = new QMenu(this);
     403              : 
     404            0 :     if (!m_readonly) {
     405            0 :       auto add = new QAction("Add include file", this);
     406            0 :       connect (add, SIGNAL(triggered()), this, SLOT (add_schemafile()));
     407            0 :       m_schema_menu->addAction(add);
     408              : 
     409            0 :       auto remove = new QAction("Remove include file", this);
     410            0 :       connect (remove, SIGNAL(triggered()), this, SLOT (remove_schemafile_slot()));
     411            0 :       m_schema_menu->addAction(remove);
     412              :     }
     413              :   }
     414              : 
     415            0 :   if (m_ui->schema_list->currentIndex().isValid()) {
     416            0 :     m_schema_menu->actions().at(1)->setVisible (true);
     417              :   }
     418            0 :   m_schema_menu->exec (m_ui->schema_list->mapToGlobal(pos));
     419            0 : }
     420              : 
     421            0 : void FileInfo::activate_data_context_menu (QPoint pos) {
     422            0 :   if (m_data_menu == nullptr) {
     423            0 :     m_data_menu = new QMenu(this);
     424              : 
     425            0 :     auto info = new QAction(tr("Show file info"), this);
     426            0 :     connect (info, SIGNAL(triggered()), this, SLOT (file_info_slot()));
     427            0 :     m_data_menu->addAction(info);
     428              : 
     429            0 :     if (!m_readonly) {
     430            0 :       auto add = new QAction("Add include file", this);
     431            0 :       connect (add, SIGNAL(triggered()), this, SLOT (add_datafile()));
     432            0 :       m_data_menu->addAction(add);
     433              : 
     434            0 :       auto remove = new QAction("Remove include file", this);
     435            0 :       connect (remove, SIGNAL(triggered()), this, SLOT (remove_datafile_slot()));
     436            0 :       m_data_menu->addAction(remove);
     437              :     }
     438              :   }
     439              : 
     440            0 :   if (m_ui->data_list->currentIndex().isValid()) {
     441            0 :     m_data_menu->actions().at(0)->setVisible (true);
     442            0 :     m_data_menu->actions().at(2)->setVisible (true);
     443              :   }
     444              :   else {
     445            0 :     m_data_menu->actions().at(0)->setVisible (false);
     446            0 :     m_data_menu->actions().at(2)->setVisible (false);
     447              :   }
     448            0 :   m_data_menu->exec (m_ui->data_list->mapToGlobal(pos));
     449            0 : }
     450              : 
     451            0 : void FileInfo::activate_object_context_menu (QPoint pos) {
     452            0 :   if (m_object_menu == nullptr) {
     453            0 :     m_object_menu = new QMenu(this);
     454              : 
     455            0 :     auto edit_action = new QAction(tr("&Edit object"), this);
     456            0 :     connect (edit_action, SIGNAL(triggered()), this, SLOT(edit_object_slot()));
     457            0 :     m_object_menu->addAction(edit_action);
     458              : 
     459            0 :     auto delete_action = new QAction(tr("&Delete Object"), this );
     460            0 :     connect (delete_action, SIGNAL(triggered()), this, SLOT(delete_object_slot()));
     461            0 :     m_object_menu->addAction(delete_action);
     462              : 
     463            0 :     auto rename_action = new QAction(tr("&Rename Object"), this );
     464            0 :     connect (rename_action, SIGNAL(triggered()), this, SLOT(rename_object_slot()));
     465            0 :     m_object_menu->addAction(rename_action);
     466              :   }
     467              : 
     468            0 :   if (m_ui->object_list->currentIndex().isValid()) {
     469            0 :     m_object_menu->exec(m_ui->object_list->mapToGlobal(pos));
     470              :   }
     471            0 : }
     472              : 
     473              : } //namespace dbe
        

Generated by: LCOV version 2.0-1