/*************************************************************************** * * * 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 * ***************************************************************************/ // own header #include "umlclipboard.h" // qt/kde includes #include #include #include // 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() { } TQMimeSource* UMLClipboard::copy(bool fromView/*=false*/) { //Clear previous copied data m_AssociationList.clear(); m_ItemList.clear(); m_ObjectList.clear(); m_ViewList.clear(); UMLDrag *data = 0; TQPixmap* 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 (TQMimeSource*)data; } bool UMLClipboard::paste(TQMimeSource* 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(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(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(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(TQMimeSource* 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(TQMimeSource* 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"<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(TQMimeSource* 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(TQMimeSource* 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(TQMimeSource* data) { UMLDoc *doc = UMLApp::app()->getDocument(); UMLListView *listView = UMLApp::app()->getListView(); UMLListViewItem* lvitem = dynamic_cast( listView->currentItem() ); if (!lvitem || (lvitem->getType() != Uml::lvt_Class && lvitem->getType() != Uml::lvt_Interface)) { return false; } UMLClassifier *parent = dynamic_cast(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) { TQString newName = parent->uniqChildName(Uml::ot_Attribute, obj->getName()); obj->setName(newName); } UMLAttribute *att = static_cast(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(obj); UMLOperation *exist = parent->checkOperationSignature(op->getName(), op->getParmList()); if (exist) { TQString 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( item -> firstChild() ); while( child ) { m_ItemList.append( child ); insertItemChildren( child ); child = dynamic_cast( 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(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"