You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdesdk/umbrello/umbrello/clipboard/umlclipboard.cpp

695 lines
22 KiB

/***************************************************************************
* *
* 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 <tdemessagebox.h>
#include <tdelocale.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() {
}
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<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(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"<<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(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<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) {
TQString 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) {
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<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"