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/umldrag.cpp

774 lines
25 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 "umldrag.h"
// qt/kde includes
#include <tqdom.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:
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<UMLFolder*>(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"