umbrello API Documentation

classifier.cpp

00001 /***************************************************************************
00002  *                                                                         *
00003  *   This program is free software; you can redistribute it and/or modify  *
00004  *   it under the terms of the GNU General Public License as published by  *
00005  *   the Free Software Foundation; either version 2 of the License, or     *
00006  *   (at your option) any later version.                                   *
00007  *                                                                         *
00008  *   copyright (C) 2002-2007                                               *
00009  *   Umbrello UML Modeller Authors <uml-devel@uml.sf.net>                  *
00010  ***************************************************************************/
00011 // own header
00012 #include "classifier.h"
00013 // qt/kde includes
00014 #include <kdebug.h>
00015 #include <klocale.h>
00016 #include <kmessagebox.h>
00017 // app includes
00018 #include "association.h"
00019 #include "umlassociationlist.h"
00020 #include "operation.h"
00021 #include "attribute.h"
00022 #include "template.h"
00023 #include "enumliteral.h"
00024 #include "entityattribute.h"
00025 #include "enum.h"
00026 #include "entity.h"
00027 #include "stereotype.h"
00028 #include "umldoc.h"
00029 #include "uml.h"
00030 #include "umllistview.h"
00031 #include "uniqueid.h"
00032 #include "object_factory.h"
00033 #include "model_utils.h"
00034 #include "clipboard/idchangelog.h"
00035 #include "dialogs/umloperationdialog.h"
00036 #include "dialogs/umlattributedialog.h"
00037 #include "dialogs/umltemplatedialog.h"
00038 #include "optionstate.h"
00039 
00040 using namespace Uml;
00041 
00042 UMLClassifier::UMLClassifier(const QString & name, Uml::IDType id)
00043         : UMLPackage(name, id)
00044 {
00045     init();
00046 }
00047 
00048 UMLClassifier::~UMLClassifier() {
00049 }
00050 
00051 void UMLClassifier::init() {
00052     m_BaseType = Uml::ot_Class;  // default value
00053     m_pClassAssoc = NULL;
00054     m_isRef = false;
00055 }
00056 
00057 void UMLClassifier::setBaseType(Uml::Object_Type ot) {
00058     m_BaseType = ot;
00059     Uml::Icon_Type newIcon;
00060     switch (ot) {
00061         case ot_Interface:
00062             UMLObject::setStereotype("interface");
00063             UMLObject::m_bAbstract = true;
00064             newIcon = Uml::it_Interface;
00065             break;
00066         case ot_Class:
00067             UMLObject::setStereotype(QString::null);
00068             UMLObject::m_bAbstract = false;
00069             newIcon = Uml::it_Class;
00070             break;
00071         case ot_Datatype:
00072             UMLObject::setStereotype("datatype");
00073             UMLObject::m_bAbstract = false;
00074             newIcon = Uml::it_Datatype;
00075             break;
00076         default:
00077             kError() << "UMLClassifier::setBaseType: cannot set to type "
00078                 << ot << endl;
00079             return;
00080     }
00081     // @todo get rid of direct dependencies to UMLListView
00082     //  (e.g. move utility methods to Model_Utils and/or use signals)
00083     UMLListView *listView = UMLApp::app()->getListView();
00084     listView->changeIconOf(this, newIcon);
00085 }
00086 
00087 bool UMLClassifier::isInterface() const {
00088     return (m_BaseType == ot_Interface);
00089 }
00090 
00091 bool UMLClassifier::isDatatype() const {
00092     return (m_BaseType == ot_Datatype);
00093 }
00094 
00095 UMLOperation * UMLClassifier::checkOperationSignature(
00096         const QString& name,
00097         UMLAttributeList opParams,
00098         UMLOperation *exemptOp)
00099 {
00100     UMLOperationList list = findOperations(name);
00101     if( list.count() == 0 )
00102         return NULL;
00103     const int inputParmCount = opParams.count();
00104 
00105     // there is at least one operation with the same name... compare the parameter list
00106     for (UMLOperationListIt oit(list); oit.current(); ++oit)
00107     {
00108         UMLOperation* test = oit.current();
00109         if (test == exemptOp)
00110             continue;
00111         UMLAttributeList testParams = test->getParmList( );
00112         const int pCount = testParams.count();
00113         if( pCount != inputParmCount )
00114             continue;
00115         int i = 0;
00116         while (i < pCount) {
00117             // The only criterion for equivalence is the parameter types.
00118             // (Default values are not considered.)
00119             if( testParams.at(i)->getTypeName() != opParams.at(i)->getTypeName() )
00120                 break;
00121             i++;
00122         }
00123         if( i == pCount )
00124         {//all parameters matched -> the signature is not unique
00125             return test;
00126         }
00127     }
00128     // we did not find an exact match, so the signature is unique ( acceptable )
00129     return NULL;
00130 }
00131 
00132 UMLOperation* UMLClassifier::findOperation(const QString& name,
00133                                            Model_Utils::NameAndType_List params) {
00134     UMLOperationList list = findOperations(name);
00135     if (list.count() == 0)
00136         return NULL;
00137     // If there are operation(s) with the same name then compare the parameter list
00138     const int inputParmCount = params.count();
00139     UMLOperation* test = NULL;
00140     for (UMLOperationListIt oit(list); (test = oit.current()) != NULL; ++oit) {
00141         UMLAttributeList testParams = test->getParmList();
00142         const int pCount = testParams.count();
00143         if (inputParmCount == 0 && pCount == 0)
00144             break;
00145         if (inputParmCount != pCount)
00146             continue;
00147         int i = 0;
00148         for (; i < pCount; ++i) {
00149             Model_Utils::NameAndType_ListIt nt(params.at(i));
00150             UMLClassifier *c = dynamic_cast<UMLClassifier*>((*nt).m_type);
00151             UMLClassifier *testType = testParams.at(i)->getType();
00152             if (c == NULL) {       //template parameter
00153                 if (testType->getName() != "class")
00154                     break;
00155             } else if (c != testType)
00156                 break;
00157         }
00158         if (i == pCount)
00159             break;  // all parameters matched
00160     }
00161     return test;
00162 }
00163 
00164 UMLOperation* UMLClassifier::createOperation(const QString &name /*=null*/,
00165         bool *isExistingOp  /*=NULL*/,
00166         Model_Utils::NameAndType_List *params  /*=NULL*/)
00167 {
00168     bool nameNotSet = (name.isNull() || name.isEmpty());
00169     if (! nameNotSet) {
00170         Model_Utils::NameAndType_List parList;
00171         if (params)
00172             parList = *params;
00173         UMLOperation* existingOp = findOperation(name, parList);
00174         if (existingOp != NULL) {
00175             if (isExistingOp != NULL)
00176                 *isExistingOp = true;
00177             return existingOp;
00178         }
00179     }
00180     // we did not find an exact match, so the signature is unique
00181     UMLOperation *op = new UMLOperation(this, name);
00182     if (params) {
00183         for (Model_Utils::NameAndType_ListIt it = params->begin(); it != params->end(); ++it ) {
00184             const Model_Utils::NameAndType &nt = *it;
00185             UMLAttribute *par = new UMLAttribute(op, nt.m_name, Uml::id_None, Uml::Visibility::Private,
00186                                                  nt.m_type, nt.m_initialValue);
00187             par->setParmKind(nt.m_direction);
00188             op->addParm(par);
00189         }
00190     }
00191     if (nameNotSet || params == NULL) {
00192         if (nameNotSet)
00193             op->setName( uniqChildName(Uml::ot_Operation) );
00194         do {
00195             UMLOperationDialog operationDialogue(0, op);
00196             if( operationDialogue.exec() != QDialog::Accepted ) {
00197                 delete op;
00198                 return NULL;
00199             } else if (checkOperationSignature(op->getName(), op->getParmList())) {
00200                 KMessageBox::information(0,
00201                                          i18n("An operation with the same name and signature already exists. You can not add it again."));
00202             } else {
00203                 break;
00204             }
00205         } while(1);
00206     }
00207 
00208     // operation name is ok, formally add it to the classifier
00209     if (! addOperation(op)) {
00210         delete op;
00211         return NULL;
00212     }
00213 
00214     UMLDoc *umldoc = UMLApp::app()->getDocument();
00215     umldoc->signalUMLObjectCreated(op);
00216     return op;
00217 }
00218 
00219 bool UMLClassifier::addOperation(UMLOperation* op, int position )
00220 {
00221     if (m_List.findRef(op) != -1) {
00222         kDebug() << "UMLClassifier::addOperation: findRef("
00223         << op->getName() << ") finds op (bad)"
00224         << endl;
00225         return false;
00226     }
00227     if (checkOperationSignature(op->getName(), op->getParmList()) ) {
00228         kDebug() << "UMLClassifier::addOperation: checkOperationSignature("
00229         << op->getName() << ") op is non-unique" << endl;
00230         return false;
00231     }
00232 
00233     if( position >= 0 && position <= (int)m_List.count() ) {
00234         kDebug() << "UMLClassifier::addOperation(" << op->getName()
00235             << "): inserting at position " << position << endl;
00236         m_List.insert(position,op);
00237         UMLClassifierListItemList itemList = getFilteredList(Uml::ot_Operation);
00238         UMLClassifierListItem* currentAtt;
00239         QString buf;
00240         for (UMLClassifierListItemListIt it0(itemList); (currentAtt = it0.current()); ++it0)
00241             buf.append(' ' + currentAtt->getName());
00242         kDebug() << "  UMLClassifier::addOperation list after change: " << buf << endl;
00243      } else
00244         m_List.append( op );
00245     emit operationAdded(op);
00246     UMLObject::emitModified();
00247     connect(op,SIGNAL(modified()),this,SIGNAL(modified()));
00248     return true;
00249 }
00250 
00251 bool UMLClassifier::addOperation(UMLOperation* Op, IDChangeLog* Log) {
00252     if( addOperation( Op, -1 ) )
00253         return true;
00254     else if( Log ) {
00255         Log->removeChangeByNewID( Op -> getID() );
00256     }
00257     return false;
00258 }
00259 
00260 int UMLClassifier::removeOperation(UMLOperation *op) {
00261     if (op == NULL) {
00262         kDebug() << "UMLClassifier::removeOperation called on NULL op"
00263         << endl;
00264         return -1;
00265     }
00266     if(!m_List.remove(op)) {
00267         kDebug() << "UMLClassifier::removeOperation: can't find op "
00268         << op->getName() << " in list" << endl;
00269         return -1;
00270     }
00271     // disconnection needed.
00272     // note that we don't delete the operation, just remove it from the Classifier
00273     disconnect(op,SIGNAL(modified()),this,SIGNAL(modified()));
00274     emit operationRemoved(op);
00275     UMLObject::emitModified();
00276     return m_List.count();
00277 }
00278 
00279 UMLObject* UMLClassifier::createTemplate(const QString& currentName /*= QString::null*/) {
00280     QString name = currentName;
00281     bool goodName = !name.isEmpty();
00282     if (!goodName)
00283         name = uniqChildName(Uml::ot_Template);
00284     UMLTemplate* newTemplate = new UMLTemplate(this, name);
00285 
00286     int button = QDialog::Accepted;
00287 
00288     while (button==QDialog::Accepted && !goodName) {
00289         UMLTemplateDialog templateDialogue(0, newTemplate);
00290         button = templateDialogue.exec();
00291         name = newTemplate->getName();
00292 
00293         if(name.length() == 0) {
00294             KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name"));
00295         } else if ( findChildObject(name) != NULL ) {
00296             KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name"));
00297         } else {
00298             goodName = true;
00299         }
00300     }
00301 
00302     if (button != QDialog::Accepted) {
00303         return NULL;
00304     }
00305 
00306     addTemplate(newTemplate);
00307 
00308     UMLDoc *umldoc = UMLApp::app()->getDocument();
00309     umldoc->signalUMLObjectCreated(newTemplate);
00310     return newTemplate;
00311 }
00312 
00313 int UMLClassifier::attributes() {
00314     UMLClassifierListItemList atts = getFilteredList(Uml::ot_Attribute);
00315     return atts.count();
00316 }
00317 
00318 UMLAttributeList UMLClassifier::getAttributeList() {
00319     UMLAttributeList attributeList;
00320     for (UMLObjectListIt lit(m_List); lit.current(); ++lit) {
00321         UMLObject *listItem = lit.current();
00322         if (listItem->getBaseType() == Uml::ot_Attribute) {
00323             attributeList.append(static_cast<UMLAttribute*>(listItem));
00324         }
00325     }
00326     return attributeList;
00327 }
00328 
00329 UMLOperationList UMLClassifier::findOperations(const QString &n) {
00330     const bool caseSensitive = UMLApp::app()->activeLanguageIsCaseSensitive();
00331     UMLOperationList list;
00332     for (UMLObjectListIt lit(m_List); lit.current(); ++lit) {
00333         UMLObject* obj = lit.current();
00334         if (obj->getBaseType() != Uml::ot_Operation)
00335             continue;
00336         UMLOperation *op = static_cast<UMLOperation*>(obj);
00337         if (caseSensitive) {
00338             if (obj->getName() == n)
00339                 list.append(op);
00340         } else if (obj->getName().lower() == n.lower()) {
00341             list.append(op);
00342         }
00343     }
00344     return list;
00345 }
00346 
00347 UMLObject* UMLClassifier::findChildObjectById(Uml::IDType id, bool considerAncestors /* =false */) {
00348     UMLObject *o = UMLCanvasObject::findChildObjectById(id);
00349     if (o)
00350         return o;
00351     if (considerAncestors) {
00352         UMLClassifierList ancestors = findSuperClassConcepts();
00353         for (UMLClassifier *anc = ancestors.first(); anc; anc = ancestors.next()) {
00354             UMLObject *o = anc->findChildObjectById(id);
00355             if (o)
00356                 return o;
00357         }
00358     }
00359     return NULL;
00360 }
00361 
00362 UMLClassifierList UMLClassifier::findSubClassConcepts (ClassifierType type) {
00363     UMLClassifierList list = getSubClasses();
00364     UMLAssociationList rlist = getRealizations();
00365 
00366     UMLClassifierList inheritingConcepts;
00367     Uml::IDType myID = getID();
00368     for (UMLClassifier *c = list.first(); c; c = list.next())
00369     {
00370         if (type == ALL || (!c->isInterface() && type == CLASS)
00371                 || (c->isInterface() && type == INTERFACE))
00372             inheritingConcepts.append(c);
00373     }
00374 
00375     for (UMLAssociation *a = rlist.first(); a; a = rlist.next())
00376     {
00377         if (a->getObjectId(A) != myID)
00378         {
00379             UMLObject* obj = a->getObject(A);
00380             UMLClassifier *concept = dynamic_cast<UMLClassifier*>(obj);
00381             if (concept && (type == ALL || (!concept->isInterface() && type == CLASS)
00382                             || (concept->isInterface() && type == INTERFACE))
00383                         && (inheritingConcepts.findRef(concept) == -1))
00384                 inheritingConcepts.append(concept);
00385         }
00386     }
00387 
00388     return inheritingConcepts;
00389 }
00390 
00391 UMLClassifierList UMLClassifier::findSuperClassConcepts (ClassifierType type) {
00392     UMLClassifierList list = getSuperClasses();
00393     UMLAssociationList rlist = getRealizations();
00394 
00395     UMLClassifierList parentConcepts;
00396     Uml::IDType myID = getID();
00397     for (UMLClassifier *concept = list.first(); concept; concept = list.next())
00398     {
00399         if (type == ALL || (!concept->isInterface() && type == CLASS)
00400                 || (concept->isInterface() && type == INTERFACE))
00401             parentConcepts.append(concept);
00402     }
00403 
00404     for (UMLAssociation *a = rlist.first(); a; a = rlist.next())
00405     {
00406         if (a->getObjectId(A) == myID)
00407         {
00408             UMLObject* obj = a->getObject(B);
00409             UMLClassifier *concept = dynamic_cast<UMLClassifier*>(obj);
00410             if (concept && (type == ALL || (!concept->isInterface() && type == CLASS)
00411                             || (concept->isInterface() && type == INTERFACE))
00412                         && (parentConcepts.findRef(concept) == -1))
00413                 parentConcepts.append(concept);
00414         }
00415     }
00416 
00417     return parentConcepts;
00418 }
00419 
00420 bool UMLClassifier::operator==( UMLClassifier & rhs ) {
00421   /*
00422     if ( m_List.count() != rhs.m_List.count() ) {
00423         return false;
00424     }
00425     if ( &m_List != &(rhs.m_List) ) {
00426         return false;
00427     }
00428    */
00429     return UMLCanvasObject::operator==(rhs);
00430 }
00431 
00432 
00433 void UMLClassifier::copyInto(UMLClassifier *rhs) const
00434 {
00435     UMLCanvasObject::copyInto(rhs);
00436     rhs->setBaseType(m_BaseType);
00437     // CHECK: association property m_pClassAssoc is not copied
00438     m_List.copyInto(&(rhs->m_List));
00439 }
00440 
00441 UMLObject* UMLClassifier::clone() const {
00442     UMLClassifier *clone = new UMLClassifier();
00443     copyInto(clone);
00444     return clone;
00445 }
00446 
00447 bool UMLClassifier::resolveRef() {
00448     bool success = UMLPackage::resolveRef();
00449     // Using reentrant iteration is a bare necessity here:
00450     for (UMLObjectListIt oit(m_List); oit.current(); ++oit) {
00451         UMLObject* obj = oit.current();
00452         /**** For reference, here is the non-reentrant iteration scheme -
00453               DO NOT USE THIS !
00454         for (UMLObject *obj = m_List.first(); obj; obj = m_List.next())
00455          {  ....  }
00456          ****/
00457         if (obj->resolveRef()) {
00458             UMLClassifierListItem *cli = static_cast<UMLClassifierListItem*>(obj);
00459             switch (cli->getBaseType()) {
00460                 case Uml::ot_Attribute:
00461                     emit attributeAdded(cli);
00462                     break;
00463                 case Uml::ot_Operation:
00464                     emit operationAdded(cli);
00465                     break;
00466                 case Uml::ot_Template:
00467                     emit templateAdded(cli);
00468                     break;
00469                 default:
00470                     break;
00471             }
00472         }
00473     }
00474     return success;
00475 }
00476 
00477 bool UMLClassifier::acceptAssociationType(Uml::Association_Type type)
00478 {
00479     switch(type)
00480     {
00481     case at_Generalization:
00482     case at_Aggregation:
00483     case at_Relationship:
00484     case at_Dependency:
00485     case at_Association:
00486     case at_Association_Self:
00487     case at_Containment:
00488     case at_Composition:
00489     case at_Realization:
00490     case at_UniAssociation:
00491         return true;
00492     default:
00493         return false;
00494     }
00495     return false; //shutup compiler warning
00496 }
00497 
00498 UMLAttribute* UMLClassifier::createAttribute(const QString &name /*=null*/,
00499                                              UMLObject *type,
00500                                              Uml::Visibility vis,
00501                                              const QString &init) {
00502     Uml::IDType id = UniqueID::gen();
00503     QString currentName;
00504     if (name.isNull())  {
00505         currentName = uniqChildName(Uml::ot_Attribute);
00506     } else {
00507         currentName = name;
00508     }
00509     UMLAttribute* newAttribute = new UMLAttribute(this, currentName, id, vis, type, init);
00510 
00511     int button = QDialog::Accepted;
00512     bool goodName = false;
00513 
00514     //check for name.isNull() stops dialog being shown
00515     //when creating attribute via list view
00516     while (button == QDialog::Accepted && !goodName && name.isNull()) {
00517         UMLAttributeDialog attributeDialogue(0, newAttribute);
00518         button = attributeDialogue.exec();
00519         QString name = newAttribute->getName();
00520 
00521         if(name.length() == 0) {
00522             KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name"));
00523         } else if ( findChildObject(name) != NULL ) {
00524             KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name"));
00525         } else {
00526             goodName = true;
00527         }
00528     }
00529 
00530     if (button != QDialog::Accepted) {
00531         delete newAttribute;
00532         return NULL;
00533     }
00534 
00535     addAttribute(newAttribute);
00536 
00537     UMLDoc *umldoc = UMLApp::app()->getDocument();
00538     umldoc->signalUMLObjectCreated(newAttribute);
00539     return newAttribute;
00540 }
00541 
00542 UMLAttribute* UMLClassifier::addAttribute(const QString &name, Uml::IDType id /* = Uml::id_None */) {
00543     for (UMLObjectListIt lit(m_List); lit.current(); ++lit) {
00544         UMLObject *obj = lit.current();
00545         if (obj->getBaseType() == Uml::ot_Attribute && obj->getName() == name)
00546             return static_cast<UMLAttribute*>(obj);
00547     }
00548     Uml::Visibility scope = Settings::getOptionState().classState.defaultAttributeScope;
00549     UMLAttribute *a = new UMLAttribute(this, name, id, scope);
00550     m_List.append(a);
00551     emit attributeAdded(a);
00552     UMLObject::emitModified();
00553     connect(a,SIGNAL(modified()),this,SIGNAL(modified()));
00554     return a;
00555 }
00556 
00557 UMLAttribute* UMLClassifier::addAttribute(const QString &name, UMLObject *type, Uml::Visibility scope) {
00558     UMLAttribute *a = new UMLAttribute(this);
00559     a->setName(name);
00560     a->setVisibility(scope);
00561     a->setID(UniqueID::gen());
00562     if (type)
00563         a->setType(type);
00564     m_List.append(a);
00565     emit attributeAdded(a);
00566     UMLObject::emitModified();
00567     connect(a,SIGNAL(modified()),this,SIGNAL(modified()));
00568     return a;
00569 }
00570 
00571 bool UMLClassifier::addAttribute(UMLAttribute* att, IDChangeLog* Log /* = 0 */,
00572                                  int position /* = -1 */) {
00573     if (findChildObject(att->getName()) == NULL) {
00574         att->parent()->removeChild( att );
00575         this->insertChild( att );
00576         if (position >= 0 && position < (int)m_List.count())
00577             m_List.insert(position, att);
00578         else
00579             m_List.append(att);
00580         emit attributeAdded(att);
00581         UMLObject::emitModified();
00582         connect(att, SIGNAL(modified()), this, SIGNAL(modified()));
00583         return true;
00584     } else if (Log) {
00585         Log->removeChangeByNewID(att->getID());
00586         delete att;
00587     }
00588     return false;
00589 }
00590 
00591 int UMLClassifier::removeAttribute(UMLAttribute* a) {
00592     if (!m_List.remove(a)) {
00593         kDebug() << "can't find att given in list" << endl;
00594         return -1;
00595     }
00596     emit attributeRemoved(a);
00597     UMLObject::emitModified();
00598     // If we are deleting the object, then we don't need to disconnect..this is done auto-magically
00599     // for us by QObject. -b.t.
00600     // disconnect(a,SIGNAL(modified()),this,SIGNAL(modified()));
00601     delete a;
00602     return m_List.count();
00603 }
00604 
00605 
00606 void UMLClassifier::setClassAssoc(UMLAssociation *assoc) {
00607     m_pClassAssoc = assoc;
00608 }
00609 
00610 UMLAssociation *UMLClassifier::getClassAssoc() {
00611     return m_pClassAssoc;
00612 }
00613 
00614 bool UMLClassifier::hasAbstractOps () {
00615     UMLOperationList opl( getOpList() );
00616     for(UMLOperation *op = opl.first(); op ; op = opl.next())
00617         if(op->getAbstract())
00618             return true;
00619     return false;
00620 }
00621 
00622 int UMLClassifier::operations() {
00623     return getOpList().count();
00624 }
00625 
00626 UMLOperationList UMLClassifier::getOpList(bool includeInherited) {
00627     UMLOperationList ops;
00628     for (UMLObjectListIt lit(m_List); lit.current(); ++lit) {
00629         UMLObject *li = lit.current();
00630         if (li->getBaseType() == ot_Operation)
00631             ops.append(static_cast<UMLOperation*>(li));
00632     }
00633     if (includeInherited) {
00634         UMLClassifierList parents = findSuperClassConcepts();
00635         UMLClassifier *c;
00636         for (UMLClassifierListIt pit(parents); (c = pit.current()) != NULL; ++pit) {
00637             if (c == this) {
00638                 kError() << "UMLClassifier::getOpList: class " << c->getName()
00639                     << " is parent of itself ?!?" << endl;
00640                 continue;
00641             }
00642             // get operations for each parent by recursive call
00643             UMLOperationList pops = c->getOpList(true);
00644             // add these operations to operation list, but only if unique.
00645             for (UMLOperation *po = pops.first(); po; po = pops.next()) {
00646                 QString po_as_string(po->toString(Uml::st_SigNoVis));
00647                 UMLOperation *o = NULL;
00648                 for (o = ops.first(); o; o = ops.next())
00649                     if (o->toString(Uml::st_SigNoVis) == po_as_string)
00650                         break;
00651                 if (!o)
00652                     ops.append(po);
00653             }
00654         }
00655     }
00656     return ops;
00657 }
00658 
00659 UMLClassifierListItemList UMLClassifier::getFilteredList(Object_Type ot) {
00660     UMLClassifierListItemList resultList;
00661     UMLObject *o;
00662     for (UMLObjectListIt lit(m_List); (o = lit.current()) != NULL; ++lit) {
00663         if (o->getBaseType() == Uml::ot_Association)
00664             continue;
00665         UMLClassifierListItem *listItem = static_cast<UMLClassifierListItem*>(o);
00666         if (ot == Uml::ot_UMLObject || listItem->getBaseType() == ot)
00667             resultList.append(listItem);
00668     }
00669     return resultList;
00670 }
00671 
00672 UMLTemplate* UMLClassifier::addTemplate(const QString &name, Uml::IDType id) {
00673     UMLTemplate *t = findTemplate(name);
00674     if (t)
00675         return t;
00676     t = new UMLTemplate(this, name, id);
00677     m_List.append(t);
00678     emit templateAdded(t);
00679     UMLObject::emitModified();
00680     connect(t, SIGNAL(modified()), this, SIGNAL(modified()));
00681     return t;
00682 }
00683 
00684 bool UMLClassifier::addTemplate(UMLTemplate* newTemplate, IDChangeLog* log /* = 0*/) {
00685     QString name = newTemplate->getName();
00686     if (findChildObject(name) == NULL) {
00687         newTemplate->parent()->removeChild(newTemplate);
00688         this->insertChild(newTemplate);
00689         m_List.append(newTemplate);
00690         emit templateAdded(newTemplate);
00691         UMLObject::emitModified();
00692         connect(newTemplate,SIGNAL(modified()),this,SIGNAL(modified()));
00693         return true;
00694     } else if (log) {
00695         log->removeChangeByNewID( newTemplate->getID() );
00696         delete newTemplate;
00697     }
00698     return false;
00699 }
00700 
00701 bool UMLClassifier::addTemplate(UMLTemplate* Template, int position)
00702 {
00703     QString name = Template->getName();
00704     if (findChildObject(name) == NULL) {
00705         Template->parent()->removeChild(Template);
00706         this->insertChild(Template);
00707         if( position >= 0 && position <= (int)m_List.count() )
00708             m_List.insert(position,Template);
00709         else
00710             m_List.append(Template);
00711         emit templateAdded(Template);
00712         UMLObject::emitModified();
00713         connect(Template,SIGNAL(modified()),this,SIGNAL(modified()));
00714         return true;
00715     }
00716     //else
00717     return false;
00718 }
00719 
00720 int UMLClassifier::removeTemplate(UMLTemplate* umltemplate) {
00721     if ( !m_List.remove(umltemplate) ) {
00722         kWarning() << "can't find att given in list" << endl;
00723         return -1;
00724     }
00725     emit templateRemoved(umltemplate);
00726     UMLObject::emitModified();
00727     disconnect(umltemplate,SIGNAL(modified()),this,SIGNAL(modified()));
00728     return m_List.count();
00729 }
00730 
00731 
00732 UMLTemplate *UMLClassifier::findTemplate(const QString& name) {
00733     UMLTemplateList templParams = getTemplateList();
00734     for (UMLTemplate *t = templParams.first(); t; t = templParams.next()) {
00735         if (t->getName() == name)
00736             return t;
00737     }
00738     return NULL;
00739 }
00740 
00741 int UMLClassifier::templates() {
00742     UMLClassifierListItemList tempList = getFilteredList(Uml::ot_Template);
00743     return tempList.count();
00744 }
00745 
00746 UMLTemplateList UMLClassifier::getTemplateList() {
00747     UMLTemplateList templateList;
00748     for (UMLObjectListIt lit(m_List); lit.current(); ++lit) {
00749         UMLObject *listItem = lit.current();
00750         if (listItem->getBaseType() == Uml::ot_Template) {
00751             templateList.append(static_cast<UMLTemplate*>(listItem));
00752         }
00753     }
00754     return templateList;
00755 }
00756 
00757 int UMLClassifier::takeItem(UMLClassifierListItem *item) {
00758         UMLObject* currentAtt;
00759         QString buf;
00760         for (UMLObjectListIt it0(m_List);
00761              (currentAtt = it0.current()); ++it0) {
00762             QString txt = currentAtt->getName();
00763             if (txt.isEmpty())
00764               txt = "Type-" + QString::number((int) currentAtt->getBaseType());
00765             buf.append(' ' + currentAtt->getName());
00766         }
00767         kDebug() << "  UMLClassifier::takeItem (before): m_List is " << buf << endl;
00768     int index = m_List.findRef(item);
00769     if (index == -1)
00770         return -1;
00771     switch (item->getBaseType()) {
00772         case Uml::ot_Operation: {
00773             if (removeOperation(dynamic_cast<UMLOperation*>(item)) < 0)
00774                 index = -1;
00775             break;
00776         }
00777         case Uml::ot_Attribute: {
00778             UMLAttribute *retval = dynamic_cast<UMLAttribute*>(m_List.take());
00779             if (retval) {
00780                 emit attributeRemoved(retval);
00781                 emit modified();
00782             } else {
00783                 index = -1;
00784             }
00785             break;
00786         }
00787         case Uml::ot_Template: {
00788             UMLTemplate *t = dynamic_cast<UMLTemplate*>(m_List.take());
00789             if (t) {
00790                 emit templateRemoved(t);
00791                 emit modified();
00792             } else {
00793                 index = -1;
00794             }
00795             break;
00796         }
00797         case Uml::ot_EnumLiteral: {
00798             UMLEnumLiteral *el = dynamic_cast<UMLEnumLiteral*>(m_List.take());
00799             if (el) {
00800                 UMLEnum *e = static_cast<UMLEnum*>(this);
00801                 e->signalEnumLiteralRemoved(el);
00802                 emit modified();
00803             } else {
00804                 index = -1;
00805             }
00806             break;
00807         }
00808         case Uml::ot_EntityAttribute: {
00809             UMLEntityAttribute* el = dynamic_cast<UMLEntityAttribute*>(m_List.take());
00810             if (el) {
00811                 UMLEntity *e = static_cast<UMLEntity*>(this);
00812                 e->signalEntityAttributeRemoved(el);
00813                 emit modified();
00814             } else {
00815                 index = -1;
00816             }
00817             break;
00818         }
00819         default:
00820             index = -1;
00821             break;
00822     }
00823     return index;
00824 }
00825 
00826 void UMLClassifier::setOriginType(UMLClassifier *origType) {
00827     m_pSecondary = origType;
00828 }
00829 
00830 UMLClassifier * UMLClassifier::originType() {
00831     return static_cast<UMLClassifier*>(m_pSecondary);
00832 }
00833 
00834 void UMLClassifier::setIsReference(bool isRef) {
00835     m_isRef = isRef;
00836 }
00837 
00838 bool UMLClassifier::isReference() {
00839     return m_isRef;
00840 }
00841 
00842 UMLAssociationList  UMLClassifier::getUniAssociationToBeImplemented() {
00843     UMLAssociationList associations = getSpecificAssocs(Uml::at_UniAssociation);
00844     UMLAssociationList uniAssocListToBeImplemented;
00845 
00846     for(UMLAssociation *a = associations.first(); a; a = associations.next()) {
00847         if (a->getObjectId(Uml::B) == getID())
00848             continue;  // we need to be at the A side
00849 
00850         QString roleNameB = a->getRoleName(Uml::B);
00851         if (!roleNameB.isEmpty()) {
00852             UMLAttributeList atl = getAttributeList();
00853             bool found = false;
00854             //make sure that an attribute with the same name doesn't already exist
00855             for (UMLAttribute *at = atl.first(); at ; at = atl.next()) {
00856                 if (at->getName() == roleNameB) {
00857                     found = true;
00858                     break;
00859                 }
00860             }
00861             if (!found) {
00862                 uniAssocListToBeImplemented.append(a);
00863             }
00864         }
00865     }
00866     return uniAssocListToBeImplemented;
00867 }
00868 
00869 void UMLClassifier::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) {
00870     QString tag;
00871     switch (m_BaseType) {
00872         case Uml::ot_Class:
00873             tag = "UML:Class";
00874             break;
00875         case Uml::ot_Interface:
00876             tag = "UML:Interface";
00877             break;
00878         case Uml::ot_Datatype:
00879             tag = "UML:DataType";
00880             break;
00881         default:
00882             kError() << "UMLClassifier::saveToXMI() internal error: basetype is "
00883                 << m_BaseType << endl;
00884             return;
00885     }
00886     QDomElement classifierElement = UMLObject::save(tag, qDoc);
00887     if (m_BaseType == Uml::ot_Datatype && m_pSecondary != NULL)
00888         classifierElement.setAttribute( "elementReference",
00889                                         ID2STR(m_pSecondary->getID()) );
00890 
00891     //save templates
00892     UMLClassifierListItemList list = getFilteredList(Uml::ot_Template);
00893     if (list.count()) {
00894         QDomElement tmplElement = qDoc.createElement( "UML:ModelElement.templateParameter" );
00895         for (UMLClassifierListItem *tmpl = list.first(); tmpl; tmpl = list.next() ) {
00896             tmpl->saveToXMI(qDoc, tmplElement);
00897         }
00898         classifierElement.appendChild( tmplElement );
00899     }
00900 
00901     //save generalizations (we are the subclass, the other end is the superclass)
00902     UMLAssociationList generalizations = getSpecificAssocs(Uml::at_Generalization);
00903     if (generalizations.count()) {
00904         QDomElement genElement = qDoc.createElement("UML:GeneralizableElement.generalization");
00905         for (UMLAssociation *a = generalizations.first(); a; a = generalizations.next()) {
00906             // We are the subclass if we are at the role A end.
00907             if (m_nId != a->getObjectId(Uml::A))
00908                 continue;
00909             QDomElement gElem = qDoc.createElement("UML:Generalization");
00910             gElem.setAttribute( "xmi.idref", ID2STR(a->getID()) );
00911             genElement.appendChild(gElem);
00912         }
00913         if (genElement.hasChildNodes())
00914             classifierElement.appendChild( genElement );
00915     }
00916 
00917     // save attributes
00918     QDomElement featureElement = qDoc.createElement( "UML:Classifier.feature" );
00919     UMLClassifierListItemList attList = getFilteredList(Uml::ot_Attribute);
00920     for (UMLClassifierListItem *pAtt = attList.first(); pAtt; pAtt = attList.next() )
00921         pAtt -> saveToXMI( qDoc, featureElement );
00922 
00923     // save operations
00924     UMLOperationList opList = getOpList();
00925     for (UMLOperation *pOp = opList.first(); pOp; pOp = opList.next() )
00926         pOp -> saveToXMI( qDoc, featureElement );
00927     if (featureElement.hasChildNodes())
00928         classifierElement.appendChild( featureElement );
00929 
00930     // save contained objects
00931     if (m_objects.count()) {
00932         QDomElement ownedElement = qDoc.createElement( "UML:Namespace.ownedElement" );
00933         for (UMLObjectListIt oit(m_objects); oit.current(); ++oit) {
00934             UMLObject *obj = oit.current();
00935             obj->saveToXMI (qDoc, ownedElement);
00936         }
00937         classifierElement.appendChild( ownedElement );
00938     }
00939     qElement.appendChild( classifierElement );
00940 }
00941 
00942 UMLClassifierListItem* UMLClassifier::makeChildObject(const QString& xmiTag) {
00943     UMLClassifierListItem* pObject = NULL;
00944     if (tagEq(xmiTag, "Operation")) {
00945         pObject = new UMLOperation(this);
00946     } else if (tagEq(xmiTag, "Attribute")) {
00947         if (getBaseType() != Uml::ot_Class)
00948             return NULL;
00949         pObject = new UMLAttribute(this);
00950     } else if (tagEq(xmiTag, "TemplateParameter")) {
00951         pObject = new UMLTemplate(this);
00952     }
00953     return pObject;
00954 }
00955 
00956 bool UMLClassifier::load(QDomElement& element) {
00957     UMLClassifierListItem *child = NULL;
00958     m_SecondaryId = element.attribute( "elementReference", "" );
00959     if (!m_SecondaryId.isEmpty()) {
00960         // @todo We do not currently support composition.
00961         m_isRef = true;
00962     }
00963     bool totalSuccess = true;
00964     for (QDomNode node = element.firstChild(); !node.isNull();
00965             node = node.nextSibling()) {
00966         if (node.isComment())
00967             continue;
00968         element = node.toElement();
00969         QString tag = element.tagName();
00970         if (tagEq(tag, "ModelElement.templateParameter") ||
00971                 tagEq(tag, "Classifier.feature") ||
00972                 tagEq(tag, "Namespace.ownedElement") ||
00973                 tagEq(tag, "Namespace.contents")) {
00974             load(element);
00975             // Not evaluating the return value from load()
00976             // because we want a best effort.
00977 
00978         } else if ((child = makeChildObject(tag)) != NULL) {
00979             if (child->loadFromXMI(element)) {
00980                 switch (child->getBaseType()) {
00981                     case Uml::ot_Template:
00982                         addTemplate( static_cast<UMLTemplate*>(child) );
00983                         break;
00984                     case Uml::ot_Operation:
00985                         if (! addOperation(static_cast<UMLOperation*>(child)) ) {
00986                             kError() << "UMLClassifier::load: error from addOperation(op)"
00987                                       << endl;
00988                             delete child;
00989                             totalSuccess = false;
00990                         }
00991                         break;
00992                     case Uml::ot_Attribute:
00993                         addAttribute( static_cast<UMLAttribute*>(child) );
00994                         break;
00995                     default:
00996                         break;
00997                 }
00998             } else {
00999                 kWarning() << "UMLClassifier::load: failed to load " << tag << endl;
01000                 delete child;
01001                 totalSuccess = false;
01002             }
01003         } else if (!Model_Utils::isCommonXMIAttribute(tag)) {
01004             UMLDoc *umldoc = UMLApp::app()->getDocument();
01005             UMLObject *pObject = Object_Factory::makeObjectFromXMI(tag);
01006             if (pObject == NULL) {
01007                 // Not setting totalSuccess to false
01008                 // because we want a best effort.
01009                 continue;
01010             }
01011             pObject->setUMLPackage(this);
01012             if (! pObject->loadFromXMI(element)) {
01013                 removeObject(pObject);
01014                 delete pObject;
01015                 totalSuccess = false;
01016             }
01017         }
01018     }
01019     return totalSuccess;
01020 }
01021 
01022 
01023 
01024 #include "classifier.moc"
KDE Logo
This file is part of the documentation for umbrello Version 3.1.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Jun 26 08:07:54 2007 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003