1 /*
2 SPDX-License-Identifier: GPL-2.0-or-later
3 SPDX-FileCopyrightText: 2002-2021 Umbrello UML Modeller Authors <umbrello-devel@kde.org>
4 */
5
6 // own header
7 #include "umllistviewitem.h"
8
9 // app includes
10 #include "debug_utils.h"
11 #include "folder.h"
12 #include "classifier.h"
13 #include "entity.h"
14 #include "template.h"
15 #include "attribute.h"
16 #include "operation.h"
17 #include "instanceattribute.h"
18 #include "entityconstraint.h"
19 #include "umldoc.h"
20 #include "umllistview.h"
21 #include "umlobjectlist.h"
22 #include "umlscene.h"
23 #include "umlview.h"
24 #include "model_utils.h"
25 #include "uniqueid.h"
26 #include "uml.h"
27 #include "cmds.h"
28
29 // kde includes
30 #include <KLocalizedString>
31 #include <KMessageBox>
32
33 // qt includes
34 #include <QDrag>
35 #include <QFile>
36 #include <QRegExp>
37 #include <QTextStream>
38 #include <QXmlStreamWriter>
39
40 // system includes
41 #include <cstdlib>
42
43 #define DBG_LVI QLatin1String("UMLListViewItem")
44
DEBUG_REGISTER(UMLListViewItem)45 DEBUG_REGISTER(UMLListViewItem)
46
47 /**
48 * Sets up an instance.
49 *
50 * @param parent The parent to this instance.
51 * @param name The name of this instance.
52 * @param t The type of this instance.
53 * @param o The object it represents.
54 */
55 UMLListViewItem::UMLListViewItem(UMLListView * parent, const QString &name,
56 ListViewType t, UMLObject* o)
57 : QTreeWidgetItem(parent)
58 {
59 init();
60 if (parent == 0) {
61 DEBUG(DBG_LVI) << "UMLListViewItem constructor called with a null listview parent";
62 }
63 m_type = t;
64 m_object = o;
65 if (o) {
66 m_id = o->id();
67 }
68 setIcon(Icon_Utils::it_Home);
69 setText(name);
70 }
71
72 /**
73 * Sets up an instance for subsequent loadFromXMI1().
74 *
75 * @param parent The parent to this instance.
76 */
UMLListViewItem(UMLListView * parent)77 UMLListViewItem::UMLListViewItem(UMLListView * parent)
78 : QTreeWidgetItem(parent)
79 {
80 init();
81 if (parent == 0) {
82 DEBUG(DBG_LVI) << "UMLListViewItem constructor called with a NULL listview parent";
83 }
84 }
85
86 /**
87 * Sets up an instance for subsequent loadFromXMI1().
88 *
89 * @param parent The parent to this instance.
90 */
UMLListViewItem(UMLListViewItem * parent)91 UMLListViewItem::UMLListViewItem(UMLListViewItem * parent)
92 : QTreeWidgetItem(parent)
93 {
94 init();
95 }
96
97 /**
98 * Sets up an instance.
99 *
100 * @param parent The parent to this instance.
101 * @param name The name of this instance.
102 * @param t The type of this instance.
103 * @param o The object it represents.
104 */
UMLListViewItem(UMLListViewItem * parent,const QString & name,ListViewType t,UMLObject * o)105 UMLListViewItem::UMLListViewItem(UMLListViewItem * parent, const QString &name, ListViewType t, UMLObject *o)
106 : QTreeWidgetItem(parent)
107 {
108 init();
109 m_type = t;
110 m_object = o;
111 if (!o) {
112 m_id = Uml::ID::None;
113 updateFolder();
114 } else {
115 parent->addChildItem(o, this);
116 updateObject();
117 m_id = o->id();
118 }
119 setText(name);
120 if (!Model_Utils::typeIsRootView(t)) {
121 setFlags(flags() | Qt::ItemIsEditable);
122 }
123 }
124
125 /**
126 * Sets up an instance.
127 *
128 * @param parent The parent to this instance.
129 * @param name The name of this instance.
130 * @param t The type of this instance.
131 * @param id The id of this instance.
132 */
UMLListViewItem(UMLListViewItem * parent,const QString & name,ListViewType t,Uml::ID::Type id)133 UMLListViewItem::UMLListViewItem(UMLListViewItem * parent, const QString &name, ListViewType t, Uml::ID::Type id)
134 : QTreeWidgetItem(parent)
135 {
136 init();
137 m_type = t;
138 m_id = id;
139 switch (m_type) {
140 case lvt_Collaboration_Diagram:
141 setIcon(Icon_Utils::it_Diagram_Collaboration);
142 break;
143 case lvt_Class_Diagram:
144 setIcon(Icon_Utils::it_Diagram_Class);
145 break;
146 case lvt_State_Diagram:
147 setIcon(Icon_Utils::it_Diagram_State);
148 break;
149 case lvt_Activity_Diagram:
150 setIcon(Icon_Utils::it_Diagram_Activity);
151 break;
152 case lvt_Sequence_Diagram:
153 setIcon(Icon_Utils::it_Diagram_Sequence);
154 break;
155 case lvt_Component_Diagram:
156 setIcon(Icon_Utils::it_Diagram_Component);
157 break;
158 case lvt_Deployment_Diagram:
159 setIcon(Icon_Utils::it_Diagram_Deployment);
160 break;
161 case lvt_UseCase_Diagram:
162 setIcon(Icon_Utils::it_Diagram_Usecase);
163 break;
164 case lvt_Object_Diagram:
165 setIcon(Icon_Utils::it_Diagram_Object);
166 break;
167 default:
168 setIcon(Icon_Utils::it_Diagram);
169 }
170 // Constructor also used by folder so just make sure we don't need to
171 // to set pixmap to folder. doesn't hurt diagrams.
172 updateFolder();
173 setText(name);
174 setFlags(flags() | Qt::ItemIsEditable);
175 }
176
177 /**
178 * Standard destructor.
179 */
~UMLListViewItem()180 UMLListViewItem::~UMLListViewItem()
181 {
182 }
183
184 /**
185 * Initializes key variables of the class.
186 */
init()187 void UMLListViewItem::init()
188 {
189 m_type = lvt_Unknown;
190 m_object = 0;
191 m_id = Uml::ID::None;
192 }
193
194 /**
195 * Returns the signature of items that are operations.
196 * @return signature of an operation item, else an empty string
197 */
toolTip() const198 QString UMLListViewItem::toolTip() const
199 {
200 UMLObject *obj = umlObject();
201 if (obj) {
202 switch (obj->baseType()) {
203 case UMLObject::ot_Class:
204 return obj->doc();
205 case UMLObject::ot_Operation:
206 {
207 UMLOperation *op = obj->asUMLOperation();
208 return op->toString(Uml::SignatureType::ShowSig);
209 }
210 case UMLObject::ot_Attribute:
211 {
212 UMLAttribute *at = obj->asUMLAttribute();
213 return at->toString(Uml::SignatureType::ShowSig);
214 }
215 default:
216 return QString();
217 }
218 }
219 else {
220 return QString();
221 }
222 }
223
224 /**
225 * Returns the type this instance represents.
226 *
227 * @return The type this instance represents.
228 */
type() const229 UMLListViewItem::ListViewType UMLListViewItem::type() const
230 {
231 return m_type;
232 }
233
234 /**
235 * Adds the child listview item representing the given UMLObject.
236 */
addChildItem(UMLObject * child,UMLListViewItem * childItem)237 void UMLListViewItem::addChildItem(UMLObject *child, UMLListViewItem *childItem)
238 {
239 if (!child) {
240 uError() << "UMLListViewItem::addChildItem called with null child";
241 return;
242 }
243 m_comap[child] = childItem;
244 }
245
246 /**
247 * Deletes the child listview item representing the given UMLObject.
248 */
deleteChildItem(UMLObject * child)249 void UMLListViewItem::deleteChildItem(UMLObject *child)
250 {
251 if (!child) {
252 uError() << "UMLListViewItem::deleteChildItem called with null child";
253 return;
254 }
255 UMLListViewItem *childItem = findChildObject(child);
256 if (childItem == 0) {
257 uError() << child->name() << ": child listview item not found";
258 return;
259 }
260 m_comap.remove(child);
261 delete childItem;
262 }
263
setVisible(bool state)264 void UMLListViewItem::setVisible(bool state)
265 {
266 setHidden(!state);
267 }
268
269 /**
270 * Returns the id this class represents.
271 *
272 * @return The id this class represents.
273 */
ID() const274 Uml::ID::Type UMLListViewItem::ID() const
275 {
276 if (m_object) {
277 return m_object->id();
278 }
279 return m_id;
280 }
281
282 /**
283 * Sets the id this class represents.
284 * This only sets the ID locally, not at the UMLObject that is perhaps
285 * associated to this UMLListViewItem.
286 * @param id the id this class represents
287 */
setID(Uml::ID::Type id)288 void UMLListViewItem::setID(Uml::ID::Type id)
289 {
290 if (m_object) {
291 Uml::ID::Type oid = m_object->id();
292 if (id != Uml::ID::None && oid != id) {
293 DEBUG(DBG_LVI) << "new id " << Uml::ID::toString(id) << " does not agree with object id "
294 << Uml::ID::toString(oid);
295 }
296 }
297 m_id = id;
298 }
299
300 /**
301 * Set the UMLObject associated with this instance.
302 *
303 * @param obj The object this class represents.
304 */
setUMLObject(UMLObject * obj)305 void UMLListViewItem::setUMLObject(UMLObject * obj)
306 {
307 m_object = obj;
308 }
309
310 /**
311 * Return the UMLObject associated with this instance.
312 *
313 * @return The object this class represents.
314 */
umlObject() const315 UMLObject * UMLListViewItem::umlObject() const
316 {
317 return m_object;
318 }
319
320 /**
321 * Returns true if the UMLListViewItem of the given ID is a parent of
322 * this UMLListViewItem.
323 */
isOwnParent(Uml::ID::Type listViewItemID)324 bool UMLListViewItem::isOwnParent(Uml::ID::Type listViewItemID)
325 {
326 UMLListView* listView = static_cast<UMLListView*>(treeWidget());
327 QTreeWidgetItem *lvi = static_cast<QTreeWidgetItem*>(listView->findItem(listViewItemID));
328 if (lvi == 0) {
329 uError() << "ListView->findItem(" << Uml::ID::toString(listViewItemID) << ") returns NULL";
330 return true;
331 }
332 for (QTreeWidgetItem *self = static_cast<QTreeWidgetItem*>(this); self; self = self->parent()) {
333 if (lvi == self)
334 return true;
335 }
336 return false;
337 }
338
339 /**
340 * Updates the representation of the object.
341 */
updateObject()342 void UMLListViewItem::updateObject()
343 {
344 if (m_object == 0)
345 return;
346
347 // check if parent has been changed, remap parent if so
348 UMLListViewItem *oldParent = dynamic_cast<UMLListViewItem*>(parent());
349 if (oldParent && oldParent->m_object != m_object->parent() &&
350 dynamic_cast<UMLPackage*>(m_object->parent())) {
351 UMLListViewItem *newParent = UMLApp::app()->listView()->findUMLObject(m_object->umlPackage());
352 if (newParent) {
353 oldParent->removeChild(this);
354 newParent->addChild(this);
355 }
356 }
357
358 Uml::Visibility::Enum scope = m_object->visibility();
359 UMLObject::ObjectType ot = m_object->baseType();
360 QString modelObjText = m_object->name();
361 if (Model_Utils::isClassifierListitem(ot)) {
362 UMLClassifierListItem *pNarrowed = m_object->asUMLClassifierListItem();
363 modelObjText = pNarrowed->toString(Uml::SignatureType::SigNoVis);
364 } else if (ot == UMLObject::ot_InstanceAttribute) {
365 UMLInstanceAttribute *pNarrowed = m_object->asUMLInstanceAttribute();
366 modelObjText = pNarrowed->toString();
367 }
368 setText(modelObjText);
369
370 Icon_Utils::IconType icon = Icon_Utils::it_Home;
371 switch (ot) {
372 case UMLObject::ot_Package:
373 if (m_object->stereotype() == QLatin1String("subsystem"))
374 icon = Icon_Utils::it_Subsystem;
375 else
376 icon = Icon_Utils::it_Package;
377 break;
378 case UMLObject::ot_Operation:
379 if (scope == Uml::Visibility::Public)
380 icon = Icon_Utils::it_Public_Method;
381 else if (scope == Uml::Visibility::Private)
382 icon = Icon_Utils::it_Private_Method;
383 else if (scope == Uml::Visibility::Implementation)
384 icon = Icon_Utils::it_Private_Method;
385 else
386 icon = Icon_Utils::it_Protected_Method;
387 break;
388
389 case UMLObject::ot_Attribute:
390 case UMLObject::ot_EntityAttribute:
391 case UMLObject::ot_InstanceAttribute:
392 if (scope == Uml::Visibility::Public)
393 icon = Icon_Utils::it_Public_Attribute;
394 else if (scope == Uml::Visibility::Private)
395 icon = Icon_Utils::it_Private_Attribute;
396 else if (scope == Uml::Visibility::Implementation)
397 icon = Icon_Utils::it_Private_Attribute;
398 else
399 icon = Icon_Utils::it_Protected_Attribute;
400 break;
401 case UMLObject::ot_UniqueConstraint:
402 m_type = Model_Utils::convert_OT_LVT(umlObject());
403 icon = Model_Utils::convert_LVT_IT(m_type);
404 break;
405
406 case UMLObject::ot_Class:
407 icon = Model_Utils::convert_LVT_IT(m_type, m_object);
408 break;
409
410 case UMLObject::ot_Association:
411 icon = Model_Utils::convert_LVT_IT(m_type, m_object);
412 break;
413
414 default:
415 icon = Model_Utils::convert_LVT_IT(m_type);
416 break;
417 }//end switch
418 if (icon)
419 setIcon(icon);
420 }
421
422 /**
423 * Updates the icon on a folder.
424 */
updateFolder()425 void UMLListViewItem::updateFolder()
426 {
427 Icon_Utils::IconType icon = Model_Utils::convert_LVT_IT(m_type, m_object);
428
429 if (icon) {
430 if (Model_Utils::typeIsFolder(m_type)) {
431 icon = (Icon_Utils::IconType)((int)icon + (int)isExpanded());
432 }
433 setIcon(icon);
434 }
435 }
436
437 /**
438 * Overrides default method.
439 * Will call default method but also makes sure correct icon is shown.
440 */
setOpen(bool expand)441 void UMLListViewItem::setOpen(bool expand)
442 {
443 QTreeWidgetItem::setExpanded(expand);
444 updateFolder();
445 }
446
447 /**
448 * Changes the current text of column 0.
449 */
setText(const QString & newText)450 void UMLListViewItem::setText(const QString &newText)
451 {
452 setText(0, newText);
453 }
454
455 /**
456 * Changes the current text.
457 */
setText(int column,const QString & newText)458 void UMLListViewItem::setText(int column, const QString &newText)
459 {
460 m_label = newText;
461 QTreeWidgetItem::setText(column, newText);
462 }
463
464 /**
465 * Returns the saved text.
466 */
getSavedText() const467 QString UMLListViewItem::getSavedText() const
468 {
469 return m_label;
470 }
471
472 /**
473 * Set the pixmap corresponding to the given IconType.
474 */
setIcon(Icon_Utils::IconType iconType)475 void UMLListViewItem::setIcon(Icon_Utils::IconType iconType)
476 {
477 QPixmap p = Icon_Utils::SmallIcon(iconType);
478 if (!p.isNull()) {
479 QTreeWidgetItem::setIcon(0, QIcon(p));
480 }
481 }
482
483 /**
484 * This slot is called to finish item editing
485 */
slotEditFinished(const QString & newText)486 void UMLListViewItem::slotEditFinished(const QString &newText)
487 {
488 m_label = text(0);
489
490 DEBUG(DBG_LVI) << this << "text=" << newText;
491 UMLListView* listView = static_cast<UMLListView*>(treeWidget());
492 UMLDoc* doc = listView->document();
493 if (newText == m_label) {
494 return;
495 }
496 if (newText.isEmpty()) {
497 cancelRenameWithMsg();
498 return;
499 }
500 switch (m_type) {
501 case lvt_UseCase:
502 case lvt_Actor:
503 case lvt_Class:
504 case lvt_Package:
505 case lvt_UseCase_Folder:
506 case lvt_Logical_Folder:
507 case lvt_Component_Folder:
508 case lvt_Deployment_Folder:
509 case lvt_EntityRelationship_Folder:
510 case lvt_Interface:
511 case lvt_Datatype:
512 case lvt_Enum:
513 case lvt_EnumLiteral:
514 case lvt_Subsystem:
515 case lvt_Component:
516 case lvt_Port:
517 case lvt_Node:
518 case lvt_Category:
519 if (m_object == 0 || !doc->isUnique(newText)) {
520 cancelRenameWithMsg();
521 return;
522 }
523 UMLApp::app()->executeCommand(new Uml::CmdRenameUMLObject(m_object, newText));
524 doc->setModified(true);
525 m_label = newText;
526 break;
527
528 case lvt_Operation: {
529 if (m_object == 0) {
530 cancelRenameWithMsg();
531 return;
532 }
533 UMLOperation *op = m_object->asUMLOperation();
534 if (!op) {
535 cancelRenameWithMsg();
536 return;
537 }
538 UMLClassifier *parent = op->umlParent()->asUMLClassifier();
539 Model_Utils::OpDescriptor od;
540 Model_Utils::Parse_Status st = Model_Utils::parseOperation(newText, od, parent);
541 if (st == Model_Utils::PS_OK) {
542 // TODO: Check that no operation with the exact same profile exists.
543 UMLApp::app()->executeCommand(new Uml::CmdRenameUMLObject(op, od.m_name));
544 op->setType(od.m_pReturnType);
545 UMLAttributeList parmList = op->getParmList();
546 const int newParmListCount = parmList.count();
547 if (newParmListCount > od.m_args.count()) {
548 // Remove parameters at end of of list that no longer exist.
549 for (int i = od.m_args.count(); i < newParmListCount; i++) {
550 UMLAttribute *a = parmList.at(i);
551 op->removeParm(a, false);
552 }
553 }
554 Model_Utils::NameAndType_ListIt lit = od.m_args.begin();
555 for (int i = 0; lit != od.m_args.end(); ++lit, ++i) {
556 const Model_Utils::NameAndType& nm_tp = *lit;
557 UMLAttribute *a;
558 if (i < newParmListCount) {
559 a = parmList.at(i);
560 } else {
561 a = new UMLAttribute(op);
562 a->setID(UniqueID::gen());
563 }
564 UMLApp::app()->executeCommand(new Uml::CmdRenameUMLObject(a, nm_tp.m_name));
565 a->setType(nm_tp.m_type);
566 a->setParmKind(nm_tp.m_direction);
567 a->setInitialValue(nm_tp.m_initialValue);
568 if (i >= newParmListCount) {
569 op->addParm(a);
570 }
571 }
572 m_label = op->toString(Uml::SignatureType::SigNoVis);
573 } else {
574 KMessageBox::error(0,
575 Model_Utils::psText(st),
576 i18n("Rename canceled"));
577 }
578 setText(m_label);
579 break;
580 }
581
582 case lvt_Attribute:
583 case lvt_EntityAttribute:
584 case lvt_InstanceAttribute: {
585 if (m_object == 0) {
586 cancelRenameWithMsg();
587 return;
588 }
589 UMLClassifier *parent = m_object->umlParent()->asUMLClassifier();
590 Model_Utils::NameAndType nt;
591 Uml::Visibility::Enum vis;
592 Model_Utils::Parse_Status st;
593 st = Model_Utils::parseAttribute(newText, nt, parent, &vis);
594 if (st == Model_Utils::PS_OK) {
595 UMLObject *exists = parent ? parent->findChildObject(newText) : 0;
596 if (exists) {
597 cancelRenameWithMsg();
598 return;
599 }
600 UMLApp::app()->executeCommand(new Uml::CmdRenameUMLObject(m_object, nt.m_name));
601 UMLAttribute *pAtt = m_object->asUMLAttribute();
602 pAtt->setType(nt.m_type);
603 pAtt->setVisibility(vis);
604 pAtt->setParmKind(nt.m_direction);
605 pAtt->setInitialValue(nt.m_initialValue);
606 m_label = pAtt->toString(Uml::SignatureType::SigNoVis);
607 } else {
608 KMessageBox::error(0,
609 Model_Utils::psText(st),
610 i18n("Rename canceled"));
611 }
612 setText(m_label);
613 break;
614 }
615
616 case lvt_PrimaryKeyConstraint:
617 case lvt_UniqueConstraint:
618 case lvt_ForeignKeyConstraint:
619 case lvt_CheckConstraint: {
620 if (m_object == 0) {
621 cancelRenameWithMsg();
622 return;
623 }
624 UMLEntity *parent = m_object->umlParent()->asUMLEntity();
625 QString name;
626 Model_Utils::Parse_Status st;
627 st = Model_Utils::parseConstraint(newText, name, parent);
628 if (st == Model_Utils::PS_OK) {
629 UMLObject *exists = parent->findChildObject(name);
630 if (exists) {
631 cancelRenameWithMsg();
632 return;
633 }
634 UMLApp::app()->executeCommand(new Uml::CmdRenameUMLObject(m_object, name));
635
636 UMLEntityConstraint* uec = m_object->asUMLEntityConstraint();
637 m_label = uec->toString(Uml::SignatureType::SigNoVis);
638 } else {
639 KMessageBox::error(0,
640 Model_Utils::psText(st),
641 i18n("Rename canceled"));
642 }
643 setText(m_label);
644 break;
645 }
646
647 case lvt_Template: {
648 if (m_object == 0) {
649 cancelRenameWithMsg();
650 return;
651 }
652 UMLClassifier *parent = m_object->umlParent()->asUMLClassifier();
653 Model_Utils::NameAndType nt;
654 Model_Utils::Parse_Status st = Model_Utils::parseTemplate(newText, nt, parent);
655 if (st == Model_Utils::PS_OK) {
656 UMLObject *exists = parent ? parent->findChildObject(newText) : 0;
657 if (exists) {
658 cancelRenameWithMsg();
659 return;
660 }
661 UMLApp::app()->executeCommand(new Uml::CmdRenameUMLObject(m_object, nt.m_name));
662 UMLTemplate *tmpl = m_object->asUMLTemplate();
663 tmpl->setType(nt.m_type);
664 m_label = tmpl->toString(Uml::SignatureType::SigNoVis);
665 } else {
666 KMessageBox::error(0,
667 Model_Utils::psText(st),
668 i18n("Rename canceled"));
669 }
670 setText(m_label);
671 break;
672 }
673
674 case lvt_UseCase_Diagram:
675 case lvt_Class_Diagram:
676 case lvt_Sequence_Diagram:
677 case lvt_Collaboration_Diagram:
678 case lvt_State_Diagram:
679 case lvt_Activity_Diagram:
680 case lvt_Component_Diagram:
681 case lvt_Deployment_Diagram:
682 case lvt_Object_Diagram:{
683 UMLView *view = doc->findView(ID());
684 if (view == 0) {
685 cancelRenameWithMsg();
686 return;
687 }
688 UMLView *anotherView = doc->findView(view->umlScene()->type(), newText);
689 if (anotherView && anotherView->umlScene()->ID() == ID()) {
690 anotherView = 0;
691 }
692 if (anotherView) {
693 cancelRenameWithMsg();
694 return;
695 }
696 view->umlScene()->setName(newText);
697 setText(newText);
698 doc->signalDiagramRenamed(view);
699 break;
700 }
701 default:
702 KMessageBox::error(0,
703 i18n("Renaming an item of listview type %1 is not yet implemented.", m_type),
704 i18n("Function Not Implemented"));
705 setText(m_label);
706 break;
707 }
708 doc->setModified(true);
709 }
710
711 /**
712 * Auxiliary method for okRename().
713 */
cancelRenameWithMsg()714 void UMLListViewItem::cancelRenameWithMsg()
715 {
716 DEBUG(DBG_LVI) << this << " - column=" << ":TODO:col" << ", text=" << text(0);
717 KMessageBox::error(0,
718 i18n("The name you entered was invalid.\nRenaming process has been canceled."),
719 i18n("Name Not Valid"));
720 setText(m_label);
721 }
722
723 /**
724 * Overrides the default sorting to sort by item type.
725 * Sort the listview items by type and position within the corresponding list
726 * of UMLObjects. If the item does not have a UMLObject then place it last.
727 */
728 #if 0
729 int UMLListViewItem::compare(QTreeWidgetItem *other, int col, bool ascending) const
730 {
731 UMLListViewItem *ulvi = other->asUMLListViewItem();
732 ListViewType ourType = type();
733 ListViewType otherType = ulvi->type();
734
735 if (ourType < otherType)
736 return -1;
737 if (ourType > otherType)
738 return 1;
739 // ourType == otherType
740 const bool subItem = Model_Utils::typeIsClassifierList(ourType);
741 const int alphaOrder = key(col, ascending).compare(other->key(col, ascending));
742 int retval = 0;
743 QString dbgPfx = "compare(type=" + QString::number((int)ourType)
744 + ", self=" + text() + ", other=" + ulvi->text()
745 + "): return ";
746 UMLObject *otherObj = ulvi->umlObject();
747 if (m_object == 0) {
748 retval = (subItem ? 1 : alphaOrder);
749 #ifdef DEBUG_LVITEM_INSERTION_ORDER
750 DEBUG(DBG_LVI) << dbgPfx << retval << " because (m_object==0)";
751 #endif
752 return retval;
753 }
754 if (otherObj == 0) {
755 retval = (subItem ? -1 : alphaOrder);
756 #ifdef DEBUG_LVITEM_INSERTION_ORDER
757 DEBUG(DBG_LVI) << dbgPfx << retval << " because (otherObj==0)";
758 #endif
759 return retval;
760 }
761 UMLClassifier *ourParent = m_object->umlParent()->asUMLClassifier();
762 UMLClassifier *otherParent = otherObj->umlParent()->asUMLClassifier();
763 if (ourParent == 0) {
764 retval = (subItem ? 1 : alphaOrder);
765 #ifdef DEBUG_LVITEM_INSERTION_ORDER
766 DEBUG(DBG_LVI) << dbgPfx << retval << " because (ourParent==0)";
767 #endif
768 return retval;
769 }
770 if (otherParent == 0) {
771 retval = (subItem ? -1 : alphaOrder);
772 #ifdef DEBUG_LVITEM_INSERTION_ORDER
773 DEBUG(DBG_LVI) << dbgPfx << retval << " because (otherParent==0)";
774 #endif
775 return retval;
776 }
777 if (ourParent != otherParent) {
778 retval = (subItem ? 0 : alphaOrder);
779 #ifdef DEBUG_LVITEM_INSERTION_ORDER
780 DEBUG(DBG_LVI) << dbgPfx << retval << " because (ourParent != otherParent)";
781 #endif
782 return retval;
783 }
784 UMLClassifierListItem *thisUmlItem = m_object->asUMLClassifierListItem();
785 UMLClassifierListItem *otherUmlItem = otherObj->asUMLClassifierListItem();
786 if (thisUmlItem == 0) {
787 retval = (subItem ? 1 : alphaOrder);
788 #ifdef DEBUG_LVITEM_INSERTION_ORDER
789 DEBUG(DBG_LVI) << dbgPfx << retval << " because (thisUmlItem==0)";
790 #endif
791 return retval;
792 }
793 if (otherUmlItem == 0) {
794 retval = (subItem ? -1 : alphaOrder);
795 #ifdef DEBUG_LVITEM_INSERTION_ORDER
796 DEBUG(DBG_LVI) << dbgPfx << retval << " because (otherUmlItem==0)";
797 #endif
798 return retval;
799 }
800 UMLClassifierListItemList items = ourParent->getFilteredList(thisUmlItem->baseType());
801 int myIndex = items.indexOf(thisUmlItem);
802 int otherIndex = items.indexOf(otherUmlItem);
803 if (myIndex < 0) {
804 retval = (subItem ? -1 : alphaOrder);
805 uError() << dbgPfx << retval << " because (myIndex < 0)";
806 return retval;
807 }
808 if (otherIndex < 0) {
809 retval = (subItem ? 1 : alphaOrder);
810 uError() << dbgPfx << retval << " because (otherIndex < 0)";
811 return retval;
812 }
813 return (myIndex < otherIndex ? -1 : myIndex > otherIndex ? 1 : 0);
814 }
815 #endif
816
817 /**
818 * Create a deep copy of this UMLListViewItem, but using the
819 * given parent instead of the parent of this UMLListViewItem.
820 * Return the new UMLListViewItem created.
821 */
deepCopy(UMLListViewItem * newParent)822 UMLListViewItem* UMLListViewItem::deepCopy(UMLListViewItem *newParent)
823 {
824 QString nm = text(0);
825 ListViewType t = type();
826 UMLObject *o = umlObject();
827 UMLListViewItem* newItem;
828 if (o)
829 newItem = new UMLListViewItem(newParent, nm, t, o);
830 else
831 newItem = new UMLListViewItem(newParent, nm, t, m_id);
832 for (int i=0; i < childCount(); i++) {
833 UMLListViewItem *childItem = static_cast<UMLListViewItem*>(child(i));
834 childItem->deepCopy(newItem);
835 }
836 return newItem;
837 }
838
839 /**
840 * Find the UMLListViewItem that is related to the given UMLObject
841 * in the tree rooted at the current UMLListViewItem.
842 * Return a pointer to the item or NULL if not found.
843 */
findUMLObject(const UMLObject * o)844 UMLListViewItem* UMLListViewItem::findUMLObject(const UMLObject *o)
845 {
846 if (m_object == o)
847 return this;
848 for (int i = 0; i < childCount(); i++) {
849 UMLListViewItem *item = static_cast<UMLListViewItem*>(child(i));
850 UMLListViewItem *testItem = item->findUMLObject(o);
851 if (testItem)
852 return testItem;
853 }
854 return 0;
855 }
856
857 /**
858 * Find the UMLListViewItem that represents the given UMLObject in the
859 * children of the current UMLListViewItem.
860 * Return a pointer to the item or NULL if not found.
861 */
findChildObject(UMLObject * child)862 UMLListViewItem* UMLListViewItem::findChildObject(UMLObject *child)
863 {
864 ChildObjectMap::iterator it = m_comap.find(child);
865 if (it != m_comap.end()) {
866 return *it;
867 }
868 return 0;
869 }
870
871 /**
872 * Find the UMLListViewItem of the given ID in the tree rooted at
873 * the current UMLListViewItem.
874 * Return a pointer to the item or NULL if not found.
875 *
876 * @param id The ID to search for.
877 * @return The item with the given ID or NULL if not found.
878 */
findItem(Uml::ID::Type id)879 UMLListViewItem * UMLListViewItem::findItem(Uml::ID::Type id)
880 {
881 if (ID() == id) {
882 return this;
883 }
884 for (int i = 0; i < childCount(); ++i) {
885 UMLListViewItem *childItem = static_cast<UMLListViewItem*>(child(i));
886 UMLListViewItem *inner = childItem->findItem(id);
887 if (inner) {
888 return inner;
889 }
890 }
891 return 0;
892 }
893
894 /**
895 * Saves the listview item to a "listitem" tag.
896 */
saveToXMI1(QXmlStreamWriter & writer)897 void UMLListViewItem::saveToXMI1(QXmlStreamWriter& writer)
898 {
899 writer.writeStartElement(QLatin1String("listitem"));
900 Uml::ID::Type id = ID();
901 QString idStr = Uml::ID::toString(id);
902 //DEBUG(DBG_LVI) << "id = " << idStr << ", type = " << m_type;
903 if (id != Uml::ID::None)
904 writer.writeAttribute(QLatin1String("id"), idStr);
905 writer.writeAttribute(QLatin1String("type"), QString::number(m_type));
906 if (m_object == 0) {
907 if (! Model_Utils::typeIsDiagram(m_type) && m_type != lvt_View)
908 uError() << text(0) << ": m_object is NULL";
909 if (m_type != lvt_View)
910 writer.writeAttribute(QLatin1String("label"), text(0));
911 } else if (m_object->id() == Uml::ID::None) {
912 if (text(0).isEmpty()) {
913 DEBUG(DBG_LVI) << "Skipping empty item";
914 return;
915 }
916 DEBUG(DBG_LVI) << "saving local label " << text(0) << " because umlobject ID is not set";
917 if (m_type != lvt_View)
918 writer.writeAttribute(QLatin1String("label"), text(0));
919 } else if (m_object->baseType() == UMLObject::ot_Folder) {
920 UMLFolder *extFolder = m_object->asUMLFolder();
921 if (!extFolder->folderFile().isEmpty()) {
922 writer.writeAttribute(QLatin1String("open"), QLatin1String("0"));
923 writer.writeEndElement();
924 return;
925 }
926 }
927 writer.writeAttribute(QLatin1String("open"), QString::number(isExpanded()));
928 for (int i = 0; i < childCount(); i++) {
929 UMLListViewItem *childItem = static_cast<UMLListViewItem*>(child(i));
930 childItem->saveToXMI1(writer);
931 }
932 writer.writeEndElement();
933 }
934
935 /**
936 * Loads a "listitem" tag, this is only used by the clipboard currently.
937 */
loadFromXMI1(QDomElement & qElement)938 bool UMLListViewItem::loadFromXMI1(QDomElement& qElement)
939 {
940 QString id = qElement.attribute(QLatin1String("id"), QLatin1String("-1"));
941 QString type = qElement.attribute(QLatin1String("type"), QLatin1String("-1"));
942 QString label = qElement.attribute(QLatin1String("label"));
943 QString open = qElement.attribute(QLatin1String("open"), QLatin1String("1"));
944 if (!label.isEmpty())
945 setText(label);
946 else if (id == QLatin1String("-1")) {
947 uError() << "Item of type " << type << " has neither ID nor label";
948 return false;
949 }
950
951 m_id = Uml::ID::fromString(id);
952 if (m_id != Uml::ID::None) {
953 UMLListView* listView = static_cast<UMLListView*>(treeWidget());
954 m_object = listView->document()->findObjectById(m_id);
955 }
956 m_type = (ListViewType)(type.toInt());
957 if (m_object)
958 updateObject();
959 setOpen((bool)open.toInt());
960 return true;
961 }
962
childItem(int i)963 UMLListViewItem* UMLListViewItem::childItem(int i)
964 {
965 return static_cast<UMLListViewItem*>(child(i));
966 }
967
toString(ListViewType type)968 QString UMLListViewItem::toString(ListViewType type)
969 {
970 switch (type) {
971 case lvt_View:
972 return QLatin1String("lvt_View");
973 case lvt_Logical_View:
974 return QLatin1String("lvt_Logical_View");
975 case lvt_UseCase_View:
976 return QLatin1String("lvt_UseCase_View");
977 case lvt_Logical_Folder:
978 return QLatin1String("lvt_Logical_Folder");
979 case lvt_UseCase_Folder:
980 return QLatin1String("lvt_UseCase_Folder");
981 case lvt_UseCase_Diagram:
982 return QLatin1String("lvt_UseCase_Diagram");
983 case lvt_Collaboration_Diagram:
984 return QLatin1String("lvt_Collaboration_Diagram");
985 case lvt_Class_Diagram:
986 return QLatin1String("lvt_Class_Diagram");
987 case lvt_State_Diagram:
988 return QLatin1String("lvt_State_Diagram");
989 case lvt_Activity_Diagram:
990 return QLatin1String("lvt_Activity_Diagram");
991 case lvt_Sequence_Diagram:
992 return QLatin1String("lvt_Sequence_Diagram");
993 case lvt_Object_Diagram:
994 return QLatin1String("lvt_Object_Diagram");
995 case lvt_Actor:
996 return QLatin1String("lvt_Actor");
997 case lvt_Association:
998 return QLatin1String("lvt_Association");
999 case lvt_UseCase:
1000 return QLatin1String("lvt_UseCase");
1001 case lvt_Class:
1002 return QLatin1String("lvt_Class");
1003 case lvt_Attribute:
1004 return QLatin1String("lvt_Attribute");
1005 case lvt_Operation:
1006 return QLatin1String("lvt_Operation");
1007 case lvt_Template:
1008 return QLatin1String("lvt_Template");
1009 case lvt_Interface:
1010 return QLatin1String("lvt_Interface");
1011 case lvt_Package:
1012 return QLatin1String("lvt_Package");
1013 case lvt_Component_Diagram:
1014 return QLatin1String("lvt_Component_Diagram");
1015 case lvt_Component_Folder:
1016 return QLatin1String("lvt_Component_Folder");
1017 case lvt_Component_View:
1018 return QLatin1String("lvt_Component_View");
1019 case lvt_Component:
1020 return QLatin1String("lvt_Component");
1021 case lvt_Diagrams:
1022 return QLatin1String("lvt_Diagrams");
1023 case lvt_Artifact:
1024 return QLatin1String("lvt_Artifact");
1025 case lvt_Deployment_Diagram:
1026 return QLatin1String("lvt_Deployment_Diagram");
1027 case lvt_Deployment_Folder:
1028 return QLatin1String("lvt_Deployment_Folder");
1029 case lvt_Deployment_View:
1030 return QLatin1String("lvt_Deployment_View");
1031 case lvt_Port:
1032 return QLatin1String("lvt_Port");
1033 case lvt_Node:
1034 return QLatin1String("lvt_Node");
1035 case lvt_Datatype:
1036 return QLatin1String("lvt_Datatype");
1037 case lvt_Datatype_Folder:
1038 return QLatin1String("lvt_Datatype_Folder");
1039 case lvt_Enum:
1040 return QLatin1String("lvt_Enum");
1041 case lvt_Entity:
1042 return QLatin1String("lvt_Entity");
1043 case lvt_EntityAttribute:
1044 return QLatin1String("lvt_EntityAttribute");
1045 case lvt_EntityRelationship_Diagram:
1046 return QLatin1String("lvt_EntityRelationship_Diagram");
1047 case lvt_EntityRelationship_Folder:
1048 return QLatin1String("lvt_EntityRelationship_Folder");
1049 case lvt_EntityRelationship_Model:
1050 return QLatin1String("lvt_EntityRelationship_Model");
1051 case lvt_Subsystem:
1052 return QLatin1String("lvt_Subsystem");
1053 case lvt_Model:
1054 return QLatin1String("lvt_Model");
1055 case lvt_EnumLiteral:
1056 return QLatin1String("lvt_EnumLiteral");
1057 case lvt_UniqueConstraint:
1058 return QLatin1String("lvt_UniqueConstraint");
1059 case lvt_PrimaryKeyConstraint:
1060 return QLatin1String("lvt_PrimaryKeyConstraint");
1061 case lvt_ForeignKeyConstraint:
1062 return QLatin1String("lvt_ForeignKeyConstraint");
1063 case lvt_CheckConstraint:
1064 return QLatin1String("lvt_CheckConstraint");
1065 case lvt_Category:
1066 return QLatin1String("lvt_Category");
1067 case lvt_Properties:
1068 return QLatin1String("lvt_Properties");
1069 case lvt_Unknown:
1070 return QLatin1String("lvt_Unknown");
1071 case lvt_Instance:
1072 return QLatin1String("lvt_Instance");
1073 case lvt_InstanceAttribute:
1074 return QLatin1String("lvt_InstanceAttribute");
1075 default:
1076 return QLatin1String("? ListViewType ?");
1077 }
1078 }
1079
1080 /**
1081 * Overloading operator for debugging output.
1082 */
operator <<(QDebug dbg,const UMLListViewItem & item)1083 QDebug operator<<(QDebug dbg, const UMLListViewItem& item)
1084 {
1085 dbg.nospace() << "UMLListViewItem: " << item.text(0)
1086 << ", type=" << UMLListViewItem::toString(item.type())
1087 << ", id=" << Uml::ID::toString(item.ID())
1088 << ", children=" << item.childCount();
1089 return dbg.space();
1090 }
1091