diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | bd9e6617827818fd043452c08c606f07b78014a0 (patch) | |
tree | 425bb4c3168f9c02f10150f235d2cb998dcc6108 /umbrello/umbrello/clipboard | |
download | tdesdk-bd9e6617827818fd043452c08c606f07b78014a0.tar.gz tdesdk-bd9e6617827818fd043452c08c606f07b78014a0.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdesdk@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'umbrello/umbrello/clipboard')
-rw-r--r-- | umbrello/umbrello/clipboard/Makefile.am | 6 | ||||
-rw-r--r-- | umbrello/umbrello/clipboard/idchangelog.cpp | 97 | ||||
-rw-r--r-- | umbrello/umbrello/clipboard/idchangelog.h | 126 | ||||
-rw-r--r-- | umbrello/umbrello/clipboard/umlclipboard.cpp | 694 | ||||
-rw-r--r-- | umbrello/umbrello/clipboard/umlclipboard.h | 194 | ||||
-rw-r--r-- | umbrello/umbrello/clipboard/umldrag.cpp | 773 | ||||
-rw-r--r-- | umbrello/umbrello/clipboard/umldrag.h | 223 |
7 files changed, 2113 insertions, 0 deletions
diff --git a/umbrello/umbrello/clipboard/Makefile.am b/umbrello/umbrello/clipboard/Makefile.am new file mode 100644 index 00000000..91dc58f7 --- /dev/null +++ b/umbrello/umbrello/clipboard/Makefile.am @@ -0,0 +1,6 @@ +INCLUDES = -I$(top_builddir)/umbrello/umbrello/dialogs $(all_includes) + +METASOURCES = AUTO + +noinst_LTLIBRARIES = libclipboard.la +libclipboard_la_SOURCES = umldrag.cpp umlclipboard.cpp idchangelog.cpp diff --git a/umbrello/umbrello/clipboard/idchangelog.cpp b/umbrello/umbrello/clipboard/idchangelog.cpp new file mode 100644 index 00000000..1521c1cc --- /dev/null +++ b/umbrello/umbrello/clipboard/idchangelog.cpp @@ -0,0 +1,97 @@ +/*************************************************************************** + * * + * 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> * + ***************************************************************************/ + +#include "idchangelog.h" + +#include <kdebug.h> + +IDChangeLog::IDChangeLog() {} + +IDChangeLog::IDChangeLog(const IDChangeLog& Other) { + m_LogArray = Other.m_LogArray; +} + +IDChangeLog::~IDChangeLog() {} + +IDChangeLog& IDChangeLog::operator=(const IDChangeLog& Other) { + m_LogArray = Other.m_LogArray; + + return *this; +} + +bool IDChangeLog::operator==(const IDChangeLog& /*Other*/) { + /*It needs to be Implemented*/ + return false; +} + +Uml::IDType IDChangeLog::findNewID(Uml::IDType OldID) { + uint count = m_LogArray.size(); + for(uint i = 0; i < count; i++) { + if((m_LogArray.point(i)).y() == OldID) { + return (m_LogArray.point(i)).x(); + } + } + + return Uml::id_None; +} + +IDChangeLog& IDChangeLog::operator+=(const IDChangeLog& Other) { + //m_LogArray.putpoints(m_LogArray.size(), Other.m_LogArray.size(), Other) + uint count = Other.m_LogArray.size(); + for(uint i = 0; i < count; i++) { + addIDChange((Other.m_LogArray.point(i)).y(), (Other.m_LogArray.point(i)).x()); + } + + return *this; +} + +void IDChangeLog::addIDChange(Uml::IDType OldID, Uml::IDType NewID) { + uint pos; + if(!findIDChange(OldID, NewID, pos)) { + pos = m_LogArray.size(); + m_LogArray.resize(pos + 1); + m_LogArray.setPoint(pos, NewID, OldID); + } else { + m_LogArray.setPoint(pos, NewID, OldID); + } +} + +Uml::IDType IDChangeLog::findOldID(Uml::IDType NewID) { + uint count = m_LogArray.size(); + for(uint i = 0; i < count; i++) { + if((m_LogArray.point(i)).x() == NewID) { + return (m_LogArray.point(i)).y(); + } + } + + return Uml::id_None; +} + +bool IDChangeLog::findIDChange(Uml::IDType OldID, Uml::IDType NewID, uint& pos) { + uint count = m_LogArray.size(); + for(uint i = 0; i < count; i++) { + if(((m_LogArray.point(i)).y() == OldID) && ((m_LogArray.point(i)).x() == NewID)) { + pos = i; + return true; + } + } + + return false; +} + +void IDChangeLog::removeChangeByNewID(Uml::IDType OldID) { + uint count = m_LogArray.size(); + for(uint i = 0; i < count; i++) { + if((m_LogArray.point(i)).y() == OldID) { + m_LogArray.setPoint(i, Uml::id_None, OldID); + } + } +} diff --git a/umbrello/umbrello/clipboard/idchangelog.h b/umbrello/umbrello/clipboard/idchangelog.h new file mode 100644 index 00000000..1d92cd0d --- /dev/null +++ b/umbrello/umbrello/clipboard/idchangelog.h @@ -0,0 +1,126 @@ +/*************************************************************************** + * * + * 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-2006 * + * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> * + ***************************************************************************/ + +#ifndef IDCHANGELOG_H +#define IDCHANGELOG_H + + +/** + * This class contains all the ID translations done for each + * UMLObject pasted. It contains for each old id its new + * assigned id. + * + * @author Gustavo Madrigal + * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org + */ + +#include <qstring.h> +#include <qvaluevector.h> + +#include "../umlnamespace.h" + +class IDChangeLog { +public: + /** + * Constructor. + */ + IDChangeLog(); + + /** + * Copy constructor. + */ + IDChangeLog(const IDChangeLog& Other); + + /** + * Deconstructor. + */ + ~IDChangeLog(); + + /** + * Overloaded '=' operator. + */ + IDChangeLog& operator=(const IDChangeLog& Other); + + /** + * Overloaded '==' operator. + */ + bool operator==(const IDChangeLog& Other); + + /** + * Adds a new ID Change to the log. + */ + void addIDChange(Uml::IDType OldID, Uml::IDType NewID); + + /** + * Appends another IDChangeLog to this instance of IDChangeLog and + * returns a reference to itself. + */ + IDChangeLog& operator+=(const IDChangeLog& Other); + + /** + * Returns the new assigned ID of the object that had OldID as its + * previous id. + */ + Uml::IDType findNewID(Uml::IDType OldID); + + /** + * Returns the old ID of an UMLobject given its new one. + */ + Uml::IDType findOldID(Uml::IDType NewID); + + /** + * Removes a change giving an New ID. + */ + void removeChangeByNewID( Uml::IDType OldID); + + enum SpecialIDs + { + NullID = -1000 ///< An impossible id value. + }; + +private: + /** + * Each change is a Point (x=newID, y=oldID) + */ + class Point { + public: + Point() + {} + Point(const Uml::IDType &x, const Uml::IDType &y) + : m_x(x), m_y(y) + {} + virtual ~Point() {} + void setX(const Uml::IDType &x) { m_x = x; } + Uml::IDType x() const { return m_x; } + void setY(const Uml::IDType &y) { m_y = y; } + Uml::IDType y() const { return m_y; } + private: + Uml::IDType m_x, m_y; + }; +class PointArray : QValueVector<Point> { + public: + void setPoint(uint i, const Uml::IDType &x, const Uml::IDType &y) { + Point point(x, y); + QValueVector<Point>::at(i) = point; + } + const Point& point( uint i ) const { return QValueVector<Point>::at(i); } + uint size() const { return QValueVector<Point>::size(); } + bool resize( uint size ) { QValueVector<Point>::resize(size); return true; } + }; + PointArray m_LogArray; + + /** + * Finds a specific change in the log. + */ + bool findIDChange(Uml::IDType OldID, Uml::IDType NewID, uint& pos); +}; + +#endif 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" diff --git a/umbrello/umbrello/clipboard/umlclipboard.h b/umbrello/umbrello/clipboard/umlclipboard.h new file mode 100644 index 00000000..9be92111 --- /dev/null +++ b/umbrello/umbrello/clipboard/umlclipboard.h @@ -0,0 +1,194 @@ +/*************************************************************************** + * * + * 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-2006 * + * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> * + ***************************************************************************/ + +#ifndef UMLCLIPBOARD_H +#define UMLCLIPBOARD_H + +#include "../associationwidgetlist.h" +#include "../umlobjectlist.h" +#include "../umllistviewitemlist.h" +#include "../umllistviewitem.h" +#include "../umlviewlist.h" +#include "../umlwidgetlist.h" + +class IDChangeLog; +class QMimeSource; + +/** + * This class manages the uml's interaction with the KDE + * Clipboard. It makes possible to copy stuff from one uml + * instance to another one. + * + * @short Clipboard management class + * @author Gustavo Madrigal + * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org + */ +class UMLClipboard : public QObject { + Q_OBJECT +public: + /** + * Constructor. + */ + UMLClipboard(); + + /** + * Deconstructor. + */ + virtual ~UMLClipboard(); + + /** + * Inserts the clipboard's contents. + * + * @param Data Pointer to the MIME format clipboard data. + * @return True for successful operation. + */ + bool paste(QMimeSource* Data); + + /** + * Copies the selected stuff from the list view or current diagram + * to a QMimeSource ready to be put in the clipboard. + * + * @return Pointer to the created clipboard data. + */ + QMimeSource* copy(bool fromView = false); + + /// Enumeration that codes the different types of UML clips. + enum UMLCopyType + { + clip1 = 1, ///<UMLObjects (not diagrams) + clip2 = 2, ///<UMLObjects, UMLListViewItems (not diagrams) and diagrams + clip3 = 3, ///<UMLListViewItems (not diagrams) + clip4 = 4, ///<UMLObjects, Associations and UMLWidgets + clip5 = 5 ///<Only Attributes and Operations + }; + +private: + /** + * Cleans the list of associations taking out the ones + * that point to an object not in m_ObjectList. + * + * @param associations The list of associations to process. + */ + void CleanAssociations(AssociationWidgetList& associations); + + /** + * If clipboard has mime type application/x-uml-clip1, + * pastes the data from the clipboard. + * + * @param data Pointer to the source clip. + * @return True for successful operation. + */ + bool pasteClip1(QMimeSource* data); + + /** + * If clipboard has mime type application/x-uml-clip2, + * pastes the data from the clipboard. + * + * @param data Pointer to the source clip. + * @return True for successful operation. + */ + bool pasteClip2(QMimeSource* data); + + /** + * If clipboard has mime type application/x-uml-clip3, + * pastes the data from the clipboard. + * + * @param data Pointer to the source clip. + * @return True for successful operation. + */ + bool pasteClip3(QMimeSource* data); + + /** + * If clipboard has mime type application/x-uml-clip4, + * pastes the data from the clipboard. + * + * @param data Pointer to the source clip. + * @return True for successful operation. + */ + bool pasteClip4(QMimeSource* data); + + /** + * If clipboard has mime type application/x-uml-clip5, + * pastes the data from the clipboard. + * + * @param data Pointer to the source clip. + * @return True for successful operation. + */ + bool pasteClip5(QMimeSource* data); + + /** + * When pasting widgets see if they can be pasted on + * different diagram types. Will return true if all the + * widgets to be pasted can be. At the moment this only + * includes NoteWidgets and lines of text. + * + * @param widgetList List of widgets to examine. + * @return True if all widgets can be put on different diagrams. + */ + bool checkPasteWidgets(UMLWidgetList & widgetList); + + UMLObjectList m_ObjectList; + UMLListViewItemList m_ItemList; + UMLWidgetList m_WidgetList; + AssociationWidgetList m_AssociationList; + UMLViewList m_ViewList; + UMLCopyType m_type; ///< Type of copy operation to perform. + +private: + /** + * Fills the member lists with all the objects and other + * stuff to be copied to the clipboard. + */ + bool fillSelectionLists(UMLListViewItemList& SelectedItems); + + /** + * Checks the whole list to determine the copy action + * type to be * performed, sets the type in the m_type + * member variable. + */ + void setCopyType(UMLListViewItemList& SelectedItems); + + /** + * Searches the child items of a UMLListViewItem to + * establish which Copy type is to be perfomed. + */ + void checkItemForCopyType(UMLListViewItem* Item, + bool& WithDiagrams, + bool& WithObjects, + bool& OnlyAttsOps); + + /** + * Adds the children of a UMLListViewItem to m_ItemList. + */ + bool insertItemChildren(UMLListViewItem* Item, + UMLListViewItemList& SelectedItems); + + /** + * Inserts the data of the children of the given item + * into the item data list. Used for clip type 4. Used + * to make * sure classes have all the attributes and + * operations saved. + */ + bool insertItemChildren(UMLListViewItem* item); + + /** + * Pastes the children of a UMLListViewItem (The Parent) + */ + bool pasteChildren(UMLListViewItem* parent, IDChangeLog *chgLog); + + /** + * Gives a `sorry' message box if you're pasting an item which + * already exists and can't be duplicated. + */ + void pasteItemAlreadyExists(); +}; + +#endif diff --git a/umbrello/umbrello/clipboard/umldrag.cpp b/umbrello/umbrello/clipboard/umldrag.cpp new file mode 100644 index 00000000..f9fa6629 --- /dev/null +++ b/umbrello/umbrello/clipboard/umldrag.cpp @@ -0,0 +1,773 @@ +/*************************************************************************** + * * + * 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 "umldrag.h" + +// qt/kde includes +#include <qdom.h> +#include <kdebug.h> + +// local includes +#include "idchangelog.h" +#include "../uml.h" +#include "../umldoc.h" +#include "../umlview.h" +#include "../umlobject.h" +#include "../folder.h" +#include "../classifier.h" +#include "../umlwidget.h" +#include "../umllistview.h" +#include "../umllistviewitem.h" +#include "../associationwidget.h" +#include "../object_factory.h" +#include "../model_utils.h" + +#define nfmt 4 +class UMLDragPrivate { +public: + QCString fmt[nfmt]; + QCString subtype; + QByteArray enc[nfmt]; + + UMLDragPrivate() { + setSubType("clip1", 0); + } + + void setType(const QCString& st, int index) { + if (index < nfmt) { + fmt[index] = st.lower(); + } + } + + void setSubType(const QCString& st, int index) { + if (index < nfmt) { + subtype = st.lower(); + fmt[index] = "application/x-uml-"; + fmt[index].append(subtype); + } + } + + const char* format(int i) const { + if(i < nfmt) { + return fmt[i]; + } + return 0; + } +}; + +UMLDrag::UMLDrag(UMLObjectList& objects, QWidget* dragSource /*= 0*/, const char* name /*= 0*/) + : QDragObject(dragSource, name) { + data = new UMLDragPrivate; + setUMLDataClip1(objects); +} + +UMLDrag::UMLDrag(UMLObjectList& objects, UMLListViewItemList& umlListViewItems, UMLViewList& diagrams, + QWidget* dragSource /*= 0*/, const char* name /*= 0*/ ): QDragObject(dragSource, name) { + data = new UMLDragPrivate; + setUMLDataClip2(objects, umlListViewItems, diagrams); +} + +UMLDrag::UMLDrag(UMLListViewItemList& umlListViewItems, QWidget* dragSource /*= 0*/, + const char* name /*= 0*/ ): QDragObject(dragSource, name) { + data = new UMLDragPrivate; + setUMLDataClip3(umlListViewItems); +} + +UMLDrag::UMLDrag(UMLObjectList& objects, + UMLWidgetList& widgets, AssociationWidgetList& associationDatas, + QPixmap& pngImage, Uml::Diagram_Type dType, QWidget * dragSource /*= 0*/, + const char * name /*= 0*/ ): QDragObject(dragSource, name) { + data = new UMLDragPrivate; + setUMLDataClip4(objects, widgets, associationDatas, pngImage, dType); +} + +UMLDrag::UMLDrag(UMLObjectList& objects, int, + QWidget* /*dragSource = 0*/, const char* /*name = 0*/ ) { + data = new UMLDragPrivate; + setUMLDataClip5(objects); +} + +UMLDrag::UMLDrag(QWidget* dragSource /*= 0*/, const char * name /*= 0*/ ): QDragObject(dragSource, name) { + data = new UMLDragPrivate; +} + +UMLDrag::~UMLDrag() { + delete data; +} + +void UMLDrag::setSubType(const QCString& string, int index) { + data->setSubType(string, index); +} + +void UMLDrag::setEncodedData(const QByteArray& encodedData, int index) { + data->enc[index] = encodedData.copy(); +} + +QByteArray UMLDrag::encodedData(const char* dataName) const { + QString str(dataName); + for (int i = 0; i < 4; i++) { + if ( !qstricmp(dataName,data->fmt[i]) ) { + return data->enc[i]; + } + } + return QByteArray(); +} + +const char* UMLDrag::format(int index) const { + char* result = (char*)data->format(index); + return result; +} + +void UMLDrag::setUMLDataClip1(UMLObjectList& objects) { + setSubType("clip1", 0); + + QDomDocument domDoc; + QDomElement xmiclip = domDoc.createElement("xmiclip"); + domDoc.appendChild(xmiclip); + QDomElement objectsTag = domDoc.createElement("umlobjects"); + xmiclip.appendChild(objectsTag); + + UMLObjectListIt object_it(objects); + UMLObject* obj = 0; + while ( (obj=object_it.current()) != 0 ) { + ++object_it; + obj->saveToXMI(domDoc, objectsTag); + } + + QDomElement itemsTag = domDoc.createElement("umllistviewitems"); + xmiclip.appendChild(itemsTag); + + setEncodedData(domDoc.toString().utf8(), 0); +} + +void UMLDrag::setUMLDataClip2(UMLObjectList& objects, UMLListViewItemList& umlListViewItems, + UMLViewList& diagrams) { + setSubType("clip2", 0); + + QDomDocument domDoc; + QDomElement xmiclip = domDoc.createElement("xmiclip"); + domDoc.appendChild(xmiclip); + QDomElement objectsTag = domDoc.createElement("umlobjects"); + xmiclip.appendChild(objectsTag); + + UMLObjectListIt object_it(objects); + UMLObject* obj = 0; + while ( (obj=object_it.current()) != 0 ) { + ++object_it; + obj->saveToXMI(domDoc, objectsTag); + } + + QDomElement viewsTag = domDoc.createElement("umlviews"); + xmiclip.appendChild(viewsTag); + + UMLViewListIt diagram_it(diagrams); + UMLView* view = 0; + while ( (view=diagram_it.current()) != 0 ) { + ++diagram_it; + view->saveToXMI(domDoc, viewsTag); + } + + QDomElement itemsTag = domDoc.createElement("umllistviewitems"); + xmiclip.appendChild(itemsTag); + + UMLListViewItemListIt item_it2(umlListViewItems); + UMLListViewItem* item = 0; + while ( (item=item_it2.current()) != 0 ) { + ++item_it2; + item->saveToXMI(domDoc, itemsTag); + } + setEncodedData(domDoc.toString().utf8(), 0); +} + +void UMLDrag::setUMLDataClip3(UMLListViewItemList& umlListViewItems) { + setSubType("clip3", 0); + + QDomDocument domDoc; + QDomElement xmiclip = domDoc.createElement("xmiclip"); + domDoc.appendChild(xmiclip); + + QDomElement itemsTag = domDoc.createElement("umllistviewitems"); + xmiclip.appendChild(itemsTag); + + UMLListViewItemListIt item_it2(umlListViewItems); + UMLListViewItem* item = 0; + while ( (item=item_it2.current()) != 0 ) { + ++item_it2; + item->saveToXMI(domDoc, itemsTag); + } + setEncodedData(domDoc.toString().utf8(), 0); +} + +void UMLDrag::setUMLDataClip4(UMLObjectList& objects, UMLWidgetList& widgets, AssociationWidgetList& associations, + QPixmap& pngImage, Uml::Diagram_Type dType ) { + setSubType("clip4", 0); + + QDomDocument domDoc; + QDomElement xmiclip = domDoc.createElement("xmiclip"); + xmiclip.setAttribute("diagramtype", dType); + domDoc.appendChild(xmiclip); + QDomElement objectsTag = domDoc.createElement("umlobjects"); + xmiclip.appendChild(objectsTag); + + UMLObjectListIt object_it(objects); + UMLObject* obj = 0; + while ( (obj=object_it.current()) != 0 ) { + ++object_it; + obj->saveToXMI(domDoc, objectsTag); + } + + QDomElement widgetsTag = domDoc.createElement("widgets"); + xmiclip.appendChild(widgetsTag); + + UMLWidgetListIt widget_it(widgets); + UMLWidget* widget = 0; + while ( (widget=widget_it.current()) != 0 ) { + ++widget_it; + widget->saveToXMI(domDoc, widgetsTag); + } + + QDomElement associationWidgetsTag = domDoc.createElement("associations"); + xmiclip.appendChild(associationWidgetsTag); + + AssociationWidgetListIt associations_it(associations); + AssociationWidget* association; + while ( (association=associations_it.current()) != 0 ) { + ++associations_it; + association->saveToXMI(domDoc, associationWidgetsTag); + } + + QDomElement itemsTag = domDoc.createElement("umllistviewitems"); + xmiclip.appendChild(itemsTag); + + setEncodedData(domDoc.toString().utf8(), 0); + + data->setType("image/PNG", 1); + long l_size = (pngImage.convertToImage()).numBytes(); + QByteArray clipdata; + clipdata.resize(l_size); + QDataStream clipstream(clipdata, IO_WriteOnly); + clipstream << pngImage; + setEncodedData(clipdata, 1); +} + +void UMLDrag::setUMLDataClip5(UMLObjectList& objects) { + setSubType("clip5", 0); + + QDomDocument domDoc; + QDomElement xmiclip = domDoc.createElement("xmiclip"); + domDoc.appendChild(xmiclip); + QDomElement objectsTag = domDoc.createElement("umlobjects"); + xmiclip.appendChild(objectsTag); + + UMLObjectListIt object_it(objects); + UMLObject* obj = 0; + while ( (obj=object_it.current()) != 0 ) { + ++object_it; + obj->saveToXMI(domDoc, objectsTag); + } + + QDomElement itemsTag = domDoc.createElement("umllistviewitems"); + xmiclip.appendChild(itemsTag); + + setEncodedData(domDoc.toString().utf8(), 0); +} + +bool UMLDrag::decodeClip1(const QMimeSource* mimeSource, UMLObjectList& objects) { + UMLDoc* doc = UMLApp::app()->getDocument(); + if ( !mimeSource->provides("application/x-uml-clip1") ) { + return false; + } + QByteArray payload = mimeSource->encodedData("application/x-uml-clip1"); + if ( !payload.size() ) { + return false; + } + QString xmiClip = QString::fromUtf8(payload); + + QString error; + int line; + QDomDocument domDoc; + if( !domDoc.setContent(xmiClip, false, &error, &line) ) { + kWarning() << "Can't set content:" << error << " Line:" << line << endl; + return false; + } + QDomNode xmiClipNode = domDoc.firstChild(); + QDomElement root = xmiClipNode.toElement(); + if ( root.isNull() ) { + return false; + } + // make sure it is an XMI clip + if ( root.tagName() != "xmiclip" ) { + return false; + } + + UMLListView *listView = UMLApp::app()->getListView(); + + //UMLObjects + QDomNode objectsNode = xmiClipNode.firstChild(); + QDomNode objectElement = objectsNode.firstChild(); + QDomElement element = objectElement.toElement(); + if ( element.isNull() ) { + return false;//return ok as it means there is no umlobjects + } + UMLObject* pObject = 0; + while ( !element.isNull() ) { + pObject = 0; + QString type = element.tagName(); + if (type == "UML:Association") { + objectElement = objectElement.nextSibling(); + element = objectElement.toElement(); + continue; + } + pObject = Object_Factory::makeObjectFromXMI(type); + + if( !pObject ) { + kWarning() << "UMLDrag::decodeClip1: Given wrong type of umlobject to create: " + << type << endl; + return false; + } + pObject->setInPaste( true ); + if( !pObject->loadFromXMI( element ) ) { + kWarning() << "UMLDrag::decodeClip1: failed to load object of type " + << type << " from XMI" << endl; + delete pObject; + return false; + } + pObject->setInPaste( false ); + if (listView->startedCopy()) { + /**************************************************************** + * If the clone() methods called IDChangeLog::addIDChange(), + * we could do the following: + UMLObject *newObj = pObject->clone(); + delete pObject; + pObject = newObj; + * but since that's not currently the case we do: */ + if(!doc->assignNewIDs(pObject)) { + return false; + } + Uml::Object_Type type = pObject->getBaseType(); + QString newName = Model_Utils::uniqObjectName(type, pObject->getUMLPackage(), + pObject->getName()); + pObject->setName(newName); + /****************************************************************/ + } + + pObject->resolveRef(); + + objects.append(pObject); + objectElement = objectElement.nextSibling(); + element = objectElement.toElement(); + } + + return true; +} + +bool UMLDrag::decodeClip2(const QMimeSource* mimeSource, UMLObjectList& objects, + UMLListViewItemList& umlListViewItems, UMLViewList& diagrams) { + + if ( !mimeSource->provides("application/x-uml-clip2") ) { + return false; + } + QByteArray payload = mimeSource->encodedData("application/x-uml-clip2"); + if ( !payload.size() ) { + return false; + } + QString xmiClip = QString::fromUtf8(payload); + + QString error; + int line; + QDomDocument domDoc; + if( !domDoc.setContent(xmiClip, false, &error, &line) ) { + kWarning() << "Can't set content:" << error << " Line:" << line << endl; + return false; + } + QDomNode xmiClipNode = domDoc.firstChild(); + QDomElement root = xmiClipNode.toElement(); + if ( root.isNull() ) { + return false; + } + // make sure it is an XMI clip + if ( root.tagName() != "xmiclip" ) { + return false; + } + + //UMLObjects + QDomNode objectsNode = xmiClipNode.firstChild(); + QDomNode objectElement = objectsNode.firstChild(); + QDomElement element = objectElement.toElement(); + if ( element.isNull() ) { + return false;//return ok as it means there is no umlobjects + } + UMLObject* pObject = 0; + while ( !element.isNull() ) { + pObject = 0; + QString type = element.tagName(); + if (type != "UML:Association") { + pObject = Object_Factory::makeObjectFromXMI(type); + + if( !pObject ) { + kWarning() << "Given wrong type of umlobject to create:" << type << endl; + return false; + } + if( !pObject->loadFromXMI(element) ) { + kWarning() << "failed to load object from XMI" << endl; + return false; + } + objects.append(pObject); + } + objectElement = objectElement.nextSibling(); + element = objectElement.toElement(); + } + + //UMLViews (diagrams) + QDomNode umlviewsNode = objectsNode.nextSibling(); + QDomNode diagramNode = umlviewsNode.firstChild(); + QDomElement diagramElement = diagramNode.toElement(); + if ( diagramElement.isNull() ) { + kWarning() << "no diagrams in XMI clip" << endl; + return false; + } + UMLListView *listView = UMLApp::app()->getListView(); + while ( !diagramElement.isNull() ) { + QString type = diagramElement.attribute("type", "0"); + Uml::Diagram_Type dt = (Uml::Diagram_Type)type.toInt(); + UMLListViewItem *parent = listView->findFolderForDiagram(dt); + if (parent == NULL) + return false; + UMLObject *po = parent->getUMLObject(); + if (po == NULL || po->getBaseType() != Uml::ot_Folder) { + kError() << "UMLDrag::decodeClip2: bad parent for view" << endl; + return false; + } + UMLFolder *f = static_cast<UMLFolder*>(po); + UMLView* view = new UMLView(f); + view->loadFromXMI(diagramElement); + diagrams.append(view); + diagramNode = diagramNode.nextSibling(); + diagramElement = diagramNode.toElement(); + } + + //listviewitems + QDomNode listItemNode = umlviewsNode.nextSibling(); + QDomNode listItems = listItemNode.firstChild(); + QDomElement listItemElement = listItems.toElement(); + if ( listItemElement.isNull() ) { + kWarning() << "no listitems in XMI clip" << endl; + return false; + } + UMLListViewItem *currentItem = (UMLListViewItem*)listView->currentItem(); + while ( !listItemElement.isNull() ) { + UMLListViewItem* itemData; + if (currentItem) + itemData = new UMLListViewItem( currentItem ); + else + itemData = new UMLListViewItem( listView ); + if ( itemData->loadFromXMI(listItemElement) ) + umlListViewItems.append(itemData); + else + delete itemData; + listItems = listItems.nextSibling(); + listItemElement = listItems.toElement(); + } + return true; +} + +bool UMLDrag::getClip3TypeAndID(const QMimeSource* mimeSource, + LvTypeAndID_List& typeAndIdList) +{ + if ( !mimeSource->provides("application/x-uml-clip3") ) { + return false; + } + QByteArray payload = mimeSource->encodedData("application/x-uml-clip3"); + if ( !payload.size() ) { + return false; + } + QTextStream clipdata(payload, IO_ReadOnly); + QString xmiClip = QString::fromUtf8(payload); + + QString error; + int line; + QDomDocument domDoc; + if( !domDoc.setContent(xmiClip, false, &error, &line) ) { + kWarning() << "getClip3Type: Can't set content:" << error << " Line:" << line << endl; + return false; + } + QDomNode xmiClipNode = domDoc.firstChild(); + QDomElement root = xmiClipNode.toElement(); + if ( root.isNull() ) { + return false; + } + // make sure it is an XMI clip + if (root.tagName() != "xmiclip") { + return false; + } + + QDomNode listItemNode = xmiClipNode.firstChild(); + QDomNode listItems = listItemNode.firstChild(); + QDomElement listItemElement = listItems.toElement(); + if ( listItemElement.isNull() ) { + kWarning() << "getClip3Type: no listitems in XMI clip" << endl; + return false; + } + while ( !listItemElement.isNull() ) { + QString typeStr = listItemElement.attribute( "type", "-1" ); + if (typeStr == "-1") { + kDebug() << "getClip3Type: bad type" << endl; + return false; + } + QString idStr = listItemElement.attribute( "id", "-1" ); + if (idStr == "-1") { + kDebug() << "getClip3Type: bad id" << endl; + return false; + } + LvTypeAndID * pData = new LvTypeAndID; + pData->type = (Uml::ListView_Type)(typeStr.toInt()); + pData->id = STR2ID(idStr); + typeAndIdList.append(pData); + listItems = listItems.nextSibling(); + listItemElement = listItems.toElement(); + } + return true; +} + +bool UMLDrag::decodeClip3(const QMimeSource* mimeSource, UMLListViewItemList& umlListViewItems, + const UMLListView* parentListView){ + if ( !mimeSource->provides("application/x-uml-clip3") ) { + return false; + } + QByteArray payload = mimeSource->encodedData("application/x-uml-clip3"); + if ( !payload.size() ) { + return false; + } + QTextStream clipdata(payload, IO_ReadOnly); + QString xmiClip = QString::fromUtf8(payload); + + QString error; + int line; + QDomDocument domDoc; + if( !domDoc.setContent(xmiClip, false, &error, &line) ) { + kWarning() << "Can't set content:" << error << " Line:" << line << endl; + return false; + } + QDomNode xmiClipNode = domDoc.firstChild(); + QDomElement root = xmiClipNode.toElement(); + if ( root.isNull() ) { + return false; + } + // make sure it is an XMI clip + if (root.tagName() != "xmiclip") { + return false; + } + + //listviewitems + QDomNode listItemNode = xmiClipNode.firstChild(); + QDomNode listItems = listItemNode.firstChild(); + QDomElement listItemElement = listItems.toElement(); + if ( listItemElement.isNull() ) { + kWarning() << "no listitems in XMI clip" << endl; + return false; + } + while ( !listItemElement.isNull() ) { + // Get the ListView_Type beforehand so that we can construct an + // UMLListViewItem instance. + QString type = listItemElement.attribute( "type", "-1" ); + if (type == "-1") { + kDebug() << "Pech gehabt" << endl; + continue; + } + Uml::ListView_Type t = (Uml::ListView_Type)(type.toInt()); + UMLListViewItem* parent = parentListView->determineParentItem(t); + UMLListViewItem* itemData = new UMLListViewItem(parent); + if ( itemData->loadFromXMI(listItemElement) ) + umlListViewItems.append(itemData); + else + delete itemData; + listItems = listItems.nextSibling(); + listItemElement = listItems.toElement(); + } + return true; +} + +bool UMLDrag::decodeClip4(const QMimeSource* mimeSource, UMLObjectList& objects, + UMLWidgetList& widgets, + AssociationWidgetList& associations, Uml::Diagram_Type & dType) { + if ( !mimeSource->provides("application/x-uml-clip4") ) { + return false; + } + QByteArray payload = mimeSource->encodedData("application/x-uml-clip4"); + if ( !payload.size() ) { + return false; + } + + QString xmiClip = QString::fromUtf8(payload); + + QString error; + int line; + QDomDocument domDoc; + if( !domDoc.setContent(xmiClip, false, &error, &line) ) { + kWarning() << "Can't set content:" << error << " Line:" << line << endl; + return false; + } + QDomNode xmiClipNode = domDoc.firstChild(); + QDomElement root = xmiClipNode.toElement(); + if ( root.isNull() ) { + return false; + } + // make sure it is an XMI clip + if ( root.tagName() != "xmiclip" ) { + return false; + } + + dType = (Uml::Diagram_Type)(root.attribute("diagramtype", "0").toInt()); + + //UMLObjects + QDomNode objectsNode = xmiClipNode.firstChild(); + QDomNode objectElement = objectsNode.firstChild(); + QDomElement element = objectElement.toElement(); + while ( !element.isNull() ) { + UMLObject* pObject = 0; + QString type = element.tagName(); + //FIXME associations don't load + if (type == "UML:Association") + continue; + pObject = Object_Factory::makeObjectFromXMI(type); + + if ( !pObject ) { + kWarning() << "Given wrong type of umlobject to create: " << type << endl; + return false; + } + + if ( !pObject->loadFromXMI( element ) ) { + kWarning() << "failed to load object from XMI" << endl; + return false; + } + + objects.append(pObject); + objectElement = objectElement.nextSibling(); + element = objectElement.toElement(); + } + + //widgets + QDomNode widgetsNode = objectsNode.nextSibling(); + QDomNode widgetNode = widgetsNode.firstChild(); + QDomElement widgetElement = widgetNode.toElement(); + if ( widgetElement.isNull() ) { + kWarning() << "no widgets in XMI clip" << endl; + return false; + } + + UMLView *view = UMLApp::app()->getCurrentView(); + while ( !widgetElement.isNull() ) { + + UMLWidget* widget = view->loadWidgetFromXMI(widgetElement); + if (widget) + widgets.append(widget); + + widgetNode = widgetNode.nextSibling(); + widgetElement = widgetNode.toElement(); + } + + //AssociationWidgets + QDomNode associationWidgetsNode = widgetsNode.nextSibling(); + QDomNode associationWidgetNode = associationWidgetsNode.firstChild(); + QDomElement associationWidgetElement = associationWidgetNode.toElement(); + while ( !associationWidgetElement.isNull() ) { + AssociationWidget* associationWidget = new AssociationWidget(view); + if (associationWidget->loadFromXMI(associationWidgetElement, widgets)) + associations.append(associationWidget); + else { + //associationWidget->cleanup(); + delete associationWidget; + } + associationWidgetNode = associationWidgetNode.nextSibling(); + associationWidgetElement = associationWidgetNode.toElement(); + } + + return true; +} + +bool UMLDrag::decodeClip5(const QMimeSource* mimeSource, UMLObjectList& objects, + UMLClassifier* newParent) { + if ( !mimeSource->provides("application/x-uml-clip5") ) { + return false; + } + QByteArray payload = mimeSource->encodedData("application/x-uml-clip5"); + if ( !payload.size() ) { + return false; + } + QString xmiClip = QString::fromUtf8(payload); + + QString error; + int line; + QDomDocument domDoc; + if( !domDoc.setContent(xmiClip, false, &error, &line) ) { + kWarning() << "Can't set content:" << error << " Line:" << line << endl; + return false; + } + QDomNode xmiClipNode = domDoc.firstChild(); + QDomElement root = xmiClipNode.toElement(); + if ( root.isNull() ) { + return false; + } + // make sure it is an XMI clip + if (root.tagName() != "xmiclip") { + return false; + } + + //UMLObjects + QDomNode objectsNode = xmiClipNode.firstChild(); + QDomNode objectElement = objectsNode.firstChild(); + QDomElement element = objectElement.toElement(); + if ( element.isNull() ) { + return false;//return ok as it means there is no umlobjects + } + while ( !element.isNull() ) { + QString type = element.tagName(); + UMLClassifierListItem *pObject = newParent->makeChildObject(type); + if( !pObject ) { + kWarning() << "Given wrong type of umlobject to create:" << type << endl; + return false; + } + if( !pObject->loadFromXMI( element ) ) { + kWarning() << "failed to load object from XMI" << endl; + return false; + } + pObject->resolveRef(); + objects.append(pObject); + objectElement = objectElement.nextSibling(); + element = objectElement.toElement(); + } + + return true; +} + +int UMLDrag::getCodingType(const QMimeSource* mimeSource) { + int result = 0; + if (mimeSource->provides("application/x-uml-clip1") ) { + result = 1; + } + if (mimeSource->provides("application/x-uml-clip2") ) { + result = 2; + } + if (mimeSource->provides("application/x-uml-clip3") ) { + result = 3; + } + if (mimeSource->provides("application/x-uml-clip4") ) { + result = 4; + } + if (mimeSource->provides("application/x-uml-clip5") ) { + result = 5; + } + + return result; +} + +#include "umldrag.moc" diff --git a/umbrello/umbrello/clipboard/umldrag.h b/umbrello/umbrello/clipboard/umldrag.h new file mode 100644 index 00000000..a56a138e --- /dev/null +++ b/umbrello/umbrello/clipboard/umldrag.h @@ -0,0 +1,223 @@ +/*************************************************************************** + * * + * 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-2006 * + * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> * + ***************************************************************************/ + +#ifndef UMLDRAG_H +#define UMLDRAG_H + +#include <qdragobject.h> +#include <qobject.h> +#include <qptrlist.h> + +#include "../umllistviewitemlist.h" +#include "../associationwidgetlist.h" +#include "../umlobjectlist.h" +#include "../umlviewlist.h" +#include "../umlwidgetlist.h" +#include "../umlnamespace.h" + +/** + * This class provides encoding and decoding for the uml data that will be used + * in a drag and drop operation or in a copy or paste operation. + * + * @author Gustavo Madrigal, Jonathan Riddell (XMI conversion) + * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org + */ + +class UMLListView; +class UMLDragPrivate; +class UMLClassifier; + +class Q_EXPORT UMLDrag : public QDragObject { + Q_OBJECT + UMLDragPrivate* data; +public: + + /** + * For use when the user selects only UML Objects from + * the ListView but no diagrams to be copied, Mime type = + * "application/x-uml-clip1 + */ + explicit UMLDrag(UMLObjectList& Objects,QWidget* dragSource = 0, const char* name = 0 ); + + /** + * For use when the user selects UML Object and Diagrams + * from the ListView to be copied, Mime type = + * "application/x-uml-clip2 + */ + UMLDrag(UMLObjectList &Objects, UMLListViewItemList& UMLListViewItems, + UMLViewList& Diagrams, QWidget * dragSource = 0, const char * name = 0 ); + + /** + * For use when the user selects only empty folders from + * the ListView to be copied, Mime type = + * "application/x-uml-clip3 + */ + explicit UMLDrag(UMLListViewItemList& UMLListViewItems, QWidget* dragSource = 0, + const char* name = 0 ); + + /* + * For use when the user selects UMLObjects from a + * Diagram. The Selected widegets and the relationships * + * between only selected widgets will be copied and also + * its respective ListView Items, Mime type = + * "application/x-uml-clip4 + */ + UMLDrag(UMLObjectList& Objects, UMLWidgetList& Widgets, AssociationWidgetList& Associations, + QPixmap& PngImage, Uml::Diagram_Type dType, QWidget* dragSource = 0, + const char* name = 0 ); + + /** + * For use when the user selects only Operations and/or + * Attributes from the ListView, Mime type = + * "application/x-uml-clip5 + */ + UMLDrag(UMLObjectList& Objects, int, QWidget* dragSource = 0, const char* name = 0); + + /** + * Constructor + */ + explicit UMLDrag(QWidget* dragSource = 0, const char* name = 0); + + /** + * Deconstructor + */ + ~UMLDrag(); + + /** + * For use when the user selects only UMLObjects from the + * ListView but no diagrams to be copied + */ + void setUMLDataClip1(UMLObjectList& Objects); + + /** + * For use when the user selects UML Object and Diagrams + * from the ListView to be copied + */ + void setUMLDataClip2(UMLObjectList& Objects, UMLListViewItemList& UMLListViewItems, + UMLViewList& Diagrams); + + /** + * For use when the user selects only empty folders from the ListView + * to be copied. + */ + void setUMLDataClip3(UMLListViewItemList& UMLListViewItems); + + /** + * For use when the user selects UML Objects from a + * Diagram. The Selected widegets and the relationships + * between only selected widgets will be copied and also + * its respective ListView Items + */ + void setUMLDataClip4(UMLObjectList& Objects, + UMLWidgetList& WidgetDatas, + AssociationWidgetList& Associations, QPixmap& PngImage, + Uml::Diagram_Type dType); + + /** + * For use when the user selects only Attirbutes and/or + * Operation from the ListView + */ + void setUMLDataClip5(UMLObjectList& Objects); + + /** + * Sets the type of the clip to "application/x-uml-" + sub + * sub should be clip[1-5] + */ + virtual void setSubType(const QCString& sub, int index); + + /** + * Sets the data in the clip + */ + virtual void setEncodedData(const QByteArray&, int index); + + /** + * Returns the type set by setSubType + */ + const char* format(int index) const; + + /** + * Returns the encoded data of the given type + * + * @param dataName the name of the data type to return + */ + virtual QByteArray encodedData(const char* dataName) const; + + /** + * For use when the user selects only UML Objects + * from the ListView but no diagrams to be + * copied, decodes Mime type = + * "application/x-uml-clip1 + */ + static bool decodeClip1(const QMimeSource* mimeSource, UMLObjectList& objects); + + /** + * For use when the user selects UML Object and Diagrams + * from the ListView to be copied, decodes Mime type = + * "application/x-uml-clip2 + */ + static bool decodeClip2(const QMimeSource* mimeSource, UMLObjectList& objects, + UMLListViewItemList& umlListViewItems, + UMLViewList& diagrams); + + /** + * For use when the user selects UMLObjects from + * the ListView to be copied, decodes Mime * type = + * "application/x-uml-clip3 + */ + static bool decodeClip3(const QMimeSource* mimeSource, + UMLListViewItemList& umlListViewItems, + const UMLListView* parentListView=0); + + struct LvTypeAndID { + Uml::ListView_Type type; + Uml::IDType id; + }; + typedef QPtrList<LvTypeAndID> LvTypeAndID_List; + typedef QPtrListIterator<LvTypeAndID> LvTypeAndID_It; + + /** + * Return just the LvTypeAndID of a Clip3. + * + * @param mimeSource The encoded source. + * @param typeAndIdList The LvTypeAndID_List decoded from the source. + * @return True if decoding was successful. + */ + static bool getClip3TypeAndID(const QMimeSource* mimeSource, + LvTypeAndID_List& typeAndIdList); + + /** + * For use when the user selects UML Objects from a + * Diagram. The Selected widegets and the relationships + * between only * selected widgets will be copied and + * also its respective ListView Items, * decodes Mime + * type = "application/x-uml-clip4 + */ + static bool decodeClip4(const QMimeSource* mimeSource, UMLObjectList& objects, + UMLWidgetList& widgets, + AssociationWidgetList& associations, + Uml::Diagram_Type & dType); + + /** + * For use when the user selects only Attributes and/or + * Operations from the ListView * copied, decodes Mime + * type = "application/x-uml-clip5 + */ + static bool decodeClip5(const QMimeSource* mimeSource, UMLObjectList& objects, + UMLClassifier *newParent); + + /** + * Converts application/x-uml-clip[1-5] clip type to an integer + */ + static int getCodingType(const QMimeSource* mimeSource); + +}; + +#endif |