1 /*
2 SPDX-License-Identifier: GPL-2.0-or-later
3 SPDX-FileCopyrightText: 2002-2020 Umbrello UML Modeller Authors <umbrello-devel@kde.org>
4 */
5
6 // own header
7 #include "floatingtextwidget.h"
8
9 // local includes
10 #include "association.h"
11 #include "associationwidget.h"
12 #include "associationpropertiesdialog.h"
13 #include "classifier.h"
14 #include "cmds.h"
15 #include "debug_utils.h"
16 #include "dialog_utils.h"
17 #include "linkwidget.h"
18 #include "classifierwidget.h"
19 #include "listpopupmenu.h"
20 #include "messagewidget.h"
21 #include "model_utils.h"
22 #include "object_factory.h"
23 #include "operation.h"
24 #include "selectoperationdialog.h"
25 #include "uml.h"
26 #include "umldoc.h"
27 #include "umlview.h"
28
29 // kde includes
30 #if QT_VERSION < 0x050000
31 #include <kfontdialog.h>
32 #endif
33 #include <KLocalizedString>
34
35 // qt includes
36 #if QT_VERSION >= 0x050000
37 #include <QFontDialog>
38 #endif
39 #include <QPointer>
40 #include <QRegExp>
41 #include <QPainter>
42 #include <QValidator>
43 #include <QXmlStreamWriter>
44
DEBUG_REGISTER_DISABLED(FloatingTextWidget)45 DEBUG_REGISTER_DISABLED(FloatingTextWidget)
46
47 /**
48 * Constructs a FloatingTextWidget instance.
49 *
50 * @param scene The parent of this FloatingTextWidget.
51 * @param role The role this FloatingTextWidget will take up.
52 * @param text The main text to display.
53 * @param id The ID to assign (-1 will prompt a new ID.)
54 */
55 FloatingTextWidget::FloatingTextWidget(UMLScene * scene, Uml::TextRole::Enum role, const QString& text, Uml::ID::Type id)
56 : UMLWidget(scene, WidgetBase::wt_Text, id),
57 m_linkWidget(0),
58 m_preText(QString()),
59 m_postText(QString()),
60 m_textRole(role),
61 m_unconstrainedPositionX(0),
62 m_unconstrainedPositionY(0),
63 m_movementDirectionX(0),
64 m_movementDirectionY(0)
65 {
66 m_Text = text;
67 m_resizable = false;
68 setZValue(10); //make sure always on top.
69 }
70
71 /**
72 * Destructor.
73 */
~FloatingTextWidget()74 FloatingTextWidget::~FloatingTextWidget()
75 {
76 }
77
78 /**
79 * Use to get the _main body_ of text (e.g. prepended and appended
80 * text is omitted) as currently displayed by the widget.
81 *
82 * @return The main text currently being displayed by the widget.
83 */
text() const84 QString FloatingTextWidget::text() const
85 {
86 // test to make sure not just the ":" between the seq number and
87 // the actual message widget
88
89 // hmm. this section looks like it could have been avoided by
90 // using pre-, post- text instead of storing in the main body of
91 // the text -b.t.
92 if (m_textRole == Uml::TextRole::Seq_Message || m_textRole == Uml::TextRole::Seq_Message_Self ||
93 m_textRole == Uml::TextRole::Coll_Message || m_textRole == Uml::TextRole::Coll_Message_Self) {
94 if (m_Text.length() <= 1 || m_Text == QLatin1String(": "))
95 return QString();
96 }
97 return m_Text;
98 }
99
100 /**
101 * Set the main body of text to display.
102 *
103 * @param t The text to display.
104 */
setText(const QString & t)105 void FloatingTextWidget::setText(const QString &t)
106 {
107 if (m_textRole == Uml::TextRole::Seq_Message || m_textRole == Uml::TextRole::Seq_Message_Self) {
108 QString op;
109 if (m_linkWidget)
110 op = m_linkWidget->lwOperationText();
111 if (op.length() > 0) {
112 if (!m_scene->showOpSig())
113 op.replace(QRegExp(QLatin1String("\\(.*\\)")), QLatin1String("()"));
114 m_Text = op;
115 }
116 else
117 m_Text = t;
118 }
119 else {
120 m_Text = t;
121 }
122
123 QSizeF s = minimumSize();
124 setSize(s.width(), s.height());
125
126 updateGeometry();
127 update();
128 }
129
130 /**
131 * Set some text to be prepended to the main body of text.
132 * @param t The text to prepend to main body which is displayed.
133 */
setPreText(const QString & t)134 void FloatingTextWidget::setPreText(const QString &t)
135 {
136 m_preText = t;
137 updateGeometry();
138 update();
139 }
140
141 /**
142 * Set some text to be appended to the main body of text.
143 * @param t The text to append to main body which is displayed.
144 */
setPostText(const QString & t)145 void FloatingTextWidget::setPostText(const QString &t)
146 {
147 m_postText = t;
148 updateGeometry();
149 update();
150 }
151
152 /**
153 * Use to get the total text (prepended + main body + appended)
154 * currently displayed by the widget.
155 *
156 * @return The text currently being displayed by the widget.
157 */
displayText() const158 QString FloatingTextWidget::displayText() const
159 {
160 QString displayText;
161 if (!m_SequenceNumber.isEmpty())
162 displayText = m_SequenceNumber + QLatin1String(": ") + m_Text;
163 else
164 displayText = m_Text;
165 displayText.prepend(m_preText);
166 displayText.append(m_postText);
167 return displayText;
168 }
169
170 /**
171 * Return state if no pre, post and main text is empty
172 * @return true if widget contains no text
173 */
isEmpty()174 bool FloatingTextWidget::isEmpty()
175 {
176 return m_Text.isEmpty() && m_preText.isEmpty() && m_postText.isEmpty();
177 }
178
179 /**
180 * Overrides method from UMLWidget.
181 */
minimumSize() const182 QSizeF FloatingTextWidget::minimumSize() const
183 {
184 const QFontMetrics &fm = getFontMetrics(FT_NORMAL);
185 int h = fm.lineSpacing();
186 int w = fm.width(displayText());
187 return QSizeF(w + 8, h + 4); // give a small margin
188 }
189
190 /**
191 * Method used by setText: its called by cmdsetTxt, Don't use it!
192 *
193 * @param t The text to display.
194 */
setTextcmd(const QString & t)195 void FloatingTextWidget::setTextcmd(const QString &t)
196 {
197 UMLApp::app()->executeCommand(new Uml::CmdSetTxt(this, t));
198 }
199
200 /**
201 * Displays a dialog box to change the text.
202 */
showChangeTextDialog()203 void FloatingTextWidget::showChangeTextDialog()
204 {
205 QString newText = text();
206 bool ok = Dialog_Utils::askName(i18n("Change Text"),
207 i18n("Enter new text:"),
208 newText);
209 if (ok && newText != text() && isTextValid(newText)) {
210 setText(newText);
211 setVisible(!text().isEmpty());
212 updateGeometry();
213 update();
214 }
215 if (!isTextValid(newText))
216 hide();
217 }
218
219 /**
220 * Shows an operation dialog box.
221 *
222 * @param enableAutoIncrement Enable auto increment checkbox
223 */
showOperationDialog(bool enableAutoIncrement)224 bool FloatingTextWidget::showOperationDialog(bool enableAutoIncrement)
225 {
226 if (!m_linkWidget) {
227 uError() << "m_linkWidget is NULL";
228 return false;
229 }
230 if (!m_linkWidget->lwClassifier()) {
231 uError() << "m_linkWidget->lwClassifier() returns a NULL classifier";
232 return false;
233 }
234 bool result = false;
235
236 QPointer<SelectOperationDialog> selectDialog = new SelectOperationDialog(m_scene->activeView(), m_linkWidget->lwClassifier(), m_linkWidget, enableAutoIncrement);
237 if (selectDialog->exec()) {
238 selectDialog->apply();
239 setMessageText();
240 result = true;
241 }
242 delete selectDialog;
243 return result;
244 }
245
246 /**
247 * Show the properties for a FloatingTextWidget.
248 * Depending on the role of the floating text widget, the options dialog
249 * for the floating text widget, the rename dialog for floating text or
250 * the options dialog for the link widget are shown.
251 */
showPropertiesDialog()252 bool FloatingTextWidget::showPropertiesDialog()
253 {
254 UMLWidget *p = dynamic_cast<UMLWidget*>(parentItem());
255 if (p && p->isInterfaceWidget()) {
256 if (p->showPropertiesDialog())
257 setText(p->name());
258 } else if (m_textRole == Uml::TextRole::Coll_Message || m_textRole == Uml::TextRole::Coll_Message_Self ||
259 m_textRole == Uml::TextRole::Seq_Message || m_textRole == Uml::TextRole::Seq_Message_Self) {
260 return showOperationDialog(false);
261 } else if (m_textRole == Uml::TextRole::Floating) {
262 // double clicking on a text line opens the dialog to change the text
263 return handleRename();
264 } else if (m_linkWidget) {
265 return m_linkWidget->showPropertiesDialog();
266 }
267 return false;
268 }
269
270 /**
271 * Use to get the pre-text which is prepended to the main body of
272 * text to be displayed.
273 *
274 * @return The pre-text currently displayed by the widget.
275 */
preText() const276 QString FloatingTextWidget::preText() const
277 {
278 return m_preText;
279 }
280
281 /**
282 * Use to get the post-text which is appended to the main body of
283 * text to be displayed.
284 *
285 * @return The post-text currently displayed by the widget.
286 */
postText() const287 QString FloatingTextWidget::postText() const
288 {
289 return m_postText;
290 }
291
292 /**
293 * Activate the FloatingTextWidget after the saved data has been loaded
294 *
295 * @param ChangeLog Pointer to the IDChangeLog.
296 * @return true for success
297 */
activate(IDChangeLog * ChangeLog)298 bool FloatingTextWidget::activate(IDChangeLog* ChangeLog /*= 0 */)
299 {
300 if (! UMLWidget::activate(ChangeLog))
301 return false;
302 update();
303 return true;
304 }
305
306 /**
307 * Set the LinkWidget that this FloatingTextWidget is related to.
308 *
309 * @param l The related LinkWidget.
310 */
setLink(LinkWidget * l)311 void FloatingTextWidget::setLink(LinkWidget * l)
312 {
313 m_linkWidget = l;
314 }
315
316 /**
317 * Returns the LinkWidget this floating text is related to.
318 *
319 * @return The LinkWidget this floating text is related to.
320 */
link() const321 LinkWidget * FloatingTextWidget::link() const
322 {
323 return m_linkWidget;
324 }
325
326 /**
327 * Sets the role type of this FloatingTextWidget.
328 *
329 * @param role The TextRole::Enum of this FloatingTextWidget.
330 */
setTextRole(Uml::TextRole::Enum role)331 void FloatingTextWidget::setTextRole(Uml::TextRole::Enum role)
332 {
333 m_textRole = role;
334 }
335
336 /**
337 * Return the role of the text widget
338 * @return The TextRole::Enum of this FloatingTextWidget.
339 */
textRole() const340 Uml::TextRole::Enum FloatingTextWidget::textRole() const
341 {
342 return m_textRole;
343 }
344
345 /**
346 * Handle the ListPopupMenu::mt_Rename case of the slotMenuSelection.
347 * Given an own method because it requires rather lengthy code.
348 */
handleRename()349 bool FloatingTextWidget::handleRename()
350 {
351 QString t;
352 if (m_textRole == Uml::TextRole::RoleAName || m_textRole == Uml::TextRole::RoleBName) {
353 t = i18n("Enter role name:");
354 } else if (m_textRole == Uml::TextRole::MultiA || m_textRole == Uml::TextRole::MultiB) {
355 t = i18n("Enter multiplicity:");
356 /*
357 // NO! shouldn't be allowed
358 } else if (m_textRole == Uml::TextRole::ChangeA || m_textRole == Uml::TextRole::ChangeB) {
359 t = i18n("Enter changeability");
360 */
361 } else if (m_textRole == Uml::TextRole::Name) {
362 t = i18n("Enter association name:");
363 } else if (m_textRole == Uml::TextRole::Floating) {
364 t = i18n("Enter new text:");
365 } else {
366 t = i18n("ERROR");
367 }
368 QString newText = text();
369 bool ok = Dialog_Utils::askName(i18n("Rename"), t, newText);
370 if (!ok || newText == text()) {
371 return false;
372 }
373
374 UMLApp::app()->executeCommand(new Uml::CmdHandleRename(this, newText));
375 return true;
376 }
377
378 /**
379 * Changes the text of linked widget.
380 * @param newText the new text
381 */
changeName(const QString & newText)382 void FloatingTextWidget::changeName(const QString& newText)
383 {
384 if (m_linkWidget && !isTextValid(newText)) {
385 AssociationWidget *assoc = dynamic_cast<AssociationWidget*>(m_linkWidget);
386 if (assoc) {
387 switch (m_textRole) {
388 case Uml::TextRole::MultiA:
389 assoc->setMultiplicity(QString(), Uml::RoleType::A);
390 break;
391 case Uml::TextRole::MultiB:
392 assoc->setMultiplicity(QString(), Uml::RoleType::B);
393 break;
394 case Uml::TextRole::RoleAName:
395 assoc->setRoleName(QString(), Uml::RoleType::A);
396 break;
397 case Uml::TextRole::RoleBName:
398 assoc->setRoleName(QString(), Uml::RoleType::B);
399 break;
400 case Uml::TextRole::ChangeA:
401 assoc->setChangeability(Uml::Changeability::Changeable, Uml::RoleType::A);
402 break;
403 case Uml::TextRole::ChangeB:
404 assoc->setChangeability(Uml::Changeability::Changeable, Uml::RoleType::B);
405 break;
406 default:
407 assoc->setName(QString());
408 break;
409 }
410 }
411 else {
412 MessageWidget *msg = dynamic_cast<MessageWidget*>(m_linkWidget);
413 if (msg) {
414 msg->setName(QString());
415 m_scene->removeWidget(this);
416 }
417 }
418 return;
419 }
420
421 if (m_linkWidget && m_textRole != Uml::TextRole::Seq_Message
422 && m_textRole != Uml::TextRole::Seq_Message_Self) {
423 m_linkWidget->setText(this, newText);
424 }
425 else {
426 setText(newText);
427 UMLApp::app()->document()->setModified(true);
428 }
429
430 setVisible(true);
431 updateGeometry();
432 update();
433 }
434
435 /**
436 * Write property of QString m_SequenceNumber.
437 */
setSequenceNumber(const QString & sequenceNumber)438 void FloatingTextWidget::setSequenceNumber(const QString &sequenceNumber)
439 {
440 m_SequenceNumber = sequenceNumber;
441 }
442
443 /**
444 * Read property of QString m_SequenceNumber.
445 */
sequenceNumber() const446 QString FloatingTextWidget::sequenceNumber() const
447 {
448 return m_SequenceNumber;
449 }
450
451 /**
452 * For a text to be valid it must be non-empty, i.e. have a length
453 * larger than zero, and have at least one non whitespace character.
454 *
455 * @param text The string to analyze.
456 * @return True if the given text is valid.
457 */
isTextValid(const QString & text)458 bool FloatingTextWidget::isTextValid(const QString &text)
459 {
460 int length = text.length();
461 if(length < 1)
462 return false;
463 for(int i=0;i<length;i++) {
464 if(!text.at(i).isSpace()) {
465 return true;
466 }
467 }
468 return false;
469 }
470
471 /**
472 * Returns a constrained position for the widget after applying the position
473 * difference.
474 * If no link widget exists, the position returned is the current widget
475 * position with the difference applied. If there's a link, the position
476 * to be returned is constrained using constrainTextPos method from the
477 * LinkWidget, if any.
478 *
479 * @param diffX The difference between current X position and new X position.
480 * @param diffY The difference between current Y position and new Y position.
481 * @return A QPointF with the constrained new position.
482 */
constrainPosition(qreal diffX,qreal diffY)483 QPointF FloatingTextWidget::constrainPosition(qreal diffX, qreal diffY)
484 {
485 qreal newX = x() + diffX;
486 qreal newY = y() + diffY;
487
488 if (link()) {
489 link()->constrainTextPos(newX, newY, width(), height(), textRole());
490 }
491
492 return QPointF(newX, newY);
493 }
494
495 /**
496 * Overridden from UMLWidget.
497 * Moves the widget to a new position using the difference between the
498 * current position and the new position.
499 * If the floating text widget is part of a sequence message, and the
500 * message widget is selected, it does nothing: the message widget will
501 * update the text position when it's moved.
502 * In any other case, the floating text widget constrains its move using
503 * constrainPosition. When the position of the floating text is constrained,
504 * it's kept at that position until it can be moved to another valid
505 * position (m_unconstrainedPositionX/Y and m_movementDirectionX/Y are
506 * used for that).
507 * Moreover, if is part of a sequence message (and the message widget
508 * isn't selected), it updates the position of the message widget.
509 * @see constrainPosition
510 *
511 * @param diffX The difference between current X position and new X position.
512 * @param diffY The difference between current Y position and new Y position.
513 */
moveWidgetBy(qreal diffX,qreal diffY)514 void FloatingTextWidget::moveWidgetBy(qreal diffX, qreal diffY)
515 {
516 if (textRole() == Uml::TextRole::Seq_Message_Self)
517 return;
518
519 if (textRole() == Uml::TextRole::Seq_Message
520 && link() && dynamic_cast<MessageWidget*>(link())
521 && dynamic_cast<MessageWidget*>(link())->isSelected()) {
522 return;
523 }
524
525 m_unconstrainedPositionX += diffX;
526 m_unconstrainedPositionY += diffY;
527 QPointF constrainedPosition = constrainPosition(diffX, diffY);
528
529 qreal newX = constrainedPosition.x();
530 qreal newY = constrainedPosition.y();
531
532 if (!m_movementDirectionX) {
533 if (m_unconstrainedPositionX != constrainedPosition.x()) {
534 m_movementDirectionX = (diffX > 0)? 1: -1;
535 }
536 } else if ((m_movementDirectionX < 0 && m_unconstrainedPositionX > x()) ||
537 (m_movementDirectionX > 0 && m_unconstrainedPositionX < x()) ) {
538 newX = m_unconstrainedPositionX;
539 m_movementDirectionX = 0;
540 }
541
542 if (!m_movementDirectionY) {
543 if (m_unconstrainedPositionY != constrainedPosition.y()) {
544 m_movementDirectionY = (diffY > 0)? 1: -1;
545 }
546 } else if ((m_movementDirectionY < 0 && m_unconstrainedPositionY > y()) ||
547 (m_movementDirectionY > 0 && m_unconstrainedPositionY < y()) ) {
548 newY = m_unconstrainedPositionY;
549 m_movementDirectionY = 0;
550 }
551
552 setX(newX);
553 setY(newY);
554
555 if (link()) {
556 link()->calculateNameTextSegment();
557 if (textRole() == Uml::TextRole::Seq_Message) {
558 MessageWidget* messageWidget = (MessageWidget*)link();
559 messageWidget->setY(newY + height());
560 }
561 }
562 }
563
564 /**
565 * Overridden from UMLWidget.
566 * Modifies the value of the diffX and diffY variables used to move the
567 * widgets.
568 * The values are constrained using constrainPosition.
569 * @see constrainPosition
570 *
571 * @param diffX The difference between current X position and new X position.
572 * @param diffY The difference between current Y position and new Y position.
573 */
constrainMovementForAllWidgets(qreal & diffX,qreal & diffY)574 void FloatingTextWidget::constrainMovementForAllWidgets(qreal &diffX, qreal &diffY)
575 {
576 QPointF constrainedPosition = constrainPosition(diffX, diffY);
577
578 diffX = constrainedPosition.x() - x();
579 diffY = constrainedPosition.y() - y();
580 }
581
582 /**
583 * Override method from UMLWidget in order to additionally check widget parentage.
584 *
585 * @param p Point to be checked.
586 *
587 * @return 'this' if UMLWidget::onWidget(p) returns non 0;
588 * else NULL.
589 */
onWidget(const QPointF & p)590 UMLWidget* FloatingTextWidget::onWidget(const QPointF &p)
591 {
592 WidgetBase *pw = dynamic_cast<WidgetBase*>(parentItem());
593 if (pw == 0) {
594 return WidgetBase::onWidget(p);
595 }
596 const WidgetBase::WidgetType t = pw->baseType();
597 bool isWidgetChild = false;
598 if (t == WidgetBase::wt_Interface) {
599 ClassifierWidget *cw = static_cast<ClassifierWidget*>(pw);
600 isWidgetChild = cw->getDrawAsCircle();
601 } else if (t == wt_Association ||
602 t == WidgetBase::wt_Port || t == WidgetBase::wt_Pin) {
603 isWidgetChild = true;
604 }
605 if (!isWidgetChild) {
606 return WidgetBase::onWidget(p);
607 }
608 const qreal w = width();
609 const qreal h = height();
610 const qreal left = pw->x() + x();
611 const qreal right = left + w;
612 const qreal top = pw->y() + y();
613 const qreal bottom = top + h;
614 // uDebug() << "child_of_pw; p=(" << p.x() << "," << p.y() << "), "
615 // << "x=" << left << ", y=" << top << ", w=" << w << ", h=" << h
616 // << "; right=" << right << ", bottom=" << bottom;
617 if (p.x() >= left && p.x() <= right &&
618 p.y() >= top && p.y() <= bottom) { // Qt coord.sys. origin in top left corner
619 // uDebug() << "floatingtext: " << m_Text;
620 return this;
621 }
622 return 0;
623 }
624
625 /**
626 * Overrides default method
627 */
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)628 void FloatingTextWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
629 {
630 Q_UNUSED(option);
631 Q_UNUSED(widget);
632
633 int w = width();
634 int h = height();
635 painter->setFont(UMLWidget::font());
636 painter->setPen(textColor());
637 painter->drawText(0, 0, w, h, Qt::AlignCenter, displayText());
638
639 UMLWidget::paint(painter, option, widget);
640 }
641
642 /**
643 * Loads the "floatingtext" XMI element.
644 */
loadFromXMI1(QDomElement & qElement)645 bool FloatingTextWidget::loadFromXMI1(QDomElement & qElement)
646 {
647 if(!UMLWidget::loadFromXMI1(qElement))
648 return false;
649
650 m_unconstrainedPositionX = x();
651 m_unconstrainedPositionY = y();
652 QString role = qElement.attribute(QLatin1String("role"));
653 if(!role.isEmpty())
654 m_textRole = Uml::TextRole::fromInt(role.toInt());
655
656 m_preText = qElement.attribute(QLatin1String("pretext"));
657 m_postText = qElement.attribute(QLatin1String("posttext"));
658 setText(qElement.attribute(QLatin1String("text"))); // use setText for geometry update
659 // If all texts are empty then this is a useless widget.
660 // In that case we return false.
661 // CAVEAT: The caller should not interpret the false return value
662 // as an indication of failure since previous umbrello versions
663 // saved lots of these empty FloatingTexts.
664 bool usefulWidget = !isEmpty();
665 return usefulWidget;
666 }
667
668 /**
669 * Reimplemented from UMLWidget::saveToXMI1 to save the widget
670 * data into XMI 'floatingtext' element.
671 */
saveToXMI1(QXmlStreamWriter & writer)672 void FloatingTextWidget::saveToXMI1(QXmlStreamWriter& writer)
673 {
674 if (isEmpty())
675 return;
676
677 writer.writeStartElement(QLatin1String("floatingtext"));
678 UMLWidget::saveToXMI1(writer);
679 writer.writeAttribute(QLatin1String("text"), m_Text);
680 writer.writeAttribute(QLatin1String("pretext"), m_preText);
681 writer.writeAttribute(QLatin1String("posttext"), m_postText);
682
683 /* No need to save these - the messagewidget already did it.
684 m_Operation = qElement.attribute("operation");
685 m_SeqNum = qElement.attribute("seqnum");
686 */
687
688 writer.writeAttribute(QLatin1String("role"), QString::number(m_textRole));
689 writer.writeEndElement();
690 }
691
692 /**
693 * Called when a menu selection has been made.
694 *
695 * @param action The action that has been selected.
696 */
slotMenuSelection(QAction * action)697 void FloatingTextWidget::slotMenuSelection(QAction* action)
698 {
699 ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action);
700 switch(sel) {
701 case ListPopupMenu::mt_Properties:
702 showPropertiesDialog();
703 break;
704
705 case ListPopupMenu::mt_Delete:
706 hide(); // This is only a workaround; if set then m_linkWidget should
707 // really delete this FloatingTextWidget.
708 update();
709 m_scene->removeWidget(this);
710 break;
711
712 case ListPopupMenu::mt_New_Operation: // needed by AssociationWidget
713 case ListPopupMenu::mt_Operation:
714 {
715 if (m_linkWidget == 0) {
716 DEBUG(DBG_SRC) << "mt_Operation: m_linkWidget is NULL";
717 return;
718 }
719 UMLClassifier* c = m_linkWidget->operationOwner();
720 if (c == 0) {
721 QString opText = text();
722 bool ok = Dialog_Utils::askName(i18nc("operation name", "Name"),
723 i18n("Enter operation name:"),
724 opText);
725 if (ok)
726 m_linkWidget->setCustomOpText(opText);
727 return;
728 }
729 UMLClassifierListItem* umlObj = Object_Factory::createChildObject(c, UMLObject::ot_Operation);
730 if (umlObj) {
731 UMLOperation* newOperation = umlObj->asUMLOperation();
732 m_linkWidget->setOperation(newOperation);
733 }
734 }
735 break;
736
737 case ListPopupMenu::mt_Select_Operation:
738 showOperationDialog(false);
739 break;
740
741 case ListPopupMenu::mt_Rename:
742 handleRename();
743 break;
744
745 case ListPopupMenu::mt_Change_Font:
746 {
747 #if QT_VERSION >= 0x050000
748 bool ok = false;
749 QFont fnt = QFontDialog::getFont(&ok, font(), m_scene->activeView());
750 if (ok) {
751 #else
752 QFont fnt = font();
753 if(KFontDialog::getFont(fnt, KFontChooser::NoDisplayFlags, m_scene->activeView())) {
754 #endif
755 if(m_textRole == Uml::TextRole::Floating || m_textRole == Uml::TextRole::Seq_Message) {
756 setFont(fnt);
757 } else if (m_linkWidget) {
758 m_linkWidget->lwSetFont(fnt);
759 }
760 }
761 }
762 break;
763
764 case ListPopupMenu::mt_Reset_Label_Positions:
765 if (m_linkWidget)
766 m_linkWidget->resetTextPositions();
767 break;
768
769 default:
770 UMLWidget::slotMenuSelection(action);
771 break;
772 }//end switch
773 }
774
775 /**
776 * Sets the text for this label if it is acting as a sequence diagram
777 * message or a collaboration diagram message.
778 */
779 void FloatingTextWidget::setMessageText()
780 {
781 if (m_linkWidget) {
782 m_linkWidget->setMessageText(this);
783 QSizeF s = minimumSize();
784 setSize(s.width(), s.height());
785
786 }
787 setVisible(!text().isEmpty());
788 }
789
790