Line data Source code
1 : /// Including QT Headers
2 : #include <QApplication>
3 : #include <QCursor>
4 : #include <QEvent>
5 : #include <QGraphicsScene>
6 : #include <QGraphicsSceneHoverEvent>
7 : #include <QGraphicsView>
8 : #include <QPainter>
9 : #include <QToolTip>
10 : /// Include oks
11 : #include "oks/method.hpp"
12 : /// Including SchemaEditor
13 : #include "dbe/SchemaClassEditor.hpp"
14 : #include "dbe/SchemaGraphicObject.hpp"
15 : #include "dbe/SchemaGraphicSegmentedArrow.hpp"
16 : #include "dbe/SchemaGraphicsScene.hpp"
17 : #include "dbe/SchemaKernelWrapper.hpp"
18 : #include "dbe/SchemaStyle.hpp"
19 :
20 : using namespace dunedaq::oks;
21 :
22 0 : dbse::SchemaGraphicObject::SchemaGraphicObject(QString& ClassName, SchemaGraphicsScene* scene, QGraphicsObject* parent)
23 : : QGraphicsObject(parent)
24 0 : , m_scene(scene)
25 0 : , LineOffsetX(0)
26 0 : , LineOffsetY(0)
27 : {
28 0 : setAcceptHoverEvents(true);
29 :
30 0 : setFlag(ItemIsMovable);
31 0 : setFlag(ItemSendsGeometryChanges, true);
32 0 : setFlag(ItemSendsScenePositionChanges, true);
33 :
34 : /// Connecting Signals
35 0 : connect(&KernelWrapper::GetInstance(), SIGNAL(ClassUpdated(QString)), this, SLOT(UpdateObject(QString)));
36 0 : connect(&KernelWrapper::GetInstance(), SIGNAL(ClassRemoved(QString)), this, SLOT(RemoveObject(QString)));
37 : /// Getting Class
38 0 : m_class_info = KernelWrapper::GetInstance().FindClass(ClassName.toStdString());
39 0 : m_class_object_name = ClassName;
40 :
41 : /// Getting class info
42 0 : GetInfo();
43 :
44 0 : set_font();
45 0 : }
46 :
47 0 : dbse::SchemaGraphicObject::~SchemaGraphicObject() {}
48 :
49 : void
50 0 : dbse::SchemaGraphicObject::hoverEnterEvent(QGraphicsSceneHoverEvent* he)
51 : {
52 : // std::cout << "hover event at scenePos" << he->scenePos().x() << "," << he->scenePos().y()
53 : // << ", pos=" << he->pos().x() << "," << he->pos().y() << "\n";
54 :
55 0 : auto text = m_class_info->get_name();
56 0 : auto desc = m_class_info->get_description();
57 0 : if (!desc.empty()) {
58 0 : text += "\n" + desc;
59 : }
60 0 : text += "\n-----------";
61 :
62 0 : std::string attr_descriptions;
63 0 : auto attributes = m_class_info->direct_attributes();
64 0 : if (attributes != nullptr) {
65 0 : for (auto attr : *attributes) {
66 0 : if (!attr->get_description().empty()) {
67 0 : attr_descriptions += "\n " + attr->get_name() + ": " + attr->get_description();
68 : }
69 : }
70 : }
71 0 : std::string rel_descriptions;
72 0 : auto relationships = m_class_info->direct_relationships();
73 0 : if (relationships != nullptr) {
74 0 : for (auto rel : *relationships) {
75 0 : if (!rel->get_description().empty()) {
76 0 : rel_descriptions += "\n " + rel->get_name() + ": " + rel->get_description();
77 : }
78 : }
79 : }
80 0 : std::string method_descriptions;
81 0 : auto methods = m_class_info->direct_methods();
82 0 : if (methods != nullptr) {
83 0 : for (auto method : *methods) {
84 0 : if (!method->get_description().empty()) {
85 0 : method_descriptions += "\n " + method->get_name() + ": " + method->get_description();
86 : }
87 : }
88 : }
89 :
90 0 : std::string sep = "\n-----";
91 0 : if (!attr_descriptions.empty()) {
92 0 : text += "\nAttributes:" + attr_descriptions;
93 0 : if (!(rel_descriptions.empty() && method_descriptions.empty())) {
94 0 : text += sep;
95 : }
96 : }
97 0 : if (!rel_descriptions.empty()) {
98 0 : text += "\nRelationships:" + rel_descriptions;
99 0 : if (!method_descriptions.empty()) {
100 0 : text += sep;
101 : }
102 : }
103 0 : if (method_descriptions != "") {
104 0 : text += "\nMethods:" + method_descriptions;
105 : }
106 : // std::cout << "text=<" << text << ">\n"; std::cout.flush();
107 0 : QToolTip::showText(he->screenPos(), QString::fromStdString(text), nullptr, QRect(), 10000);
108 0 : he->ignore();
109 0 : }
110 : void
111 0 : dbse::SchemaGraphicObject::hoverLeaveEvent(QGraphicsSceneHoverEvent* he)
112 : {
113 : // std::cout << "hover leave\n";
114 0 : QToolTip::hideText();
115 0 : he->ignore();
116 0 : }
117 :
118 : void
119 0 : dbse::SchemaGraphicObject::mouseDoubleClickEvent(QGraphicsSceneMouseEvent*)
120 : {
121 0 : QString class_name = QString::fromStdString(m_class_info->get_name());
122 0 : SchemaClassEditor::launch(class_name);
123 0 : }
124 :
125 : OksClass*
126 0 : dbse::SchemaGraphicObject::GetClass() const
127 : {
128 0 : return m_class_info;
129 : }
130 :
131 : QString
132 0 : dbse::SchemaGraphicObject::GetClassName() const
133 : {
134 0 : return m_class_object_name;
135 : }
136 :
137 : void
138 0 : dbse::SchemaGraphicObject::GetInfo()
139 : {
140 0 : m_class_attributes.clear();
141 0 : m_class_relationhips.clear();
142 0 : m_class_methods.clear();
143 :
144 0 : std::list<OksAttribute*> direct_attributes = {};
145 0 : if (m_class_info->direct_attributes()) {
146 0 : direct_attributes = *m_class_info->direct_attributes();
147 : }
148 0 : std::list<OksMethod*> direct_methods = {};
149 0 : if (m_class_info->direct_methods())
150 0 : direct_methods = *m_class_info->direct_methods();
151 :
152 0 : std::list<OksRelationship*> direct_relationships = {};
153 0 : if (m_class_info->direct_relationships())
154 0 : direct_relationships = *m_class_info->direct_relationships();
155 :
156 0 : std::list<OksAttribute*> all_attributes = {};
157 0 : if (m_class_info->all_attributes())
158 0 : all_attributes = *m_class_info->all_attributes();
159 :
160 0 : std::list<OksMethod*> all_methods = {};
161 0 : if (m_class_info->all_methods())
162 0 : all_methods = *m_class_info->all_methods();
163 :
164 0 : std::list<OksRelationship*> all_relationships = {};
165 0 : if (m_class_info->all_relationships())
166 0 : all_relationships = *m_class_info->all_relationships();
167 :
168 : // Prepare indirect relationship list
169 0 : std::list<OksAttribute*> indirect_attributes = all_attributes;
170 0 : std::list<OksMethod*> indirect_methods = all_methods;
171 0 : std::list<OksRelationship*> indirect_relationships = all_relationships;
172 :
173 0 : for (OksAttribute* attribute : direct_attributes) {
174 0 : indirect_attributes.remove(attribute);
175 : }
176 :
177 0 : for (OksMethod* method : direct_methods) {
178 0 : indirect_methods.remove(method);
179 : }
180 :
181 0 : for (OksRelationship* relationship : direct_relationships) {
182 0 : indirect_relationships.remove(relationship);
183 : }
184 :
185 0 : std::map<OksRelationship::CardinalityConstraint, std::string> m = { { OksRelationship::Zero, "0" },
186 0 : { OksRelationship::One, "1" },
187 0 : { OksRelationship::Many, "n" } };
188 :
189 : /// Getting direct Attributes
190 0 : for (OksAttribute* attribute : direct_attributes) {
191 0 : QString AttributeString(QString::fromStdString(attribute->get_name()) + " : " +
192 0 : QString::fromStdString(attribute->get_type()) +
193 0 : (attribute->get_is_multi_values() ? "[]" : ""));
194 0 : m_class_attributes.append(AttributeString);
195 :
196 0 : QString value;
197 0 : if (!attribute->get_init_value().empty()) {
198 0 : value = QString::fromStdString(" = " + attribute->get_init_value());
199 : }
200 0 : m_class_attribute_values.append(value);
201 0 : }
202 :
203 : /// Getting direct Relationships
204 0 : for (OksRelationship* relationship : direct_relationships) {
205 0 : QString relationship_string(QString::fromStdString(relationship->get_name()) + " : " +
206 0 : QString::fromStdString(relationship->get_type()) + " - " +
207 0 : QString::fromStdString(m[relationship->get_low_cardinality_constraint()]) + ":" +
208 0 : QString::fromStdString(m[relationship->get_high_cardinality_constraint()]));
209 0 : m_class_relationhips.append(relationship_string);
210 0 : }
211 :
212 : /// Getting direct Methods
213 0 : for (OksMethod* Method : direct_methods) {
214 0 : QString MethodString(QString::fromStdString(Method->get_name()) + "()");
215 0 : m_class_methods.append(MethodString);
216 0 : }
217 :
218 : /// Getting indirect Attributes
219 0 : for (OksAttribute* attribute : indirect_attributes) {
220 0 : QString attribute_string(QString::fromStdString(attribute->get_name()) + " : " +
221 0 : QString::fromStdString(attribute->get_type()));
222 0 : m_class_inherited_attributes.append(attribute_string);
223 0 : }
224 :
225 : /// Getting indirect Relationships
226 0 : for (OksRelationship* relationship : indirect_relationships) {
227 0 : QString relationship_string(QString::fromStdString(relationship->get_name()) + " : " +
228 0 : QString::fromStdString(relationship->get_type()) + " - " +
229 0 : QString::fromStdString(m[relationship->get_low_cardinality_constraint()]) + ":" +
230 0 : QString::fromStdString(m[relationship->get_high_cardinality_constraint()]));
231 0 : m_class_inherited_relationhips.append(relationship_string);
232 0 : }
233 :
234 : /// Getting indirect Methods
235 0 : for (OksMethod* method : indirect_methods) {
236 0 : QString method_string(QString::fromStdString(method->get_name()) + "()");
237 0 : m_class_inherited_methods.append(method_string);
238 0 : }
239 0 : }
240 :
241 : QRectF
242 0 : dbse::SchemaGraphicObject::boundingRect() const
243 : {
244 0 : double SpaceX = 3;
245 0 : double TotalBoundingHeight = 0;
246 0 : double TotalBoundingWidth = 0;
247 :
248 0 : QFontMetrics FontMetrics(m_font);
249 :
250 0 : TotalBoundingHeight += SpaceX * 5;
251 0 : TotalBoundingHeight += FontMetrics.boundingRect(m_class_object_name).height();
252 0 : TotalBoundingWidth += FontMetrics.boundingRect(m_class_object_name).width();
253 :
254 0 : for (int entry = 0; entry < m_class_attributes.size(); entry++) {
255 0 : QString attribute_name = m_class_attributes[entry];
256 0 : if (m_scene->show_defaults()) {
257 0 : attribute_name.append(m_class_attribute_values[entry]);
258 : }
259 0 : TotalBoundingHeight += FontMetrics.boundingRect(attribute_name).height();
260 :
261 0 : if (FontMetrics.boundingRect(attribute_name).width() > TotalBoundingWidth) {
262 0 : TotalBoundingWidth = FontMetrics.boundingRect(attribute_name).width();
263 : }
264 0 : }
265 :
266 0 : if (m_scene->inherited_properties_visible()) {
267 0 : for (auto& AttributeName : m_class_inherited_attributes) {
268 0 : TotalBoundingHeight += FontMetrics.boundingRect(AttributeName).height();
269 :
270 0 : if (FontMetrics.boundingRect(AttributeName).width() > TotalBoundingWidth)
271 0 : TotalBoundingWidth = FontMetrics.boundingRect(AttributeName).width();
272 : }
273 : }
274 :
275 0 : for (auto& relationship_name : m_class_relationhips) {
276 0 : TotalBoundingHeight += FontMetrics.boundingRect(relationship_name).height();
277 :
278 0 : if (FontMetrics.boundingRect(relationship_name).width() > TotalBoundingWidth)
279 0 : TotalBoundingWidth = FontMetrics.boundingRect(relationship_name).width();
280 : }
281 :
282 0 : if (m_scene->inherited_properties_visible()) {
283 0 : for (auto& relationship_name : m_class_inherited_relationhips) {
284 0 : TotalBoundingHeight += FontMetrics.boundingRect(relationship_name).height();
285 :
286 0 : if (FontMetrics.boundingRect(relationship_name).width() > TotalBoundingWidth)
287 0 : TotalBoundingWidth = FontMetrics.boundingRect(relationship_name).width();
288 : }
289 : }
290 :
291 0 : for (auto& MethodName : m_class_methods) {
292 0 : TotalBoundingHeight += FontMetrics.boundingRect(MethodName).height();
293 :
294 0 : if (FontMetrics.boundingRect(MethodName).width() > TotalBoundingWidth)
295 0 : TotalBoundingWidth = FontMetrics.boundingRect(MethodName).width();
296 : }
297 :
298 0 : if (m_scene->inherited_properties_visible()) {
299 0 : for (auto& MethodName : m_class_inherited_methods) {
300 0 : TotalBoundingHeight += FontMetrics.boundingRect(MethodName).height();
301 :
302 0 : if (FontMetrics.boundingRect(MethodName).width() > TotalBoundingWidth)
303 0 : TotalBoundingWidth = FontMetrics.boundingRect(MethodName).width();
304 : }
305 : }
306 :
307 0 : TotalBoundingWidth += 15;
308 0 : return QRectF(0, 0, TotalBoundingWidth, TotalBoundingHeight);
309 0 : }
310 :
311 : QPainterPath
312 0 : dbse::SchemaGraphicObject::shape() const
313 : {
314 0 : QPainterPath path;
315 0 : path.addRect(boundingRect());
316 0 : return path;
317 0 : }
318 :
319 : void
320 0 : dbse::SchemaGraphicObject::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
321 : {
322 0 : Q_UNUSED(widget)
323 0 : Q_UNUSED(option)
324 :
325 0 : double SpaceX = 3;
326 0 : double SpaceY = 3;
327 :
328 0 : QColor colour;
329 0 : QColor background;
330 0 : if (m_highlight_class) {
331 0 : colour = SchemaStyle::get_color("foreground", "highlight");
332 0 : background = SchemaStyle::get_color("background", "highlight");
333 0 : } else if (m_scene->highlight_active() &&
334 0 : (m_class_info->get_file()->get_full_file_name() == KernelWrapper::GetInstance().GetActiveSchema())) {
335 0 : colour = SchemaStyle::get_color("foreground", "active_file");
336 0 : background = SchemaStyle::get_color("background", "active_file");
337 : } else {
338 0 : colour = SchemaStyle::get_color("foreground", "default");
339 0 : background = SchemaStyle::get_color("background", "default");
340 : }
341 :
342 0 : set_font();
343 :
344 0 : const QPen bounding_box_pen = QPen(colour, 2.5);
345 0 : const QPen inner_line_pen = QPen(colour, 1.5);
346 :
347 0 : painter->setFont(m_font);
348 0 : painter->setPen(bounding_box_pen);
349 0 : painter->setBackground(background);
350 : // painter->setBackgroundMode(Qt::OpaqueMode);
351 0 : painter->drawRect(boundingRect());
352 :
353 0 : const QFontMetrics FontMetrics = painter->fontMetrics();
354 0 : const QRectF ClassNameBoundingRect = FontMetrics.boundingRect(m_class_object_name);
355 0 : const QRectF ObjectBoundingRect = boundingRect();
356 :
357 0 : double HeightOffset = ClassNameBoundingRect.height() + SpaceY;
358 0 : const auto ClassNamePosition =
359 0 : QPointF((ObjectBoundingRect.width() - ClassNameBoundingRect.width()) / 2, ClassNameBoundingRect.height());
360 0 : painter->drawText(ClassNamePosition, m_class_object_name);
361 0 : painter->drawLine(0, HeightOffset, ObjectBoundingRect.width(), HeightOffset);
362 :
363 0 : for (int entry = 0; entry < m_class_attributes.size(); entry++) {
364 0 : QString attribute_name = m_class_attributes[entry];
365 0 : if (m_scene->show_defaults()) {
366 0 : attribute_name.append(m_class_attribute_values[entry]);
367 : }
368 0 : const QRectF AttributeBoundingRect = FontMetrics.boundingRect(attribute_name);
369 0 : HeightOffset += AttributeBoundingRect.height();
370 0 : painter->drawText(QPointF(SpaceX, HeightOffset), attribute_name);
371 0 : }
372 :
373 0 : if (m_scene->inherited_properties_visible()) {
374 0 : painter->setPen(SchemaStyle::get_color("foreground", "inherited"));
375 0 : for (QString& AttributeName : m_class_inherited_attributes) {
376 0 : const QRectF AttributeBoundingRect = FontMetrics.boundingRect(AttributeName);
377 0 : HeightOffset += AttributeBoundingRect.height();
378 0 : painter->drawText(QPointF(SpaceX, HeightOffset), AttributeName);
379 : }
380 0 : painter->setPen(colour);
381 : }
382 :
383 0 : HeightOffset += SpaceY;
384 0 : painter->setPen(inner_line_pen);
385 0 : painter->drawLine(0, HeightOffset, ObjectBoundingRect.width(), HeightOffset);
386 :
387 0 : for (const QString& relationship_name : m_class_relationhips) {
388 0 : const QRectF relationship_bounding_rect = FontMetrics.boundingRect(relationship_name);
389 0 : HeightOffset += relationship_bounding_rect.height();
390 0 : painter->drawText(QPointF(SpaceX, HeightOffset), relationship_name);
391 : }
392 :
393 0 : if (m_scene->inherited_properties_visible()) {
394 0 : painter->setPen(SchemaStyle::get_color("foreground", "inherited"));
395 0 : for (const QString& relationship_name : m_class_inherited_relationhips) {
396 0 : const QRectF relationship_bounding_rect = FontMetrics.boundingRect(relationship_name);
397 0 : HeightOffset += relationship_bounding_rect.height();
398 0 : painter->drawText(QPointF(SpaceX, HeightOffset), relationship_name);
399 : }
400 0 : painter->setPen(colour);
401 : }
402 :
403 0 : HeightOffset += SpaceY;
404 0 : painter->setPen(inner_line_pen);
405 0 : painter->drawLine(0, HeightOffset, ObjectBoundingRect.width(), HeightOffset);
406 :
407 0 : for (const QString& MethodName : m_class_methods) {
408 0 : const QRectF AttributeBoundingRect = FontMetrics.boundingRect(MethodName);
409 0 : HeightOffset += AttributeBoundingRect.height();
410 0 : painter->drawText(QPointF(SpaceX, HeightOffset), MethodName);
411 : }
412 :
413 0 : if (m_scene->inherited_properties_visible()) {
414 0 : painter->setPen(SchemaStyle::get_color("foreground", "inherited"));
415 0 : for (const QString& MethodName : m_class_inherited_methods) {
416 0 : const QRectF AttributeBoundingRect = FontMetrics.boundingRect(MethodName);
417 0 : HeightOffset += AttributeBoundingRect.height();
418 0 : painter->drawText(QPointF(SpaceX, HeightOffset), MethodName);
419 : }
420 0 : painter->setPen(colour);
421 : }
422 0 : }
423 :
424 : void
425 0 : dbse::SchemaGraphicObject::AddArrow(SchemaGraphicSegmentedArrow* Arrow)
426 : {
427 0 : m_arrows.append(Arrow);
428 0 : }
429 :
430 : void
431 0 : dbse::SchemaGraphicObject::RemoveArrow(SchemaGraphicSegmentedArrow* Arrow)
432 : {
433 0 : const int index = m_arrows.indexOf(Arrow);
434 :
435 0 : if (index != -1) {
436 0 : m_arrows.removeAt(index);
437 : }
438 0 : }
439 :
440 : void
441 0 : dbse::SchemaGraphicObject::RemoveArrows()
442 : {
443 0 : for (SchemaGraphicSegmentedArrow* arrow : m_arrows) {
444 0 : arrow->GetStartItem()->RemoveArrow(arrow);
445 0 : arrow->GetEndItem()->RemoveArrow(arrow);
446 0 : scene()->removeItem(arrow);
447 : }
448 0 : }
449 :
450 : bool
451 0 : dbse::SchemaGraphicObject::HasArrow(SchemaGraphicObject* Dest) const
452 : {
453 0 : if (m_arrows.isEmpty()) {
454 : return false;
455 : }
456 :
457 0 : for (SchemaGraphicSegmentedArrow* Arrow : m_arrows) {
458 0 : SchemaGraphicObject* ArrowSource = Arrow->GetStartItem();
459 0 : SchemaGraphicObject* ArrowDest = Arrow->GetEndItem();
460 :
461 0 : if ((ArrowSource == this) && (ArrowDest == Dest)) {
462 0 : return true;
463 : }
464 : }
465 :
466 0 : return false;
467 : }
468 :
469 : void
470 0 : dbse::SchemaGraphicObject::update_arrows()
471 : {
472 0 : for (SchemaGraphicSegmentedArrow* arrow : m_arrows) {
473 0 : arrow->UpdatePosition();
474 : }
475 0 : }
476 :
477 : void
478 0 : dbse::SchemaGraphicObject::set_font()
479 : {
480 0 : if (m_highlight_class) {
481 0 : m_font = SchemaStyle::get_font("highlight");
482 : } else {
483 0 : m_font = SchemaStyle::get_font("default");
484 : }
485 0 : if (m_class_info->get_is_abstract() && m_scene->highlight_abstract()) {
486 : // Use selected font but with style from abstract class font
487 0 : m_font.setStyle(SchemaStyle::get_font("abstract").style());
488 : }
489 0 : }
490 :
491 : void
492 0 : dbse::SchemaGraphicObject::toggle_highlight_class()
493 : {
494 0 : m_highlight_class = !m_highlight_class;
495 0 : set_font();
496 0 : update_arrows();
497 0 : }
498 :
499 : QVariant
500 0 : dbse::SchemaGraphicObject::itemChange(GraphicsItemChange change, const QVariant& value)
501 : {
502 0 : if (change == ItemPositionChange)
503 0 : for (SchemaGraphicSegmentedArrow* arrow : m_arrows) {
504 0 : arrow->UpdatePosition();
505 : }
506 :
507 0 : return value;
508 : }
509 :
510 : void
511 0 : dbse::SchemaGraphicObject::UpdateObject(QString Name)
512 : {
513 0 : if (Name != m_class_object_name) {
514 : return;
515 : }
516 :
517 : /// Updating object info
518 0 : GetInfo();
519 : /// Updating object representation
520 0 : SchemaGraphicsScene* Scene = dynamic_cast<SchemaGraphicsScene*>(scene());
521 :
522 0 : if (Scene) {
523 0 : QStringList ClassesList;
524 0 : ClassesList.append(Name);
525 :
526 0 : QList<QPointF> ClassesPositions;
527 0 : QPointF ClassPosition(this->scenePos());
528 0 : ClassesPositions.append(ClassPosition);
529 :
530 0 : Scene->RemoveClassObject(this);
531 0 : Scene->AddItemsToScene(QStringList(m_class_object_name), ClassesPositions);
532 0 : }
533 :
534 : /// Repainting object
535 0 : update();
536 : }
537 :
538 : void
539 0 : dbse::SchemaGraphicObject::RemoveObject(QString Name)
540 : {
541 0 : if (Name != m_class_object_name) {
542 : return;
543 : }
544 :
545 : /// Updating object representation
546 0 : SchemaGraphicsScene* Scene = dynamic_cast<SchemaGraphicsScene*>(scene());
547 :
548 0 : if (Scene) {
549 0 : Scene->RemoveClassObject(this);
550 : }
551 : }
|