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
|