/*************************************************************************** * * * 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 "umldrag.h" // qt/kde includes #include #include // 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: TQCString fmt[nfmt]; TQCString subtype; TQByteArray enc[nfmt]; UMLDragPrivate() { setSubType("clip1", 0); } void setType(const TQCString& st, int index) { if (index < nfmt) { fmt[index] = st.lower(); } } void setSubType(const TQCString& 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, TQWidget* dragSource /*= 0*/, const char* name /*= 0*/) : TQDragObject(dragSource, name) { data = new UMLDragPrivate; setUMLDataClip1(objects); } UMLDrag::UMLDrag(UMLObjectList& objects, UMLListViewItemList& umlListViewItems, UMLViewList& diagrams, TQWidget* dragSource /*= 0*/, const char* name /*= 0*/ ): TQDragObject(dragSource, name) { data = new UMLDragPrivate; setUMLDataClip2(objects, umlListViewItems, diagrams); } UMLDrag::UMLDrag(UMLListViewItemList& umlListViewItems, TQWidget* dragSource /*= 0*/, const char* name /*= 0*/ ): TQDragObject(dragSource, name) { data = new UMLDragPrivate; setUMLDataClip3(umlListViewItems); } UMLDrag::UMLDrag(UMLObjectList& objects, UMLWidgetList& widgets, AssociationWidgetList& associationDatas, TQPixmap& pngImage, Uml::Diagram_Type dType, TQWidget * dragSource /*= 0*/, const char * name /*= 0*/ ): TQDragObject(dragSource, name) { data = new UMLDragPrivate; setUMLDataClip4(objects, widgets, associationDatas, pngImage, dType); } UMLDrag::UMLDrag(UMLObjectList& objects, int, TQWidget* /*dragSource = 0*/, const char* /*name = 0*/ ) { data = new UMLDragPrivate; setUMLDataClip5(objects); } UMLDrag::UMLDrag(TQWidget* dragSource /*= 0*/, const char * name /*= 0*/ ): TQDragObject(dragSource, name) { data = new UMLDragPrivate; } UMLDrag::~UMLDrag() { delete data; } void UMLDrag::setSubType(const TQCString& string, int index) { data->setSubType(string, index); } void UMLDrag::setEncodedData(const TQByteArray& encodedData, int index) { data->enc[index] = encodedData.copy(); } TQByteArray UMLDrag::encodedData(const char* dataName) const { TQString str(dataName); for (int i = 0; i < 4; i++) { if ( !qstricmp(dataName,data->fmt[i]) ) { return data->enc[i]; } } return TQByteArray(); } const char* UMLDrag::format(int index) const { char* result = (char*)data->format(index); return result; } void UMLDrag::setUMLDataClip1(UMLObjectList& objects) { setSubType("clip1", 0); TQDomDocument domDoc; TQDomElement xmiclip = domDoc.createElement("xmiclip"); domDoc.appendChild(xmiclip); TQDomElement 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); } TQDomElement itemsTag = domDoc.createElement("umllistviewitems"); xmiclip.appendChild(itemsTag); setEncodedData(domDoc.toString().utf8(), 0); } void UMLDrag::setUMLDataClip2(UMLObjectList& objects, UMLListViewItemList& umlListViewItems, UMLViewList& diagrams) { setSubType("clip2", 0); TQDomDocument domDoc; TQDomElement xmiclip = domDoc.createElement("xmiclip"); domDoc.appendChild(xmiclip); TQDomElement 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); } TQDomElement 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); } TQDomElement 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); TQDomDocument domDoc; TQDomElement xmiclip = domDoc.createElement("xmiclip"); domDoc.appendChild(xmiclip); TQDomElement 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, TQPixmap& pngImage, Uml::Diagram_Type dType ) { setSubType("clip4", 0); TQDomDocument domDoc; TQDomElement xmiclip = domDoc.createElement("xmiclip"); xmiclip.setAttribute("diagramtype", dType); domDoc.appendChild(xmiclip); TQDomElement 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); } TQDomElement 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); } TQDomElement 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); } TQDomElement itemsTag = domDoc.createElement("umllistviewitems"); xmiclip.appendChild(itemsTag); setEncodedData(domDoc.toString().utf8(), 0); data->setType("image/PNG", 1); long l_size = (pngImage.convertToImage()).numBytes(); TQByteArray clipdata; clipdata.resize(l_size); TQDataStream clipstream(clipdata, IO_WriteOnly); clipstream << pngImage; setEncodedData(clipdata, 1); } void UMLDrag::setUMLDataClip5(UMLObjectList& objects) { setSubType("clip5", 0); TQDomDocument domDoc; TQDomElement xmiclip = domDoc.createElement("xmiclip"); domDoc.appendChild(xmiclip); TQDomElement 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); } TQDomElement itemsTag = domDoc.createElement("umllistviewitems"); xmiclip.appendChild(itemsTag); setEncodedData(domDoc.toString().utf8(), 0); } bool UMLDrag::decodeClip1(const TQMimeSource* mimeSource, UMLObjectList& objects) { UMLDoc* doc = UMLApp::app()->getDocument(); if ( !mimeSource->provides("application/x-uml-clip1") ) { return false; } TQByteArray payload = mimeSource->encodedData("application/x-uml-clip1"); if ( !payload.size() ) { return false; } TQString xmiClip = TQString::fromUtf8(payload); TQString error; int line; TQDomDocument domDoc; if( !domDoc.setContent(xmiClip, false, &error, &line) ) { kWarning() << "Can't set content:" << error << " Line:" << line << endl; return false; } TQDomNode xmiClipNode = domDoc.firstChild(); TQDomElement 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 TQDomNode objectsNode = xmiClipNode.firstChild(); TQDomNode objectElement = objectsNode.firstChild(); TQDomElement 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; TQString 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(); TQString 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 TQMimeSource* mimeSource, UMLObjectList& objects, UMLListViewItemList& umlListViewItems, UMLViewList& diagrams) { if ( !mimeSource->provides("application/x-uml-clip2") ) { return false; } TQByteArray payload = mimeSource->encodedData("application/x-uml-clip2"); if ( !payload.size() ) { return false; } TQString xmiClip = TQString::fromUtf8(payload); TQString error; int line; TQDomDocument domDoc; if( !domDoc.setContent(xmiClip, false, &error, &line) ) { kWarning() << "Can't set content:" << error << " Line:" << line << endl; return false; } TQDomNode xmiClipNode = domDoc.firstChild(); TQDomElement root = xmiClipNode.toElement(); if ( root.isNull() ) { return false; } // make sure it is an XMI clip if ( root.tagName() != "xmiclip" ) { return false; } //UMLObjects TQDomNode objectsNode = xmiClipNode.firstChild(); TQDomNode objectElement = objectsNode.firstChild(); TQDomElement 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; TQString 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) TQDomNode umlviewsNode = objectsNode.nextSibling(); TQDomNode diagramNode = umlviewsNode.firstChild(); TQDomElement diagramElement = diagramNode.toElement(); if ( diagramElement.isNull() ) { kWarning() << "no diagrams in XMI clip" << endl; return false; } UMLListView *listView = UMLApp::app()->getListView(); while ( !diagramElement.isNull() ) { TQString 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(po); UMLView* view = new UMLView(f); view->loadFromXMI(diagramElement); diagrams.append(view); diagramNode = diagramNode.nextSibling(); diagramElement = diagramNode.toElement(); } //listviewitems TQDomNode listItemNode = umlviewsNode.nextSibling(); TQDomNode listItems = listItemNode.firstChild(); TQDomElement 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 TQMimeSource* mimeSource, LvTypeAndID_List& typeAndIdList) { if ( !mimeSource->provides("application/x-uml-clip3") ) { return false; } TQByteArray payload = mimeSource->encodedData("application/x-uml-clip3"); if ( !payload.size() ) { return false; } TQTextStream clipdata(payload, IO_ReadOnly); TQString xmiClip = TQString::fromUtf8(payload); TQString error; int line; TQDomDocument domDoc; if( !domDoc.setContent(xmiClip, false, &error, &line) ) { kWarning() << "getClip3Type: Can't set content:" << error << " Line:" << line << endl; return false; } TQDomNode xmiClipNode = domDoc.firstChild(); TQDomElement root = xmiClipNode.toElement(); if ( root.isNull() ) { return false; } // make sure it is an XMI clip if (root.tagName() != "xmiclip") { return false; } TQDomNode listItemNode = xmiClipNode.firstChild(); TQDomNode listItems = listItemNode.firstChild(); TQDomElement listItemElement = listItems.toElement(); if ( listItemElement.isNull() ) { kWarning() << "getClip3Type: no listitems in XMI clip" << endl; return false; } while ( !listItemElement.isNull() ) { TQString typeStr = listItemElement.attribute( "type", "-1" ); if (typeStr == "-1") { kDebug() << "getClip3Type: bad type" << endl; return false; } TQString 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 TQMimeSource* mimeSource, UMLListViewItemList& umlListViewItems, const UMLListView* parentListView){ if ( !mimeSource->provides("application/x-uml-clip3") ) { return false; } TQByteArray payload = mimeSource->encodedData("application/x-uml-clip3"); if ( !payload.size() ) { return false; } TQTextStream clipdata(payload, IO_ReadOnly); TQString xmiClip = TQString::fromUtf8(payload); TQString error; int line; TQDomDocument domDoc; if( !domDoc.setContent(xmiClip, false, &error, &line) ) { kWarning() << "Can't set content:" << error << " Line:" << line << endl; return false; } TQDomNode xmiClipNode = domDoc.firstChild(); TQDomElement root = xmiClipNode.toElement(); if ( root.isNull() ) { return false; } // make sure it is an XMI clip if (root.tagName() != "xmiclip") { return false; } //listviewitems TQDomNode listItemNode = xmiClipNode.firstChild(); TQDomNode listItems = listItemNode.firstChild(); TQDomElement 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. TQString 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 TQMimeSource* mimeSource, UMLObjectList& objects, UMLWidgetList& widgets, AssociationWidgetList& associations, Uml::Diagram_Type & dType) { if ( !mimeSource->provides("application/x-uml-clip4") ) { return false; } TQByteArray payload = mimeSource->encodedData("application/x-uml-clip4"); if ( !payload.size() ) { return false; } TQString xmiClip = TQString::fromUtf8(payload); TQString error; int line; TQDomDocument domDoc; if( !domDoc.setContent(xmiClip, false, &error, &line) ) { kWarning() << "Can't set content:" << error << " Line:" << line << endl; return false; } TQDomNode xmiClipNode = domDoc.firstChild(); TQDomElement 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 TQDomNode objectsNode = xmiClipNode.firstChild(); TQDomNode objectElement = objectsNode.firstChild(); TQDomElement element = objectElement.toElement(); while ( !element.isNull() ) { UMLObject* pObject = 0; TQString 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 TQDomNode widgetsNode = objectsNode.nextSibling(); TQDomNode widgetNode = widgetsNode.firstChild(); TQDomElement 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 TQDomNode associationWidgetsNode = widgetsNode.nextSibling(); TQDomNode associationWidgetNode = associationWidgetsNode.firstChild(); TQDomElement 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 TQMimeSource* mimeSource, UMLObjectList& objects, UMLClassifier* newParent) { if ( !mimeSource->provides("application/x-uml-clip5") ) { return false; } TQByteArray payload = mimeSource->encodedData("application/x-uml-clip5"); if ( !payload.size() ) { return false; } TQString xmiClip = TQString::fromUtf8(payload); TQString error; int line; TQDomDocument domDoc; if( !domDoc.setContent(xmiClip, false, &error, &line) ) { kWarning() << "Can't set content:" << error << " Line:" << line << endl; return false; } TQDomNode xmiClipNode = domDoc.firstChild(); TQDomElement root = xmiClipNode.toElement(); if ( root.isNull() ) { return false; } // make sure it is an XMI clip if (root.tagName() != "xmiclip") { return false; } //UMLObjects TQDomNode objectsNode = xmiClipNode.firstChild(); TQDomNode objectElement = objectsNode.firstChild(); TQDomElement element = objectElement.toElement(); if ( element.isNull() ) { return false;//return ok as it means there is no umlobjects } while ( !element.isNull() ) { TQString 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 TQMimeSource* 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"