diff --git a/CMakeLists.txt b/CMakeLists.txt index b08a214..4edf68a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.12) -project(dbe VERSION 1.8.0) +project(dbe VERSION 1.8.1) find_package(daq-cmake REQUIRED) diff --git a/include/dbe/FileInfo.hpp b/include/dbe/FileInfo.hpp index f0d2aeb..30bd75b 100644 --- a/include/dbe/FileInfo.hpp +++ b/include/dbe/FileInfo.hpp @@ -12,6 +12,7 @@ #include #include +#include namespace dbe { @@ -33,7 +34,9 @@ namespace dbe static QList get_path_urls(); static QStringList get_path_list(); static QString prune_path(QString file); - static bool match_path(QString& file, QStringList& includes); + static bool match_path(const QString& file, + const QString& top_file, + const QStringList& includes); static void parse_all_objects(); static QString check_file_includes(const QString& file); @@ -54,6 +57,8 @@ namespace dbe void add_datafile(); void add_schemafile(); void add_includefile(QFileDialog* fd); + void add_missing_datafiles(); + void add_missing_schemafiles(); void remove_datafile_slot(); void remove_schemafile_slot(); @@ -73,7 +78,11 @@ namespace dbe QMenu* m_object_menu{nullptr}; QUuid const m_uuid; + bool m_updating{false}; + static std::map> s_obj_map; + static std::map> s_missing_schema_map; + static std::map> s_missing_data_map; static QStringList s_path_list; static QList s_path_urls; diff --git a/src/structure/FileInfo.cpp b/src/structure/FileInfo.cpp index b108226..fc91123 100644 --- a/src/structure/FileInfo.cpp +++ b/src/structure/FileInfo.cpp @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include @@ -23,6 +25,8 @@ QString FileInfo::s_data_path{"."}; QStringList FileInfo::s_path_list{}; QList FileInfo::s_path_urls{}; std::map> FileInfo::s_obj_map{}; +std::map> FileInfo::s_missing_schema_map{}; +std::map> FileInfo::s_missing_data_map{}; void FileInfo::setup_paths() { QString DUNEDAQ_DB_PATH = getenv ( "DUNEDAQ_DB_PATH" ); @@ -57,16 +61,22 @@ QString FileInfo::prune_path(QString file) { return file; } -bool FileInfo::match_path(QString& file, QStringList& includes) { +bool FileInfo::match_path(const QString& file, + const QString& top_file, + const QStringList& includes) { + if (top_file.endsWith(file)) { + return true; + } + if (s_path_list.isEmpty()) { setup_paths(); } QStringList candidates{file}; - // element is a copy here, not a reference - for (const QString element : s_path_list) { + for (const auto& element : s_path_list) { if (file.startsWith(element)) { - candidates.append(file.remove(element)); + auto short_name = file; + candidates.append(short_name.remove(element)); } } @@ -100,6 +110,8 @@ void FileInfo::parse_all_objects() { auto name = QString::fromStdString(obj.full_name()); if (!s_obj_map.contains(file)) { s_obj_map.insert({file,{}}); + s_missing_schema_map.insert({file,{}}); + s_missing_data_map.insert({file,{}}); } s_obj_map.at(file).insert({name, obj}); } @@ -109,6 +121,17 @@ void FileInfo::parse_all_objects() { QString FileInfo::check_file_includes(const QString& filename) { QString message{}; + auto fname = prune_path(filename); + if (!s_missing_schema_map.contains(fname)) { + s_missing_schema_map.insert({fname,{}}); + } else { + s_missing_schema_map.at(fname).clear(); + } + if (!s_missing_data_map.contains(fname)) { + s_missing_data_map.insert({fname,{}}); + } else { + s_missing_data_map.at(fname).clear(); + } QStringList includes(config::api::get::file::inclusions_singlefile ( filename)); if (s_obj_map.contains(prune_path(filename))) { @@ -117,11 +140,12 @@ QString FileInfo::check_file_includes(const QString& filename) { dbe::config::api::info::onclass::definition (obj.class_name(), false); auto schema_file = QString::fromStdString(classdef.p_schema_path); - if (!match_path(schema_file, includes)) { + if (!match_path(schema_file, filename, includes)) { message += QString("Object " + id + " is of class " + QString::fromStdString(obj.class_name()) + " defined in file " + schema_file + " which is not included
"); + s_missing_schema_map.at(fname).insert(prune_path(schema_file)); } std::vector relobjs; for (auto rel: classdef.p_relationships) { @@ -137,14 +161,14 @@ QString FileInfo::check_file_includes(const QString& filename) { relobjs = dbegraph::linked::through::relation> (obj, rel); } - includes.append(prune_path(filename)); for (auto relobj : relobjs) { auto file = QString::fromStdString(relobj.contained_in()); - if (!(match_path(file, includes))) { + if (!(match_path(file, filename, includes))) { message += QString("Object " + id + " has relationship to " + QString::fromStdString(relobj.full_name()) + " in file " + file + " which is not included
"); + s_missing_data_map.at(fname).insert(prune_path(file)); } } } @@ -184,6 +208,9 @@ FileInfo::FileInfo(QString filename, QWidget* /*parent*/) connect (m_ui->add_schema, SIGNAL(pressed()), this, SLOT (add_schemafile())); connect (m_ui->add_data, SIGNAL(pressed()), this, SLOT (add_datafile())); + connect (m_ui->add_missing_schema, SIGNAL(pressed()), this, SLOT (add_missing_schemafiles())); + connect (m_ui->add_missing, SIGNAL(pressed()), this, SLOT (add_missing_datafiles())); + connect (m_ui->schema_list, SIGNAL (customContextMenuRequested(QPoint)), this, SLOT (activate_schema_context_menu(QPoint))); @@ -202,17 +229,20 @@ FileInfo::FileInfo(QString filename, QWidget* /*parent*/) } void FileInfo::filemodel_updated() { + if (m_updating) { + return; + } parse_includes(); parse_objects(); } - void FileInfo::parse_objects() { parse_all_objects(); m_ui->object_list->clear(); - if (s_obj_map.contains(prune_path(m_filename))) { - auto& omap = s_obj_map.at(prune_path(m_filename)); + auto fname = prune_path(m_filename); + if (s_obj_map.contains(fname)) { + auto& omap = s_obj_map.at(fname); for (auto const& [obj_name, obj_ref] : omap) { auto item = new QListWidgetItem(obj_name); m_ui->object_list->addItem(item); @@ -220,7 +250,17 @@ void FileInfo::parse_objects() { } m_ui->object_list->update(); - m_ui->warningBox->setVisible(!check_includes()); + auto status = check_includes(); + if (!s_missing_schema_map.contains(fname)) { + s_missing_schema_map.insert({fname,{}}); + } + if (!s_missing_data_map.contains(fname)) { + s_missing_data_map.insert({fname,{}}); + } + m_ui->add_missing_schema->setVisible(!s_missing_schema_map.at(fname).empty()); + m_ui->add_missing->setVisible(!s_missing_data_map.at(fname).empty()); + + m_ui->warningBox->setVisible(!status); } @@ -346,6 +386,7 @@ void FileInfo::add_includefile(QFileDialog* fd) { fd->setSidebarUrls(s_path_urls); if (fd->exec() == QDialog::Accepted) { auto files = fd->selectedFiles(); + QScopedValueRollback rb(m_updating,true); for (auto file: files) { file = prune_path(file); config::api::commands::file::add(m_filename, file); @@ -355,6 +396,36 @@ void FileInfo::add_includefile(QFileDialog* fd) { } } +void FileInfo::add_missing_schemafiles() { + QScopedValueRollback rb(m_updating,true); + auto short_filename = prune_path(m_filename); + if (!s_missing_schema_map.contains(short_filename)) { + QMessageBox::warning (this, "Warning", + QString("Missing schema map is corrupt and does not contain %1").arg(short_filename)); + return; + } + for (const auto& file : s_missing_schema_map.at(short_filename)) { + config::api::commands::file::add(m_filename, file); + } + parse_includes(); + parse_objects(); +} + +void FileInfo::add_missing_datafiles() { + QScopedValueRollback rb(m_updating,true); + auto short_filename = prune_path(m_filename); + if (!s_missing_data_map.contains(short_filename)) { + QMessageBox::warning (this, "Warning", + QString("Missing data map is corrupt and does not contain %1").arg(short_filename)); + return; + } + for (const auto& file : s_missing_data_map.at(prune_path(m_filename))) { + config::api::commands::file::add(m_filename, file); + } + parse_includes(); + parse_objects(); +} + void FileInfo::remove_schemafile_slot() { remove_includefile(m_ui->schema_list->currentItem()->text()); } diff --git a/ui/FileInfo.ui b/ui/FileInfo.ui index 708a409..301e521 100644 --- a/ui/FileInfo.ui +++ b/ui/FileInfo.ui @@ -198,6 +198,13 @@ + + + + Add missing schema + + + @@ -259,6 +266,13 @@ + + + + Add missing files + + +