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 "elementtextitemgroup.h"
19 #include "dynamicelementtextitem.h"
20 #include "element.h"
21 #include "diagram.h"
22 #include "addelementtextcommand.h"
23 #include "QPropertyUndoCommand/qpropertyundocommand.h"
24 #include "crossrefitem.h"
25 #include "qetapp.h"
26 #include "masterelement.h"
27 #include "qgraphicsitemutility.h"
28 
29 #include <QPainter>
30 #include <QGraphicsSceneMouseEvent>
31 #include <utility>
32 
sorting(QGraphicsItem * qgia,QGraphicsItem * qgib)33 bool sorting(QGraphicsItem *qgia, QGraphicsItem *qgib)
34 {
35 	return qgia->pos().y() < qgib->pos().y();
36 }
37 
38 /**
39  * @brief ElementTextItemGroup::ElementTextItemGroup
40  * @param parent
41  */
ElementTextItemGroup(const QString & name,Element * parent)42 ElementTextItemGroup::ElementTextItemGroup(const QString &name, Element *parent) :
43 	QGraphicsItemGroup(parent),
44 	m_name(name),
45 	m_parent_element(parent)
46 {
47 	setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable);
48 	connect(parent, &Element::linkedElementChanged, this, &ElementTextItemGroup::updateXref);
49 }
50 
~ElementTextItemGroup()51 ElementTextItemGroup::~ElementTextItemGroup()
52 {}
53 
54 /**
55  * @brief ElementTextItemGroup::addToGroup
56  * @param item
57  */
addToGroup(QGraphicsItem * item)58 void ElementTextItemGroup::addToGroup(QGraphicsItem *item)
59 {
60 	if(item->type() == DynamicElementTextItem::Type)
61 	{
62 			//Befor add text to this group we must to set the text at the same rotation of this group
63 		if((item->rotation() != rotation()) && !m_block_alignment_update)
64 			item->setRotation(rotation());
65 
66 		QGraphicsItemGroup::addToGroup(item);
67 		updateAlignment();
68 
69 		DynamicElementTextItem *deti = qgraphicsitem_cast<DynamicElementTextItem *>(item);
70 		connect(deti, &DynamicElementTextItem::fontChanged,      this, &ElementTextItemGroup::updateAlignment);
71 		connect(deti, &DynamicElementTextItem::textChanged,          this, &ElementTextItemGroup::updateAlignment);
72 		connect(deti, &DynamicElementTextItem::textFromChanged,      this, &ElementTextItemGroup::updateAlignment);
73 		connect(deti, &DynamicElementTextItem::infoNameChanged,      this, &ElementTextItemGroup::updateAlignment);
74 		connect(deti, &DynamicElementTextItem::compositeTextChanged, this, &ElementTextItemGroup::updateAlignment);
75 		connect(deti, &DynamicElementTextItem::plainTextChanged,     this, &ElementTextItemGroup::updateAlignment);
76 		connect(deti, &DynamicElementTextItem::textWidthChanged,     this, &ElementTextItemGroup::updateAlignment);
77 
78 		connect(deti, &DynamicElementTextItem::textFromChanged, this, &ElementTextItemGroup::updateXref);
79 		connect(deti, &DynamicElementTextItem::infoNameChanged, this, &ElementTextItemGroup::updateXref);
80 
81 		updateXref();
82 	}
83 }
84 
85 /**
86  * @brief ElementTextItemGroup::removeFromGroup
87  * @param item
88  */
removeFromGroup(QGraphicsItem * item)89 void ElementTextItemGroup::removeFromGroup(QGraphicsItem *item)
90 {
91 	QGraphicsItemGroup::removeFromGroup(item);
92 		//the item transformation is not reseted, we must to do it, because for exemple if the group rotation is 45°
93 		//When item is removed from group, visually the item is unchanged (so 45°) but if we call item->rotation() the returned value is 0.
94 	item->resetTransform();
95 	item->setRotation(this->rotation());
96 	item->setFlag(QGraphicsItem::ItemIsSelectable, true);
97 	updateAlignment();
98 
99 	if(DynamicElementTextItem *deti = qgraphicsitem_cast<DynamicElementTextItem *>(item))
100 	{
101 		disconnect(deti, &DynamicElementTextItem::fontChanged,      this, &ElementTextItemGroup::updateAlignment);
102 		disconnect(deti, &DynamicElementTextItem::textChanged,          this, &ElementTextItemGroup::updateAlignment);
103 		disconnect(deti, &DynamicElementTextItem::textFromChanged,      this, &ElementTextItemGroup::updateAlignment);
104 		disconnect(deti, &DynamicElementTextItem::infoNameChanged,      this, &ElementTextItemGroup::updateAlignment);
105 		disconnect(deti, &DynamicElementTextItem::compositeTextChanged, this, &ElementTextItemGroup::updateAlignment);
106 		disconnect(deti, &DynamicElementTextItem::plainTextChanged,     this, &ElementTextItemGroup::updateAlignment);
107 		disconnect(deti, &DynamicElementTextItem::textWidthChanged,     this, &ElementTextItemGroup::updateAlignment);
108 
109 		disconnect(deti, &DynamicElementTextItem::textFromChanged, this, &ElementTextItemGroup::updateXref);
110 		disconnect(deti, &DynamicElementTextItem::infoNameChanged, this, &ElementTextItemGroup::updateXref);
111 
112 		updateXref();
113 	}
114 }
115 
116 /**
117  * @brief ElementTextItemGroup::blockAlignmentUpdate
118  * If true, the texts in this group are never aligned, moved, rotated etc...
119  * the texts stay as it was, until blockAlignmentUpdate is set to false.
120  * @param block
121  */
blockAlignmentUpdate(bool block)122 void ElementTextItemGroup::blockAlignmentUpdate(bool block)
123 {
124 	m_block_alignment_update = block;
125 }
126 
127 /**
128  * @brief ElementTextItemGroup::setAlignement
129  * Set the alignement of this group
130  * @param alignement
131  */
setAlignment(Qt::Alignment alignement)132 void ElementTextItemGroup::setAlignment(Qt::Alignment alignement)
133 {
134 	m_alignment = alignement;
135 	updateAlignment();
136 	emit alignmentChanged(alignement);
137 }
138 
alignment() const139 Qt::Alignment ElementTextItemGroup::alignment() const
140 {
141 	return m_alignment;
142 }
143 
144 /**
145  * @brief ElementTextItemGroup::setAlignment
146  * Update the alignement of the items in this group, according
147  * to the current alignement.
148  * @param alignement
149  */
updateAlignment()150 void ElementTextItemGroup::updateAlignment()
151 {
152 	if(m_block_alignment_update)
153 		return;
154 
155 	prepareGeometryChange();
156 
157 	QList <DynamicElementTextItem *> texts = this->texts();
158 
159 	qreal rotation_ = rotation();
160 
161 		//Set the rotation of this group to 0° relative to the scene
162 	qreal rot = rotation();
163 	QGraphicsItem *parent = parentItem();
164 	while (parent) {
165 		rot += parent->rotation();
166 		parent = parent->parentItem();
167 	}
168 	if(rot != 0)
169 		setRotation(rotation() - rot);
170 
171 
172 	if(texts.size() == 1)
173 	{
174 		prepareGeometryChange();
175 
176 		QGraphicsItem *first = texts.first();
177 		setPos(mapFromScene(first->mapToScene(pos())));
178 		first->setPos(0,0);
179 	}
180 	else if (texts.size() > 1)
181 	{
182 		qreal width = 0;
183 		for(QGraphicsItem *item : texts)
184 			if(item->boundingRect().width() > width)
185 				width = item->boundingRect().width();
186 
187 		prepareGeometryChange();
188 		std::sort(texts.begin(), texts.end(), sorting);
189 
190 		qreal y_offset = 0;
191 
192 		if(m_alignment == Qt::AlignLeft)
193 		{
194 			QPointF ref = texts.first()->pos();
195 
196 			for(QGraphicsItem *item : texts)
197 			{
198 				item->setPos(0, ref.y()+y_offset);
199 				y_offset+=item->boundingRect().height() + m_vertical_adjustment;
200 			}
201 		}
202 		else if(m_alignment == Qt::AlignVCenter)
203 		{
204 			QPointF ref(width/2,0);
205 
206 			for(QGraphicsItem *item : texts)
207 			{
208 				item->setPos(ref.x() - item->boundingRect().width()/2,
209 							 ref.y() + y_offset);
210 				y_offset+=item->boundingRect().height() + m_vertical_adjustment;
211 			}
212 		}
213 		else if (m_alignment == Qt::AlignRight)
214 		{
215 			QPointF ref(width,0);
216 
217 			for(QGraphicsItem *item : texts)
218 			{
219 				item->setPos(ref.x() - item->boundingRect().width(),
220 							 ref.y() + y_offset);
221 				y_offset+=item->boundingRect().height() + m_vertical_adjustment;
222 			}
223 		}
224 	}
225 
226 		//Restor the rotation
227 	setRotation(rotation_);
228 
229 	if(m_Xref_item)
230 		m_Xref_item->autoPos();
231 	if(m_slave_Xref_item)
232 		adjustSlaveXrefPos();
233 	if(m_hold_to_bottom_of_page)
234 		autoPos();
235 }
236 
237 /**
238  * @brief ElementTextItemGroup::setVerticalAdjustment
239  * Set the value of the vertical adjustment to @v.
240  * The vertical adjutment is use to adjust the space between the texts of this group.
241  * @param v
242  */
setVerticalAdjustment(int v)243 void ElementTextItemGroup::setVerticalAdjustment(int v)
244 {
245 	prepareGeometryChange();
246 	m_vertical_adjustment = v;
247 	updateAlignment();
248 	emit verticalAdjustmentChanged(v);
249 }
250 
251 /**
252  * @brief ElementTextItemGroup::setName
253  * @param name Set the name of this group
254  */
setName(QString name)255 void ElementTextItemGroup::setName(QString name)
256 {
257 	m_name = std::move(name);
258 	emit nameChanged(m_name);
259 }
260 
setHoldToBottomPage(bool hold)261 void ElementTextItemGroup::setHoldToBottomPage(bool hold)
262 {
263 	if(m_hold_to_bottom_of_page == hold)
264 		return;
265 
266 	m_hold_to_bottom_of_page = hold;
267 	if(m_hold_to_bottom_of_page)
268 	{
269 		setFlag(QGraphicsItem::ItemIsSelectable, false);
270 		setFlag(QGraphicsItem::ItemIsMovable, false);
271 		connect(m_parent_element, &Element::yChanged, this, &ElementTextItemGroup::autoPos);
272 		connect(m_parent_element, &Element::rotationChanged, this, &ElementTextItemGroup::autoPos);
273 		if(m_parent_element->linkType() == Element::Master)
274 		{
275 				//We use timer to let the time of the parent element xref to be updated, befor update the position of this group
276 				//because the position of this group is related to the size of the parent element Xref
277 			m_linked_changed_timer = connect(m_parent_element, &Element::linkedElementChanged,
278 											 [this]() {QTimer::singleShot(200, this, &ElementTextItemGroup::autoPos);});
279 			if(m_parent_element->diagram())
280 				m_XrefChanged_timer = connect(m_parent_element->diagram()->project(), &QETProject::XRefPropertiesChanged,
281 											  [this]()	{QTimer::singleShot(200, this, &ElementTextItemGroup::autoPos);});
282 		}
283 		autoPos();
284 	}
285 	else
286 	{
287 		setFlag(QGraphicsItem::ItemIsSelectable, true);
288 		setFlag(QGraphicsItem::ItemIsMovable, true);
289 		disconnect(m_parent_element, &Element::yChanged, this, &ElementTextItemGroup::autoPos);
290 		disconnect(m_parent_element, &Element::rotationChanged, this, &ElementTextItemGroup::autoPos);
291 		if(m_parent_element->linkType() == Element::Master)
292 		{
293 			disconnect(m_linked_changed_timer);
294 			if(m_XrefChanged_timer)
295 				disconnect(m_XrefChanged_timer);
296 		}
297 	}
298 
299 	emit holdToBottomPageChanged(hold);
300 }
301 
setFrame(const bool frame)302 void ElementTextItemGroup::setFrame(const bool frame)
303 {
304 	m_frame = frame;
305 	update();
306 	emit frameChanged(m_frame);
307 }
308 
frame() const309 bool ElementTextItemGroup::frame() const {
310 	return m_frame;
311 }
312 
313 /**
314  * @brief ElementTextItemGroup::texts
315  * @return Every texts in this group
316  */
texts() const317 QList<DynamicElementTextItem *> ElementTextItemGroup::texts() const
318 {
319 	QList<DynamicElementTextItem *> list;
320 	for(QGraphicsItem *qgi : childItems())
321 	{
322 		if(qgi->type() == DynamicElementTextItem::Type)
323 			list << static_cast<DynamicElementTextItem *>(qgi);
324 	}
325 	return list;
326 }
327 
328 /**
329  * @brief ElementTextItemGroup::diagram
330  * @return The diagram of this group, or nullptr if this group is not in a diagram
331  */
diagram() const332 Diagram *ElementTextItemGroup::diagram() const
333 {
334 	if(scene())
335 		return static_cast<Diagram *>(scene());
336 	else
337 		return nullptr;
338 }
339 
340 /**
341  * @brief ElementTextItemGroup::parentElement
342  * @return The parent element of this group or nullptr
343  */
parentElement() const344 Element *ElementTextItemGroup::parentElement() const
345 {
346 	if(parentItem() && parentItem()->type() == Element::Type)
347 		return static_cast<Element *>(parentItem());
348 	else
349 		return nullptr;
350 }
351 
352 /**
353  * @brief ElementTextItemGroup::toXml
354  * Export data of this group to xml
355  * @param dom_document
356  * @return
357  */
toXml(QDomDocument & dom_document) const358 QDomElement ElementTextItemGroup::toXml(QDomDocument &dom_document) const
359 {
360 	QDomElement dom_element = dom_document.createElement(this->xmlTaggName());
361 	dom_element.setAttribute("name", m_name);
362 
363 	dom_element.setAttribute("x", QString::number(pos().x()));
364 	dom_element.setAttribute("y", QString::number(pos().y()));
365 
366 	QMetaEnum me = QMetaEnum::fromType<Qt::Alignment>();
367 	dom_element.setAttribute("alignment", me.valueToKey(m_alignment));
368 
369 	dom_element.setAttribute("rotation", this->rotation());
370 	dom_element.setAttribute("vertical_adjustment", m_vertical_adjustment);
371 	dom_element.setAttribute("frame", m_frame? "true" : "false");
372 
373 	dom_element.setAttribute("hold_to_bottom_page", m_hold_to_bottom_of_page == true ? "true" : "false");
374 
375 	QDomElement dom_texts = dom_document.createElement("texts");
376 	for(DynamicElementTextItem *deti : texts())
377 	{
378 		QDomElement text = dom_document.createElement("text");
379 		text.setAttribute("uuid", deti->uuid().toString());
380 		dom_texts.appendChild(text);
381 	}
382 
383 	dom_element.appendChild(dom_texts);
384 	return dom_element;
385 }
386 
387 /**
388  * @brief ElementTextItemGroup::fromXml
389  * Import data of this group from xml
390  * @param dom_element
391  */
fromXml(QDomElement & dom_element)392 void ElementTextItemGroup::fromXml(QDomElement &dom_element)
393 {
394 	if (dom_element.tagName() != xmlTaggName()) {
395 		qDebug() << "ElementTextItemGroup::fromXml : Wrong tagg name";
396 		return;
397 	}
398 
399 	setName(dom_element.attribute("name", "no name"));
400 	QMetaEnum me = QMetaEnum::fromType<Qt::Alignment>();
401 	setAlignment(Qt::Alignment(me.keyToValue(dom_element.attribute("alignment").toStdString().data())));
402 
403 	setPos(dom_element.attribute("x", QString::number(0)).toDouble(),
404 		   dom_element.attribute("y", QString::number(0)).toDouble());
405 
406 	setRotation(dom_element.attribute("rotation", QString::number(0)).toDouble());
407 	setVerticalAdjustment(dom_element.attribute("vertical_adjustment").toInt());
408 	setFrame(dom_element.attribute("frame", "false") == "true"? true : false);
409 
410 	QString hold = dom_element.attribute("hold_to_bottom_page", "false");
411 	setHoldToBottomPage(hold == "true" ? true : false);
412 
413 	if(parentElement())
414 	{
415 		m_block_alignment_update = true;
416 		for(const QDomElement& text : QET::findInDomElement(dom_element, "texts", "text"))
417 		{
418 			DynamicElementTextItem *deti = nullptr;
419 			QUuid uuid(text.attribute("uuid"));
420 
421 			for(DynamicElementTextItem *txt : parentElement()->dynamicTextItems())
422 				if(txt->uuid() == uuid)
423 					deti = txt;
424 
425 			if (deti)
426 				parentElement()->addTextToGroup(deti, this);
427 		}
428 		m_block_alignment_update = false;
429 	}
430 }
431 
432 /**
433  * @brief ElementTextItemGroup::paint
434  * @param painter
435  * @param option
436  * @param widget
437  */
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)438 void ElementTextItemGroup::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
439 {
440 	Q_UNUSED(option);
441 	Q_UNUSED(widget);
442 	if(isSelected())
443 	{
444 		painter->save();
445 		QPen t;
446 		t.setColor(Qt::gray);
447 		t.setStyle(Qt::DashDotLine);
448 		t.setCosmetic(true);
449 		painter->setPen(t);
450 		painter->drawRoundRect(boundingRect().adjusted(1, 1, -1, -1), 10, 10);
451 
452 		painter->restore();
453 	}
454 	if(m_frame)
455 	{
456 		qreal font_size = 1;
457 		QRectF rect;
458 		for(DynamicElementTextItem *deti : this->texts())
459 		{
460 			font_size = std::max(font_size, deti->font().pointSizeF());
461 			rect = rect.united(mapFromItem(deti, deti->frameRect()).boundingRect());
462 		}
463 
464 			//Adjust the thickness according to the font size
465 		qreal w=0.3;
466 		if (font_size >= 5)
467 		{
468 			w = font_size*0.1;
469 			if(w > 2.5)
470 				w = 2.5;
471 		}
472 
473 		painter->save();
474 		QPen pen;
475 		pen.setWidthF(w);
476 		painter->setPen(pen);
477 		painter->setRenderHint(QPainter::Antialiasing);
478 
479 			//Adjust the rounding of the rectangle according to the size of the font
480 		qreal ro = font_size/3;
481 		painter->drawRoundedRect(rect, ro, ro);
482 		painter->restore();
483 	}
484 }
485 
486 /**
487  * @brief ElementTextItemGroup::boundingRect
488  * @return
489  */
boundingRect() const490 QRectF ElementTextItemGroup::boundingRect() const
491 {
492 		//If we refer to the Qt doc, the bounding rect of a QGraphicsItemGroup,
493 		//is the bounding of all childrens in the group
494 		//When add an item in the group, the bounding rect is good, but
495 		//if we move an item already in the group, the bounding rect of the group stay unchanged.
496 		//We reimplement this function to avoid this behavior.
497 	QRectF rect;
498 	for(QGraphicsItem *qgi : texts())
499 	{
500 		QRectF r(qgi->pos(), QSize(qgi->boundingRect().width(), qgi->boundingRect().height()));
501 		rect = rect.united(r);
502 	}
503 	return rect;
504 }
505 
setRotation(qreal angle)506 void ElementTextItemGroup::setRotation(qreal angle)
507 {
508 	QGraphicsItemGroup::setRotation(angle);
509 	emit rotationChanged(angle);
510 }
511 
setPos(const QPointF & pos)512 void ElementTextItemGroup::setPos(const QPointF &pos)
513 {
514 	QPointF old_pos = this->pos();
515 	QGraphicsItemGroup::setPos(pos);
516 	if (old_pos.x() != this->pos().x())
517 		emit xChanged();
518 	if (old_pos.y() != this->pos().y())
519 		emit yChanged();
520 }
521 
setPos(qreal x,qreal y)522 void ElementTextItemGroup::setPos(qreal x, qreal y)
523 {
524 	QPointF old_pos = this->pos();
525 	QGraphicsItemGroup::setPos(x,y);
526 	if (old_pos.x() != this->pos().x())
527 		emit xChanged();
528 	if (old_pos.y() != this->pos().y())
529 		emit yChanged();
530 }
531 
532 /**
533  * @brief ElementTextItemGroup::mousePressEvent
534  * @param event
535  */
mousePressEvent(QGraphicsSceneMouseEvent * event)536 void ElementTextItemGroup::mousePressEvent(QGraphicsSceneMouseEvent *event)
537 {
538 	if(event->button() == Qt::LeftButton)
539 	{
540 		m_first_move = true;
541 		if(event->modifiers() & Qt::ControlModifier)
542 			setSelected(!isSelected());
543 	}
544 
545 	QGraphicsItemGroup::mousePressEvent(event);
546 }
547 
548 /**
549  * @brief ElementTextItemGroup::mouseMoveEvent
550  * @param event
551  */
mouseMoveEvent(QGraphicsSceneMouseEvent * event)552 void ElementTextItemGroup::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
553 {
554 	if((event->buttons() & Qt::LeftButton) && (flags() & ItemIsMovable))
555 	{
556 		if(diagram() && m_first_move)
557 			diagram()->elementTextsMover().beginMovement(diagram(), this);
558 
559 		if(m_first_move)
560 		{
561 			m_initial_position = pos();
562 			if(parentElement())
563 				parentElement()->setHighlighted(true);
564 		}
565 
566 		QPointF current_parent_pos;
567 		QPointF button_down_parent_pos;
568 		current_parent_pos = mapToParent(mapFromScene(event->scenePos()));
569 		button_down_parent_pos = mapToParent(mapFromScene(event->buttonDownScenePos(Qt::LeftButton)));
570 
571 		QPointF new_pos = m_initial_position + current_parent_pos - button_down_parent_pos;
572 		event->modifiers() == Qt::ControlModifier ? setPos(new_pos) : setPos(Diagram::snapToGrid(new_pos));
573 
574 		if(diagram())
575 			diagram()->elementTextsMover().continueMovement(event);
576 	} else {
577 		event->ignore();
578 	}
579 
580 	if(m_first_move)
581 		m_first_move = false;
582 }
583 
584 /**
585  * @brief ElementTextItemGroup::mouseReleaseEvent
586  * @param event
587  */
mouseReleaseEvent(QGraphicsSceneMouseEvent * event)588 void ElementTextItemGroup::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
589 {
590 	if(diagram())
591 	{
592 		diagram()->elementTextsMover().endMovement();
593 		if(parentElement())
594 			parentElement()->setHighlighted(false);
595 	}
596 
597 	if(!(event->modifiers() & Qt::ControlModifier))
598 		QGraphicsItemGroup::mouseReleaseEvent(event);
599 }
600 
mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event)601 void ElementTextItemGroup::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
602 {
603 	if(m_slave_Xref_item)
604 	{
605 		if(m_slave_Xref_item->boundingRect().contains(mapToItem(m_slave_Xref_item, event->pos())))
606 		{
607 			if(parentElement()->linkType() == Element::Slave && !parentElement()->linkedElements().isEmpty())
608 			{
609 				m_slave_Xref_item->setDefaultTextColor(Qt::black);
610 				Element *elmt = parentElement()->linkedElements().first();
611 
612 					//Unselect and ungrab mouse to prevent unwanted
613 					//move when linked element is in the same scene of this.
614 				setSelected(false);
615 				ungrabMouse();
616 
617 				if(scene() != elmt->scene())
618 					elmt->diagram()->showMe();
619 				elmt->setSelected(true);
620 
621 					//Zoom to the element
622 				for(QGraphicsView *view : elmt->scene()->views())
623 				{
624 					QRectF fit = elmt->sceneBoundingRect();
625 					fit.adjust(-200, -200, 200, 200);
626 					view->fitInView(fit, Qt::KeepAspectRatioByExpanding);
627 				}
628 			}
629 		}
630 	}
631 }
632 
633 /**
634  * @brief ElementTextItemGroup::keyPressEvent
635  * @param event
636  */
keyPressEvent(QKeyEvent * event)637 void ElementTextItemGroup::keyPressEvent(QKeyEvent *event)
638 {
639  	if(event->modifiers() == Qt::ControlModifier)
640 	{
641 		if(event->key() == Qt::Key_Left && m_alignment	!= Qt::AlignLeft)
642 		{
643 			if(diagram())
644 				diagram()->undoStack().push(new AlignmentTextsGroupCommand(this, Qt::AlignLeft));
645 			else
646 				setAlignment(Qt::AlignLeft);
647 		}
648 		else if (event->key() == Qt::Key_Up && m_alignment	!= Qt::AlignVCenter)
649 		{
650 			if(diagram())
651 				diagram()->undoStack().push(new AlignmentTextsGroupCommand(this, Qt::AlignVCenter));
652 			else
653 				setAlignment(Qt::AlignVCenter);
654 		}
655 		else if (event->key() == Qt::Key_Right && m_alignment	!= Qt::AlignRight)
656 		{
657 			if(diagram())
658 				diagram()->undoStack().push(new AlignmentTextsGroupCommand(this, Qt::AlignRight));
659 			else
660 				setAlignment(Qt::AlignRight);
661 		}
662 	}
663 	event->ignore();
664 }
665 
hoverEnterEvent(QGraphicsSceneHoverEvent * event)666 void ElementTextItemGroup::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
667 {
668 		//The pos of the event is not in this item coordinate,
669 		//but in child item hovered by the mouse, so we use the scene pos.
670 	if(m_slave_Xref_item &&
671 	   m_slave_Xref_item->boundingRect().contains(m_slave_Xref_item->mapFromScene(event->scenePos())))
672 		m_slave_Xref_item->setDefaultTextColor(Qt::blue);
673 
674 	QGraphicsItemGroup::hoverEnterEvent(event);
675 }
676 
hoverLeaveEvent(QGraphicsSceneHoverEvent * event)677 void ElementTextItemGroup::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
678 {
679 	if(m_slave_Xref_item)
680 		m_slave_Xref_item->setDefaultTextColor(Qt::black);
681 
682 	QGraphicsItemGroup::hoverLeaveEvent(event);
683 }
684 
updateXref()685 void ElementTextItemGroup::updateXref()
686 {
687 	if(m_parent_element->diagram())
688 	{
689 		QETProject *project = m_parent_element->diagram()->project();
690 
691 		if(m_parent_element->linkType() == Element::Master &&
692 		   !m_parent_element->linkedElements().isEmpty())
693 		{
694 
695 			XRefProperties xrp = project->defaultXRefProperties(m_parent_element->kindInformations()["type"].toString());
696 
697 			if(xrp.snapTo() == XRefProperties::Label)
698 			{
699 					//At least one text owned by this group must be set with
700 					//textFrom -> element info and element info name -> label
701 					//for display a xref
702 				for(DynamicElementTextItem *deti : texts())
703 				{
704 					if(deti->textFrom() == DynamicElementTextItem::ElementInfo &&
705 					   deti->infoName() == "label")
706 					{
707 						if(!m_Xref_item)
708 							m_Xref_item = new CrossRefItem(m_parent_element, this);
709 						m_Xref_item->autoPos();
710 						return;
711 					}
712 				}
713 			}
714 		}
715 		else if(m_parent_element->linkType() == Element::Slave &&
716 				!m_parent_element->linkedElements().isEmpty())
717 		{
718 			Element *master_elmt = m_parent_element->linkedElements().first();
719 			for(DynamicElementTextItem *deti : texts())
720 			{
721 				if((deti->textFrom() == DynamicElementTextItem::ElementInfo && deti->infoName() == "label") ||
722 				   (deti->textFrom() == DynamicElementTextItem::CompositeText && deti->compositeText().contains("%{label")))
723 				{
724 					XRefProperties xrp = project->defaultXRefProperties(master_elmt->kindInformations()["type"].toString());
725 					QString xref_label = xrp.slaveLabel();
726 					xref_label = autonum::AssignVariables::formulaToLabel(xref_label, master_elmt->rSequenceStruct(), master_elmt->diagram(), master_elmt);
727 
728 					if(!m_slave_Xref_item)
729 					{
730 						m_slave_Xref_item = new QGraphicsTextItem(xref_label, this);
731 						m_slave_Xref_item->setFont(QETApp::diagramTextsFont(5));
732 
733 						m_update_slave_Xref_connection << connect(master_elmt, &Element::xChanged,                       this, &ElementTextItemGroup::updateXref);
734 						m_update_slave_Xref_connection << connect(master_elmt, &Element::yChanged,                       this, &ElementTextItemGroup::updateXref);
735 						m_update_slave_Xref_connection << connect(master_elmt, &Element::elementInfoChange,              this, &ElementTextItemGroup::updateXref);
736 						m_update_slave_Xref_connection << connect(project,     &QETProject::projectDiagramsOrderChanged, this, &ElementTextItemGroup::updateXref);
737 						m_update_slave_Xref_connection << connect(project,     &QETProject::diagramRemoved,              this, &ElementTextItemGroup::updateXref);
738 						m_update_slave_Xref_connection << connect(project,     &QETProject::XRefPropertiesChanged,       this, &ElementTextItemGroup::updateXref);
739 					}
740 					else
741 						m_slave_Xref_item->setPlainText(xref_label);
742 
743 					adjustSlaveXrefPos();
744 					return;
745 				}
746 			}
747 
748 		}
749 	}
750 
751 
752 		//There is no reason to have a xref, we delete it if exist
753 	if(m_Xref_item)
754 	{
755 		delete m_Xref_item;
756 		m_Xref_item = nullptr;
757 	}
758 	if(m_slave_Xref_item)
759 	{
760 		delete m_slave_Xref_item;
761 		m_slave_Xref_item = nullptr;
762 		m_update_slave_Xref_connection.clear();
763 	}
764 }
765 
adjustSlaveXrefPos()766 void ElementTextItemGroup::adjustSlaveXrefPos()
767 {
768 	QRectF r = boundingRect();
769 	QPointF pos(r.center().x() - m_slave_Xref_item->boundingRect().width()/2,
770 				r.bottom());
771 	m_slave_Xref_item->setPos(pos);
772 }
773 
autoPos()774 void ElementTextItemGroup::autoPos()
775 {
776 	int offset = 5;
777 
778 	if(m_parent_element->linkType() == Element::Master)
779 	{
780 		if(!diagram())
781 			return;
782 
783 		MasterElement *master = static_cast<MasterElement *>(m_parent_element);
784 		XRefProperties xrp = diagram()->project()->defaultXRefProperties(master->kindInformations()["type"].toString());
785 		if(xrp.snapTo() == XRefProperties::Bottom)
786 		{
787 			QRectF rectXref = master->XrefBoundingRect();
788 			offset = xrp.offset() <= 40 ? 5 : xrp.offset();
789 
790 			offset += (int)rectXref.height();
791 		}
792 	}
793 	qreal r = rotation();
794 	centerToBottomDiagram(this, m_parent_element, offset);
795 		//centerToBottomDiagram change the rotation of this group if needed,
796 		//but setRotation is not a virtual function of QGraphicsItem, and the function centerToBottomDiagram
797 		//work with a QGraphicsItem. So we emit the signal if rotation changed
798 	if(rotation() != r)
799 		emit rotationChanged(rotation());
800 }
801 
802