Line data Source code
1 : // DUNE DAQ modification notice:
2 : // This file has been modified from the original ATLAS dbe source for the DUNE DAQ project.
3 : // Fork baseline commit: dbe-02-12-17 (2022-05-12).
4 : // Renamed since fork: no.
5 :
6 : /// Including QT Headers
7 : #include "dbe/table.hpp"
8 : #include "dbe/Conversion.hpp"
9 : #include "dbe/Exceptions.hpp"
10 : #include "dbe/StyleUtility.hpp"
11 : #include "dbe/confaccessor.hpp"
12 : #include "dbe/config_api_set.hpp"
13 : #include "dbe/dbcontroller.hpp"
14 : #include "dbe/messenger.hpp"
15 : #include "dbe/treenode.hpp"
16 :
17 : #include <QBrush>
18 : #include <QFont>
19 : #include <QMimeData>
20 :
21 : #include <bitset>
22 :
23 0 : dbe::models::table::table(QObject* parent)
24 : : QAbstractTableModel(parent)
25 0 : , enabled(false)
26 : {
27 0 : model_common_connections();
28 0 : }
29 :
30 0 : dbe::models::table::~table() {}
31 :
32 : int
33 0 : dbe::models::table::rowCount(const QModelIndex& parent) const
34 : {
35 0 : if (!parent.isValid()) {
36 0 : return this_structure.size();
37 : }
38 :
39 : return 0;
40 : }
41 :
42 : int
43 0 : dbe::models::table::columnCount(const QModelIndex& parent) const
44 : {
45 0 : if (!parent.isValid()) {
46 0 : return this_headers.size();
47 : }
48 :
49 : return 0;
50 : }
51 :
52 : QVariant
53 0 : dbe::models::table::data(const QModelIndex& index, int role) const
54 : {
55 :
56 0 : if (index.isValid()) {
57 0 : TableNode* TableItem = getnode(index);
58 :
59 0 : if (role == Qt::DisplayRole) {
60 0 : QString Data;
61 :
62 0 : for (QString const& i : TableItem->GetData()) {
63 0 : static QString space{ ", " };
64 0 : Data.append(i).append(space);
65 0 : }
66 0 : Data.remove(Data.length() - 2, 2);
67 :
68 0 : return QVariant(Data);
69 0 : }
70 :
71 : if (role == Qt::ToolTipRole) {
72 0 : return TableItem->get_tooltip();
73 : }
74 : if (role == Qt::FontRole) {
75 0 : if (dynamic_cast<TableAttributeNode*>(TableItem))
76 0 : return QFont("Helvetica", 10, -1, false);
77 0 : else if (dynamic_cast<TableRelationshipNode*>(TableItem))
78 0 : return QFont("Courier", 10, QFont::Bold);
79 : else {
80 0 : return QFont("SansSerif", 10, QFont::Bold);
81 : }
82 : }
83 :
84 : if (role == Qt::ForegroundRole) {
85 0 : if (dynamic_cast<TableAttributeNode*>(TableItem))
86 0 : return QBrush(StyleUtility::TableColorAttribute);
87 0 : else if (dynamic_cast<TableRelationshipNode*>(TableItem))
88 0 : return QBrush(StyleUtility::TableColorRelationship);
89 : else {
90 0 : dref obj_desc = this_objects[index.row()];
91 0 : tref Object = dbe::inner::dbcontroller::get({ obj_desc.UID(), obj_desc.class_name() });
92 0 : if (!confaccessor::check_file_rw(QString::fromStdString(Object.contained_in()))) {
93 0 : return QBrush(StyleUtility::FileReadOnlyForeground);
94 : }
95 0 : return QVariant();
96 0 : }
97 : }
98 :
99 : if (role == Qt::BackgroundRole) {
100 0 : auto attr_node = dynamic_cast<TableAttributeNode*>(TableItem);
101 0 : if (attr_node != nullptr) {
102 0 : auto val = attr_node->GetData();
103 0 : if (val.size() == 1 && val[0].toStdString() == attr_node->GetAttribute().p_default_value) {
104 0 : return QBrush(StyleUtility::DefaultValueBackground);
105 : }
106 0 : return QBrush(StyleUtility::TableAttributeBackground);
107 0 : } else if (dynamic_cast<TableRelationshipNode*>(TableItem)) {
108 0 : return QBrush(StyleUtility::TableRelationshipBackground);
109 : } else {
110 0 : dref obj_desc = this_objects[index.row()];
111 0 : tref Object = dbe::inner::dbcontroller::get({ obj_desc.UID(), obj_desc.class_name() });
112 0 : if (!confaccessor::check_file_rw(QString::fromStdString(Object.contained_in()))) {
113 0 : return QBrush(StyleUtility::FileReadOnlyBackground);
114 : }
115 0 : }
116 : }
117 : }
118 0 : return QVariant();
119 : }
120 :
121 : bool
122 0 : dbe::models::table::setData(const QModelIndex& index, const QVariant& value, int role)
123 : {
124 0 : if (!index.isValid() || role != Qt::EditRole) {
125 : return false;
126 : }
127 :
128 0 : TableNode* TableItem = getnode(index);
129 :
130 0 : QStringList OldDataList = TableItem->GetData();
131 :
132 0 : QStringList NewDataList = value.toStringList();
133 :
134 0 : if (NewDataList == OldDataList) {
135 : return false;
136 : }
137 :
138 0 : dref obj_desc = this_objects[index.row()];
139 :
140 0 : tref Object = dbe::inner::dbcontroller::get({ obj_desc.UID(), obj_desc.class_name() });
141 :
142 0 : if (dynamic_cast<TableRelationshipNode*>(TableItem)) {
143 0 : TableRelationshipNode* RelationshipNode = dynamic_cast<TableRelationshipNode*>(TableItem);
144 0 : dunedaq::conffwk::relationship_t RelationshipData = RelationshipNode->GetRelationship();
145 0 : dbe::config::api::set::relation(Object, RelationshipData, NewDataList);
146 0 : } else if (dynamic_cast<TableAttributeNode*>(TableItem)) {
147 0 : TableAttributeNode* AttributeNode = dynamic_cast<TableAttributeNode*>(TableItem);
148 0 : dunedaq::conffwk::attribute_t AttributeData = AttributeNode->GetAttribute();
149 0 : dbe::config::api::set::attribute(Object, AttributeData, NewDataList);
150 0 : }
151 :
152 0 : return true;
153 0 : }
154 :
155 : QVariant
156 0 : dbe::models::table::headerData(int section, Qt::Orientation orientation, int role) const
157 : {
158 0 : if (role == Qt::DisplayRole) {
159 0 : if (orientation == Qt::Horizontal) {
160 0 : return this_headers.at(section);
161 : }
162 0 : if (orientation == Qt::Vertical) {
163 0 : return section + 1;
164 : }
165 : }
166 :
167 0 : if (role == Qt::FontRole) {
168 0 : return QFont("Helvetica [Cronyx]", 10);
169 : }
170 :
171 0 : return QVariant();
172 : }
173 :
174 : Qt::ItemFlags
175 0 : dbe::models::table::flags(const QModelIndex& index) const
176 : {
177 0 : if (index.isValid()) {
178 0 : dref obj_desc = this_objects[index.row()];
179 0 : tref Object = dbe::inner::dbcontroller::get({ obj_desc.UID(), obj_desc.class_name() });
180 :
181 0 : if (confaccessor::check_file_rw(QString::fromStdString(Object.contained_in()))) {
182 0 : return (Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled);
183 : }
184 0 : }
185 :
186 0 : return (Qt::ItemIsEnabled | Qt::ItemIsSelectable);
187 : }
188 :
189 : Qt::DropActions
190 0 : dbe::models::table::supportedDropActions() const
191 : {
192 0 : return Qt::CopyAction;
193 : }
194 :
195 : QStringList
196 0 : dbe::models::table::mimeTypes() const
197 : {
198 0 : QStringList types;
199 0 : types << "application/vnd.text.list";
200 0 : return types;
201 0 : }
202 :
203 : bool
204 0 : dbe::models::table::dropMimeData(const QMimeData* data,
205 : Qt::DropAction action,
206 : int row,
207 : int column,
208 : const QModelIndex& parent)
209 : {
210 0 : Q_UNUSED(row)
211 0 : Q_UNUSED(column)
212 0 : Q_UNUSED(parent)
213 :
214 0 : bool Accept = true;
215 :
216 0 : if (action == Qt::IgnoreAction) {
217 : return true;
218 : }
219 :
220 0 : if (!data->hasFormat("application/vnd.text.list")) {
221 : return false;
222 : }
223 :
224 : /// Here if parent is valid it indicates that the drop ocurred on an item otherwise it ocurred on a top level item
225 0 : QByteArray encodedData = data->data("application/vnd.text.list");
226 :
227 0 : QDataStream stream(&encodedData, QIODevice::ReadOnly);
228 :
229 0 : QList<QStringList> newItems;
230 :
231 0 : while (!stream.atEnd()) {
232 0 : QStringList text;
233 0 : stream >> text;
234 0 : newItems << text;
235 0 : }
236 :
237 0 : for (int i = 0; i < newItems.size(); ++i) {
238 0 : if (newItems.at(0).at(1) != newItems.at(i).at(1)) {
239 0 : Accept = false;
240 : }
241 : }
242 :
243 0 : if (Accept) {
244 0 : BuildTableFromObject(newItems);
245 0 : emit ResetTab();
246 : }
247 :
248 0 : return Accept;
249 0 : }
250 :
251 : bool
252 0 : dbe::models::table::BuildTableFromClass(const QString& cname, bool include_derived)
253 : {
254 0 : reset(cname);
255 :
256 0 : cptr<dbe::datahandler> dbaccess_guard = confaccessor::gethandler();
257 :
258 0 : dunedaq::conffwk::class_t classinfo = dbe::config::api::info::onclass::definition(cname.toStdString(), false);
259 :
260 0 : setheader(classinfo);
261 :
262 0 : if (treenode* NodeClass = dbaccess_guard->getnode(cname)) {
263 0 : std::vector<treenode*> classnodes{ NodeClass };
264 :
265 0 : if (include_derived) {
266 :
267 0 : for (std::string const& sbcname : classinfo.p_subclasses) {
268 0 : if (treenode* sbcnode = dbaccess_guard->getnode(sbcname)) {
269 0 : classnodes.push_back(sbcnode);
270 : }
271 : }
272 : }
273 :
274 : /// Looping over classes
275 : /// Only in the case of derived classes this will be more than one
276 :
277 0 : for (treenode* clelement : classnodes) {
278 : /// All objects from that class
279 :
280 0 : for (treenode* child : clelement->GetChildren()) {
281 0 : this_structure.append(createrow(child));
282 0 : }
283 : }
284 :
285 0 : enabled = true;
286 0 : return true;
287 0 : } else {
288 : return false;
289 : }
290 0 : }
291 :
292 : QList<dbe::models::table::type_datum*>
293 0 : dbe::models::table::createrow(treenode const* rownode)
294 : {
295 :
296 0 : dref obj = rownode->GetObject();
297 :
298 0 : this_objects.append(obj);
299 :
300 0 : dunedaq::conffwk::class_t const& cdef = dbe::config::api::info::onclass::definition(obj.class_name(), false);
301 0 : std::vector<dunedaq::conffwk::attribute_t> const& attributes = cdef.p_attributes;
302 0 : std::vector<dunedaq::conffwk::relationship_t> const& relations = cdef.p_relationships;
303 :
304 0 : assert(attributes.size() + relations.size() < 1025);
305 0 : std::bitset<1024> hindex; // maximum number of columns to display
306 :
307 0 : {
308 0 : int column = 0;
309 :
310 0 : for (dunedaq::conffwk::attribute_t const& attr : attributes) {
311 0 : hindex.set(column++, this_headers.contains(QString::fromStdString(attr.p_name)));
312 : }
313 :
314 0 : for (dunedaq::conffwk::relationship_t const& rel : relations) {
315 0 : hindex.set(column++, this_headers.contains(QString::fromStdString(rel.p_name)));
316 : }
317 : }
318 :
319 : // Create the row for this object
320 0 : QList<TableNode*> Row;
321 0 : Row.append(
322 0 : new TableNode(QStringList{ rownode->GetData(0).toString() }, QVariant(QString::fromStdString(cdef.p_description))));
323 0 : {
324 : // Loop over object values and add them to the row
325 : // Values are represent as nodes ( attributes or relations ) and these contain
326 : // the structured data associated either with a attribute / multi-attribute or a relation
327 0 : std::size_t column = 0;
328 :
329 0 : for (treenode* valuenode : rownode->GetChildren()) {
330 0 : QStringList values;
331 : // Every valuenode has its attributes and relations defined as its childs
332 :
333 0 : if (hindex[column++]) {
334 :
335 0 : for (treenode* nodevalues : valuenode->GetChildren()) {
336 : // Here we need to filter such that only values corresponding to the header are kept
337 : // Add only the first of values in a list of values
338 0 : values.append(nodevalues->GetData(0).toString());
339 0 : }
340 :
341 0 : if (AttributeNode* NodeAttribute = dynamic_cast<AttributeNode*>(valuenode)) {
342 0 : Row.append(new TableAttributeNode(NodeAttribute->attribute_t(), values));
343 0 : } else if (RelationshipNode* NodeRelationship = dynamic_cast<RelationshipNode*>(valuenode)) {
344 0 : Row.append(new TableRelationshipNode(NodeRelationship->relation_t(), values));
345 : }
346 : }
347 0 : }
348 : }
349 :
350 0 : return Row;
351 0 : }
352 :
353 : void
354 0 : dbe::models::table::reset(QString const& cname)
355 : {
356 :
357 0 : for (auto& List : this_structure) {
358 0 : qDeleteAll(List);
359 : }
360 :
361 0 : this_objects.clear();
362 0 : this_structure.clear();
363 0 : this_headers.clear();
364 0 : this_class_name = cname;
365 0 : }
366 :
367 : void
368 0 : dbe::models::table::setheader(dunedaq::conffwk::class_t const& cinfo)
369 : {
370 0 : if (!this_headers.contains("Object Name")) {
371 0 : this_headers.append("Object Name");
372 : }
373 :
374 0 : for (auto& i : cinfo.p_attributes) {
375 0 : if (!this_headers.contains(QString::fromStdString(i.p_name))) {
376 0 : this_headers.append(QString::fromStdString(i.p_name));
377 : }
378 : }
379 :
380 0 : for (auto& i : cinfo.p_relationships) {
381 0 : if (!this_headers.contains(QString::fromStdString(i.p_name))) {
382 0 : this_headers.append(QString::fromStdString(i.p_name));
383 : }
384 : }
385 0 : }
386 :
387 : bool
388 0 : dbe::models::table::BuildTableFromObject(QList<QStringList> BuildList)
389 : {
390 0 : reset(BuildList.at(0).at(1));
391 :
392 0 : treenode* classnode = confaccessor::gethandler()->getnode(this_class_name);
393 :
394 0 : dunedaq::conffwk::class_t classinfo =
395 0 : dbe::config::api::info::onclass::definition(this_class_name.toStdString(), false);
396 :
397 0 : setheader(classinfo);
398 :
399 0 : confaccessor::gethandler()->FetchMore(classnode);
400 :
401 0 : for (const QStringList& i : BuildList) {
402 0 : QString name = i.at(0);
403 0 : treenode* node = confaccessor::gethandler()->getnode(this_class_name, name);
404 0 : this_structure.append(createrow(node));
405 0 : }
406 :
407 0 : enabled = false;
408 0 : return true;
409 0 : }
410 :
411 : dbe::tref
412 0 : dbe::models::table::GetTableObject(int ObjectIndex) const
413 : {
414 0 : return this_objects.at(ObjectIndex).ref();
415 : }
416 :
417 : bool
418 0 : dbe::models::table::is_built() const
419 : {
420 0 : return enabled;
421 : }
422 :
423 : QString
424 0 : dbe::models::table::get_class_name() const
425 : {
426 0 : return this_class_name;
427 : }
428 :
429 : QAbstractItemModel*
430 0 : dbe::models::table::ReturnSourceModel() const
431 : {
432 0 : return nullptr;
433 : }
434 :
435 : QList<dbe::dref>*
436 0 : dbe::models::table::GetTableObjects()
437 : {
438 0 : return &this_objects;
439 : }
440 :
441 : dbe::TableNode*
442 0 : dbe::models::table::getnode(const QModelIndex& Index) const
443 : {
444 0 : if (Index.isValid()) {
445 0 : return this_structure.at(Index.row()).at(Index.column());
446 : }
447 :
448 : return nullptr;
449 : }
450 :
451 : void
452 0 : dbe::models::table::ResetModel()
453 : {
454 0 : beginResetModel();
455 0 : endResetModel();
456 0 : }
457 :
458 : void
459 0 : dbe::models::table::slot_data_dropped(QMimeData const& data, Qt::DropAction action)
460 : {
461 0 : QModelIndex dum;
462 0 : this->dropMimeData(&data, action, 0, 0, dum);
463 0 : }
464 :
465 : dbe::tref
466 0 : dbe::models::table::getobject(QModelIndex const& index) const
467 : {
468 0 : if (index.isValid()) {
469 0 : return this_objects[index.row()].ref();
470 : }
471 :
472 0 : throw daq::dbe::cannot_handle_invalid_qmodelindex(ERS_HERE);
473 : }
474 :
475 : dunedaq::conffwk::class_t
476 0 : dbe::models::table::getclass(QModelIndex const& index) const
477 : {
478 0 : if (index.isValid()) {
479 0 : return class_type_info;
480 : }
481 :
482 0 : return dunedaq::conffwk::class_t();
483 : }
484 :
485 : void
486 0 : dbe::models::table::objectsUpdated(const std::vector<dbe::dref>& objects)
487 : {
488 0 : update_multiple_objects(objects);
489 0 : }
490 :
491 : //-----------------------------------------------------------------------------------------------------
492 0 : MODEL_COMMON_INTERFACE_CREATE_THAT_OBJ_IMPL(dbe::models::table)
493 : {
494 0 : Q_UNUSED(index);
495 0 : if (treenode* handlerclass = confaccessor::gethandler()->getnode(obj.class_name())) {
496 0 : if (obj.class_name() == this_class_name.toStdString() or
497 0 : config::api::info::onclass::derived(this_class_name.toStdString(), obj.class_name())) {
498 :
499 0 : dbe::treenode const* handlernode = dbe::datahandler::findchild(handlerclass, QString::fromStdString(obj.UID()));
500 :
501 0 : if (handlernode == nullptr) {
502 0 : handlernode = new ObjectNode(obj, false, handlerclass);
503 : }
504 :
505 0 : emit layoutAboutToBeChanged();
506 :
507 : // We assume that the objects are sorted and we want to insert a new element
508 :
509 0 : tref const handlerobj = handlernode->GetObject();
510 0 : auto sit = this_structure.begin();
511 0 : auto it = this_objects.begin();
512 :
513 0 : for (; it != this_objects.end() and sit != this_structure.end() and it->UID() < handlerobj.UID(); ++it, ++sit) {
514 : }
515 :
516 0 : this_structure.insert(++sit, createrow(handlernode));
517 :
518 0 : this_objects.insert(++it, handlerobj);
519 :
520 : // Normally we would have to call changePersistentIndex.
521 : // Because an objectnode is created which had no index
522 : // before this creation had occured there is no need to call it.
523 0 : emit layoutChanged();
524 0 : }
525 : }
526 0 : }
527 :
528 0 : MODEL_COMMON_INTERFACE_DELETE_THAT_OBJ_IMPL(dbe::models::table)
529 : {
530 0 : if (index.isValid()) {
531 0 : try {
532 0 : this->removeRows(index.row(), 1, index.parent());
533 0 : } catch (daq::dbe::ObjectChangeWasNotSuccessful const& err) {
534 0 : WARN("Object cannot be deleted", dbe::config::errors::parse(err).c_str());
535 0 : }
536 : }
537 0 : }
538 :
539 0 : MODEL_COMMON_INTERFACE_RENAME_THAT_OBJ_IMPL(dbe::models::table)
540 : {
541 0 : if (index.isValid()) {
542 0 : type_datum* element = getnode(index);
543 0 : element->resetdata(QStringList(QString::fromStdString(obj.ref().UID())));
544 0 : this_objects[index.row()] = obj.ref();
545 0 : emit dataChanged(index, index);
546 : }
547 0 : }
548 :
549 0 : MODEL_COMMON_INTERFACE_UPDATE_THAT_OBJ_IMPL(dbe::models::table)
550 : {
551 0 : if (treenode* handlerclass = confaccessor::gethandler()->getnode(obj.class_name())) {
552 0 : if (obj.class_name() == this_class_name.toStdString() or
553 0 : config::api::info::onclass::derived(this_class_name.toStdString(), obj.class_name())) {
554 0 : dbe::treenode const* handlernode = dbe::datahandler::findchild(handlerclass, QString::fromStdString(obj.UID()));
555 :
556 0 : tref handlerobj = handlernode->GetObject();
557 :
558 0 : auto sit = this_structure.begin();
559 0 : auto it = this_objects.begin();
560 :
561 : // find the object to be updated by looping through both objects and nodes
562 :
563 0 : for (; it != this_objects.end() and sit != this_structure.end() and it->UID() != handlerobj.UID(); ++it, ++sit)
564 :
565 : ;
566 :
567 : // delete all table nodes in the list ( remove elements of the row )
568 0 : for (TableNode* x : *sit) {
569 0 : delete x;
570 : }
571 :
572 : // Recreate the row
573 0 : *sit = createrow(handlernode);
574 :
575 0 : int row = index.row() == 0 ? 0 : index.row() - 1;
576 :
577 0 : int column = index.column() == 0 ? 0 : index.column() - 1;
578 :
579 0 : emit dataChanged(createIndex(row, column), createIndex(row + 1, column + 1));
580 0 : }
581 : }
582 0 : }
583 :
584 : //----------------------------------------------------------------------------------------------------
585 :
586 : //-----------------------------------------------------------------------------------------------------
587 0 : MODEL_COMMON_INTERFACE_SLOTS_DEF(dbe::models::table)
588 : //-----------------------------------------------------------------------------------------------------
589 :
590 : //-----------------------------------------------------------------------------------------------------
591 0 : MODEL_COMMON_INTERFACE_LOOKUP_IMPL(dbe::models::table)
592 : {
593 0 : for (int row = 0; row < this_objects.size(); ++row) {
594 0 : dref ListElement = this_objects.at(row);
595 :
596 0 : if (ListElement.UID() == obj.UID()) {
597 0 : return this->index(row, 0);
598 : }
599 0 : }
600 :
601 0 : return QModelIndex();
602 : }
603 :
604 : //-----------------------------------------------------------------------------------------------------
605 :
606 : //-----------------------------------------------------------------------------------------------------
607 0 : MODEL_REMOVE_ROWS_DEF(dbe::models::table)
608 : {
609 0 : beginRemoveRows(parent, row, row + count - 1);
610 :
611 0 : for (; count != 0; --count) {
612 0 : this_structure.removeOne(this_structure.at(row + count - 1));
613 0 : this_objects.removeAt(row + count - 1);
614 : }
615 :
616 0 : endRemoveRows();
617 0 : return true;
618 : }
619 :
620 : //-----------------------------------------------------------------------------------------------------
|