1 /*
2 Copyright 2006-2019 The QElectroTech Team
3 This file is part of QElectroTech.
4
5 QElectroTech is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 2 of the License, or
8 (at your option) any later version.
9
10 QElectroTech is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include "crossrefitem.h"
19 #include "element.h"
20 #include "qetapp.h"
21 #include "diagramposition.h"
22 #include "diagram.h"
23 #include "qgraphicsitemutility.h"
24 #include "assignvariables.h"
25 #include "dynamicelementtextitem.h"
26 #include "elementtextitemgroup.h"
27
28 //define the height of the header.
29 static int header = 5;
30 //define the minimal height of the cross (without header)
31 static int cross_min_heigth = 33;
32
33 /**
34 * @brief CrossRefItem::CrossRefItem
35 * @param elmt : element to display the cross ref
36 */
CrossRefItem(Element * elmt)37 CrossRefItem::CrossRefItem(Element *elmt) :
38 QGraphicsObject(elmt),
39 m_element(elmt)
40 {init();}
41
42 /**
43 * @brief CrossRefItem::CrossRefItem
44 * @param elmt : element to display the cross ref
45 * @param text : If the Xref must be displayed under a text, the text.
46 */
CrossRefItem(Element * elmt,DynamicElementTextItem * text)47 CrossRefItem::CrossRefItem(Element *elmt, DynamicElementTextItem *text) :
48 QGraphicsObject(text),
49 m_element (elmt),
50 m_text(text)
51 {init();}
52
53 /**
54 * @brief CrossRefItem::CrossRefItem
55 * @param elmt : element to display the cross ref
56 * @param group : If the Xref must be displayed under a group, the group.
57 */
CrossRefItem(Element * elmt,ElementTextItemGroup * group)58 CrossRefItem::CrossRefItem(Element *elmt, ElementTextItemGroup *group) :
59 QGraphicsObject(group),
60 m_element(elmt),
61 m_group(group)
62 {init();}
63
64 /**
65 * @brief CrossRefItem::~CrossRefItem
66 * Default destructor
67 */
~CrossRefItem()68 CrossRefItem::~CrossRefItem() {}
69
70 /**
71 * @brief CrossRefItem::init
72 * init this Xref
73 */
init()74 void CrossRefItem::init()
75 {
76 if(!m_element->diagram())
77 {
78 qDebug() << "CrossRefItem constructor" << "element is not in a diagram";
79 return;
80 }
81
82 QETProject *project = m_element->diagram()->project();
83 connect(project, &QETProject::XRefPropertiesChanged, this, &CrossRefItem::updateProperties);
84
85 m_properties = m_element->diagram()->project()->defaultXRefProperties(m_element->kindInformations()["type"].toString());
86 setAcceptHoverEvents(true);
87
88 setUpConnection();
89 linkedChanged();
90 updateLabel();
91 }
92
93 /**
94 * @brief CrossRefItem::setUpConnection
95 * Set up several connection to keep up to date the Xref
96 */
setUpConnection()97 void CrossRefItem::setUpConnection()
98 {
99 for(const QMetaObject::Connection& c : m_update_connection)
100 disconnect(c);
101
102 m_update_connection.clear();
103 QETProject *project = m_element->diagram()->project();
104 bool set=false;
105
106 if(m_properties.snapTo() == XRefProperties::Label && (m_text || m_group)) //Snap to label and parent is a text or a group
107 set=true;
108 else if(m_properties.snapTo() == XRefProperties::Bottom && !m_text && !m_group) //Snap to bottom of element and parent is the element itself
109 {
110 m_update_connection << connect(m_element, SIGNAL(yChanged()), this, SLOT(autoPos()));
111 m_update_connection << connect(m_element, SIGNAL(rotationChanged()), this, SLOT(autoPos()));
112 set=true;
113 }
114
115 if(set)
116 {
117 m_update_connection << connect(project, &QETProject::projectDiagramsOrderChanged, this, &CrossRefItem::updateLabel);
118 m_update_connection << connect(project, &QETProject::diagramRemoved, this, &CrossRefItem::updateLabel);
119 m_update_connection << connect(m_element, &Element::linkedElementChanged, this, &CrossRefItem::linkedChanged);
120 linkedChanged();
121 updateLabel();
122 }
123 }
124
125 /**
126 * @brief CrossRefItem::boundingRect
127 * @return the bounding rect of this item
128 */
boundingRect() const129 QRectF CrossRefItem::boundingRect() const {
130 return m_bounding_rect;
131 }
132
133 /**
134 * @brief CrossRefItem::shape
135 * @return the shape of this item
136 */
shape() const137 QPainterPath CrossRefItem::shape() const{
138 return m_shape_path;
139 }
140
141 /**
142 * @brief CrossRefItem::elementPositionText
143 * @param elmt
144 * @return the string corresponding to the position of @elmt in the diagram.
145 * if @add_prefix is true, prefix (for power and delay contact) is added to the poistion text.
146 */
elementPositionText(const Element * elmt,const bool & add_prefix) const147 QString CrossRefItem::elementPositionText(const Element *elmt, const bool &add_prefix) const
148 {
149 XRefProperties xrp = m_element->diagram()->project()->defaultXRefProperties(m_element->kindInformations()["type"].toString());
150 QString formula = xrp.masterLabel();
151 autonum::sequentialNumbers seq;
152 QString txt = autonum::AssignVariables::formulaToLabel(formula, seq, elmt->diagram(), elmt);
153
154 if (add_prefix)
155 {
156 if (elmt->kindInformations()["type"].toString() == "power") txt.prepend(m_properties.prefix("power"));
157 else if (elmt->kindInformations()["type"].toString().contains("delay")) txt.prepend(m_properties.prefix("delay"));
158 else if (elmt->kindInformations()["state"].toString() == "SW") txt.prepend(m_properties.prefix("switch"));
159 }
160 return txt;
161 }
162
163 /**
164 * @brief CrossRefItem::updateProperties
165 * update the curent properties
166 */
updateProperties()167 void CrossRefItem::updateProperties()
168 {
169 XRefProperties xrp = m_element->diagram()->project()->defaultXRefProperties(m_element->kindInformations()["type"].toString());
170
171 if (m_properties != xrp)
172 {
173 m_properties = xrp;
174 hide();
175 if(m_properties.snapTo() == XRefProperties::Label && (m_text || m_group)) //Snap to label and parent is text or group
176 show();
177 else if((m_properties.snapTo() == XRefProperties::Bottom && !m_text && !m_group)) //Snap to bottom of element is the parent
178 show();
179
180 setUpConnection();
181 updateLabel();
182 }
183 }
184
185 /**
186 * @brief CrossRefItem::updateLabel
187 * Update the content of the item
188 */
updateLabel()189 void CrossRefItem::updateLabel()
190 {
191 //init the shape and bounding rect
192 m_shape_path = QPainterPath();
193 prepareGeometryChange();
194 m_bounding_rect = QRectF();
195
196 //init the painter
197 QPainter qp;
198 qp.begin(&m_drawing);
199 QPen pen_;
200 pen_.setWidthF(0.5);
201 qp.setPen(pen_);
202 qp.setFont(QETApp::diagramTextsFont(5));
203
204 //Draw cross or contact, only if master element is linked.
205 if (! m_element->linkedElements().isEmpty())
206 {
207 XRefProperties::DisplayHas dh = m_properties.displayHas();
208
209 if (dh == XRefProperties::Cross)
210 drawAsCross(qp);
211 else if (dh == XRefProperties::Contacts)
212 drawAsContacts(qp);
213 }
214
215 // AddExtraInfo(qp, "comment");
216 // AddExtraInfo(qp, "location");
217 qp.end();
218
219 autoPos();
220 update();
221 }
222
223 /**
224 * @brief CrossRefItem::autoPos
225 * Calculate and set position automaticaly.
226 */
autoPos()227 void CrossRefItem::autoPos() {
228 //We calcul the position according to the @snapTo of the xrefproperties
229 if (m_properties.snapTo() == XRefProperties::Bottom)
230 centerToBottomDiagram(this, m_element, m_properties.offset() <= 40 ? 5 : m_properties.offset());
231 else
232 centerToParentBottom(this);
233 }
234
sceneEvent(QEvent * event)235 bool CrossRefItem::sceneEvent(QEvent *event)
236 {
237 //By default when a QGraphicsItem is a child of a QGraphicsItemGroup
238 //all events are forwarded to group.
239 //We override it, when this Xref is in a group
240 if(m_group)
241 {
242 switch (event->type())
243 {
244 case QEvent::GraphicsSceneHoverEnter:
245 hoverEnterEvent(static_cast<QGraphicsSceneHoverEvent *>(event));
246 break;
247 case QEvent::GraphicsSceneHoverMove:
248 hoverMoveEvent(static_cast<QGraphicsSceneHoverEvent *>(event));
249 break;
250 case QEvent::GraphicsSceneHoverLeave:
251 hoverLeaveEvent(static_cast<QGraphicsSceneHoverEvent *>(event));
252 break;
253 case QEvent::GraphicsSceneMouseDoubleClick:
254 mouseDoubleClickEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
255 break;
256 default:break;
257 }
258 return true;
259 }
260
261 return QGraphicsObject::sceneEvent(event);
262 }
263
264 /**
265 * @brief CrossRefItem::paint
266 * Paint this item
267 * @param painter
268 * @param option
269 * @param widget
270 */
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)271 void CrossRefItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
272 Q_UNUSED(option);
273 Q_UNUSED(widget);
274 m_drawing.play(painter);
275 }
276
277 /**
278 * @brief CrossRefItem::mouseDoubleClickEvent
279 * @param event
280 */
mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event)281 void CrossRefItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
282 {
283 event->accept();
284 if (m_hovered_contact && m_hovered_contact->scene())
285 {
286 //Show and select the linked slave element
287 if (scene() != m_hovered_contact->scene())
288 {
289 m_hovered_contact->diagram()->showMe();
290 }
291 m_hovered_contact->setSelected(true);
292
293 //Zoom to the linked slave element
294 foreach(QGraphicsView *view, m_hovered_contact->diagram()->views())
295 {
296 QRectF fit = m_hovered_contact->sceneBoundingRect();
297 fit.adjust(-200, -200, 200, 200);
298 view->fitInView(fit, Qt::KeepAspectRatioByExpanding);
299 }
300 }
301 }
302
hoverEnterEvent(QGraphicsSceneHoverEvent * event)303 void CrossRefItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
304 {
305 m_hovered_contact = nullptr;
306 QGraphicsObject::hoverEnterEvent(event);
307 }
308
hoverMoveEvent(QGraphicsSceneHoverEvent * event)309 void CrossRefItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
310 {
311 QPointF pos = event->pos();
312
313 if (m_hovered_contact)
314 {
315 foreach(QRectF rect, m_hovered_contacts_map.values(m_hovered_contact))
316 {
317 //Mouse hover the same rect than previous hover event
318 if (rect.contains(pos))
319 {
320 QGraphicsObject::hoverMoveEvent(event);
321 return;
322 }
323 }
324
325 //At this point, mouse don't hover previous rect
326 m_hovered_contact = nullptr;
327
328 foreach (Element *elmt, m_hovered_contacts_map.keys())
329 {
330 foreach(QRectF rect, m_hovered_contacts_map.values(elmt))
331 {
332 //Mouse hover a contact
333 if (rect.contains(pos))
334 {
335 m_hovered_contact = elmt;
336 }
337 }
338 }
339
340 updateLabel();
341 QGraphicsObject::hoverMoveEvent(event);
342 return;
343 }
344 else
345 {
346 foreach (Element *elmt, m_hovered_contacts_map.keys())
347 {
348 foreach(QRectF rect, m_hovered_contacts_map.values(elmt))
349 {
350 //Mouse hover a contact
351 if (rect.contains(pos))
352 {
353 m_hovered_contact = elmt;
354 updateLabel();
355 QGraphicsObject::hoverMoveEvent(event);
356 return;
357 }
358 }
359 }
360 }
361 }
362
hoverLeaveEvent(QGraphicsSceneHoverEvent * event)363 void CrossRefItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
364 {
365 m_hovered_contact = nullptr;
366 updateLabel();
367 QGraphicsObject::hoverLeaveEvent(event);
368 }
369
linkedChanged()370 void CrossRefItem::linkedChanged()
371 {
372 for(const QMetaObject::Connection& c : m_slave_connection)
373 disconnect(c);
374
375 m_slave_connection.clear();
376
377 if(!isVisible())
378 return;
379
380 for(Element *elmt : m_element->linkedElements())
381 {
382 m_slave_connection << connect(elmt, &Element::xChanged, this, &CrossRefItem::updateLabel);
383 m_slave_connection << connect(elmt, &Element::yChanged, this, &CrossRefItem::updateLabel);
384 }
385
386 updateLabel();
387 }
388
389 /**
390 * @brief CrossRefItem::buildHeaderContact
391 * Draw the QPicture of m_hdr_no_ctc and m_hdr_nc_ctc
392 */
buildHeaderContact()393 void CrossRefItem::buildHeaderContact() {
394 if (!m_hdr_no_ctc.isNull() && !m_hdr_nc_ctc.isNull()) return;
395
396 //init the painter
397 QPainter qp;
398 QPen pen_;
399 pen_.setWidthF(0.2);
400
401 //draw the NO contact
402 if (m_hdr_no_ctc.isNull()) {
403 qp.begin(&m_hdr_no_ctc);
404 qp.setPen(pen_);
405 qp.drawLine(0, 3, 5, 3);
406 QPointF p1[3] = {
407 QPointF(5, 0),
408 QPointF(10, 3),
409 QPointF(15, 3),
410 };
411 qp.drawPolyline(p1,3);
412 qp.end();
413 }
414
415 //draw the NC contact
416 if (m_hdr_nc_ctc.isNull()) {
417 qp.begin(&m_hdr_nc_ctc);
418 qp.setPen(pen_);
419 QPointF p2[3] = {
420 QPointF(0, 3),
421 QPointF(5, 3),
422 QPointF(5, 0)
423 };
424 qp.drawPolyline(p2,3);
425 QPointF p3[3] = {
426 QPointF(4, 0),
427 QPointF(10, 3),
428 QPointF(15, 3),
429 };
430 qp.drawPolyline(p3,3);
431 qp.end();
432 }
433 }
434
435 /**
436 * @brief CrossRefItem::setUpCrossBoundingRect
437 * Get the numbers of slaves elements linked to this parent element,
438 * for calculate the size of the cross bounding rect.
439 * The cross ref item is drawing according to the size of the cross bounding rect.
440 */
setUpCrossBoundingRect(QPainter & painter)441 void CrossRefItem::setUpCrossBoundingRect(QPainter &painter)
442 {
443 //No need to calcul if nothing is linked
444 if (m_element->isFree()) return;
445
446 QStringList no_str, nc_str;
447
448 foreach (Element *elmt, NOElements())
449 no_str.append(elementPositionText(elmt, true));
450 foreach(Element *elmt, NCElements())
451 nc_str.append(elementPositionText(elmt, true));
452
453
454 //There is no string to display, we return now
455 if (no_str.isEmpty() && nc_str.isEmpty()) return;
456
457 //this is the default size of cross ref item
458 QRectF default_bounding(0, 0, 40, header + cross_min_heigth);
459
460 //Bounding rect of the NO text
461 QRectF no_bounding;
462 foreach(QString str, no_str)
463 {
464 QRectF bounding = painter.boundingRect(QRectF (), Qt::AlignCenter, str);
465 no_bounding = no_bounding.united(bounding);
466 }
467 //Adjust according to the NO
468 if (no_bounding.height() > default_bounding.height() - header)
469 default_bounding.setHeight(no_bounding.height() + header); //adjust the height
470 if (no_bounding.width() > default_bounding.width()/2)
471 default_bounding.setWidth(no_bounding.width()*2); //adjust the width
472
473 //Bounding rect of the NC text
474 QRectF nc_bounding;
475 foreach(QString str, nc_str)
476 {
477 QRectF bounding = painter.boundingRect(QRectF (), Qt::AlignCenter, str);
478 nc_bounding = nc_bounding.united(bounding);
479 }
480 //Adjust according to the NC
481 if (nc_bounding.height() > default_bounding.height() - header)
482 default_bounding.setHeight(nc_bounding.height() + header); //adjust the heigth
483 if (nc_bounding.width() > default_bounding.width()/2)
484 default_bounding.setWidth(nc_bounding.width()*2); //adjust the width
485
486 //Minor adjustement for better visual
487 default_bounding.adjust(0, 0, 4, 0);
488 m_shape_path.addRect(default_bounding);
489 prepareGeometryChange();
490 m_bounding_rect = default_bounding;
491 }
492
493 /**
494 * @brief CrossRefItem::drawAsCross
495 * Draw this crossref with a cross
496 * @param painter, painter to use
497 */
drawAsCross(QPainter & painter)498 void CrossRefItem::drawAsCross(QPainter &painter)
499 {
500 //calcul the size of the cross
501 setUpCrossBoundingRect(painter);
502 m_hovered_contacts_map.clear();
503
504 //Bounding rect is empty that mean there's no contact to draw
505 if (boundingRect().isEmpty()) return;
506
507 //draw the cross
508 QRectF br = boundingRect();
509 painter.drawLine(br.width()/2, 0, br.width()/2, br.height()); //vertical line
510 painter.drawLine(0, header, br.width(), header); //horizontal line
511
512 //Add the symbolic contacts
513 buildHeaderContact();
514 QPointF p((m_bounding_rect.width()/4) - (m_hdr_no_ctc.width()/2), 0);
515 painter.drawPicture (p, m_hdr_no_ctc);
516 p.setX((m_bounding_rect.width() * 3/4) - (m_hdr_nc_ctc.width()/2));
517 painter.drawPicture (p, m_hdr_nc_ctc);
518
519 //and fill it
520 fillCrossRef(painter);
521 }
522
523 /**
524 * @brief CrossRefItem::drawAsContacts
525 * Draw this crossref with symbolic contacts
526 * @param painter painter to use
527 */
drawAsContacts(QPainter & painter)528 void CrossRefItem::drawAsContacts(QPainter &painter)
529 {
530 if (m_element -> isFree())
531 return;
532
533 m_drawed_contacts = 0;
534 m_hovered_contacts_map.clear();
535 QRectF bounding_rect;
536
537 //Draw each linked contact
538 foreach (Element *elmt, m_element->linkedElements())
539 {
540 DiagramContext info = elmt->kindInformations();
541
542 for (int i=0; i<info["number"].toInt(); i++)
543 {
544 int option = 0;
545
546 QString state = info["state"].toString();
547 if (state == "NO") option = NO;
548 else if (state == "NC") option = NC;
549 else if (state == "SW") option = SW;
550
551 QString type = info["type"].toString();
552 if (type == "power") option += Power;
553 else if (type == "delayOn") option += DelayOn;
554 else if (type == "delayOff") option += DelayOff;
555 else if (type == "delayOnOff") option += DelayOnOff;
556
557 QRectF br = drawContact(painter, option, elmt);
558 bounding_rect = bounding_rect.united(br);
559 }
560 }
561
562 bounding_rect.adjust(-4, -4, 4, 4);
563 prepareGeometryChange();
564 m_bounding_rect = bounding_rect;
565 m_shape_path.addRect(bounding_rect);
566 }
567
568 /**
569 * @brief CrossRefItem::drawContact
570 * Draw one contact, the type of contact to draw is define in @flags.
571 * @param painter, painter to use
572 * @param flags, define how to draw the contact (see enul CONTACTS)
573 * @param elmt, the element to display text (the position of the contact)
574 * @return The bounding rect of the draw (contact + text)
575 */
drawContact(QPainter & painter,int flags,Element * elmt)576 QRectF CrossRefItem::drawContact(QPainter &painter, int flags, Element *elmt)
577 {
578 QString str = elementPositionText(elmt);
579 int offset = m_drawed_contacts*10;
580 QRectF bounding_rect;
581
582 QPen pen = painter.pen();
583 m_hovered_contact == elmt ? pen.setColor(Qt::blue) :pen.setColor(Qt::black);
584 painter.setPen(pen);
585
586 //Draw NO or NC contact
587 if (flags &NOC)
588 {
589 bounding_rect = QRectF(0, offset, 24, 10);
590
591 //draw the basic line
592 painter.drawLine(0, offset+6, 8, offset+6);
593 painter.drawLine(16, offset+6, 24, offset+6);
594
595 ///take exemple of this code for display the terminal text
596 /*QFont font = QETApp::diagramTextsFont(4);
597 font.setBold(true);
598 painter.setFont(font);
599 QRectF bt(0, offset, 24, 10);
600 int txt = 10 + m_drawed_contacts;
601 painter.drawText(bt, Qt::AlignLeft|Qt::AlignTop, QString::number(txt));
602 painter.drawText(bt, Qt::AlignRight|Qt::AlignTop, QString::number(txt));
603 painter.setFont(QETApp::diagramTextsFont(5));*/
604
605 //draw open contact
606 if (flags &NO) {
607 painter.drawLine(8, offset+9, 16, offset+6);
608 }
609 //draw close contact
610 if (flags &NC) {
611 QPointF p1[3] = {
612 QPointF(8, offset+6),
613 QPointF(9, offset+6),
614 QPointF(9, offset+2.5)
615 };
616 painter.drawPolyline(p1,3);
617 painter.drawLine(8, offset+3, 16, offset+6);
618 }
619
620 //draw half circle for power contact
621 if (flags &Power) {
622 QRectF arc(4, offset+4, 4, 4);
623 if (flags &NO)
624 painter.drawArc(arc, 180*16, 180*16);
625 else
626 painter.drawArc(arc, 0, 180*16);
627 }
628
629 // draw half circle for delay contact
630 if(flags &Delay) {
631 // for delay on contact
632 if (flags &DelayOn) {
633 if (flags &NO) {
634 painter.drawLine(12, offset+8, 12, offset+11);
635 QRectF r(9.5, offset+9, 5, 3);
636 painter.drawArc(r, 180*16, 180*16);
637 }
638 if (flags &NC) {
639 painter.drawLine(QPointF(12.5, offset+5), QPointF(12.5, offset+8));
640 QRectF r(10, offset+6, 5, 3);
641 painter.drawArc(r, 180*16, 180*16);
642 }
643 }
644 // for delay off contact
645 else if ( flags &DelayOff){
646 if (flags &NO) {
647 painter.drawLine(12, offset+8, 12, offset+9.5);
648 QRectF r(9.5, offset+9.5, 5, 3);
649 painter.drawArc(r, 0, 180*16);
650 }
651 if (flags &NC) {
652 painter.drawLine(QPointF(12.5, offset+5), QPointF(12.5, offset+7));
653 QRectF r(10, offset+7.5, 5, 3);
654 painter.drawArc(r, 0, 180*16);
655 }
656
657 }
658 else {
659 // for delay on contact
660 if (flags &NO) {
661 painter.drawLine(12, offset+8, 12, offset+11);
662 QRectF r(9.5, offset+11.7, 5, 3);
663 painter.drawArc(r, 0, 180*16);
664 QRectF rl(9.5, offset+9, 5, 3);
665 painter.drawArc(rl, 180*16, 180*16);
666 }
667 if (flags &NC) {
668 painter.drawLine(QPointF(12.5, offset+5), QPointF(12.5, offset+8));
669 QRectF r(9.5, offset+10.7, 5, 3);
670 painter.drawArc(r, 0, 180*16);
671 QRectF rl(9.5, offset+8, 5, 3);
672 painter.drawArc(rl, 180*16, 180*16);
673 }
674 }
675 }
676
677 QRectF text_rect = painter.boundingRect(QRectF(30, offset, 5, 10), Qt::AlignLeft | Qt::AlignVCenter, str);
678 painter.drawText(text_rect, Qt::AlignLeft | Qt::AlignVCenter, str);
679 bounding_rect = bounding_rect.united(text_rect);
680
681 if (m_hovered_contacts_map.contains(elmt))
682 {
683 m_hovered_contacts_map.insertMulti(elmt, bounding_rect);
684 }
685 else
686 {
687 m_hovered_contacts_map.insert(elmt, bounding_rect);
688 }
689
690 ++m_drawed_contacts;
691 }
692
693 //Draw a switch contact
694 else if (flags &SW)
695 {
696 bounding_rect = QRectF(0, offset, 24, 20);
697
698 //draw the NO side
699 painter.drawLine(0, offset+6, 8, offset+6);
700 //Draw the NC side
701 QPointF p1[3] = {
702 QPointF(0, offset+16),
703 QPointF(8, offset+16),
704 QPointF(8, offset+12)
705 };
706 painter.drawPolyline(p1, 3);
707
708 //Draw the common side
709 QPointF p2[3] = {
710 QPointF(7, offset+14),
711 QPointF(16, offset+11),
712 QPointF(24, offset+11),
713 };
714 painter.drawPolyline(p2, 3);
715
716 //Draw the half ellipse off delay
717 if (flags &Delay)
718 {
719 painter.drawLine(12, offset+13, 12, offset+16);
720 if (flags &DelayOn) {
721 QRectF r(9.5, offset+14, 5, 3);
722 painter.drawArc(r, 180*16, 180*16);
723 }
724 else if (flags &DelayOff) {
725 QRectF r(9.5, offset+16.5, 5, 3);
726 painter.drawArc(r, 0, 180*16);
727 }
728 else if (flags &DelayOnOff) {
729 QRectF r(9.5, offset+14, 5, 3);
730 painter.drawArc(r, 180*16, 180*16);
731 QRectF rr(9.5, offset+17, 5, 3);
732 painter.drawArc(rr, 0, 180*16);
733 }
734 }
735
736 //Draw position text
737 QRectF text_rect = painter.boundingRect(QRectF(30, offset+5, 5, 10), Qt::AlignLeft | Qt::AlignVCenter, str);
738 painter.drawText(text_rect, Qt::AlignLeft | Qt::AlignVCenter, str);
739 bounding_rect = bounding_rect.united(text_rect);
740
741 if (m_hovered_contacts_map.contains(elmt)) {
742 m_hovered_contacts_map.insertMulti(elmt, bounding_rect);
743 }
744 else {
745 m_hovered_contacts_map.insert(elmt, bounding_rect);
746 }
747
748 //a switch contact take place of two normal contact
749 m_drawed_contacts += 2;
750 }
751
752 return bounding_rect;
753 }
754
755 /**
756 * @brief CrossRefItem::fillCrossRef
757 * Fill the content of the cross ref
758 * @param painter painter to use.
759 */
fillCrossRef(QPainter & painter)760 void CrossRefItem::fillCrossRef(QPainter &painter)
761 {
762 if (m_element->isFree()) return;
763
764 qreal middle_cross = m_bounding_rect.width()/2;
765
766 //Fill NO
767 QPointF no_top_left(0, header);
768 foreach(Element *elmt, NOElements())
769 {
770 QPen pen = painter.pen();
771 m_hovered_contact == elmt ? pen.setColor(Qt::blue) :pen.setColor(Qt::black);
772 painter.setPen(pen);
773
774 QString str = elementPositionText(elmt, true);
775 QRectF bounding = painter.boundingRect(QRectF(no_top_left, QSize(middle_cross, 1)), Qt::AlignLeft, str);
776 painter.drawText(bounding, Qt::AlignLeft, str);
777
778 if (m_hovered_contacts_map.contains(elmt))
779 {
780 m_hovered_contacts_map.insertMulti(elmt, bounding);
781 }
782 else
783 {
784 m_hovered_contacts_map.insert(elmt, bounding);
785 }
786
787 no_top_left.ry() += bounding.height();
788 }
789
790 //Fill NC
791 QPointF nc_top_left(middle_cross, header);
792 foreach(Element *elmt, NCElements())
793 {
794 QPen pen = painter.pen();
795 m_hovered_contact == elmt ? pen.setColor(Qt::blue) :pen.setColor(Qt::black);
796 painter.setPen(pen);
797
798 QString str = elementPositionText(elmt, true);
799 QRectF bounding = painter.boundingRect(QRectF(nc_top_left, QSize(middle_cross, 1)), Qt::AlignRight, str);
800 painter.drawText(bounding, Qt::AlignRight, str);
801
802 if (m_hovered_contacts_map.contains(elmt))
803 {
804 m_hovered_contacts_map.insertMulti(elmt, bounding);
805 }
806 else
807 {
808 m_hovered_contacts_map.insert(elmt, bounding);
809 }
810
811 nc_top_left.ry() += bounding.height();
812 }
813 }
814
815 /**
816 * @brief CrossRefItem::AddExtraInfo
817 * Add the comment info of the parent item if needed.
818 * @param painter painter to use for draw the text
819 * @param type type of Info do be draw e.g. comment, location.
820 */
AddExtraInfo(QPainter & painter,const QString & type)821 void CrossRefItem::AddExtraInfo(QPainter &painter, const QString& type)
822 {
823 QString text = autonum::AssignVariables::formulaToLabel(m_element -> elementInformations()[type].toString(), m_element->rSequenceStruct(), m_element->diagram(), m_element);
824 bool must_show = m_element -> elementInformations().keyMustShow(type);
825
826 if (!text.isEmpty() && must_show)
827 {
828 painter.save();
829 painter.setFont(QETApp::diagramTextsFont(6));
830
831 QRectF r, text_bounding;
832 qreal center = boundingRect().center().x();
833 qreal width = boundingRect().width() > 70 ? boundingRect().width()/2 : 35;
834
835 r = QRectF(QPointF(center - width, boundingRect().bottom()),
836 QPointF(center + width, boundingRect().bottom() + 1));
837
838 text_bounding = painter.boundingRect(r, Qt::TextWordWrap | Qt::AlignHCenter, text);
839 painter.drawText(text_bounding, Qt::TextWordWrap | Qt::AlignHCenter, text);
840
841 text_bounding.adjust(-1,0,1,0); //adjust only for better visual
842
843 m_shape_path.addRect(text_bounding);
844 prepareGeometryChange();
845 m_bounding_rect = m_bounding_rect.united(text_bounding);
846 if (type == "comment") painter.drawRoundedRect(text_bounding, 2, 2);
847 painter.restore();
848 }
849 }
850
851 /**
852 * @brief CrossRefItem::NOElements
853 * @return The linked elements of @m_element wich are open or switch contact.
854 * If linked element is a power contact, xref propertie is set to don't show power contact
855 * and this cross item must be drawed as cross, the element is not append in the list.
856 */
NOElements() const857 QList<Element *> CrossRefItem::NOElements() const
858 {
859 QList<Element *> no_list;
860
861 foreach (Element *elmt, m_element->linkedElements())
862 {
863 //We continue if element is a power contact and xref propertie
864 //is set to don't show power contact
865 if (m_properties.displayHas() == XRefProperties::Cross &&
866 !m_properties.showPowerContact() &&
867 elmt -> kindInformations()["type"].toString() == "power")
868 continue;
869
870 QString state = elmt->kindInformations()["state"].toString();
871
872 if (state == "NO" || state == "SW")
873 {
874 no_list.append(elmt);
875 }
876 }
877
878 return no_list;
879 }
880
881 /**
882 * @brief CrossRefItem::NCElements
883 * @return The linked elements of @m_element wich are close or switch contact
884 * If linked element is a power contact, xref propertie is set to don't show power contact
885 * and this cross item must be drawed as cross, the element is not append in the list.
886 */
NCElements() const887 QList<Element *> CrossRefItem::NCElements() const
888 {
889 QList<Element *> nc_list;
890
891 foreach (Element *elmt, m_element->linkedElements())
892 {
893 //We continue if element is a power contact and xref propertie
894 //is set to don't show power contact
895 if (m_properties.displayHas() == XRefProperties::Cross &&
896 !m_properties.showPowerContact() &&
897 elmt -> kindInformations()["type"].toString() == "power")
898 continue;
899
900 QString state = elmt->kindInformations()["state"].toString();
901
902 if (state == "NC" || state == "SW")
903 {
904 nc_list.append(elmt);
905 }
906 }
907
908 return nc_list;
909 }
910