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 "umlclipboard.h"
8 
9 // local includes
10 #include "debug_utils.h"
11 #include "diagram_utils.h"
12 #include "umldragdata.h"
13 #include "idchangelog.h"
14 #include "associationwidget.h"
15 #include "attribute.h"
16 #include "classifier.h"
17 #include "enum.h"
18 #include "entity.h"
19 #include "floatingtextwidget.h"
20 #include "messagewidget.h"
21 #include "operation.h"
22 #include "template.h"
23 #include "enumliteral.h"
24 #include "entityattribute.h"
25 #include "model_utils.h"
26 #include "notewidget.h"
27 #include "umldoc.h"
28 #include "umllistview.h"
29 #include "umllistviewitem.h"
30 #include "umlobjectlist.h"
31 #include "umlscene.h"
32 #include "umlview.h"
33 #include "umlwidget.h"
34 #include "uml.h"
35 
36 // kde includes
37 #include <KMessageBox>
38 #include <KLocalizedString>
39 
40 // qt includes
41 #include <QMimeData>
42 #include <QPixmap>
43 
44 /**
45  * Constructor.
46  */
UMLClipboard()47 UMLClipboard::UMLClipboard()
48 {
49     m_type = clip1;
50 }
51 
52 /**
53  * Deconstructor.
54  */
~UMLClipboard()55 UMLClipboard::~UMLClipboard()
56 {
57 }
58 
59 /**
60  * Copy operation.
61  * @param fromView   flag if it is from view
62  * @return           the mime data
63  */
copy(bool fromView)64 QMimeData* UMLClipboard::copy(bool fromView/*=false*/)
65 {
66     // Clear previous copied data
67     m_AssociationList.clear();
68     m_ObjectList.clear();
69     m_ViewList.clear();
70 
71     UMLDragData *data = 0;
72     QPixmap* png = 0;
73 
74     UMLListView * listView = UMLApp::app()->listView();
75 
76     if (fromView) {
77         m_type = clip4;
78         UMLView *view = UMLApp::app()->currentView();
79         if (view == 0) {
80             uError() << "UMLApp::app()->currentView() is NULL";
81             return 0;
82         }
83         UMLScene *scene = view->umlScene();
84         if (scene == 0) {
85             uError() << "currentView umlScene() is NULL";
86             return 0;
87         }
88         m_WidgetList = scene->selectedWidgetsExt();
89         //if there is no selected widget then there is no copy action
90         if (!m_WidgetList.count()) {
91             return 0;
92         }
93         m_AssociationList = scene->selectedAssocs();
94         scene->copyAsImage(png);
95 
96         // Clip4 needs related widgets.
97         addRelatedWidgets();
98 
99         // Clip4 needs UMLObjects because it's possible the UMLObject
100         // is no longer there when pasting this mime data. This happens for
101         // example when using cut-paste or pasting to another Umbrello
102         // instance.
103         fillObjectListForWidgets(m_WidgetList);
104 
105         foreach (WidgetBase* widget, m_AssociationList) {
106             if (widget->umlObject() != 0) {
107                 m_ObjectList.append(widget->umlObject());
108             }
109         }
110     } else {
111         // The copy action is being performed from the ListView
112         UMLListViewItemList itemsSelected = listView->selectedItems();
113         if (itemsSelected.count() <= 0) {
114             return 0;
115         }
116 
117         // Set What type of copy operation are we performing and
118         // also fill m_ViewList with all the selected Diagrams
119         setCopyType(itemsSelected);
120 
121         // If we are copying a diagram or part of a diagram, select the items
122         // on the ListView that correspond to a UseCase, Actor or Concept
123         // in the Diagram
124         if (m_type == clip2) {
125             foreach (UMLView* view, m_ViewList) {
126                 UMLScene *scene = view->umlScene();
127                 if (scene == 0) {
128                     uError() << "currentView umlScene() is NULL";
129                     continue;
130                 }
131                 fillObjectListForWidgets(scene->widgetList());
132 
133                 AssociationWidgetList associations = scene->associationList();
134                 foreach (AssociationWidget* association, associations) {
135                     if (association->umlObject() != 0) {
136                         m_ObjectList.append(association->umlObject());
137                     }
138                 }
139             }
140         } else {
141             // Clip1, 4 and 5: fill the clip with only the specific objects
142             // selected in the list view
143             if (!fillSelectionLists(itemsSelected)) {
144                 return 0;
145             }
146 
147             if (itemsSelected.count() <= 0) {
148                 return 0;
149             }
150         }
151     }
152 
153     int i = 0;
154     switch(m_type) {
155     case clip1:
156         data = new UMLDragData(m_ObjectList);
157         break;
158     case clip2:
159         data = new UMLDragData(m_ObjectList, m_ViewList);
160         break;
161     case clip3:
162         data = new UMLDragData(m_ItemList);
163         break;
164     case clip4:
165         if (png) {
166             UMLView *view = UMLApp::app()->currentView();
167             data = new UMLDragData(m_ObjectList, m_WidgetList,
168                                    m_AssociationList, *png, view->umlScene());
169         } else {
170             return 0;
171         }
172         break;
173     case clip5:
174         data = new UMLDragData(m_ObjectList, i);
175         // The int i is used to differentiate
176         // which UMLDragData constructor gets called.
177         break;
178     }
179 
180     return (QMimeData*)data;
181 }
182 
183 /**
184  * Inserts the clipboard's contents.
185  *
186  * @param data   Pointer to the MIME format clipboard data.
187  * @return       True for successful operation.
188  */
paste(const QMimeData * data)189 bool UMLClipboard::paste(const QMimeData* data)
190 {
191     UMLDoc *doc = UMLApp::app()->document();
192 
193     int codingType = UMLDragData::getCodingType(data);
194     if (codingType == 6
195             && UMLApp::app()->currentView()) {
196         return Diagram_Utils::importGraph(data, UMLApp::app()->currentView()->umlScene());
197     }
198     QString mimeType = QLatin1String("application/x-uml-clip") + QString::number(codingType);
199     uDebug() << "Pasting mimeType=" << mimeType << "data=" << data->data(mimeType);
200 
201     bool result = false;
202     doc->beginPaste();
203 
204     switch (codingType) {
205     case 1:
206         result = pasteClip1(data);
207         break;
208     case 2:
209         result = pasteClip2(data);
210         break;
211     case 3:
212         result = pasteClip3(data);
213         break;
214     case 4:
215         result = pasteClip4(data);
216         break;
217     case 5:
218         result = pasteClip5(data);
219         break;
220     default:
221         break;
222     }
223     doc->endPaste();
224     return result;
225 }
226 
227 /**
228  * Fills object list based on a selection of widgets
229  *
230  * @param UMLWidgetList& widgets
231  */
addRelatedWidgets()232 void UMLClipboard::addRelatedWidgets()
233 {
234     UMLWidgetList relatedWidgets;
235     UMLWidget *pWA =0, *pWB = 0;
236 
237     foreach (UMLWidget* widget, m_WidgetList) {
238         if (widget->isMessageWidget()) {
239             MessageWidget * pMessage = widget->asMessageWidget();
240             pWA = (UMLWidget*)pMessage->objectWidget(Uml::RoleType::A);
241             pWB = (UMLWidget*)pMessage->objectWidget(Uml::RoleType::B);
242             if (!relatedWidgets.contains(pWA))
243                 relatedWidgets.append(pWA);
244             if (!relatedWidgets.contains(pWB))
245                 relatedWidgets.append(pWB);
246         }
247     }
248 
249     foreach(AssociationWidget *pAssoc, m_AssociationList) {
250         pWA = pAssoc->widgetForRole(Uml::RoleType::A);
251         pWB = pAssoc->widgetForRole(Uml::RoleType::B);
252         if (!relatedWidgets.contains(pWA))
253             relatedWidgets.append(pWA);
254         if (!relatedWidgets.contains(pWB))
255             relatedWidgets.append(pWB);
256     }
257 
258     foreach(UMLWidget *widget, relatedWidgets) {
259         if (!m_WidgetList.contains(widget))
260             m_WidgetList.append(widget);
261     }
262 }
263 
264 /**
265  * Fills object list based on a selection of widgets
266  *
267  * @param UMLWidgetList& widgets
268  */
fillObjectListForWidgets(const UMLWidgetList & widgets)269 void UMLClipboard::fillObjectListForWidgets(const UMLWidgetList& widgets)
270 {
271     // The order of the packages in the clip matters. So we collect
272     // the packages and add them from the root package to the deeper levels
273     UMLObjectList packages;
274 
275     foreach (UMLWidget* widget, widgets) {
276         UMLObject* widgetObject = widget->umlObject();
277         if (widgetObject != 0) {
278             packages.clear();
279 
280             UMLPackage* package = widgetObject->umlPackage();
281             while (package != 0) {
282                 packages.prepend(package);
283                 package = package->umlPackage();
284             }
285 
286             foreach (UMLObject* package, packages) {
287                 if (!m_ObjectList.contains(package)) {
288                     m_ObjectList.append(package);
289                 }
290             }
291 
292             if (!m_ObjectList.contains(widgetObject)) {
293                 m_ObjectList.append(widgetObject);
294             }
295         }
296     }
297 }
298 
299 /**
300  * Fills the member lists with all the objects and other
301  * stuff to be copied to the clipboard.
302  * @param selectedItems   list of selected items
303  */
fillSelectionLists(UMLListViewItemList & selectedItems)304 bool UMLClipboard::fillSelectionLists(UMLListViewItemList& selectedItems)
305 {
306     UMLListViewItem::ListViewType type;
307     switch(m_type) {
308     case clip4:
309         break;
310     case clip3:
311         foreach (UMLListViewItem* item, selectedItems) {
312             type = item->type();
313             if (!Model_Utils::typeIsClassifierList(type)) {
314                 m_ItemList.append(item);
315                 insertItemChildren(item, selectedItems);
316             }
317         }
318         break;
319     case clip2:
320     case clip1:
321         foreach (UMLListViewItem* item, selectedItems) {
322             type = item->type();
323             if (!Model_Utils::typeIsClassifierList(type)) {
324                 if (Model_Utils::typeIsCanvasWidget(type)) {
325                     if (item->umlObject() == nullptr)
326                         uError() << "UMLClipboard::fillSelectionLists: selected lvitem has no umlObject";
327                     else
328                         m_ObjectList.append(item->umlObject());
329                 }
330                 insertItemChildren(item, selectedItems);
331             }
332         }
333         break;
334     case clip5:
335         foreach (UMLListViewItem* item, selectedItems) {
336             type = item->type();
337             if(Model_Utils::typeIsClassifierList(type)) {
338                 m_ObjectList.append(item->umlObject());
339             } else {
340                 return false;
341             }
342         }
343         break;
344     }
345 
346     return true;
347 }
348 
349 /**
350  * Checks the whole list to determine the copy action
351  * type to be performed, sets the type in the m_type
352  * member variable.
353  * @param selectedItems   list of selected items
354  */
setCopyType(UMLListViewItemList & selectedItems)355 void UMLClipboard::setCopyType(UMLListViewItemList& selectedItems)
356 {
357     bool withDiagrams = false; //If the selection includes diagrams
358     bool withObjects = false; //If the selection includes objects
359     bool onlyAttsOps = false; //If the selection only includes Attributes and/or Operations
360 
361     foreach (UMLListViewItem* item, selectedItems) {
362         checkItemForCopyType(item, withDiagrams, withObjects, onlyAttsOps);
363     }
364     if (onlyAttsOps) {
365         m_type = clip5;
366     } else if (withDiagrams) {
367         m_type = clip2;
368     } else if(withObjects) {
369         m_type = clip1;
370     } else {
371         m_type = clip3;
372     }
373 }
374 
375 /**
376  * Searches the child items of a UMLListViewItem to
377  * establish which Copy type is to be performed.
378  * @param item          parent of the children
379  * @param withDiagrams  includes diagrams
380  * @param withObjects   includes objects
381  * @param onlyAttsOps   includes only attributes and/or operations
382  */
checkItemForCopyType(UMLListViewItem * item,bool & withDiagrams,bool & withObjects,bool & onlyAttsOps)383 void UMLClipboard::checkItemForCopyType(UMLListViewItem* item, bool & withDiagrams, bool & withObjects,
384                                         bool & onlyAttsOps)
385 {
386     if(!item) {
387         return;
388     }
389     UMLDoc *doc = UMLApp::app()->document();
390     onlyAttsOps = true;
391     UMLView * view = 0;
392     UMLListViewItem * child = 0;
393     UMLListViewItem::ListViewType type = item->type();
394     if (Model_Utils::typeIsCanvasWidget(type)) {
395         withObjects = true;
396         onlyAttsOps = false;
397     } else if (Model_Utils::typeIsDiagram(type)) {
398         withDiagrams = true;
399         onlyAttsOps = false;
400         view = doc->findView(item->ID());
401         if (view)
402             m_ViewList.append(view);
403         else
404             uError() << "doc->findView(" << Uml::ID::toString(item->ID()) << ") returns NULL";
405     } else if (Model_Utils::typeIsFolder(type)) {
406         onlyAttsOps = false;
407         for (int i =0; i < item->childCount(); i++) {
408             child = (UMLListViewItem*)item->child(i);
409             checkItemForCopyType(child, withDiagrams, withObjects, onlyAttsOps);
410         }
411     }
412 }
413 
414 /**
415  * Traverse children of a UMLListViewItem and add its UMLObjects to the list
416  *
417  * @param item            parent of the children to insert
418  * @param selectedItems   list of selected items
419  * @return                success flag
420  */
insertItemChildren(UMLListViewItem * item,UMLListViewItemList & selectedItems)421 bool UMLClipboard::insertItemChildren(UMLListViewItem * item, UMLListViewItemList& selectedItems)
422 {
423     if (item->childCount()) {
424         for(int i = 0; i < item->childCount(); i++) {
425             UMLListViewItem * child = (UMLListViewItem*)item->child(i);
426             m_ItemList.append(child);
427             UMLListViewItem::ListViewType type = child->type();
428             if (!Model_Utils::typeIsClassifierList(type) &&
429                 !Model_Utils::typeIsDiagram(type)) {
430                 m_ObjectList.append(child->umlObject());
431             }
432             // If the child is selected, remove it from the list of selected items
433             // otherwise it will be inserted twice in m_ObjectList.
434             if (child->isSelected()) {
435                 selectedItems.removeAll(child);
436             }
437             insertItemChildren(child, selectedItems);
438         }
439     }
440     return true;
441 }
442 
443 /**
444  * If clipboard has mime type application/x-uml-clip1,
445  * Pastes the data from the clipboard into the current Doc.
446  * @param data   mime type
447  */
pasteClip1(const QMimeData * data)448 bool UMLClipboard::pasteClip1(const QMimeData* data)
449 {
450     UMLObjectList objects;
451     return UMLDragData::decodeClip1(data, objects);
452 }
453 
454 /**
455  * If clipboard has mime type application/x-uml-clip2,
456  * Pastes the data from the clipboard into the current Doc.
457  * @param data   mime type
458  * @return       success flag
459  */
pasteClip2(const QMimeData * data)460 bool UMLClipboard::pasteClip2(const QMimeData* data)
461 {
462     UMLDoc*             doc = UMLApp::app()->document();
463     UMLObjectList       objects;
464     UMLViewList         views;
465 
466     if (!UMLDragData::decodeClip2(data, objects, views)) {
467         uDebug() << "UMLDragData::decodeClip2 returned error";
468         return false;
469     }
470 
471     if (NoteWidget::s_pCurrentNote) {
472         NoteWidget::s_pCurrentNote = 0;
473     } else {
474         foreach (UMLView* pView, views) {
475             if (!doc->addUMLView(pView)) {
476                 return false;
477             }
478         }
479     }
480 
481     return true;
482 }
483 
484 /**
485  * If clipboard has mime type application/x-uml-clip3,
486  * Pastes the data from the clipboard into the current Doc.
487  *
488  * Note: clip3 is only used to determine if the selected items can be dragged
489  * onto the view. Pasting only listview items makes no sense. Clip3 is implemented
490  * as a fallback-clip when clip 1, 2, 4 or 5 are not applicable. But that should
491  * never happen.
492  *
493  * Todo: remove clip3 altogether.
494  *
495  * @param data   mime type
496  * @return       success flag
497  */
pasteClip3(const QMimeData * data)498 bool UMLClipboard::pasteClip3(const QMimeData* data)
499 {
500     UMLDoc *doc = UMLApp::app()->document();
501     UMLListViewItemList itemdatalist;
502     IDChangeLog* idchanges = doc->changeLog();
503 
504     if(!idchanges) {
505         return false;
506     }
507 
508     UMLListView *listView = UMLApp::app()->listView();
509     return UMLDragData::decodeClip3(data, itemdatalist, listView);
510 }
511 
512 /**
513  * If clipboard has mime type application/x-uml-clip4,
514  * Pastes the data from the clipboard into the current Doc.
515  * @param data   mime type
516  * @return       success flag
517  */
pasteClip4(const QMimeData * data)518 bool UMLClipboard::pasteClip4(const QMimeData* data)
519 {
520     UMLDoc *doc = UMLApp::app()->document();
521 
522     UMLObjectList objects;
523     UMLWidgetList widgets;
524     AssociationWidgetList assocs;
525 
526     IDChangeLog* idchanges = 0;
527 
528     Uml::DiagramType::Enum diagramType;
529 
530     if(!UMLDragData::decodeClip4(data, objects, widgets, assocs, diagramType)) {
531         return false;
532     }
533 
534     UMLScene *currentScene = UMLApp::app()->currentView()->umlScene();
535 
536     idchanges = doc->changeLog();
537     if(!idchanges) {
538         return false;
539     }
540      //make sure the file we are pasting into has the objects
541      //we need if there are widgets to be pasted
542     foreach (UMLObject* obj, objects) {
543         if(!doc->assignNewIDs(obj)) {
544             return false;
545         }
546 
547      }
548 
549     //now add any widget we are want to paste
550     bool objectAlreadyExists = false;
551     currentScene->beginPartialWidgetPaste();
552 
553     foreach (UMLWidget* widget, widgets) {
554 
555         Uml::ID::Type oldId = widget->id();
556         Uml::ID::Type newId = idchanges->findNewID(oldId);
557         // how should findWidget find ::None id, which is returned for the first entry ?
558         if (currentScene->findWidget(newId)) {
559             uError() << "widget (oldID=" << Uml::ID::toString(oldId) << ", newID="
560                 << Uml::ID::toString(newId) << ") already exists in target view.";
561             widgets.removeAll(widget);
562             delete widget;
563             objectAlreadyExists = true;
564         } else {
565             if (currentScene->isActivityDiagram() || currentScene->isStateDiagram()) {
566                 widget->setID(doc->assignNewID(widget->id()));
567             }
568         }
569     }
570 
571     //now paste the associations
572     foreach (AssociationWidget* assoc, assocs) {
573         if (!currentScene->addAssociation(assoc, true)) {
574             currentScene->endPartialWidgetPaste();
575             return false;
576         }
577     }
578 
579     currentScene->clearSelected();
580     currentScene->selectWidgets(widgets);
581     foreach (AssociationWidget* assoc, assocs) {
582         currentScene->selectWidgetsOfAssoc(assoc);
583     }
584 
585     //Activate all the pasted associations and widgets
586     currentScene->activate();
587     currentScene->endPartialWidgetPaste();
588 
589     if (objectAlreadyExists) {
590         pasteItemAlreadyExists();
591     }
592     return true;
593 }
594 
595 /**
596  * If clipboard has mime type application/x-uml-clip5,
597  * Pastes the data from the clipboard into the current Doc.
598  * @param data   mime type
599  * @return       success flag
600  */
pasteClip5(const QMimeData * data)601 bool UMLClipboard::pasteClip5(const QMimeData* data)
602 {
603     UMLDoc *doc = UMLApp::app()->document();
604     UMLListView *listView = UMLApp::app()->listView();
605     UMLListViewItem* lvitem = dynamic_cast<UMLListViewItem *>(listView->currentItem());
606     if (!lvitem || !Model_Utils::typeIsClassifier(lvitem->type())) {
607         return false;
608     }
609     UMLClassifier *parent = lvitem->umlObject()->asUMLClassifier();
610 
611     if (parent == 0) {
612         uError() << "parent is not a UMLClassifier";
613         return false;
614     }
615 
616     UMLObjectList objects;
617 
618     IDChangeLog* idchanges = 0;
619     bool result = UMLDragData::decodeClip5(data, objects, parent);
620 
621     if(!result) {
622         return false;
623     }
624 
625     doc->setModified(true);
626     idchanges = doc->changeLog();
627     // Assume success if at least one child object could be pasted
628     if (objects.count())
629         result = false;
630 
631     foreach (UMLObject* obj, objects) {
632         obj->setID(doc->assignNewID(obj->id()));
633         switch(obj->baseType()) {
634         case UMLObject::ot_Attribute :
635             {
636                 UMLObject *exist = parent->findChildObject(obj->name(), UMLObject::ot_Attribute);
637                 if (exist) {
638                     QString newName = parent->uniqChildName(UMLObject::ot_Attribute, obj->name());
639                     obj->setName(newName);
640                 }
641                 UMLAttribute *att = obj->asUMLAttribute();
642                 if (parent->addAttribute(att, idchanges)) {
643                     result = true;
644                 } else {
645                     uError() << parent->name() << "->addAttribute("
646                              << att->name() << ") failed";
647                 }
648                 break;
649             }
650         case UMLObject::ot_Operation :
651             {
652                 UMLOperation *op = obj->asUMLOperation();
653                 UMLOperation *exist = parent->checkOperationSignature(op->name(), op->getParmList());
654                 if (exist) {
655                     QString newName = parent->uniqChildName(UMLObject::ot_Operation, obj->name());
656                     op->setName(newName);
657                 }
658                 if (parent->addOperation(op, idchanges)) {
659                     result = true;
660                 } else {
661                     uError() << parent->name() << "->addOperation("
662                              << op->name() << ") failed";
663                 }
664                 break;
665             }
666         case UMLObject::ot_Template:
667             {
668                 UMLTemplate* tp = obj->asUMLTemplate();
669                 UMLTemplate* exist = parent->findTemplate(tp->name());
670                 if (exist) {
671                     QString newName = parent->uniqChildName(UMLObject::ot_Template, obj->name());
672                     tp->setName(newName);
673                 }
674                 if (parent->addTemplate(tp, idchanges)) {
675                     result = true;
676                 } else {
677                     uError() << parent->name() << "->addTemplate("
678                              << tp->name() << ") failed";
679                 }
680                 break;
681             }
682         case UMLObject::ot_EnumLiteral:
683            {
684                UMLEnum* enumParent = parent->asUMLEnum();
685                // if parent is not a UMLEnum, bail out immediately;
686                if (!enumParent) {
687                    result = false;
688                    uError() << "Parent is not a UMLEnum";
689                    break;
690                }
691 
692                UMLObject* exist = enumParent->findChildObject(obj->name(), UMLObject::ot_EnumLiteral);
693                if (exist) {
694                    QString newName = enumParent->uniqChildName(UMLObject::ot_EnumLiteral, obj->name());
695                    obj->setName(newName);
696                }
697                UMLEnumLiteral* enl = obj->asUMLEnumLiteral();
698 
699                if (enumParent->addEnumLiteral(enl, idchanges)) {
700                    result = true;
701                } else {
702                    uError() << enumParent->name() << "->addEnumLiteral("
703                             << enl->name() << ") failed";
704                }
705                break;
706            }
707         case UMLObject::ot_EntityAttribute :
708             {
709                 UMLEntity* entityParent = parent->asUMLEntity();
710                 // if parent is not a UMLEntity, bail out immediately;
711                 if (!entityParent) {
712                     result = false;
713                     uError() << "Parent is not a UMLEntity";
714                     break;
715                 }
716                 UMLObject *exist = entityParent->findChildObject(obj->name(), UMLObject::ot_EntityAttribute);
717                 if (exist) {
718                     QString newName = entityParent->uniqChildName(UMLObject::ot_EntityAttribute, obj->name());
719                     obj->setName(newName);
720                 }
721                 UMLEntityAttribute *att = obj->asUMLEntityAttribute();
722 
723                 if (entityParent->addEntityAttribute(att, idchanges)) {
724                     result = true;
725                 } else {
726                     uError() << parent->name() << "->addEntityAttribute(" << att->name() << ") failed";
727                 }
728                 break;
729             }
730         default :
731             uWarning() << "pasting unknown children type in clip type 5";
732             return false;
733         }
734     }
735 
736     return result;
737 }
738 
739 /**
740  * Gives a `sorry' message box if you're pasting an item which
741  * already exists and can't be duplicated.
742  */
pasteItemAlreadyExists()743 void UMLClipboard::pasteItemAlreadyExists()
744 {
745     UMLView *currentView = UMLApp::app()->currentView();
746     KMessageBox::sorry(currentView,
747                         i18n("At least one of the items in the clipboard "
748                              "could not be pasted because an item of the "
749                              "same name already exists.  Any other items "
750                              "have been pasted."),
751                         i18n("Paste Error"));
752 }
753 
754