1 /**
2 * UGENE - Integrated Bioinformatics Tools.
3 * Copyright (C) 2008-2021 UniPro <ugene@unipro.ru>
4 * http://ugene.net
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
20 */
21
22 #include "ItemViewStyle.h"
23
24 #include <QAbstractTextDocumentLayout>
25 #include <QBitmap>
26 #include <QColorDialog>
27 #include <QDomDocument>
28 #include <QFontDialog>
29 #include <QGraphicsSceneMouseEvent>
30 #include <QGraphicsSimpleTextItem>
31 #include <QGraphicsView>
32 #include <QPainter>
33 #include <QRadialGradient>
34 #include <QStyleOptionGraphicsItem>
35 #include <QTextDocument>
36 #include <QtMath>
37
38 #include <U2Core/QVariantUtils.h>
39
40 #include <U2Lang/ActorModel.h>
41 #include <U2Lang/WorkflowSettings.h>
42
43 #include "WorkflowViewController.h"
44 #include "WorkflowViewItems.h"
45
46 namespace U2 {
47
48 const StyleId ItemStyles::SIMPLE = "simple";
49 const StyleId ItemStyles::EXTENDED = "ext";
50
51 #define BGC QString("-bgc")
52 #define FONT QString("-font")
53
54 const QColor ITEM_WITH_ENABLED_BREAKPOINT_BORDER_COLOR = QColor(178, 34, 34);
55 const QColor ITEM_WITH_DISABLED_BREAKPOINT_BORDER_COLOR = QColor(184, 134, 11);
56
ItemViewStyle(WorkflowProcessItem * p,const QString & id)57 ItemViewStyle::ItemViewStyle(WorkflowProcessItem *p, const QString &id)
58 : QGraphicsObject(p),
59 defFont(WorkflowSettings::defaultFont()), id(id) {
60 setVisible(false);
61 bgColorAction = new QAction(tr("Background color"), this);
62 connect(bgColorAction, SIGNAL(triggered()), SLOT(selectBGColor()));
63
64 fontAction = new QAction(tr("Font"), this);
65 connect(fontAction, SIGNAL(triggered()), SLOT(selectFont()));
66 }
67
selectBGColor()68 void ItemViewStyle::selectBGColor() {
69 QColor res = QColorDialog::getColor(bgColor, owner->scene()->views().first());
70 if (res.isValid()) {
71 bgColor = res;
72 WorkflowScene *sc = qobject_cast<WorkflowScene *>(owner->scene());
73 if (sc != nullptr) {
74 sc->setModified(true);
75 }
76 }
77 }
78
selectFont()79 void ItemViewStyle::selectFont() {
80 bool ok;
81 QFont res = QFontDialog::getFont(&ok, defFont, owner->scene()->views().first(), tr("Characters Font"), QFontDialog::DontUseNativeDialog);
82 if (ok) {
83 defFont = res;
84 WorkflowScene *sc = qobject_cast<WorkflowScene *>(owner->scene());
85 if (sc != nullptr) {
86 sc->setModified(true);
87 }
88 }
89 }
90
saveState(QDomElement & el) const91 void ItemViewStyle::saveState(QDomElement &el) const {
92 if (bgColor != defaultColor())
93 el.setAttribute(id + BGC, QVariantUtils::var2String(bgColor));
94 if (defFont != QFont())
95 el.setAttribute(id + FONT, defFont.toString());
96 }
97
loadState(QDomElement & el)98 void ItemViewStyle::loadState(QDomElement &el) {
99 if (el.hasAttribute(id + BGC)) {
100 QColor bgc = QVariantUtils::String2Var(el.attribute(id + BGC)).value<QColor>();
101 if (bgc.isValid()) {
102 bgColor = bgc;
103 }
104 }
105 if (el.hasAttribute(id + FONT)) {
106 defFont.fromString(el.attribute(id + FONT));
107 }
108 }
109
SimpleProcStyle(WorkflowProcessItem * pit)110 SimpleProcStyle::SimpleProcStyle(WorkflowProcessItem *pit)
111 : ItemViewStyle(pit, ItemStyles::SIMPLE) {
112 owner = (pit);
113 owner->connect(owner->getProcess(), SIGNAL(si_labelChanged()), SLOT(sl_update()));
114 bgColor = defaultColor();
115 }
116
defaultColor() const117 QColor SimpleProcStyle::defaultColor() const {
118 /*QColor ret(Qt::darkCyan);
119 ret.setAlpha(200);*/
120 QColor ret = WorkflowSettings::getBGColor();
121 return ret;
122 }
123
boundingRect(void) const124 QRectF SimpleProcStyle::boundingRect(void) const {
125 // extra space added for clean antialiased painting
126 return QRectF(-R - 2, -R - 2, R * 2 + 4, R * 2 + 4);
127 }
128
shape() const129 QPainterPath SimpleProcStyle::shape() const {
130 QPainterPath contour;
131 contour.addEllipse(QPointF(0, 0), R, R);
132 return contour;
133 }
134
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)135 void SimpleProcStyle::paint(QPainter *painter,
136 const QStyleOptionGraphicsItem *option,
137 QWidget *widget) {
138 Q_UNUSED(option);
139 Q_UNUSED(widget);
140 // painter->fillRect(boundingRect(), QBrush(Qt::magenta, Qt::Dense6Pattern));
141 painter->setRenderHint(QPainter::Antialiasing);
142 QPainterPath contour;
143 contour.addEllipse(QPointF(0, 0), R, R);
144
145 QPen pen;
146 if (owner->isBreakpointInserted()) {
147 const QColor borderColor = (owner->isBreakpointEnabled()) ? ITEM_WITH_ENABLED_BREAKPOINT_BORDER_COLOR : ITEM_WITH_DISABLED_BREAKPOINT_BORDER_COLOR;
148 pen.setColor(borderColor);
149 }
150 if (owner->isSelected()) {
151 pen.setWidthF(2);
152 pen.setStyle(Qt::DashLine);
153 }
154 painter->setPen(pen);
155
156 QRadialGradient rg(R / 2, -R / 2, R * 2);
157 rg.setColorAt(1, bgColor);
158 rg.setColorAt(0, QColor(Qt::white));
159 QBrush procBrush(rg);
160 painter->drawPath(contour);
161 painter->fillPath(contour, procBrush);
162
163 painter->save();
164 QTextDocument d;
165 d.setDefaultFont(defFont);
166 d.setHtml("<center>" + owner->getProcess()->getLabel().toHtmlEscaped() + "</center>");
167 d.setTextWidth(R * 2);
168 // d.setDefaultTextOption(QTextOption(Qt::AlignHCenter));
169 painter->translate(-d.size().width() / 2, -d.size().height() / 2);
170 // painter->translate(-R, -R);
171 d.drawContents(painter, QRectF(0, 0, 2 * R, 2 * R));
172 painter->restore();
173 }
174
175 // QPainterPath shape () const;
176
177 #define MARGIN 5
178
ExtendedProcStyle(WorkflowProcessItem * pit)179 ExtendedProcStyle::ExtendedProcStyle(WorkflowProcessItem *pit)
180 : ItemViewStyle(pit, ItemStyles::EXTENDED),
181 autoResize(true), resizing(NoResize) {
182 owner = (pit);
183 Actor *process = pit->getProcess();
184
185 doc = process->getDescription();
186 if (doc) {
187 owner->connect(doc, SIGNAL(contentsChanged()), SLOT(sl_update()));
188 } else {
189 doc = new QTextDocument(pit);
190 doc->setHtml(QString("<center><b>%1</b></center><hr>%2<br>aLSKDJALSK LASDJ LASKD LASJD ALSKDJ XCKLJSLC Jas dlkjsdf sdlkjsdlfj sdlkfjlsdkfjs dlkfjsdlkfjsld flsdkjflsd kfjlsdkfj lsdkfjlsd flskfjsldkfjsldf jsdlkfjsdlkfjsdlfkjsdlfj")
191 .arg(process->getLabel())
192 .arg(process->getProto()->getDocumentation()));
193 }
194 owner->connect(fontAction, SIGNAL(triggered()), SLOT(sl_update()));
195 desc = new DescriptionItem(this);
196 refresh();
197
198 resizeModeAction = new QAction(tr("Auto-resize to text"), this);
199 resizeModeAction->setCheckable(true);
200 resizeModeAction->setChecked(autoResize);
201 connect(resizeModeAction, SIGNAL(toggled(bool)), SLOT(setAutoResizeEnabled(bool)));
202
203 bgColor = defaultColor();
204 }
205
defaultColor() const206 QColor ExtendedProcStyle::defaultColor() const {
207 return WorkflowSettings::getBGColor();
208 }
209
210 #define MINW 2 * R
211 #define MAXW 6 * R
212
refresh()213 void ExtendedProcStyle::refresh() {
214 doc->setDefaultFont(defFont);
215 if (autoResize) {
216 bool snap2grid = WorkflowSettings::snap2Grid();
217 qreal w, h;
218 int cycle = 0;
219 do {
220 QSizeF docFrame = doc->size();
221 w = docFrame.width() + MARGIN * 2;
222 if (snap2grid) {
223 w = roundUp(w, GRID_STEP);
224 doc->setTextWidth(w - MARGIN * 2);
225 docFrame = doc->size();
226 }
227 h = qMax(2 * R, docFrame.height()) + MARGIN * 2;
228 if (snap2grid) {
229 h = roundUp(h, GRID_STEP);
230 }
231 // printf("ideal=%f, actual=%f\n",doc->idealWidth(),w);
232
233 // try to improve docFrame proportions
234 if (++cycle > 2) {
235 break;
236 }
237 if ((h / w < 0.6 && w > (MINW + MAXW) / 2) // doc is disproportionately wide
238 || (h / w > 1.6 && w < MAXW) // doc is disproportionately long and can be widen
239 || (w < MINW || w > MAXW)) { // width is out of bounds
240 doc->setTextWidth(qBound(MINW, (qreal)(h / 1.6), MAXW - MARGIN * 2));
241 }
242 } while (true);
243
244 bounds = QRectF(-R, -R, w, h);
245 } else {
246 // bounds.setSize(bounds.size().expandedTo(doc->size() + QSizeF(MARGIN*2,MARGIN*2)));
247 }
248 desc->setDocument(doc);
249 }
250
shape() const251 QPainterPath ExtendedProcStyle::shape() const {
252 QPainterPath contour;
253 contour.addRoundedRect(bounds, MARGIN, MARGIN);
254 return contour;
255 }
256
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget *)257 void ExtendedProcStyle::paint(QPainter *painter,
258 const QStyleOptionGraphicsItem *option,
259 QWidget *) {
260 if (owner->isSelected()) {
261 ((QStyleOptionGraphicsItem *)option)->state |= QStyle::State_Selected;
262 }
263 bgColor.setAlpha(64);
264 QRectF tb = boundingRect();
265 painter->fillRect(tb, QBrush(bgColor));
266
267 painter->setRenderHint(QPainter::Antialiasing);
268
269 if (doc->pageCount() > 1) {
270 QPointF tp = bounds.bottomRight();
271
272 // draw a page corner
273 // QPen pen;
274 // pen.setWidthF(1.2);
275 // painter->setPen(pen);
276 // qreal len = 6;
277 // painter->drawLine(tp.x() - len, tp.y() - len, tp.x(), tp.y() - len);
278 // painter->drawLine(tp.x() - len, tp.y() - len, tp.x() - len, tp.y());
279
280 // draw 3 dots at corner
281 QPointF dt(tp.x() - 7, tp.y() - 5);
282 QPainterPath dot;
283 dot.addEllipse(dt, 1.2, 1.2);
284 dot.addEllipse(dt - QPointF(4, 0), 1.2, 1.2);
285 dot.addEllipse(dt - QPointF(8, 0), 1.2, 1.2);
286 painter->fillPath(dot, QBrush(QColor(0x33, 0x33, 0x33)));
287 }
288
289 QPen pen;
290 pen.setWidthF(1.3);
291 if (owner->isSelected()) {
292 pen.setStyle(Qt::DashLine);
293 }
294 if (owner->isBreakpointInserted()) {
295 const QColor borderColor = (owner->isBreakpointEnabled()) ? ITEM_WITH_ENABLED_BREAKPOINT_BORDER_COLOR : ITEM_WITH_DISABLED_BREAKPOINT_BORDER_COLOR;
296 pen.setColor(borderColor);
297 }
298
299 painter->setPen(pen);
300 painter->drawRoundedRect(tb, MARGIN, MARGIN);
301 }
302
303 #define RESIZE_AREA 4
sceneEventFilter(QGraphicsItem * watched,QEvent * event)304 bool ExtendedProcStyle::sceneEventFilter(QGraphicsItem *watched, QEvent *event) {
305 assert(watched == owner);
306 Q_UNUSED(watched);
307
308 bool ret = false;
309
310 switch (event->type()) {
311 case QEvent::GraphicsSceneHoverEnter:
312 case QEvent::GraphicsSceneHoverMove: {
313 QGraphicsSceneHoverEvent *he = dynamic_cast<QGraphicsSceneHoverEvent *>(event);
314 ret = updateCursor(he->pos());
315 } break;
316 case QEvent::GraphicsSceneMouseRelease:
317 case QEvent::GraphicsSceneHoverLeave:
318 if (event->type() == QEvent::GraphicsSceneMouseRelease) {
319 desc->mouseReleaseEvent(dynamic_cast<QGraphicsSceneMouseEvent *>(event));
320 }
321 if (resizing) {
322 owner->unsetCursor();
323 }
324 resizing = NoResize;
325 break;
326 case QEvent::GraphicsSceneMouseMove:
327 if (resizing && event->spontaneous()) {
328 QGraphicsSceneMouseEvent *me = (dynamic_cast<QGraphicsSceneMouseEvent *>(event));
329 WorkflowSettings::setSnap2Grid(false);
330 QPointF newPos;
331 if ((me->buttons() & Qt::LeftButton)) {
332 ret = true;
333 QRectF b2 = bounds;
334 QPointF p = me->pos();
335 QPointF p2 = p - me->lastPos();
336
337 if (resizing & RightResize && // border is either "pulled" or "pushed" by mouse pointer
338 // in the latter case pointer should be close to the border
339 ((p2.x() < 0 && b2.right() > p.x()) || (p2.x() > 0 && b2.right() < p.x()) || (qAbs(b2.right() - p.x()) < RESIZE_AREA))) {
340 qreal rb = b2.right() + p2.x();
341 b2.setRight(rb);
342
343 owner->updatePorts();
344
345 if (b2.width() < MARGIN * 2 + R) {
346 return true;
347 }
348 }
349
350 if (resizing & LeftResize && ((p2.x() < 0 && b2.left() > p.x()) || (p2.x() > 0 && b2.left() < p.x()) || (qAbs(b2.left() - p.x()) < RESIZE_AREA))) {
351 b2.setWidth(b2.width() - p2.x());
352 newPos = owner->scenePos();
353 newPos.setX(newPos.x() - (b2.width() - bounds.width()));
354
355 if (b2.width() < MARGIN * 2 + R) {
356 return true;
357 }
358
359 setFixedBounds(b2);
360 owner->setPos(newPos);
361 }
362
363 if (resizing & TopResize &&
364 ((p2.y() < 0 && b2.top() > p.y()) || (p2.y() > 0 && b2.top() < p.y()) || (qAbs(b2.top() - p.y()) < RESIZE_AREA))) {
365 b2.setHeight(b2.height() - p2.y());
366
367 newPos = owner->scenePos();
368 newPos.setY(newPos.y() - (b2.height() - bounds.height()));
369
370 qreal minHeight = R + MARGIN * 2;
371
372 WorkflowScene *sc = qobject_cast<WorkflowScene *>(owner->scene());
373 if (b2.height() < minHeight || newPos.y() < sc->sceneRect().top()) {
374 return true;
375 }
376
377 setFixedBounds(b2);
378 owner->setPos(newPos);
379 }
380
381 if (resizing & BottomResize && ((p2.y() < 0 && b2.bottom() > p.y()) || (p2.y() > 0 && b2.bottom() < p.y()) || (qAbs(b2.bottom() - p.y()) < RESIZE_AREA))) {
382 b2.setBottom(b2.bottom() + p2.y());
383 owner->updatePorts();
384 }
385 // qreal minHeight = qMax(doc->size().height(), R) + MARGIN*2;
386 qreal minHeight = R + MARGIN * 2;
387 if (b2.height() < minHeight) {
388 b2.setHeight(minHeight);
389 }
390
391 setFixedBounds(b2);
392
393 WorkflowScene *sc = qobject_cast<WorkflowScene *>(owner->scene());
394 if (sc != nullptr) {
395 sc->setModified(true);
396 }
397 }
398 }
399 break;
400 /*case QEvent::GraphicsSceneMousePress:
401 mousePressEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
402 break;
403 case QEvent::GraphicsSceneMouseDoubleClick:
404 mouseDoubleClickEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
405 break;
406 case QEvent::GraphicsSceneWheel:
407 wheelEvent(static_cast<QGraphicsSceneWheelEvent *>(event));
408 break;
409 case QEvent::KeyPress:
410 keyPressEvent(static_cast<QKeyEvent *>(event));
411 break;
412 case QEvent::KeyRelease:
413 keyReleaseEvent(static_cast<QKeyEvent *>(event));
414 break;
415 case QEvent::InputMethod:
416 inputMethodEvent(static_cast<QInputMethodEvent *>(event));
417 break;*/
418 default:
419 return false;
420 }
421
422 return ret;
423 }
424
updateCursor(const QPointF & p)425 bool ExtendedProcStyle::updateCursor(const QPointF &p) {
426 resizing = NoResize;
427 qreal dx = qAbs(bounds.right() - p.x());
428 qreal dy = qAbs(bounds.bottom() - p.y());
429 if (dx < RESIZE_AREA) {
430 resizing |= RightResize;
431 }
432 if (dx > (bounds.width() - RESIZE_AREA)) {
433 resizing |= LeftResize;
434 }
435 if (dy < RESIZE_AREA) {
436 resizing |= BottomResize;
437 }
438 if (dy > (bounds.height() - RESIZE_AREA)) {
439 resizing |= TopResize;
440 }
441
442 switch (resizing) {
443 case NoResize:
444 owner->unsetCursor();
445 break;
446 case RightResize:
447 case LeftResize:
448 owner->setCursor(Qt::SizeHorCursor);
449 break;
450 case BottomResize:
451 case TopResize:
452 owner->setCursor(Qt::SizeVerCursor);
453 break;
454 case RBResize:
455 case LTResize:
456 owner->setCursor(Qt::SizeFDiagCursor);
457 break;
458 case LBResize:
459 case RTResize:
460 owner->setCursor(Qt::SizeBDiagCursor);
461 break;
462 }
463 return resizing != NoResize;
464 }
465
setFixedBounds(const QRectF & b)466 void ExtendedProcStyle::setFixedBounds(const QRectF &b) {
467 doc->setPageSize(b.size() - QSizeF(MARGIN * 2, MARGIN * 2));
468 if (bounds != b) {
469 bounds = b;
470 owner->prepareUpdate();
471
472 foreach (WorkflowPortItem *pit, owner->getPortItems()) {
473 pit->adaptOwnerShape();
474 }
475 }
476 owner->update();
477 resizeModeAction->setChecked(false);
478 }
479
setAutoResizeEnabled(bool b)480 void ExtendedProcStyle::setAutoResizeEnabled(bool b) {
481 autoResize = b;
482 if (autoResize) {
483 doc->setPageSize(QSizeF(-1, -1));
484 owner->sl_update();
485 }
486 }
487
getContextMenuActions() const488 QList<QAction *> ExtendedProcStyle::getContextMenuActions() const {
489 QList<QAction *> ret;
490 ret << resizeModeAction << bgColorAction << fontAction;
491 return ret;
492 }
493
494 //#define ARM QString("arm")
495 #define BOUNDS QString("bounds")
496
saveState(QDomElement & el) const497 void ExtendedProcStyle::saveState(QDomElement &el) const {
498 // el.setAttribute(ARM, autoResize);
499 if (!autoResize) {
500 el.setAttribute(BOUNDS, QVariantUtils::var2String(bounds));
501 }
502 ItemViewStyle::saveState(el);
503 }
504
loadState(QDomElement & el)505 void ExtendedProcStyle::loadState(QDomElement &el) {
506 if (el.hasAttribute(BOUNDS)) {
507 QRectF b = QVariantUtils::String2Var(el.attribute(BOUNDS)).toRectF();
508 if (!b.isNull()) {
509 setFixedBounds(b);
510 }
511 }
512 ItemViewStyle::loadState(el);
513 }
514
linkHovered(const QString & url)515 void ExtendedProcStyle::linkHovered(const QString &url) {
516 if (url.isEmpty()) {
517 owner->unsetCursor();
518 } else {
519 owner->setCursor(Qt::PointingHandCursor);
520 }
521 }
522
HintItem(const QString & text,QGraphicsItem * parent)523 HintItem::HintItem(const QString &text, QGraphicsItem *parent)
524 : QGraphicsTextItem(text, parent), dragging(false) {
525 setFlag(QGraphicsItem::ItemIsSelectable);
526 #if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0))
527 setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
528 #endif
529 document()->setDefaultTextOption(QTextOption(Qt::AlignCenter));
530 setTextWidth(qMin(3 * R, document()->idealWidth()));
531 QRectF tb = boundingRect();
532 setPos(-tb.width() / 2, -tb.height() - 3);
533 setDefaultTextColor(QColor(Qt::gray).darker());
534 QFont f = font();
535 f.setWeight(QFont::Light);
536 setFont(f);
537 }
538
itemChange(GraphicsItemChange change,const QVariant & value)539 QVariant HintItem::itemChange(GraphicsItemChange change, const QVariant &value) {
540 if (change == ItemSelectedChange && value.toBool()) {
541 parentItem()->setSelected(true);
542 return false;
543 }
544 if (change == ItemPositionChange) {
545 QPointF newPos = value.toPointF();
546 if (scene()) {
547 QRectF bound = boundingRect();
548 QRectF sceneRect = scene()->sceneRect();
549 // scene topLeft in parent coords
550 QPointF tl = mapToParent(mapFromScene(sceneRect.topLeft()));
551 sceneRect.moveTopLeft(tl);
552
553 qreal x0 = sceneRect.left() - bound.left();
554 qreal x1 = sceneRect.left() + sceneRect.width() - bound.right();
555 qreal y0 = sceneRect.top() - bound.top();
556 qreal y1 = sceneRect.top() + sceneRect.height() - bound.bottom();
557
558 newPos.setX(qBound(x0, newPos.x(), x1));
559 newPos.setY(qBound(y0, newPos.y(), y1));
560 }
561 return newPos;
562 }
563 if (change == ItemPositionHasChanged) {
564 parentItem()->update();
565 if (scene()) {
566 foreach (QGraphicsView *v, scene()->views()) {
567 v->ensureVisible(this, 0, 0);
568 }
569 }
570 }
571 return QGraphicsItem::itemChange(change, value);
572 }
573
mouseMoveEvent(QGraphicsSceneMouseEvent * event)574 void HintItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
575 if (event->buttons() & Qt::LeftButton) {
576 if (!dragging) {
577 initPos = pos();
578 dragging = true;
579 }
580
581 QPointF delta = event->screenPos() - event->buttonDownScreenPos(Qt::LeftButton);
582 setPos(initPos + delta);
583 } else {
584 event->ignore();
585 }
586 }
587
mouseReleaseEvent(QGraphicsSceneMouseEvent * event)588 void HintItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
589 dragging = false;
590 QGraphicsTextItem::mouseReleaseEvent(event);
591 }
592
DescriptionItem(ExtendedProcStyle * p)593 DescriptionItem::DescriptionItem(ExtendedProcStyle *p)
594 : QGraphicsTextItem(p) {
595 setPos(-R + MARGIN, -R + MARGIN);
596 setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard);
597 p->connect(this, SIGNAL(linkActivated(const QString &)), SIGNAL(linkActivated(const QString &)));
598 p->connect(this, SIGNAL(linkHovered(const QString &)), SLOT(linkHovered(const QString &)));
599 }
600
boundingRect() const601 QRectF DescriptionItem::boundingRect() const {
602 QRectF bounds = parentItem()->boundingRect();
603 bounds.setBottomRight(bounds.bottomRight() - QPointF(MARGIN, MARGIN));
604 bounds.translate(R - MARGIN, R - MARGIN);
605 return bounds;
606 }
607
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)608 void DescriptionItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
609 QStyleOptionGraphicsItem deselectedOption = *option;
610 deselectedOption.state &= ~(QStyle::State_Selected | QStyle::State_HasFocus);
611 QGraphicsTextItem::paint(painter, &deselectedOption, widget);
612 }
613
mouseReleaseEvent(QGraphicsSceneMouseEvent * event)614 void DescriptionItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
615 event->setPos(mapFromParent(event->pos()));
616 QGraphicsTextItem::mouseReleaseEvent(event);
617 }
618
sceneEvent(QEvent * event)619 bool DescriptionItem::sceneEvent(QEvent *event) {
620 switch (event->type()) {
621 case QEvent::GraphicsSceneHoverMove:
622 case QEvent::GraphicsSceneHoverEnter: {
623 ExtendedProcStyle *owner = qgraphicsitem_cast<ExtendedProcStyle *>(parentItem());
624 if (owner->resizing) {
625 QGraphicsSceneHoverEvent *he = static_cast<QGraphicsSceneHoverEvent *>(event);
626 const QPointF &p = mapToParent(he->pos());
627 owner->updateCursor(p);
628 }
629 } break;
630 default:
631 break;
632 }
633 return QGraphicsTextItem::sceneEvent(event);
634 }
635
contextMenuEvent(QGraphicsSceneContextMenuEvent * event)636 void DescriptionItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
637 QAbstractTextDocumentLayout *layout = document()->documentLayout();
638 const QString &href = layout->anchorAt(event->pos());
639
640 if (href.isEmpty()) {
641 event->ignore();
642 return;
643 }
644
645 ItemViewStyle *style = qgraphicsitem_cast<ItemViewStyle *>(parentItem());
646 WorkflowProcessItem const *procItem = style->getOwner();
647 Actor *actor = procItem->getProcess();
648 WorkflowScene *ws = procItem->getWorkflowScene();
649 ws->setupLinkCtxMenu(href, actor, event->screenPos());
650 }
651
652 } // namespace U2
653