/***************************************************************************
 *                                                                         *
 *   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-2006                                               *
 *   Umbrello UML Modeller Authors <uml-devel@uml.sf.net>                  *
 ***************************************************************************/

// own header
#include "umlobject.h"
// qt/kde includes
#include <tqregexp.h>
#include <kdebug.h>
#include <tdeapplication.h>
// app includes
#include "uniqueid.h"
#include "uml.h"
#include "umldoc.h"
#include "umllistview.h"
#include "umllistviewitem.h"
#include "package.h"
#include "folder.h"
#include "stereotype.h"
#include "object_factory.h"
#include "model_utils.h"
#include "codeimport/import_utils.h"
#include "docwindow.h"
#include "dialogs/classpropdlg.h"

UMLObject::UMLObject(const UMLObject * parent, const TQString &name, Uml::IDType id)
        : TQObject(const_cast<UMLObject*>(parent), "UMLObject" ) {
    init();
    if (id == Uml::id_None)
        m_nId = UniqueID::gen();
    else
        m_nId = id;
    m_Name = name;
}

UMLObject::UMLObject(const TQString &name, Uml::IDType id)
        :  TQObject(UMLApp::app()->getDocument()) {
    init();
    if (id == Uml::id_None)
        m_nId = UniqueID::gen();
    else
        m_nId = id;
    m_Name = name;
}

UMLObject::UMLObject(const UMLObject * parent)
        : TQObject(const_cast<UMLObject*>(parent)) {
    init();
}

UMLObject::~UMLObject() {
}

void UMLObject::init() {
    m_BaseType = Uml::ot_UMLObject;
    m_nId = Uml::id_None;
    m_pUMLPackage = NULL;
    m_Name = "";
    m_Vis = Uml::Visibility::Public;
    m_pStereotype = NULL;
    m_Doc = "";
    m_bAbstract = false;
    m_bStatic = false;
    m_bInPaste = false;
    m_bCreationWasSignalled = false;
    m_pSecondary = NULL;
}

bool UMLObject::showProperties(int page, bool assoc) {
    DocWindow *docwindow = UMLApp::app()->getDocWindow();
    docwindow->updateDocumentation(false);
    ClassPropDlg* dlg = new ClassPropDlg((TQWidget*)UMLApp::app(), this, page, assoc);
    bool modified = false;
    if (dlg->exec()) {
        docwindow->showDocumentation(this, true);
        UMLApp::app()->getDocument()->setModified(true);
        modified = true;
    }
    dlg->close(true); //wipe from memory
    return modified;
}

bool UMLObject::acceptAssociationType(Uml::Association_Type)
{// A UMLObject accepts nothing. This should be reimplemented by the subclasses
    return false;
}

void UMLObject::setID(Uml::IDType NewID) {
    m_nId = NewID;
    emitModified();
}

void UMLObject::setName(const TQString &strName) {
    m_Name = strName;
    emitModified();
}

TQString UMLObject::getName() const {
    return m_Name;
}

TQString UMLObject::getFullyQualifiedName(const TQString& separator,
                                         bool includeRoot /* = false */) const {
    TQString fqn;
    if (m_pUMLPackage) {
        bool skipPackage = false;
        if (!includeRoot) {
            UMLDoc *umldoc = UMLApp::app()->getDocument();
            if (umldoc->rootFolderType(m_pUMLPackage) != Uml::N_MODELTYPES ||
                m_pUMLPackage == umldoc->getDatatypeFolder())
                skipPackage = true;
        }
        if (!skipPackage) {
            TQString tempSeparator = separator;
            if (tempSeparator.isEmpty())
                tempSeparator = UMLApp::app()->activeLanguageScopeSeparator();
            fqn = m_pUMLPackage->getFullyQualifiedName(tempSeparator, includeRoot);
            fqn.append(tempSeparator);
        }
    }
    fqn.append(m_Name);
    return fqn;
}

bool UMLObject::operator==(UMLObject & rhs ) {
    if( this == &rhs )
        return true;

    //don't compare IDs, these are program specific and
    //don't mean the objects are the same
    //***** CHECK: Who put in this comment? What was the reason?
    //***** Currently some operator== in umbrello compare the IDs
    //***** while others don't.

    if( m_Name != rhs.m_Name )
        return false;

    // Packages create different namespaces, therefore they should be
    // part of the equality test.
    if( m_pUMLPackage != rhs.m_pUMLPackage )
        return false;

    // Making the type part of an object's identity has its problems:
    // Not all programming languages support declarations of the same
    // name but different type.
    // In such cases, the code generator is responsible for generating
    // the appropriate error message.
    if( m_BaseType != rhs.m_BaseType )
        return false;

    // The documentation should not be part of the equality test.
    // If two objects are the same but differ only in their documentation,
    // what does that mean?
    //if( m_Doc != rhs.m_Doc )
    //  return false;

    // The scope should not be part of the equality test.
    // What does it mean if two objects are the same but differ in their
    // scope? - I'm not aware of any programming language that would
    // support that.
    //if( m_Vis != rhs.m_Vis )
    //  return false;

    // See comments above
    //if( m_pStereotype != rhs.m_pStereotype )
    //  return false;

    // See comments above
    //if( m_bAbstract != rhs.m_bAbstract )
    //  return false;

    // See comments above
    //if( m_bStatic != rhs.m_bStatic )
    //  return false;

    return true;
}

void UMLObject::copyInto(UMLObject *rhs) const
{
    // Data members with copy constructor
    rhs->m_Doc = m_Doc;
    rhs->m_pStereotype = m_pStereotype;
    rhs->m_bAbstract = m_bAbstract;
    rhs->m_bStatic = m_bStatic;
    rhs->m_BaseType = m_BaseType;
    rhs->m_Vis = m_Vis;
    rhs->m_pUMLPackage = m_pUMLPackage;

    // We don't want the same name existing twice.
    rhs->m_Name = Model_Utils::uniqObjectName(m_BaseType, m_pUMLPackage, m_Name);

    // Create a new ID.
    rhs->m_nId = UniqueID::gen();

    // Hope that the parent from TQObject is okay.
    if (rhs->parent() != parent())
        kDebug() << "copyInto has a wrong parent" << endl;
}


bool UMLObject::getAbstract() const{
    return m_bAbstract;
}

void UMLObject::setAbstract(bool bAbstract) {
    m_bAbstract = bAbstract;
    emitModified();
}

void UMLObject::setInPaste(bool bInPaste /* =true */) {
    m_bInPaste = bInPaste;
}

/** Returns true if this UMLObject has classifier scope, otherwise false (the default). */
bool UMLObject::getStatic() const
{
    return m_bStatic;
}
/** Sets the value for m_bStatic. */
void UMLObject::setStatic(bool bStatic)
{
    m_bStatic = bStatic;
    emitModified();
}

void UMLObject::emitModified()
{
    UMLDoc *umldoc = UMLApp::app()->getDocument();
    if (! umldoc->loading())
        emit modified();
}

void UMLObject::setDoc(const TQString &d) {
    m_Doc = d;
    //emit modified();  No, this is done centrally at DocWindow::updateDocumentation()
}

Uml::Object_Type UMLObject::getBaseType() const {
    return m_BaseType;
}

void UMLObject::setBaseType(Uml::Object_Type ot) {
    m_BaseType = ot;
}

Uml::IDType UMLObject::getID() const {
    return m_nId;
}

TQString UMLObject::getDoc() const {
    return m_Doc;
}

Uml::Visibility UMLObject::getVisibility() const {
    return m_Vis;
}

void UMLObject::setVisibility(Uml::Visibility s) {
    m_Vis = s;
    emitModified();
}

void UMLObject::setUMLStereotype(UMLStereotype *stereo) {
    if (stereo == m_pStereotype)
        return;
    if (stereo) {
        stereo->incrRefCount();
    }
    if (m_pStereotype) {
        m_pStereotype->decrRefCount();
        if (m_pStereotype->refCount() == 0) {
            UMLDoc *pDoc = UMLApp::app()->getDocument();
            pDoc->removeStereotype(m_pStereotype);
            delete m_pStereotype;
        }
    }
    m_pStereotype = stereo;
    // TODO: don't emit modified() if predefined folder
    emitModified();
}

void UMLObject::setStereotype(const TQString &_name) {
    if (_name.isEmpty()) {
        setUMLStereotype(NULL);
        return;
    }
    UMLDoc *pDoc = UMLApp::app()->getDocument();
    UMLStereotype *s = pDoc->findOrCreateStereotype(_name);
    setUMLStereotype(s);
}

void UMLObject::setPackage(const TQString &_name) {
    UMLObject *pkgObj = NULL;
    if (!_name.isEmpty()) {
        UMLDoc* umldoc = UMLApp::app()->getDocument();
        pkgObj = umldoc->findUMLObject(_name);
        if (pkgObj == NULL) {
            kDebug() << "UMLObject::setPackage: creating UMLPackage "
                << _name << " for " << m_Name << endl;
            pkgObj = Import_Utils::createUMLObject(Uml::ot_Package, _name);
        } else {
            const Uml::Object_Type ot = pkgObj->getBaseType();
            if (ot != Uml::ot_Package && ot != Uml::ot_Folder && ot != Uml::ot_Component) {
                kError() << "UMLObject::setPackage(" << m_Name << "): "
                    << "existing " << _name << " is not a container" << endl;
                // This should not happen - if it does, there may be further problems.
                // A container name should not overlap with another name in the same scope.
                pkgObj = Import_Utils::createUMLObject(Uml::ot_Package, _name);
            }
        }
    }
    setUMLPackage( static_cast<UMLPackage *>(pkgObj) );
}

void UMLObject::setUMLPackage(UMLPackage* pPkg) {
    m_pUMLPackage = pPkg;
    emitModified();
}

const UMLStereotype * UMLObject::getUMLStereotype() {
    return m_pStereotype;
}

TQString UMLObject::getStereotype(bool includeAdornments /* = false */) const {
    if (m_pStereotype == NULL)
        return "";
    TQString name = m_pStereotype->getName();
    if (includeAdornments)
        name = TQString::fromUtf8("«") + name + TQString::fromUtf8("»");
    return name;
}

TQString UMLObject::getPackage(const TQString& separator, bool includeRoot) {
    TQString tempSeparator = separator;
    if (tempSeparator.isEmpty())
        tempSeparator = UMLApp::app()->activeLanguageScopeSeparator();
    TQString fqn = getFullyQualifiedName(tempSeparator, includeRoot);
    if (!fqn.contains(tempSeparator))
        return "";
    TQString scope = fqn.left(fqn.length() - tempSeparator.length() - m_Name.length());
    return scope;
}

UMLPackageList UMLObject::getPackages(bool includeRoot) const {
    UMLPackageList pkgList;
    UMLPackage* pkg = m_pUMLPackage;
    while (pkg != NULL) {
        pkgList.prepend(pkg);
        pkg = pkg->getUMLPackage();
    }
    if (!includeRoot)
        pkgList.removeFirst();
    return pkgList;
}

UMLPackage* UMLObject::getUMLPackage() {
    return m_pUMLPackage;
}

TQString UMLObject::getSecondaryId() const {
    return m_SecondaryId;
}

void UMLObject::setSecondaryId(const TQString& id) {
    m_SecondaryId = id;
}

TQString UMLObject::getSecondaryFallback() const {
    return m_SecondaryFallback;
}

void UMLObject::setSecondaryFallback(const TQString& id) {
    m_SecondaryFallback = id;
}

void UMLObject::maybeSignalObjectCreated() {
    if (!m_bCreationWasSignalled &&
            m_BaseType != Uml::ot_Stereotype &&
            m_BaseType != Uml::ot_Association &&
            m_BaseType != Uml::ot_Role) {
        m_bCreationWasSignalled = true;
        UMLDoc* umldoc = UMLApp::app()->getDocument();
        umldoc->signalUMLObjectCreated(this);
    }
}

bool UMLObject::resolveRef() {
    if (m_pSecondary || (m_SecondaryId.isEmpty() && m_SecondaryFallback.isEmpty())) {
        maybeSignalObjectCreated();
        return true;
    }
#ifdef VERBOSE_DEBUGGING
    kDebug() << "UMLObject::resolveRef(" << m_Name << "): m_SecondaryId is "
              << m_SecondaryId << endl;
#endif
    UMLDoc *pDoc = UMLApp::app()->getDocument();
    // In the new, XMI standard compliant save format,
    // the type is the xmi.id of a UMLClassifier.
    if (! m_SecondaryId.isEmpty()) {
        m_pSecondary = pDoc->findObjectById(STR2ID(m_SecondaryId));
        if (m_pSecondary != NULL) {
            if (m_pSecondary->getBaseType() == Uml::ot_Stereotype) {
                m_pStereotype = static_cast<UMLStereotype*>(m_pSecondary);
                m_pStereotype->incrRefCount();
                m_pSecondary = NULL;
            }
            m_SecondaryId = "";
            maybeSignalObjectCreated();
            return true;
        }
        if (m_SecondaryFallback.isEmpty()) {
            kDebug() << "UMLObject::resolveRef: object with xmi.id=" << m_SecondaryId
                << " not found, setting to undef" << endl;
            UMLFolder *datatypes = pDoc->getDatatypeFolder();
            m_pSecondary = Object_Factory::createUMLObject(Uml::ot_Datatype, "undef", datatypes, false);
            return true;
        }
    }
    if (m_SecondaryFallback.isEmpty()) {
        kError() << "UMLObject::resolveRef(" << m_Name
            << "): cannot find type with id "
            << m_SecondaryId << endl;
        return false;
    }
#ifdef VERBOSE_DEBUGGING
    kDebug() << "UMLObject::resolveRef(" << m_Name
              << "): could not resolve secondary ID " << m_SecondaryId
              << ", using secondary fallback " << m_SecondaryFallback
              << endl;
#endif
    m_SecondaryId = m_SecondaryFallback;
    // Assume we're dealing with the older Umbrello format where
    // the type name was saved in the "type" attribute rather
    // than the xmi.id of the model object of the attribute type.
    m_pSecondary = pDoc->findUMLObject( m_SecondaryId, Uml::ot_UMLObject, this );
    if (m_pSecondary) {
        m_SecondaryId = "";
        maybeSignalObjectCreated();
        return true;
    }
    // Work around Object_Factory::createUMLObject()'s incapability
    // of on-the-fly scope creation:
    if (m_SecondaryId.contains("::")) {
        // TODO: Merge Import_Utils::createUMLObject() into Object_Factory::createUMLObject()
        m_pSecondary = Import_Utils::createUMLObject(Uml::ot_UMLObject, m_SecondaryId, m_pUMLPackage);
        if (m_pSecondary) {
            if (Import_Utils::newUMLObjectWasCreated()) {
                maybeSignalObjectCreated();
                kapp->processEvents();
                kDebug() << "UMLObject::resolveRef: Import_Utils::createUMLObject() "
                          << "created a new type for " << m_SecondaryId << endl;
            } else {
                kDebug() << "UMLObject::resolveRef: Import_Utils::createUMLObject() "
                          << "returned an existing type for " << m_SecondaryId << endl;
            }
            m_SecondaryId = "";
            return true;
        }
        kError() << "UMLObject::resolveRef: Import_Utils::createUMLObject() "
                  << "failed to create a new type for " << m_SecondaryId << endl;
        return false;
    }
    kDebug() << "UMLObject::resolveRef: Creating new type for " << m_SecondaryId << endl;
    // This is very C++ specific - we rely on  some '*' or
    // '&' to decide it's a ref type. Plus, we don't recognize
    // typedefs of ref types.
    bool isReferenceType = ( m_SecondaryId.contains('*') ||
                             m_SecondaryId.contains('&') );
    Uml::Object_Type ot = Uml::ot_Class;
    if (isReferenceType) {
        ot = Uml::ot_Datatype;
    } else {
        if (Model_Utils::isCommonDataType(m_SecondaryId))
            ot = Uml::ot_Datatype;
    }
    m_pSecondary = Object_Factory::createUMLObject(ot, m_SecondaryId, NULL);
    if (m_pSecondary == NULL)
        return false;
    m_SecondaryId = "";
    maybeSignalObjectCreated();
    //kapp->processEvents();
    return true;
}

TQDomElement UMLObject::save( const TQString &tag, TQDomDocument & qDoc ) {
    /*
      Call as the first action of saveToXMI() in child class:
      This creates the TQDomElement with which to work.
    */
    TQDomElement qElement = qDoc.createElement(tag);
    qElement.setAttribute( "isSpecification", "false" );
    if (m_BaseType != Uml::ot_Association &&
            m_BaseType != Uml::ot_Role &&
            m_BaseType != Uml::ot_Attribute) {
        qElement.setAttribute( "isLeaf", "false" );
        qElement.setAttribute( "isRoot", "false" );
        if (m_bAbstract)
            qElement.setAttribute( "isAbstract", "true" );
        else
            qElement.setAttribute( "isAbstract", "false" );
    }
    qElement.setAttribute( "xmi.id", ID2STR(m_nId) );
    qElement.setAttribute( "name", m_Name );
    if (m_BaseType != Uml::ot_Operation &&
            m_BaseType != Uml::ot_Role &&
            m_BaseType != Uml::ot_Attribute) {
        Uml::IDType nmSpc;
        if (m_pUMLPackage)
            nmSpc = m_pUMLPackage->getID();
        else
            nmSpc = UMLApp::app()->getDocument()->getModelID();
        qElement.setAttribute( "namespace", ID2STR(nmSpc) );
    }
    if (! m_Doc.isEmpty())
        qElement.setAttribute( "comment", m_Doc );  //CHECK: uml13.dtd compliance
#ifdef XMI_FLAT_PACKAGES
    if (m_pUMLPackage)             //FIXME: uml13.dtd compliance
        qElement.setAttribute( "package", m_pUMLPackage->getID() );
#endif
    TQString visibility = m_Vis.toString(false);
    qElement.setAttribute( "visibility", visibility);
    if (m_pStereotype != NULL)
        qElement.setAttribute( "stereotype", ID2STR(m_pStereotype->getID()) );
    if (m_bStatic)
        qElement.setAttribute( "ownerScope", "classifier" );
    /* else
        qElement.setAttribute( "ownerScope", "instance" );
     *** ownerScope defaults to instance if not set **********/
    return qElement;
}

bool UMLObject::load( TQDomElement& ) {
    // This body is not usually executed because child classes
    // overwrite the load method.
    return true;
}

bool UMLObject::loadStereotype(TQDomElement & element) {
    TQString tag = element.tagName();
    if (!Uml::tagEq(tag, "stereotype"))
        return false;
    TQString stereo = element.attribute("xmi.value", "");
    if (stereo.isEmpty() && element.hasChildNodes()) {
        /* like so:
         <UML:ModelElement.stereotype>
           <UML:Stereotype xmi.idref = '07CD'/>
         </UML:ModelElement.stereotype>
         */
        TQDomNode stereoNode = element.firstChild();
        TQDomElement stereoElem = stereoNode.toElement();
        tag = stereoElem.tagName();
        if (Uml::tagEq(tag, "Stereotype")) {
            stereo = stereoElem.attribute("xmi.idref", "");
        }
    }
    if (stereo.isEmpty())
        return false;
    Uml::IDType stereoID = STR2ID(stereo);
    UMLDoc *pDoc = UMLApp::app()->getDocument();
    m_pStereotype = pDoc->findStereotypeById(stereoID);
    if (m_pStereotype)
        m_pStereotype->incrRefCount();
    else
        m_SecondaryId = stereo;  // leave it to resolveRef()
    return true;
}

bool UMLObject::loadFromXMI( TQDomElement & element) {
    UMLDoc* umldoc = UMLApp::app()->getDocument();
    if (umldoc == NULL) {
        kError() << "UMLObject::loadFromXMI: umldoc is NULL" << endl;
        return false;
    }
    // Read the name first so that if we encounter a problem, the error
    // message can say the name.
    m_Name = element.attribute( "name", "" );
    TQString id = element.attribute( "xmi.id", "" );
    if (id.isEmpty() || id == "-1") {
        if (m_BaseType == Uml::ot_Role) {
            // Before version 1.4, Umbrello did not save the xmi.id
            // of UMLRole objects.
            m_nId = UniqueID::gen();
        } else {
            kError() << "UMLObject::loadFromXMI(" << m_Name
            << "): nonexistent or illegal xmi.id" << endl;
            return false;
        }
    } else {
        m_nId = STR2ID(id);
        if (m_BaseType == Uml::ot_Role) {
            // Some older Umbrello versions had a problem with xmi.id's
            // of other objects being reused for the UMLRole, see e.g.
            // attachment 21179 at http://bugs.kde.org/147988 .
            // If the xmi.id is already being used then we generate a new one.
            UMLObject *o = umldoc->findObjectById(m_nId);
            if (o) {
                kDebug() << "loadFromXMI(UMLRole): id " << id
                    << " is already in use, generating a new one." << endl;
                m_nId = UniqueID::gen();
            }
        }
    }

    if (element.hasAttribute("documentation"))  // for bkwd compat.
        m_Doc = element.attribute( "documentation", "" );
    else
        m_Doc = element.attribute( "comment", "" );  //CHECK: need a UML:Comment?

    m_Vis = Uml::Visibility::Public;
    if (element.hasAttribute("scope")) {        // for bkwd compat.
        TQString scope = element.attribute( "scope", "" );
        if (scope == "instance_level")         // nsuml compat.
            m_bStatic = false;
        else if (scope == "classifier_level")  // nsuml compat.
            m_bStatic = true;
        else {
            int nScope = scope.toInt();
            if (nScope >= Uml::Visibility::Public && nScope <= Uml::Visibility::Protected)
              m_Vis = (Uml::Visibility::Value)nScope;
            else
                kError() << "UMLObject::loadFromXMI(" << m_Name
                << "): illegal scope" << endl;  // soft error
        }
    } else {
        TQString visibility = element.attribute( "visibility", "public" );
        if (visibility == "private"
                || visibility == "private_vis")    // for compatibility with other programs
              m_Vis = Uml::Visibility::Private;
        else if (visibility == "protected"
                       || visibility == "protected_vis")  // for compatibility with other programs
          m_Vis = Uml::Visibility::Protected;
        else if (visibility == "implementation")
          m_Vis = Uml::Visibility::Implementation;
    }

    TQString stereo = element.attribute( "stereotype", "" );
    if (!stereo.isEmpty()) {
        Uml::IDType stereoID = STR2ID(stereo);
        m_pStereotype = umldoc->findStereotypeById(stereoID);
        if (m_pStereotype) {
            m_pStereotype->incrRefCount();
        } else {
            kDebug() << "UMLObject::loadFromXMI(" << m_Name << "): "
                << "UMLStereotype " << ID2STR(stereoID)
                << " not found, creating now." << endl;
            setStereotype(stereo);
        }
    }

    if( element.hasAttribute("abstract") ) {     // for bkwd compat.
        TQString abstract = element.attribute( "abstract", "0" );
        m_bAbstract = (bool)abstract.toInt();
    } else {
        TQString isAbstract = element.attribute( "isAbstract", "false" );
        m_bAbstract = (isAbstract == "true");
    }

    if( element.hasAttribute("static") ) {       // for bkwd compat.
        TQString staticScope = element.attribute( "static", "0" );
        m_bStatic = (bool)staticScope.toInt();
    } else {
        TQString ownerScope = element.attribute( "ownerScope", "instance" );
        m_bStatic = (ownerScope == "classifier");
    }

    // If the node has child nodes, check whether attributes can be
    // extracted from them.
    if (element.hasChildNodes()) {
        TQDomNode node = element.firstChild();
        if (node.isComment())
            node = node.nextSibling();
        TQDomElement elem = node.toElement();
        while( !elem.isNull() ) {
            TQString tag = elem.tagName();
            if (Uml::tagEq(tag, "name")) {
                m_Name = elem.attribute("xmi.value", "");
                if (m_Name.isEmpty())
                    m_Name = elem.text();
            } else if (Uml::tagEq(tag, "visibility")) {
                TQString vis = elem.attribute("xmi.value", "");
                if (vis.isEmpty())
                    vis = elem.text();
                if (vis == "private" || vis == "private_vis")
                    m_Vis = Uml::Visibility::Private;
                else if (vis == "protected" || vis == "protected_vis")
                    m_Vis = Uml::Visibility::Protected;
                else if (vis == "implementation")
                    m_Vis = Uml::Visibility::Implementation;
            } else if (Uml::tagEq(tag, "isAbstract")) {
                TQString isAbstract = elem.attribute("xmi.value", "");
                if (isAbstract.isEmpty())
                    isAbstract = elem.text();
                m_bAbstract = (isAbstract == "true");
            } else if (Uml::tagEq(tag, "ownerScope")) {
                TQString ownerScope = elem.attribute("xmi.value", "");
                if (ownerScope.isEmpty())
                    ownerScope = elem.text();
                m_bStatic = (ownerScope == "classifier");
            } else {
                loadStereotype(elem);
            }
            node = node.nextSibling();
            if (node.isComment())
                node = node.nextSibling();
            elem = node.toElement();
        }
    }

    // Operations, attributes, enum literals, templates, stereotypes,
    // and association role objects get added and signaled elsewhere.
    if (m_BaseType != Uml::ot_Operation && m_BaseType != Uml::ot_Attribute &&
            m_BaseType != Uml::ot_EnumLiteral && m_BaseType != Uml::ot_EntityAttribute &&
            m_BaseType != Uml::ot_Template && m_BaseType != Uml::ot_Stereotype &&
            m_BaseType != Uml::ot_Role) {
        if (m_bInPaste) {
            m_pUMLPackage = NULL;  // forget any old parent
            UMLListView *listView = UMLApp::app()->getListView();
            UMLListViewItem *parentItem = (UMLListViewItem*)listView->currentItem();
            if (parentItem) {
                Uml::ListView_Type lvt = parentItem->getType();
                if (Model_Utils::typeIsContainer(lvt) ||
                        lvt == Uml::lvt_Class ||
                        lvt == Uml::lvt_Interface) {
                    UMLObject *o = parentItem->getUMLObject();
                    m_pUMLPackage = static_cast<UMLPackage*>( o );
                }
            }
        }
        if (m_pUMLPackage) {
            m_pUMLPackage->addObject(this);
        } else if (umldoc->rootFolderType(this) == Uml::N_MODELTYPES) {
            // m_pUMLPackage is not set on the root folders.
            kDebug() << "UMLObject::loadFromXMI(" << m_Name << "): m_pUMLPackage is not set"
                << endl;
        }
    }
    return load(element);
}

kdbgstream& operator<< (kdbgstream& s, const UMLObject& a) {
    s << a.getName();
    return s;
}

#include "umlobject.moc"
