summaryrefslogtreecommitdiffstats
path: root/umbrello/umbrello/clipboard/umlclipboard.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'umbrello/umbrello/clipboard/umlclipboard.cpp')
-rw-r--r--umbrello/umbrello/clipboard/umlclipboard.cpp694
1 files changed, 694 insertions, 0 deletions
diff --git a/umbrello/umbrello/clipboard/umlclipboard.cpp b/umbrello/umbrello/clipboard/umlclipboard.cpp
new file mode 100644
index 00000000..c65c576e
--- /dev/null
+++ b/umbrello/umbrello/clipboard/umlclipboard.cpp
@@ -0,0 +1,694 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "umlclipboard.h"
+
+// qt/kde includes
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+
+// local includes
+#include "umldrag.h"
+#include "idchangelog.h"
+#include "../associationwidget.h"
+#include "../attribute.h"
+#include "../classifier.h"
+#include "../floatingtextwidget.h"
+#include "../operation.h"
+#include "../umldoc.h"
+#include "../umllistview.h"
+#include "../umllistviewitem.h"
+#include "../umlobjectlist.h"
+#include "../umlview.h"
+#include "../umlwidget.h"
+#include "../uml.h"
+#include "../model_utils.h"
+
+UMLClipboard::UMLClipboard() {
+ m_type = clip1;
+}
+
+UMLClipboard::~UMLClipboard() {
+}
+
+QMimeSource* UMLClipboard::copy(bool fromView/*=false*/) {
+ //Clear previous copied data
+ m_AssociationList.clear();
+ m_ItemList.clear();
+ m_ObjectList.clear();
+ m_ViewList.clear();
+
+ UMLDrag *data = 0;
+ QPixmap* png = 0;
+
+ UMLListView * listView = UMLApp::app()->getListView();
+ UMLListViewItemList selectedItems;
+ selectedItems.setAutoDelete(false);
+
+ if(fromView) {
+ m_type = clip4;
+ UMLView *view = UMLApp::app()->getCurrentView();
+ view->checkSelections();
+ if(!view->getSelectedWidgets(m_WidgetList)) {
+ return 0;
+ }
+ //if there is no selected widget then there is no copy action
+ if(!m_WidgetList.count()) {
+ return 0;
+ }
+ m_AssociationList = view->getSelectedAssocs();
+ view->copyAsImage(png);
+
+ } else { //if the copy action is being performed from the ListView
+ if(!listView->getSelectedItems(selectedItems)) {
+ return 0;
+ }
+ //Set What type of copy operation are we performing and
+ //also fill m_ViewList with all the selected Diagrams
+ setCopyType(selectedItems);
+
+ //if we are copying a diagram or part of a diagram, select the items
+ //on the ListView that correspond to a UseCase, Actor or Concept
+ //in the Diagram
+ if(m_type == clip2) {
+ //Fill the member lists with all the object and stuff to be copied
+ //to the clipboard
+ selectedItems.clear();
+ //For each selected view select all the Actors, USe Cases and Concepts
+ //widgets in the ListView
+ for (UMLViewListIt vit(m_ViewList); vit.current(); ++vit) {
+ UMLObjectList objects = vit.current()->getUMLObjects();
+ for (UMLObjectListIt oit(objects); oit.current(); ++oit) {
+ UMLObject *o = oit.current();
+ UMLListViewItem *item = listView->findUMLObject(o);
+ if(item) {
+ listView->setSelected(item, true);
+ }
+ }
+ }
+ if(!listView->getSelectedItems(selectedItems)) {
+ return 0;
+ }
+ }
+ if(!fillSelectionLists(selectedItems)) {
+ return 0;
+ }
+ }
+ int i =0;
+ switch(m_type) {
+ case clip1:
+ data = new UMLDrag(m_ObjectList);
+ break;
+ case clip2:
+ data = new UMLDrag(m_ObjectList, m_ItemList, m_ViewList);
+ break;
+ case clip3:
+ data = new UMLDrag(m_ItemList);
+ break;
+ case clip4:
+ if(png) {
+ UMLView *view = UMLApp::app()->getCurrentView();
+ data = new UMLDrag(m_ObjectList, m_WidgetList,
+ m_AssociationList, *png, view->getType());
+ } else {
+ return 0;
+ }
+ break;
+ case clip5:
+ data = new UMLDrag(m_ObjectList, i);
+ // The int i is used to differentiate
+ // which UMLDrag constructor gets called.
+ break;
+ }
+
+ return (QMimeSource*)data;
+}
+
+bool UMLClipboard::paste(QMimeSource* data) {
+ UMLDoc *doc = UMLApp::app()->getDocument();
+ bool result = false;
+ doc->beginPaste();
+ switch(UMLDrag::getCodingType(data)) {
+ case 1:
+ result = pasteClip1(data);
+ break;
+ case 2:
+ result = pasteClip2(data);
+ break;
+ case 3:
+ result = pasteClip3(data);
+ break;
+ case 4:
+ result = pasteClip4(data);
+ break;
+ case 5:
+ result = pasteClip5(data);
+ break;
+ default:
+ break;
+ }
+ doc->endPaste();
+ return result;
+}
+
+bool UMLClipboard::fillSelectionLists(UMLListViewItemList& SelectedItems) {
+ UMLListViewItemListIt it(SelectedItems);
+ UMLListViewItem* item = 0;
+ Uml::ListView_Type type;
+ switch(m_type) {
+ case clip4:
+ break;
+ case clip3:
+ for ( ; it.current(); ++it ) {
+ item = (UMLListViewItem*)it.current();
+ type = item->getType();
+ if ( !Model_Utils::typeIsClassifierList(type) ) {
+ m_ItemList.append(item);
+ insertItemChildren(item, SelectedItems);
+ //Because it is being called when m_type is 3
+ //it will insert only child empty folders of other folders.
+ //If a child folder
+ //is not empty that means m_type wouldn't be 3 because if a folder is
+ //selected then its complete contents are treated as if
+ //they were selected
+ }
+ }
+ break;
+ case clip2:
+ case clip1:
+ for ( ; it.current(); ++it ) {
+ item = (UMLListViewItem*)it.current();
+ type = item->getType();
+ if ( !Model_Utils::typeIsClassifierList(type) ) {
+
+ m_ItemList.append(item);
+
+ if ( Model_Utils::typeIsCanvasWidget(type) ) {
+ m_ObjectList.append(item->getUMLObject());
+ }
+ insertItemChildren(it.current(), SelectedItems);
+ }
+ }
+ break;
+ case clip5:
+ for ( ; it.current(); ++it ) {
+ item = (UMLListViewItem*)it.current();
+ type = item->getType();
+ if( Model_Utils::typeIsClassifierList(type) ) {
+ m_ItemList.append(item);
+ m_ObjectList.append(item->getUMLObject());
+
+ } else {
+ return false;
+ }
+ }
+ break;
+ }
+
+ return true;
+}
+
+void UMLClipboard::setCopyType(UMLListViewItemList& SelectedItems) {
+ bool withDiagrams = false; //If the selection includes diagrams
+ bool withObjects = false; //If the selection includes objects
+ bool onlyAttsOps = false; //If the selection only includes Attributes and/or Operations
+ UMLListViewItemListIt it(SelectedItems);
+ for ( ; it.current(); ++it ) {
+ checkItemForCopyType(it.current(), withDiagrams, withObjects, onlyAttsOps);
+ }
+ if(onlyAttsOps) {
+ m_type = clip5;
+ } else if(withDiagrams) {
+ m_type = clip2;
+ } else if(withObjects) {
+ m_type = clip1;
+ } else {
+ m_type = clip3;
+ }
+}
+
+void UMLClipboard::checkItemForCopyType(UMLListViewItem* Item, bool & WithDiagrams, bool &WithObjects,
+ bool &OnlyAttsOps) {
+ if(!Item) {
+ return;
+ }
+ UMLDoc *doc = UMLApp::app()->getDocument();
+ OnlyAttsOps = true;
+ UMLView * view = 0;
+ UMLListViewItem * child = 0;
+ Uml::ListView_Type type = Item->getType();
+ if ( Model_Utils::typeIsCanvasWidget(type) ) {
+ WithObjects = true;
+ OnlyAttsOps = false;
+ } else if ( Model_Utils::typeIsDiagram(type) ) {
+ WithDiagrams = true;
+ OnlyAttsOps = false;
+ view = doc->findView( Item->getID() );
+ m_ViewList.append( view );
+ } else if ( Model_Utils::typeIsFolder(type) ) {
+ OnlyAttsOps = false;
+ if(Item->childCount()) {
+ child = (UMLListViewItem*)Item->firstChild();
+ while(child) {
+ checkItemForCopyType(child, WithDiagrams, WithObjects, OnlyAttsOps);
+ child = (UMLListViewItem*)child->nextSibling();
+ }
+ }
+ }
+}
+
+/** Adds the children of a UMLListViewItem to m_ItemList */
+bool UMLClipboard::insertItemChildren(UMLListViewItem * Item, UMLListViewItemList& SelectedItems) {
+ if(Item->childCount()) {
+ UMLListViewItem * child = (UMLListViewItem*)Item->firstChild();
+ int type;
+ while(child) {
+ m_ItemList.append(child);
+ type = child->getType();
+ if(type == Uml::lvt_Actor || type == Uml::lvt_UseCase || type == Uml::lvt_Class) {
+ m_ObjectList.append(child->getUMLObject());
+ }
+ // If the child is selected, remove it from the list of selected items
+ // otherwise it will be inserted twice in m_ObjectList.
+ if(child->isSelected()) {
+ SelectedItems.remove(SelectedItems.find(child) );
+ }
+ insertItemChildren(child, SelectedItems);
+ child = (UMLListViewItem*)child->nextSibling();
+ }
+ }
+ return true;
+}
+
+bool UMLClipboard::pasteChildren(UMLListViewItem *parent, IDChangeLog *chgLog) {
+ if (!parent) {
+ kWarning() << "Paste Children Error, parent missing" << endl;
+ return false;
+ }
+ UMLDoc *doc = UMLApp::app()->getDocument();
+ UMLListView *listView = UMLApp::app()->getListView();
+ UMLListViewItem *childItem = static_cast<UMLListViewItem*>(parent->firstChild());
+ while (childItem) {
+ Uml::IDType oldID = childItem->getID();
+ Uml::IDType newID = chgLog->findNewID(oldID);
+ UMLListViewItem *shouldNotExist = listView->findItem(newID);
+ if (shouldNotExist) {
+ kError() << "UMLClipboard::pasteChildren: new list view item " << ID2STR(newID)
+ << " already exists (internal error)" << endl;
+ childItem = static_cast<UMLListViewItem*>(childItem->nextSibling());
+ continue;
+ }
+ UMLObject *newObj = doc->findObjectById(newID);
+ if (newObj) {
+ kDebug() << "UMLClipboard::pasteChildren: adjusting lvitem(" << ID2STR(oldID)
+ << ") to new UMLObject(" << ID2STR(newID) << ")" << endl;
+ childItem->setUMLObject(newObj);
+ childItem->setText(newObj->getName());
+ } else {
+ kDebug() << "UMLClipboard::pasteChildren: no UMLObject found for lvitem "
+ << ID2STR(newID) << endl;
+ }
+ childItem = static_cast<UMLListViewItem*>(childItem->nextSibling());
+ }
+ return true;
+}
+
+/** Cleans the list of associations taking out the ones that point to an object
+ not in m_ObjectList. */
+void UMLClipboard::CleanAssociations(AssociationWidgetList& associations) {
+ AssociationWidgetListIt it(associations);
+ AssociationWidget* assoc = it.current();
+
+ while (assoc) {
+ ++it;
+ assoc = it.current();
+ }
+}
+
+/** If clipboard has mime type application/x-uml-clip1,
+Pastes the data from the clipboard into the current Doc */
+bool UMLClipboard::pasteClip1(QMimeSource* data) {
+ UMLObjectList objects;
+ if (! UMLDrag::decodeClip1(data, objects)) {
+ return false;
+ }
+ UMLListView *lv = UMLApp::app()->getListView();
+ if ( !lv->startedCopy() )
+ return true;
+ lv->setStartedCopy(false);
+ /* If we get here we are pasting after a Copy and need to
+ // paste possible children.
+ UMLListViewItem* itemdata = 0;
+ UMLListViewItemListIt it(itemdatalist);
+ while ( (itemdata=it.current()) != 0 ) {
+ if(itemdata -> childCount()) {
+ if(!pasteChildren(itemdata, idchanges)) {
+ return false;
+ }
+ }
+ ++it;
+ }
+ */
+ return true;
+}
+
+/** If clipboard has mime type application/x-uml-clip2,
+Pastes the data from the clipboard into the current Doc */
+bool UMLClipboard::pasteClip2(QMimeSource* data) {
+ UMLDoc *doc = UMLApp::app()->getDocument();
+ UMLListViewItemList itemdatalist;
+ UMLObjectList objects;
+ objects.setAutoDelete(false);
+ UMLViewList views;
+ IDChangeLog* idchanges = 0;
+
+ bool result = UMLDrag::decodeClip2(data, objects, itemdatalist, views);
+ if(!result) {
+ return false;
+ }
+ UMLObject *obj = 0;
+ UMLObjectListIt object_it(objects);
+ idchanges = doc->getChangeLog();
+ if(!idchanges) {
+ return false;
+ }
+ while ( (obj=object_it.current()) != 0 ) {
+ ++object_it;
+ if(!doc->assignNewIDs(obj)) {
+ kDebug()<<"UMLClipboard: error adding umlobject"<<endl;
+ return false;
+ }
+ }
+
+ UMLView * pView = 0;
+ UMLViewListIt view_it( views );
+ while ( ( pView =view_it.current()) != 0 ) {
+ ++view_it;
+ if( !doc->addUMLView( pView ) ) {
+ return false;
+ }
+ }
+
+ UMLListView *listView = UMLApp::app()->getListView();
+ UMLListViewItem* item = 0;
+ UMLListViewItem* itemdata = 0;
+ UMLListViewItemListIt it(itemdatalist);
+ while ( (itemdata=it.current()) != 0 ) {
+ item = listView->createItem(*itemdata, *idchanges);
+ if(!item) {
+ return false;
+ }
+ if(itemdata -> childCount()) {
+ if(!pasteChildren(item, idchanges)) {
+ return false;
+ }
+ }
+ ++it;
+ }
+
+ return result;
+}
+
+/** If clipboard has mime type application/x-uml-clip3,
+Pastes the data from the clipboard into the current Doc */
+bool UMLClipboard::pasteClip3(QMimeSource* data) {
+ UMLDoc *doc = UMLApp::app()->getDocument();
+ UMLListViewItemList itemdatalist;
+ UMLListViewItem* item = 0;
+ UMLListViewItem* itemdata = 0;
+ IDChangeLog* idchanges = doc->getChangeLog();
+
+ if(!idchanges) {
+ return false;
+ }
+
+ UMLListView *listView = UMLApp::app()->getListView();
+ bool result = UMLDrag::decodeClip3(data, itemdatalist, listView);
+ if(!result) {
+ return false;
+ }
+ UMLListViewItemListIt it(itemdatalist);
+ while ( (itemdata=it.current()) != 0 ) {
+ item = listView->createItem(*itemdata, *idchanges);
+ if(itemdata -> childCount()) {
+ if(!pasteChildren(item, idchanges)) {
+ return false;
+ }
+ }
+ ++it;
+ }
+
+ return result;
+}
+
+/** If clipboard has mime type application/x-uml-clip4,
+Pastes the data from the clipboard into the current Doc */
+bool UMLClipboard::pasteClip4(QMimeSource* data) {
+ UMLDoc *doc = UMLApp::app()->getDocument();
+
+ UMLObjectList objects;
+ objects.setAutoDelete(false);
+
+
+ UMLWidgetList widgets;
+ widgets.setAutoDelete(false);
+
+ AssociationWidgetList assocs;
+ assocs.setAutoDelete(false);
+
+ IDChangeLog* idchanges = 0;
+
+ Uml::Diagram_Type diagramType;
+
+ if( !UMLDrag::decodeClip4(data, objects, widgets, assocs, diagramType) ) {
+ return false;
+ }
+
+ if( diagramType != UMLApp::app()->getCurrentView()->getType() ) {
+ if( !checkPasteWidgets(widgets) ) {
+ assocs.setAutoDelete(true);
+ assocs.clear();
+ return false;
+ }
+ }
+ UMLObjectListIt object_it(objects);
+ idchanges = doc->getChangeLog();
+ if(!idchanges) {
+ return false;
+ }
+ //make sure the file we are pasting into has the objects
+ //we need if there are widgets to be pasted
+ UMLObject* obj = 0;
+ while ( (obj=object_it.current()) != 0 ) {
+ ++object_it;
+
+ if(!doc->assignNewIDs(obj)) {
+ return false;
+ }
+
+ }
+
+ //now add any widget we are want to paste
+ bool objectAlreadyExists = false;
+ UMLView *currentView = UMLApp::app()->getCurrentView();
+ currentView->beginPartialWidgetPaste();
+ UMLWidget* widget =0;
+ UMLWidgetListIt widget_it(widgets);
+ while ( (widget=widget_it.current()) != 0 ) {
+ ++widget_it;
+
+ Uml::IDType oldId = widget->getID();
+ Uml::IDType newId = idchanges->findNewID(oldId);
+ if (currentView->findWidget(newId)) {
+ kError() << "UMLClipboard::pasteClip4: widget (oldID=" << ID2STR(oldId)
+ << ", newID=" << ID2STR(newId) << ") already exists in target view."
+ << endl;
+ widgets.remove(widget);
+ delete widget;
+ objectAlreadyExists = true;
+ } else if (! currentView->addWidget(widget, true)) {
+ currentView->endPartialWidgetPaste();
+ return false;
+ }
+ }
+
+ //now paste the associations
+ AssociationWidget* assoc;
+ AssociationWidgetListIt assoc_it(assocs);
+ while ( (assoc=assoc_it.current()) != 0 ) {
+ ++assoc_it;
+ if (!currentView->addAssociation(assoc, true)) {
+ currentView->endPartialWidgetPaste();
+ return false;
+ }
+ }
+
+ //Activate all the pasted associations and widgets
+ currentView->activate();
+ currentView->endPartialWidgetPaste();
+
+ /*
+ UMLListView *listView = UMLApp::app()->getListView();
+ UMLListViewItem* item = 0;
+ UMLListViewItem* itemdata = 0;
+ UMLListViewItemListIt it(itemdatalist);
+ while ( (itemdata=it.current()) != 0 ) {
+ item = listView->createItem(*itemdata, *idchanges);
+ if(!item) {
+ return false;
+ }
+ if(itemdata -> childCount()) {
+ if(!pasteChildren(item, idchanges)) {
+ return false;
+ }
+ }
+ ++it;
+ }*/
+
+ if (objectAlreadyExists) {
+ pasteItemAlreadyExists();
+ }
+ return true;
+}
+
+/** If clipboard has mime type application/x-uml-clip5,
+Pastes the data from the clipboard into the current Doc */
+bool UMLClipboard::pasteClip5(QMimeSource* data) {
+ UMLDoc *doc = UMLApp::app()->getDocument();
+ UMLListView *listView = UMLApp::app()->getListView();
+ UMLListViewItem* lvitem = dynamic_cast<UMLListViewItem *>( listView->currentItem() );
+ if (!lvitem ||
+ (lvitem->getType() != Uml::lvt_Class && lvitem->getType() != Uml::lvt_Interface)) {
+ return false;
+ }
+ UMLClassifier *parent = dynamic_cast<UMLClassifier *>(lvitem->getUMLObject());
+ if (parent == NULL) {
+ kError() << "UMLClipboard::pasteClip5: parent is not a UMLClassifier"
+ << endl;
+ return false;
+ }
+
+ UMLObjectList objects;
+ objects.setAutoDelete(false);
+ IDChangeLog* idchanges = 0;
+ bool result = UMLDrag::decodeClip5(data, objects, parent);
+
+ if(!result) {
+ return false;
+ }
+
+ UMLObject *obj = 0;
+ doc->setModified(true);
+ idchanges = doc->getChangeLog();
+ // Assume success if at least one child object could be pasted
+ if (objects.count())
+ result = false;
+
+ for (UMLObjectListIt it(objects); (obj = it.current()) != NULL; ++it) {
+ obj->setID(doc->assignNewID(obj->getID()));
+ switch(obj->getBaseType()) {
+ case Uml::ot_Attribute :
+ {
+ UMLObject *exist = parent->findChildObject(obj->getName(), Uml::ot_Attribute);
+ if (exist) {
+ QString newName = parent->uniqChildName(Uml::ot_Attribute, obj->getName());
+ obj->setName(newName);
+ }
+ UMLAttribute *att = static_cast<UMLAttribute*>(obj);
+ if (parent->addAttribute(att, idchanges)) {
+ result = true;
+ } else {
+ kError() << "UMLClipboard::pasteClip5: " << parent->getName()
+ << "->addAttribute(" << att->getName() << ") failed" << endl;
+ }
+ break;
+ }
+ case Uml::ot_Operation :
+ {
+ UMLOperation *op = static_cast<UMLOperation*>(obj);
+ UMLOperation *exist = parent->checkOperationSignature(op->getName(), op->getParmList());
+ if (exist) {
+ QString newName = parent->uniqChildName(Uml::ot_Operation, obj->getName());
+ op->setName(newName);
+ }
+ if (parent->addOperation(op, idchanges)) {
+ result = true;
+ } else {
+ kError() << "UMLClipboard::pasteClip5: " << parent->getName()
+ << "->addOperation(" << op->getName() << ") failed" << endl;
+ }
+ break;
+ }
+ default :
+ kWarning() << "pasting unknown children type in clip type 5" << endl;
+ return false;
+ }
+ }
+
+ return result;
+}
+
+bool UMLClipboard::insertItemChildren( UMLListViewItem * item ) {
+ if( item -> childCount() ) {
+ UMLListViewItem * child =dynamic_cast<UMLListViewItem *>( item -> firstChild() );
+ while( child ) {
+ m_ItemList.append( child );
+ insertItemChildren( child );
+ child = dynamic_cast<UMLListViewItem *>( child->nextSibling() );
+ }
+ }
+ return true;
+}
+
+bool UMLClipboard::checkPasteWidgets( UMLWidgetList & widgetList ) {
+ bool retval = true;
+ UMLWidget * p = 0;
+ UMLWidgetListIt it( widgetList );
+ while ( ( p = it.current()) != 0 ) {
+ ++it;
+ switch( p -> getBaseType() ) {
+ case Uml::wt_Note:
+ break;
+
+ case Uml::wt_Text:
+ {
+ FloatingTextWidget *ft = static_cast<FloatingTextWidget*>(p);
+ if (ft->getRole() != Uml::tr_Floating) {
+ widgetList.remove(p);
+ delete ft;
+ retval = false;
+ }
+ }
+ break;
+
+ default:
+ widgetList.remove(p);
+ delete p;
+ retval = false;
+ break;
+ }
+ }
+ return retval;
+}
+
+void UMLClipboard::pasteItemAlreadyExists() {
+ UMLView *currentView = UMLApp::app()->getCurrentView();
+ KMessageBox::sorry( currentView,
+ i18n("At least one of the items in the clipboard "
+ "could not be pasted because an item of the "
+ "same name already exists. Any other items "
+ "have been pasted."),
+ i18n("Paste Error") );
+}
+
+#include "umlclipboard.moc"