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