/*************************************************************************** * * * 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) 2003 Luis De la Parra * * copyright (C) 2004-2007 * * Umbrello UML Modeller Authors * ***************************************************************************/ #include "refactoringassistant.h" #include "../umlnamespace.h" #include "../umldoc.h" #include "../classifier.h" #include "../attribute.h" #include "../operation.h" #include "../dialogs/classpropdlg.h" #include "../dialogs/umloperationdialog.h" #include "../dialogs/umlattributedialog.h" #include "../object_factory.h" #include #include #include #include #include #include #include #include using std::type_info; RefactoringAssistant::RefactoringAssistant( UMLDoc *doc, UMLClassifier *obj, TQWidget *parent, const char *name ): KListView( parent, name ), m_doc( doc ) { loadPixmaps(); setRootIsDecorated( true ); setAcceptDrops( true ); setDropVisualizer( false ); setItemsMovable( true ); setSelectionModeExt( Single ); setShowToolTips( true ); setTooltipColumn( 0 ); setDragEnabled( true ); setDropHighlighter( true ); setFullWidth( true ); setSorting( -1 ); addColumn("Name "); m_menu = new TQPopupMenu(this); connect(this,TQT_SIGNAL(doubleClicked(TQListViewItem*)),this,TQT_SLOT(itemExecuted(TQListViewItem*))); connect(this,TQT_SIGNAL(contextMenu(KListView*, TQListViewItem*, const TQPoint&)), this,TQT_SLOT(showContextMenu(KListView*,TQListViewItem*,const TQPoint&))); resize(300,400); refactor( obj ); } RefactoringAssistant::~RefactoringAssistant() { m_umlObjectMap.clear(); clear(); } void RefactoringAssistant::refactor( UMLClassifier *obj ) { clear(); m_umlObjectMap.clear(); m_umlObject = obj; if (! m_umlObject ) { return; } addClassifier( obj, 0, true, true, true ); TQListViewItem *item = firstChild(); item->setOpen(true); for( item = item->firstChild(); item ; item = item->nextSibling() ) item->setOpen(true); } UMLObject* RefactoringAssistant::findUMLObject( const TQListViewItem *item ) { TQListViewItem *i = const_cast(item); if( m_umlObjectMap.find(i) == m_umlObjectMap.end() ) { kWarning()<<"RefactoringAssistant::findUMLObject( TQListViewItem *item )" <<"item with text "<text(0)<<"not found in uml map!"<getID()) << "does not have a ListItem" << endl; return 0L; } void RefactoringAssistant::itemExecuted( TQListViewItem *item ) { UMLObject *o = findUMLObject( item ); if(o) editProperties( ); } void RefactoringAssistant::setVisibilityIcon( TQListViewItem *item , const UMLObject *obj ) { switch(obj->getVisibility()) { case Uml::Visibility::Public: item->setPixmap(0,m_pixmaps.Public); break; case Uml::Visibility::Protected: item->setPixmap(0,m_pixmaps.Protected); break; case Uml::Visibility::Private: item->setPixmap(0,m_pixmaps.Private); break; case Uml::Visibility::Implementation: item->setPixmap(0,m_pixmaps.Implementation); break; break; } } void RefactoringAssistant::umlObjectModified( const UMLObject *obj ) { if( !obj ) obj = dynamic_cast(sender()); TQListViewItem *item = findListViewItem( obj ); if( !item ) return; item->setText( 0, obj->getName() ); if( typeid(*obj) == typeid(UMLOperation) || typeid(*obj) == typeid(UMLAttribute) ) { setVisibilityIcon( item, obj ); } } void RefactoringAssistant::operationAdded( UMLClassifierListItem *o ) { UMLOperation *op = static_cast(o); UMLClassifier *c = dynamic_cast(op->parent()); if(!c) { kWarning() << "RefactoringAssistant::operationAdded(" << op->getName() << ") - Parent of operation is not a classifier!" << endl; return; } TQListViewItem *item = findListViewItem( c ); if( !item ) { return; } for( TQListViewItem *folder = item->firstChild(); folder; folder = folder->nextSibling() ) { if( folder->text(1) == "operations" ) { item = new KListViewItem( folder, op->getName() ); m_umlObjectMap[item] = op; connect( op, TQT_SIGNAL( modified() ), this, TQT_SLOT( umlObjectModified() ) ); setVisibilityIcon( item, op ); break; } } } void RefactoringAssistant::operationRemoved( UMLClassifierListItem *o ) { UMLOperation *op = static_cast(o); TQListViewItem *item = findListViewItem( op ); if( !item ) { return; } disconnect( op, TQT_SIGNAL( modified() ), this, TQT_SLOT( umlObjectModified() ) ); m_umlObjectMap.erase(item); delete item; } void RefactoringAssistant::attributeAdded( UMLClassifierListItem *a ) { UMLAttribute *att = static_cast(a); UMLClassifier *c = dynamic_cast(att->parent()); if(!c) { kWarning() << "RefactoringAssistant::attributeAdded(" << att->getName() << ") - Parent is not a class!" << endl; return; } TQListViewItem *item = findListViewItem( c ); if( !item ) { return; } for( TQListViewItem *folder = item->firstChild(); folder; folder = folder->nextSibling() ) { if( folder->text(1) == "attributes" ) { item = new KListViewItem( folder, att->getName() ); m_umlObjectMap[item] = att; connect( att, TQT_SIGNAL( modified() ), this, TQT_SLOT( umlObjectModified() ) ); setVisibilityIcon( item, att ); break; } } } void RefactoringAssistant::attributeRemoved( UMLClassifierListItem *a ) { UMLAttribute *att = static_cast(a); TQListViewItem *item = findListViewItem( att ); if( !item ) { return; } disconnect( att, TQT_SIGNAL( modified() ), this, TQT_SLOT( umlObjectModified() ) ); m_umlObjectMap.erase(item); delete item; } void RefactoringAssistant::editProperties( ) { TQListViewItem *item = selectedItem(); if( item ) { UMLObject *o = findUMLObject( item ); if( o ) editProperties( o ); } } void RefactoringAssistant::editProperties( UMLObject *obj ) { KDialogBase *dia(0); Uml::Object_Type t = obj->getBaseType(); if (t == Uml::ot_Class || t == Uml::ot_Interface) { dia = new ClassPropDlg(this,obj,0,true); } else if (t == Uml::ot_Operation) { dia = new UMLOperationDialog(this,static_cast(obj)); } else if (t == Uml::ot_Attribute) { dia = new UMLAttributeDialog(this,static_cast(obj)); } else { kWarning()<<"RefactoringAssistant::editProperties( UMLObject *o ) caled for unknown type "<exec() ) { // need to update something? } delete dia; } void RefactoringAssistant::showContextMenu(KListView* ,TQListViewItem *item, const TQPoint &p) { m_menu->clear(); UMLObject *obj = findUMLObject( item ); if(obj) {// Menu for UMLObjects Uml::Object_Type t = obj->getBaseType(); if (t == Uml::ot_Class) { m_menu->insertItem(i18n("Add Base Class"),this,TQT_SLOT(addBaseClassifier())); m_menu->insertItem(i18n("Add Derived Class"),this,TQT_SLOT(addDerivedClassifier())); // m_menu->insertItem(i18n("Add Interface Implementation"),this,TQT_SLOT(addInterfaceImplementation())); m_menu->insertItem(i18n("Add Operation"),this,TQT_SLOT(createOperation())); m_menu->insertItem(i18n("Add Attribute"),this,TQT_SLOT(createAttribute())); } else if (t == Uml::ot_Interface) { m_menu->insertItem(i18n("Add Base Interface"),this,TQT_SLOT(addSuperClassifier())); m_menu->insertItem(i18n("Add Derived Interface"),this,TQT_SLOT(addDerivedClassifier())); m_menu->insertItem(i18n("Add Operation"),this,TQT_SLOT(createOperation())); } // else // { // kDebug()<<"No context menu for objects of type "<insertSeparator(); m_menu->insertItem(i18n("Properties"),this,TQT_SLOT(editProperties())); } else {//menu for other ViewItems if( item->text(1) == "operations" ) { m_menu->insertItem(i18n("Add Operation"),this,TQT_SLOT(createOperation())); } else if( item->text(1) == "attributes" ) { m_menu->insertItem(i18n("Add Attribute"),this,TQT_SLOT(createAttribute())); } else { kWarning()<<"RefactoringAssistant::showContextMenu() " <<"called for extraneous item"<exec(p); } void RefactoringAssistant::addBaseClassifier() { TQListViewItem *item = selectedItem(); if(!item) { kWarning()<<"RefactoringAssistant::addBaseClassifier() " <<"called with no item selected"<(obj) ) { kWarning()<<"RefactoringAssistant::addBaseClassifier() " <<"called for a non-classifier object"<getBaseType(); UMLClassifier *super = static_cast(Object_Factory::createUMLObject(t)); if(!super) return; m_doc->createUMLAssociation( obj, super, Uml::at_Generalization ); ////////////////////// Manually add the classifier to the assitant - would be nicer to do it with ///////////////////// a signal, like operations and attributes TQListViewItem *baseFolder = item->firstChild(); while( baseFolder->text(0) != i18n("Base Classifiers") ) baseFolder = baseFolder->nextSibling(); if(!baseFolder) { kWarning()<<"Cannot find Base Folder"<getName() ); item->setPixmap(0,m_pixmaps.Generalization); item->setExpandable( true ); m_umlObjectMap[item] = super; addClassifier( super, item, true, false, true); ///////////////////////// } void RefactoringAssistant::addDerivedClassifier() { TQListViewItem *item = selectedItem(); if(!item) { kWarning()<<"RefactoringAssistant::addDerivedClassifier() " <<"called with no item selected"<(obj) ) { kWarning()<<"RefactoringAssistant::addDerivedClassifier() " <<"called for a non-classifier object"<getBaseType(); UMLClassifier *derived = static_cast(Object_Factory::createUMLObject(t)); if(!derived) return; m_doc->createUMLAssociation( derived, obj, Uml::at_Generalization ); ////////////////////// Manually add the classifier to the assitant - would be nicer to do it with ///////////////////// a signal, like operations and attributes TQListViewItem *derivedFolder = item->firstChild(); while( derivedFolder->text(0) != i18n("Derived Classifiers") ) derivedFolder = derivedFolder->nextSibling(); if(!derivedFolder) { kWarning()<<"Cannot find Derived Folder"<getName() ); item->setPixmap(0,m_pixmaps.Subclass); item->setExpandable( true ); m_umlObjectMap[item] = derived; addClassifier( derived, item, false, true, true); ///////////////////////// } void RefactoringAssistant::addInterfaceImplementation() { kWarning()<<"RefactoringAssistant::addInterfaceImplementation()" <<"not implemented... finish addSuperClassifier() first!!"<(obj) ) // return; // UMLObject *n = Object_Factory::createUMLObject( Uml::ot_Interface) ); // if(!n) // return; // m_doc->createUMLAssociation( n, obj, Uml::at_Realization ); // //refresh, add classifier to assistant } void RefactoringAssistant::createOperation() { TQListViewItem *item = selectedItem(); if(!item) { kWarning()<<"RefactoringAssistant::createOperation() " <<"called with no item selected"<(findUMLObject( item )); if( !c ) return; c->createOperation(); } void RefactoringAssistant::createAttribute() { TQListViewItem *item = selectedItem(); if(!item) { kWarning()<<"RefactoringAssistant::createAttribute() " <<"called with no item selected"<(findUMLObject( item )); if( !c ) return; c->createAttribute(); } void RefactoringAssistant::addClassifier( UMLClassifier *classifier, TQListViewItem *parent, bool addSuper, bool addSub, bool recurse) { TQListViewItem *classifierItem, *item; if( parent ) { classifierItem = parent; } else { classifierItem= new KListViewItem( this, classifier->getName() ); m_umlObjectMap[classifierItem] = classifier; } connect( classifier, TQT_SIGNAL( modified() ), this, TQT_SLOT( umlObjectModified() ) ); UMLClassifier *klass = dynamic_cast(classifier); if( klass ) {// only Classes have attributes... connect( classifier, TQT_SIGNAL(attributeAdded(UMLClassifierListItem*)), this, TQT_SLOT(attributeAdded(UMLClassifierListItem*))); connect( classifier, TQT_SIGNAL(attributeRemoved(UMLClassifierListItem*)), this, TQT_SLOT(attributeRemoved(UMLClassifierListItem*))); TQListViewItem *attsFolder = new KListViewItem( classifierItem, i18n("Attributes"), "attributes" ); attsFolder->setPixmap(0,SmallIcon("folder_green_open")); attsFolder->setExpandable( true ); UMLAttributeList atts = klass->getAttributeList(); for( UMLAttribute *att = atts.first(); att; att = atts.next() ) { attributeAdded( att ); } } // add operations connect( classifier, TQT_SIGNAL(operationAdded(UMLClassifierListItem*)), this, TQT_SLOT(operationAdded(UMLClassifierListItem*))); connect( classifier, TQT_SIGNAL(operationRemoved(UMLClassifierListItem*)), this, TQT_SLOT(operationRemoved(UMLClassifierListItem*))); TQListViewItem *opsFolder = new KListViewItem( classifierItem, i18n("Operations"), "operations" ); opsFolder->setPixmap(0,SmallIcon("folder_blue_open")); opsFolder->setExpandable( true ); UMLOperationList ops(classifier->getOpList()); for( UMLOperation *op = ops.first(); op ; op = ops.next() ) { operationAdded( op ); } //if add parents if(addSuper) { TQListViewItem *superFolder = new KListViewItem( classifierItem, i18n("Base Classifiers") ); superFolder->setExpandable( true ); UMLClassifierList super = classifier->findSuperClassConcepts(); for( UMLClassifier *cl = super.first(); cl ; cl = super.next() ) { item = new KListViewItem( superFolder, cl->getName() ); item->setPixmap(0,m_pixmaps.Generalization); item->setExpandable( true ); m_umlObjectMap[item] = cl; if( recurse ) { addClassifier( cl, item, true, false, true); } } } if(addSub) { //add derived classifiers TQListViewItem *derivedFolder = new KListViewItem( classifierItem, i18n("Derived Classifiers") ); derivedFolder->setExpandable( true ); UMLClassifierList derived = classifier->findSubClassConcepts(); for( UMLClassifier *d = derived.first(); d ; d = derived.next() ) { item = new KListViewItem( derivedFolder, d->getName() ); item->setPixmap(0,m_pixmaps.Subclass); item->setExpandable( true ); m_umlObjectMap[item] = d; if( recurse ) { addClassifier( d, item, false, true, true); } } } } bool RefactoringAssistant::acceptDrag(TQDropEvent *event) const { //first check if we can accept drops at all, and if the operation // is a move within the list itself if( !acceptDrops() || !itemsMovable() || (event->source()!=viewport())) { return false; } RefactoringAssistant *me = const_cast(this); //ok, check if the move is valid TQListViewItem *movingItem = 0, *afterme = 0, *parentItem = 0; me->findDrop(event->pos(), parentItem, afterme); for( movingItem = firstChild(); movingItem != 0; movingItem = movingItem->itemBelow() ) { if( movingItem->isSelected() ) break; } if(!movingItem || !parentItem) { kDebug()<<"moving/parent items not found - can't accept drag!"<findUMLObject(movingItem)) ) { kDebug()<<"Moving object not found in uml map!"<text(0)<getBaseType(); if (t != Uml::ot_Attribute && t != Uml::ot_Operation) { kDebug()<<"only operations and attributes are movable! - return false"<text(0)<findUMLObject(parentItem); if( parentObject && dynamic_cast(parentObject) ) { //droping to a classifier, ok } else {//parent is not a classifier, so maybe it's a folder.. check types if( (parentItem->text(1) == "operations" && t == Uml::ot_Operation) || (parentItem->text(1) == "attributes" && t == Uml::ot_Attribute)) { parentObject = me->findUMLObject( parentItem->parent() ); } else { kDebug()<<"moving to item "<text(0)<<" -- "<text(1)<<" not valid"<(parentObject) && (t == Uml::ot_Attribute || t == Uml::ot_Operation)) { return true; } kDebug()<<"how did I get here? return false!!"<itemBelow() ) { if( movingItem->isSelected() ) break; } if( !movingItem || (movingItem == afterme) || !(movingObject = findUMLObject(movingItem)) ) { kWarning()<<"Moving item not found or dropping after itself or item not found in uml obj map. aborting. (drop had already been accepted)"<getBaseType(); newClassifier = dynamic_cast( findUMLObject( parentItem ) ); if(!newClassifier) { if ((parentItem->text(1) == "operations" && t == Uml::ot_Operation) || (parentItem->text(1) == "attributes" && t == Uml::ot_Attribute)) { newClassifier = dynamic_cast( findUMLObject( parentItem->parent() ) ); } if(!newClassifier) { kWarning()<<"New parent of object is not a Classifier - Drop had already been accepted - check!"<(movingObject); if(newClassifier->checkOperationSignature(op->getName(), op->getParmList())) { TQString msg = TQString(i18n("An operation with that signature already exists in %1.\n")).arg(newClassifier->getName()) + TQString(i18n("Choose a different name or parameter list." )); KMessageBox::error(this, msg, i18n("Operation Name Invalid"), false); return; } UMLClassifier *oldClassifier = dynamic_cast(op->parent()); if(oldClassifier) oldClassifier->removeOperation( op ); newClassifier->addOperation( op ); } else if (t == Uml::ot_Attribute) {kDebug()<<"moving attribute - not implemented"<(movingObject); // if(!newClassifier->checkAttributeSignature(att)) // { // TQString msg = TQString(i18n("An attribute with that signature already exists in %1.\n")).arg(newClassifier->getName()) // + // TQString(i18n("Choose a different name or parameter list." )); // KMessageBox::error(this, msg, i18n("Operation Name Invalid"), false); // return; // } // oldClassifier->removeAttribute( att ); // newClassifier->addAttribute( att ); } //emit moved(moving, afterFirst, afterme); emit moved(); } void RefactoringAssistant::loadPixmaps() { KStandardDirs *dirs = KGlobal::dirs(); TQString dataDir = dirs -> findResourceDir( "data", "umbrello/pics/object.png" ); dataDir += "/umbrello/pics/"; m_pixmaps.Public.load( dataDir + "CVpublic_var.png" ); m_pixmaps.Protected.load( dataDir + "CVprotected_var.png" ); m_pixmaps.Private.load( dataDir + "CVprivate_var.png" ); m_pixmaps.Implementation.load( dataDir + "CVimplementation_var.png" ); m_pixmaps.Generalization.load( dataDir + "generalisation.png" ); m_pixmaps.Subclass.load( dataDir + "uniassociation.png" ); } #include "refactoringassistant.moc"