diff -Nuar umbrello-kf6-15.08.1.orig/CMakeLists.txt umbrello-kf6-15.08.1/CMakeLists.txt --- umbrello-kf6-15.08.1.orig/CMakeLists.txt 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/CMakeLists.txt 2015-10-08 11:48:59.471089026 +0300 @@ -6,8 +6,8 @@ set (KDE_APPLICATIONS_VERSION_MICRO "1") set(umbrello-kf6_VERSION_MAJOR "2") -set(umbrello-kf6_VERSION_MINOR "17") -set(umbrello-kf6_VERSION_PATCH ${KDE_APPLICATIONS_VERSION_MICRO}) +set(umbrello-kf6_VERSION_MINOR "18") +set(umbrello-kf6_VERSION_PATCH "99") option(BUILD_KF5 "Build for KDE Frameworks 5" OFF) diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/actor.cpp umbrello-kf6-15.08.1/umbrello/actor.cpp --- umbrello-kf6-15.08.1.orig/umbrello/actor.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/actor.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,67 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#include "actor.h" - -/** - * Constructs an Actor. - * - * @param name The name of the Actor. - * @param id The unique id to assign to this Actor. - */ -UMLActor::UMLActor(const QString & name, Uml::ID::Type id) - : UMLCanvasObject(name, id) -{ - init(); -} - -/** - * Standard destructor. - */ -UMLActor::~UMLActor() -{ -} - -/** - * Initializes key variables of the class. - */ -void UMLActor::init() -{ - m_BaseType = UMLObject::ot_Actor; -} - -/** - * Make a clone of this object. - */ -UMLObject* UMLActor::clone() const -{ - UMLActor *clone = new UMLActor(); - UMLObject::copyInto(clone); - return clone; -} - -/** - * Creates the XMI element. - */ -void UMLActor::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) -{ - QDomElement actorElement = UMLObject::save(QLatin1String("UML:Actor"), qDoc); - qElement.appendChild(actorElement); -} - -/** - * Loads the XMI element (empty). - */ -bool UMLActor::load(QDomElement& element) -{ - Q_UNUSED(element); - return true; -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/actor.h umbrello-kf6-15.08.1/umbrello/actor.h --- umbrello-kf6-15.08.1.orig/umbrello/actor.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/actor.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,44 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef ACTOR_H -#define ACTOR_H - -#include "umlcanvasobject.h" - -/** - * This class contains the non-graphical information required for a UML Actor. - * This class inherits from @ref UMLCanvasObject which contains most of the - * information. - * The @ref UMLDoc class creates instances of this type. - * - * @short Information for a non-graphical UML Actor. - * @author Paul Hensgen - * @see UMLCanvasObject - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class UMLActor : public UMLCanvasObject -{ - Q_OBJECT -public: - explicit UMLActor(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); - virtual ~UMLActor(); - - virtual void init(); - - virtual UMLObject* clone() const; - - void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); - -protected: - bool load(QDomElement & element); -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/artifact.cpp umbrello-kf6-15.08.1/umbrello/artifact.cpp --- umbrello-kf6-15.08.1.orig/umbrello/artifact.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/artifact.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,90 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#include "artifact.h" -#include "association.h" -#include "clipboard/idchangelog.h" - -#include - -/** - * Sets up an Artifact. - * @param name The name of the Concept. - * @param id The unique id of the Concept. - */ -UMLArtifact::UMLArtifact(const QString & name, Uml::ID::Type id) - : UMLPackage(name, id), - m_drawAsType(defaultDraw) -{ - m_BaseType = UMLObject::ot_Artifact; -} - -/** - * Standard deconstructor. - */ -UMLArtifact::~UMLArtifact() -{ -} - -/** - * Make a clone of this object. - * @return the cloned object - */ -UMLObject* UMLArtifact::clone() const -{ - UMLArtifact *clone = new UMLArtifact(); - UMLObject::copyInto(clone); - return clone; -} - -/** - * Creates the UML:Artifact element including its operations, - * attributes and templates - * @param qDoc the xml document - * @param qElement the xml element - */ -void UMLArtifact::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) -{ - QDomElement artifactElement = UMLObject::save(QLatin1String("UML:Artifact"), qDoc); - artifactElement.setAttribute(QLatin1String("drawas"), m_drawAsType); - qElement.appendChild(artifactElement); -} - -/** - * Loads the UML:Artifact element including its operations, - * attributes and templates. - * @param element the xml element to load - * @return the success status of the operation - */ -bool UMLArtifact::load(QDomElement& element) -{ - QString drawAs = element.attribute(QLatin1String("drawas"), QLatin1String("0")); - m_drawAsType = (Draw_Type)drawAs.toInt(); - return true; -} - -/** - * Sets m_drawAsType for which method to draw the artifact as. - * @param type the draw type - */ -void UMLArtifact::setDrawAsType(Draw_Type type) -{ - m_drawAsType = type; -} - -/** - * Returns the value of m_drawAsType. - * @return the value of the draw type attribute - */ -UMLArtifact::Draw_Type UMLArtifact::getDrawAsType() -{ - return m_drawAsType; -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/artifact.h umbrello-kf6-15.08.1/umbrello/artifact.h --- umbrello-kf6-15.08.1.orig/umbrello/artifact.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/artifact.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,66 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef ARTIFACT_H -#define ARTIFACT_H - -#include "package.h" - -/** - * This class contains the non-graphical information required for a UML - * Artifact. - * This class inherits from @ref UMLCanvasObject which contains most of the - * information. - * - * @short Non-graphical information for a Artifact. - * @author Jonathan Riddell - * @see UMLCanvasObject - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class UMLArtifact : public UMLPackage -{ - Q_OBJECT -public: - - /** - * Artifacts can be drawn using one of several icons. - */ - enum Draw_Type { - defaultDraw, - file, - library, - table - }; - - explicit UMLArtifact(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); - virtual ~UMLArtifact(); - - virtual UMLObject* clone() const; - - void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); - - void setDrawAsType(Draw_Type type); - - Draw_Type getDrawAsType(); - -protected: - - bool load(QDomElement & element); - -private: - - /** - * Artifacts can be drawn as one of several different icons, - * this value choosing how to draw them. - */ - Draw_Type m_drawAsType; -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/association.cpp umbrello-kf6-15.08.1/umbrello/association.cpp --- umbrello-kf6-15.08.1.orig/umbrello/association.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/association.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,742 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "association.h" - -// app includes -#include "debug_utils.h" -#include "classifier.h" -#include "classpropertiesdialog.h" -#include "folder.h" -#include "uml.h" -#include "umldoc.h" -#include "umlrole.h" -#include "uniqueid.h" -#include "model_utils.h" -#include "cmds.h" - -// kde includes -#include - -// qt includes -#include -#include - -using namespace Uml; - -DEBUG_REGISTER(UMLAssociation) - -/** - * Sets up an association. - * A new unique ID is assigned internally. - * @param type The AssociationType::Enum to construct. - * @param roleA Pointer to the UMLObject in role A. - * @param roleB Pointer to the UMLObject in role B. - */ -UMLAssociation::UMLAssociation(Uml::AssociationType::Enum type, - UMLObject * roleA, UMLObject * roleB) - : UMLObject(QString()) -{ - init(type, roleA, roleB); - - m_pRole[RoleType::A]->setID(UniqueID::gen()); - m_pRole[RoleType::B]->setID(UniqueID::gen()); -} - -/** - * Constructs an association - for loading only. - * This constructor should not normally be used as it constructs - * an incomplete association (i.e. the role objects are missing.) - * @param type The AssociationType::Enum to construct. - * Default: Unknown. - */ -UMLAssociation::UMLAssociation(Uml::AssociationType::Enum type) - : UMLObject(QString(), Uml::ID::Reserved) -{ - init(type, NULL, NULL); -} - -/** - * Standard destructor. - */ -UMLAssociation::~UMLAssociation() -{ - if (m_pRole[RoleType::A] == NULL) { - uError() << "UMLAssociation destructor: m_pRole[A] is NULL already"; - } else { - delete m_pRole[RoleType::A]; - m_pRole[RoleType::A] = NULL; - } - if (m_pRole[RoleType::B] == NULL) { - uError() << "UMLAssociation destructor: m_pRole[B] is NULL already"; - } else { - delete m_pRole[RoleType::B]; - m_pRole[RoleType::B] = NULL; - } -} - -/** - * Overloaded '==' operator - */ -bool UMLAssociation::operator==(const UMLAssociation &rhs) const -{ - if (this == &rhs) { - return true; - } - return (UMLObject::operator== (rhs) && - m_AssocType == rhs.m_AssocType && - m_Name == rhs.m_Name && - m_pRole[RoleType::A] == rhs.m_pRole[RoleType::A] && - m_pRole[RoleType::B] == rhs.m_pRole[RoleType::B]); -} - -/** - * Returns the AssociationType::Enum of the UMLAssociation. - * @return The AssociationType::Enum of the UMLAssociation. - */ -Uml::AssociationType::Enum UMLAssociation::getAssocType() const -{ - return m_AssocType; -} - -/** - * Returns a String representation of this UMLAssociation. - */ -QString UMLAssociation::toString() const -{ - QString string; - if(m_pRole[RoleType::A]) - { - string += m_pRole[RoleType::A]->object()->name(); - string += QLatin1Char(':'); - string += m_pRole[RoleType::A]->name(); - } - string += QLatin1Char(':') + Uml::AssociationType::toStringI18n(m_AssocType) + QLatin1Char(':'); - if(m_pRole[RoleType::B]) - { - string += m_pRole[RoleType::B]->object()->name(); - string += QLatin1Char(':'); - string += m_pRole[RoleType::B]->name(); - } - return string; -} - -/** - * Resolve types. Required when dealing with foreign XMI files. - * Needs to be called after all UML objects are loaded from file. - * Overrides the method from UMLObject. - * Calls resolveRef() for each role. - * @return True for success. - */ -bool UMLAssociation::resolveRef() -{ - bool successA = getUMLRole(RoleType::A)->resolveRef(); - bool successB = getUMLRole(RoleType::B)->resolveRef(); - if (successA && successB) { - UMLObject *objA = getUMLRole(RoleType::A)->object(); - UMLObject *objB = getUMLRole(RoleType::B)->object(); - // Check if need to change the assoc type to Realization - if (isRealization(objA, objB)) { - m_AssocType = Uml::AssociationType::Realization; - } - m_pUMLPackage->addAssocToConcepts(this); - return true; - } - return false; -} - -/** - * Creates the or XMI element - * including its role objects. - */ -void UMLAssociation::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) -{ - if (m_AssocType == Uml::AssociationType::Generalization) { - QDomElement assocElement = UMLObject::save(QLatin1String("UML:Generalization"), qDoc); - assocElement.setAttribute(QLatin1String("discriminator"), QString()); - assocElement.setAttribute(QLatin1String("child"), Uml::ID::toString(getObjectId(RoleType::A))); - assocElement.setAttribute(QLatin1String("parent"), Uml::ID::toString(getObjectId(RoleType::B))); - qElement.appendChild(assocElement); - return; - } - if (m_AssocType == Uml::AssociationType::Realization) { - QDomElement assocElement = UMLObject::save(QLatin1String("UML:Abstraction"), qDoc); - assocElement.setAttribute(QLatin1String("client"), Uml::ID::toString(getObjectId(RoleType::A))); - assocElement.setAttribute(QLatin1String("supplier"), Uml::ID::toString(getObjectId(RoleType::B))); - qElement.appendChild(assocElement); - return; - } - if (m_AssocType == Uml::AssociationType::Dependency) { - QDomElement assocElement = UMLObject::save(QLatin1String("UML:Dependency"), qDoc); - assocElement.setAttribute(QLatin1String("client"), Uml::ID::toString(getObjectId(RoleType::A))); - assocElement.setAttribute(QLatin1String("supplier"), Uml::ID::toString(getObjectId(RoleType::B))); - qElement.appendChild(assocElement); - return; - } - if (m_AssocType == Uml::AssociationType::Child2Category) { - QDomElement assocElement = UMLObject::save(QLatin1String("UML:Child2Category"), qDoc); - assocElement.setAttribute(QLatin1String("client"), Uml::ID::toString(getObjectId(RoleType::A))); - assocElement.setAttribute(QLatin1String("supplier"), Uml::ID::toString(getObjectId(RoleType::B))); - qElement.appendChild(assocElement); - return; - } - if (m_AssocType == Uml::AssociationType::Category2Parent) { - QDomElement assocElement = UMLObject::save(QLatin1String("UML:Category2Parent"), qDoc); - assocElement.setAttribute(QLatin1String("client"), Uml::ID::toString(getObjectId(RoleType::A))); - assocElement.setAttribute(QLatin1String("supplier"), Uml::ID::toString(getObjectId(RoleType::B))); - qElement.appendChild(assocElement); - return; - } - - QDomElement associationElement = UMLObject::save(QLatin1String("UML:Association"), qDoc); - QDomElement connElement = qDoc.createElement(QLatin1String("UML:Association.connection")); - getUMLRole(RoleType::A)->saveToXMI (qDoc, connElement); - getUMLRole(RoleType::B)->saveToXMI (qDoc, connElement); - associationElement.appendChild (connElement); - qElement.appendChild(associationElement); -} - -bool UMLAssociation::showPropertiesDialog(QWidget *parent) -{ - QPointer dlg = new ClassPropertiesDialog(parent, this, true); - bool modified = false; - if (dlg->exec()) { - modified = true; - } - dlg->close(); - delete dlg; - return modified; -} - -/** - * Creates the or XMI element - * including its role objects. - */ -bool UMLAssociation::load(QDomElement & element) -{ - if (id() == Uml::ID::None) - return false; // old style XMI file. No real info in this association. - - UMLDoc * doc = UMLApp::app()->document(); - UMLObject * obj[2] = { NULL, NULL }; - if (m_AssocType == Uml::AssociationType::Generalization || - m_AssocType == Uml::AssociationType::Realization || - m_AssocType == Uml::AssociationType::Dependency || - m_AssocType == Uml::AssociationType::Child2Category || - m_AssocType == Uml::AssociationType::Category2Parent) { - QString general = element.attribute(QLatin1String("general")); - if (!general.isEmpty()) { - UMLClassifier *owningClassifier = dynamic_cast(m_pUMLPackage); - if (owningClassifier == NULL){ - uWarning() << "Cannot load UML2 generalization: m_pUMLPackage is expected " - << "to be the owning classifier (=client)"; - return false; - } - m_pRole[RoleType::A]->setObject(owningClassifier); - m_pRole[RoleType::B]->setSecondaryId(general); // defer resolution to resolveRef() - owningClassifier->addAssociationEnd(this); - m_pUMLPackage = m_pUMLPackage->umlPackage(); // reparent - m_pUMLPackage->addObject(this); - return true; - } - for (unsigned r = RoleType::A; r <= RoleType::B; ++r) { - const QString fetch = (m_AssocType == Uml::AssociationType::Generalization ? - r == RoleType::A ? QLatin1String("child") : QLatin1String("parent") - : r == RoleType::A ? QLatin1String("client") : QLatin1String("supplier")); - QString roleIdStr = element.attribute(fetch); - if (roleIdStr.isEmpty()) { - // Might be given as a child node instead - see below. - continue; - } - - // set umlobject of role if possible (else defer resolution) - obj[r] = doc->findObjectById(Uml::ID::fromString(roleIdStr)); - Uml::RoleType::Enum role = Uml::RoleType::fromInt(r); - if (obj[r] == NULL) { - m_pRole[role]->setSecondaryId(roleIdStr); // defer to resolveRef() - } else { - m_pRole[role]->setObject(obj[r]); - if (m_pUMLPackage == NULL) { - Uml::ModelType::Enum mt = Model_Utils::convert_OT_MT(obj[r]->baseType()); - m_pUMLPackage = doc->rootFolder(mt); - DEBUG(DBG_SRC) << "assoctype " << m_AssocType - << ": setting model type " << Uml::ModelType::toString(mt); - } - } - } - if (obj[RoleType::A] == NULL || obj[RoleType::B] == NULL) { - for (QDomNode node = element.firstChild(); !node.isNull(); - node = node.nextSibling()) { - if (node.isComment()) - continue; - QDomElement tempElement = node.toElement(); - QString tag = tempElement.tagName(); - if (Model_Utils::isCommonXMIAttribute(tag)) - continue; - // Permitted tag names: - // roleA: "child" "subtype" "client" - // roleB: "parent" "supertype" "supplier" - QString idStr = tempElement.attribute(QLatin1String("xmi.id")); - if (idStr.isEmpty()) - idStr = tempElement.attribute(QLatin1String("xmi.idref")); - if (idStr.isEmpty()) { - QDomNode inner = node.firstChild(); - QDomElement tmpElem = inner.toElement(); - idStr = tmpElem.attribute(QLatin1String("xmi.id")); - if (idStr.isEmpty()) - idStr = tmpElem.attribute(QLatin1String("xmi.idref")); - } - if (idStr.isEmpty()) { - uError() << "type " << m_AssocType - << ", id " << Uml::ID::toString(id()) << ": " - << "xmi id not given for " << tag; - continue; - } - // Since we know for sure that we're dealing with a non - // umbrello-kf6 file, use deferred resolution unconditionally. - if (UMLDoc::tagEq(tag, QLatin1String("child")) || - UMLDoc::tagEq(tag, QLatin1String("subtype")) || - UMLDoc::tagEq(tag, QLatin1String("client"))) { - getUMLRole(RoleType::A)->setSecondaryId(idStr); - } else { - getUMLRole(RoleType::B)->setSecondaryId(idStr); - } - } - } - - // it is a realization if either endpoint is an interface - if (isRealization(obj[RoleType::A], obj[RoleType::B])) { - m_AssocType = Uml::AssociationType::Realization; - } - return true; - } - - for (QDomNode node = element.firstChild(); !node.isNull(); - node = node.nextSibling()) { - // uml13.dtd compliant format (new style) - if (node.isComment()) - continue; - QDomElement tempElement = node.toElement(); - QString tag = tempElement.tagName(); - if (Model_Utils::isCommonXMIAttribute(tag)) - continue; - if (!UMLDoc::tagEq(tag, QLatin1String("Association.connection")) && - !UMLDoc::tagEq(tag, QLatin1String("Association.end")) && // Embarcadero's Describe - !UMLDoc::tagEq(tag, QLatin1String("Namespace.ownedElement")) && - !UMLDoc::tagEq(tag, QLatin1String("Namespace.contents"))) { - uWarning() << "unknown child node " << tag; - continue; - } - // Load role A. - QDomNode nodeA = tempElement.firstChild(); - while (nodeA.isComment()) - nodeA = nodeA.nextSibling(); - tempElement = nodeA.toElement(); - if (tempElement.isNull()) { - uWarning() << "UML:Association : element (A) is Null"; - return false; - } - tag = tempElement.tagName(); - if (UMLDoc::tagEq(tag, QLatin1String("NavigableEnd"))) { // Embarcadero's Describe - m_AssocType = Uml::AssociationType::UniAssociation; - } else if (!UMLDoc::tagEq(tag, QLatin1String("AssociationEndRole")) && - !UMLDoc::tagEq(tag, QLatin1String("AssociationEnd"))) { - uWarning() << "unknown child (A) tag " << tag; - return false; - } - if (! getUMLRole(RoleType::A)->loadFromXMI(tempElement)) - return false; - // Load role B. - QDomNode nodeB = nodeA.nextSibling(); - while (nodeB.isComment()) - nodeB = nodeB.nextSibling(); - tempElement = nodeB.toElement(); - if (tempElement.isNull()) { - uWarning() << "UML:Association : element (B) is Null"; - return false; - } - tag = tempElement.tagName(); - if (UMLDoc::tagEq(tag, QLatin1String("NavigableEnd"))) { // Embarcadero's Describe - m_AssocType = Uml::AssociationType::UniAssociation; - } else if (!UMLDoc::tagEq(tag, QLatin1String("AssociationEndRole")) && - !UMLDoc::tagEq(tag, QLatin1String("AssociationEnd"))) { - uWarning() << "unknown child (B) tag " << tag; - return false; - } - if (! getUMLRole(RoleType::B)->loadFromXMI(tempElement)) - return false; - - if (m_pUMLPackage == NULL) { - Uml::ModelType::Enum mt = Model_Utils::convert_OT_MT(getObject(RoleType::B)->baseType()); - m_pUMLPackage = doc->rootFolder(mt); - DEBUG(DBG_SRC) << "setting model type " << Uml::ModelType::toString(mt); - } - - // setting the association type: - // - // In the old days, we could just record this on the association, - // and be done with it. But thats not how the UML13.dtd does things. - // As a result, we are checking roleA for information about the - // parent association (!) which by this point in the parse, should - // be set. However, the information that the roles are allowed to have - // is not complete, so we need to finish the analysis here. - - // find self-associations - if (m_AssocType == Uml::AssociationType::Association && getObjectId(RoleType::A) == getObjectId(RoleType::B)) - m_AssocType = Uml::AssociationType::Association_Self; - - // fall-back default type - if (m_AssocType == Uml::AssociationType::Unknown) { - m_AssocType = Uml::AssociationType::Association; - } - - return true; - } - - // From here on it's old-style stuff. - QString assocTypeStr = element.attribute(QLatin1String("assoctype"), QLatin1String("-1")); - Uml::AssociationType::Enum assocType = Uml::AssociationType::Unknown; - if (assocTypeStr[0] >= QLatin1Char('a') && assocTypeStr[0] <= QLatin1Char('z')) { - // In an earlier version, the natural assoctype names were saved. - const char *assocTypeString[] = { - "generalization", // Uml::AssociationType::Generalization - "aggregation", // Uml::AssociationType::Aggregation - "dependency", // Uml::AssociationType::Dependency - "association", // Uml::AssociationType::Association - "associationself", // Uml::AssociationType::Association_Self - "collmessage", // Uml::AssociationType::Coll_Message - "seqmessage", // Uml::AssociationType::Seq_Message - "collmessageself", // Uml::AssociationType::Coll_Message_Self - "seqmessageself", // Uml::AssociationType::Seq_Message_Self - "implementation", // Uml::AssociationType::Implementation - "composition", // Uml::AssociationType::Composition - "realization", // Uml::AssociationType::Realization - "uniassociation", // Uml::AssociationType::UniAssociation - "anchor", // Uml::AssociationType::Anchor - "state", // Uml::AssociationType::State - "activity", // Uml::AssociationType::Activity - "exception", // Uml::AssociationType::Exception - "category2parent" // Uml::AssociationType::Category2Parent - "child2category" // Uml::AssociationType::Child2Category - "relationship" // Uml::AssociationType::Relationship - }; - const int arraySize = sizeof(assocTypeString) / sizeof(char*); - DEBUG(DBG_SRC) << "AssociationType string array size = " << arraySize; - - int index; - for (index = 0; index < arraySize; ++index) - if (assocTypeStr == QString::fromLatin1(assocTypeString[index])) - break; - if (index < arraySize) - assocType = Uml::AssociationType::fromInt(index); - } else { - int assocTypeNum = assocTypeStr.toInt(); - if (assocTypeNum < (int)Uml::AssociationType::Generalization || // first enum - assocTypeNum >= (int)Uml::AssociationType::Reserved) { // last enum - uWarning() << "bad assoctype of UML:AssociationType::Enum " << Uml::ID::toString(id()); - return false; - } - assocType = Uml::AssociationType::fromInt(assocTypeNum); - } - setAssociationType(assocType); - - Uml::ID::Type roleAObjID = Uml::ID::fromString(element.attribute(QLatin1String("rolea"), QLatin1String("-1"))); - Uml::ID::Type roleBObjID = Uml::ID::fromString(element.attribute(QLatin1String("roleb"), QLatin1String("-1"))); - if (assocType == Uml::AssociationType::Aggregation || - assocType == Uml::AssociationType::Composition) { - // Flip roles to compensate for changed diamond logic in AssociationLine. - // For further explanations see AssociationWidget::loadFromXMI. - Uml::ID::Type tmp = roleAObjID; - roleAObjID = roleBObjID; - roleBObjID = tmp; - } - - UMLObject * objA = doc->findObjectById(roleAObjID); - UMLObject * objB = doc->findObjectById(roleBObjID); - - if(objA) - getUMLRole(RoleType::A)->setObject(objA); - else - return false; - - if(objB) - getUMLRole(RoleType::B)->setObject(objB); - else - return false; - - setMultiplicity(element.attribute(QLatin1String("multia")), RoleType::A); - setMultiplicity(element.attribute(QLatin1String("multib")), RoleType::B); - - setRoleName(element.attribute(QLatin1String("namea")), RoleType::A); - setRoleName(element.attribute(QLatin1String("nameb")), RoleType::B); - - setRoleDoc(element.attribute(QLatin1String("doca")), RoleType::A); - setRoleDoc(element.attribute(QLatin1String("docb")), RoleType::B); - - // Visibility defaults to Public if it cant set it here.. - QString visibilityA = element.attribute(QLatin1String("visibilitya"), QLatin1String("0")); - QString visibilityB = element.attribute(QLatin1String("visibilityb"), QLatin1String("0")); - int vis = visibilityA.toInt(); - if (vis >= 200) // bkwd compat. - vis -= 200; - setVisibility((Uml::Visibility::Enum)vis, RoleType::A); - vis = visibilityB.toInt(); - if (vis >= 200) // bkwd compat. - vis -= 200; - setVisibility((Uml::Visibility::Enum)vis, RoleType::B); - - // Changeability defaults to Changeable if it cant set it here.. - QString changeabilityA = element.attribute(QLatin1String("changeabilitya"), QLatin1String("0")); - QString changeabilityB = element.attribute(QLatin1String("changeabilityb"), QLatin1String("0")); - if (changeabilityA.toInt() > 0) - setChangeability(Uml::Changeability::fromInt(changeabilityA.toInt()), RoleType::A); - if (changeabilityB.toInt() > 0) - setChangeability(Uml::Changeability::fromInt(changeabilityB.toInt()), RoleType::B); - - return true; -} - -/** - * Returns the UMLObject assigned to the given role. - * @return Pointer to the UMLObject in the given role. - */ -UMLObject* UMLAssociation::getObject(Uml::RoleType::Enum role) const -{ - if (m_pRole[role] == NULL) - return NULL; - return m_pRole[role]->object(); -} - -/** - * Returns the ID of the UMLObject assigned to the given role. - * Shorthand for getObject(role)->ID(). - * @return ID of the UMLObject in the given role. - */ -Uml::ID::Type UMLAssociation::getObjectId(Uml::RoleType::Enum role) const -{ - UMLRole *roleObj = m_pRole[role]; - if (roleObj == NULL) - return Uml::ID::None; - UMLObject *o = roleObj->object(); - if (o == NULL) { - QString auxID = roleObj->secondaryId(); - if (auxID.isEmpty()) { - uError() << "role " << role << ": getObject returns NULL"; - return Uml::ID::None; - } else { - DEBUG(DBG_SRC) << "role " << role << ": using secondary ID " << auxID; - return Uml::ID::fromString(auxID); - } - } - return o->id(); -} - -/** - * Returns the ID of the UMLObject assigned to the given role. - * CURRENTLY UNUSED. - * @return ID of the UMLObject of the given role. - */ -Uml::ID::Type UMLAssociation::getRoleId(RoleType::Enum role) const -{ - return m_pRole[role]->id(); -} - -/** - * Returns the changeability. - */ -Uml::Changeability::Enum UMLAssociation::changeability(Uml::RoleType::Enum role) const -{ - return m_pRole[role]->changeability(); -} - -/** - * Returns the Visibility of the given role. - * @return Visibility of the given role. - */ -Uml::Visibility::Enum UMLAssociation::visibility(Uml::RoleType::Enum role) const -{ - return m_pRole[role]->visibility(); -} - -/** - * Returns the multiplicity assigned to the given role. - * @return The multiplicity assigned to the given role. - */ -QString UMLAssociation::getMultiplicity(Uml::RoleType::Enum role) const -{ - return m_pRole[role]->multiplicity(); -} - -/** - * Returns the name assigned to the role A. - * @return The name assigned to the given role. - */ -QString UMLAssociation::getRoleName(Uml::RoleType::Enum role) const -{ - return m_pRole[role]->name(); -} - -/** - * Returns the documentation assigned to the given role. - * @return Documentation text of given role. - */ -QString UMLAssociation::getRoleDoc(Uml::RoleType::Enum role) const -{ - return m_pRole[role]->doc(); -} - -/** - * Get the underlying UMLRole object for the given role. - * @return Pointer to the UMLRole object for the given role. - */ -UMLRole * UMLAssociation::getUMLRole(Uml::RoleType::Enum role) const -{ - return m_pRole[role]; -} - -/** - * Set the attribute m_bOldLoadMode. - * @param value the new value to set - */ -void UMLAssociation::setOldLoadMode(bool value /* = true */) -{ - m_bOldLoadMode = value; -} - -/** - * Return the backward compatibility flag for loading files. - */ -bool UMLAssociation::getOldLoadMode() const -{ - return m_bOldLoadMode; -} - -/** - * Sets the assocType of the UMLAssociation. - * @param assocType The AssociationType::Enum of the UMLAssociation. - */ -void UMLAssociation::setAssociationType(Uml::AssociationType::Enum assocType) -{ - m_AssocType = assocType; - if (m_AssocType == Uml::AssociationType::UniAssociation) - { - // In this case we need to auto-set the multiplicity/rolenames - // of the roles -#ifdef VERBOSE_DEBUGGING - DEBUG(DBG_SRC) << " A new uni-association has been created."; -#endif - } - UMLObject::emitModified(); -} - -/** - * Sets the UMLObject playing the given role in the association. - * @param obj Pointer to the UMLObject of the given role. - * @param role The Uml::RoleType::Enum played by the association - */ -void UMLAssociation::setObject(UMLObject *obj, Uml::RoleType::Enum role) -{ - m_pRole[role]->setObject(obj); -} - -/** - * Sets the visibility of the given role of the UMLAssociation. - * @param value Visibility of role. - * @param role The Uml::RoleType::Enum to which the visibility is being applied - */ -void UMLAssociation::setVisibility(Visibility::Enum value, Uml::RoleType::Enum role) -{ - m_pRole[role]->setVisibility(value); -} - -/** - * Sets the changeability of the given role of the UMLAssociation. - * @param value Changeability_Type of the given role. - * @param role The Uml::RoleType::Enum to which the changeability is being set - */ -void UMLAssociation::setChangeability(Uml::Changeability::Enum value, Uml::RoleType::Enum role) -{ - m_pRole[role]->setChangeability(value); -} - -/** - * Sets the multiplicity of the given role of the UMLAssociation. - * @param multi The multiplicity of the given role. - * @param role The Uml::RoleType::Enum to which the multiplicity is being applied - */ -void UMLAssociation::setMultiplicity(const QString &multi, Uml::RoleType::Enum role) -{ - if (m_pRole[role]->multiplicity() != multi) { - UMLApp::app()->executeCommand(new CmdChangeMultiplicity(m_pRole[role], multi)); - } -} - -/** - * Sets the name of the given role of the UMLAssociation. - * @param roleName The name to set for the given role. - * @param role The Uml::RoleType::Enum for which to set the name. - */ -void UMLAssociation::setRoleName(const QString &roleName, Uml::RoleType::Enum role) -{ - m_pRole[role]->setName(roleName); -} - -/** - * Sets the documentation on the given role in the association. - * @param doc The string with the documentation. - * @param role The Uml::RoleType::Enum to which the documentation is being applied - */ -void UMLAssociation::setRoleDoc(const QString &doc, Uml::RoleType::Enum role) -{ - m_pRole[role]->setDoc(doc); -} - -/** - * When the association type is "Generalization" and at least one of the - * given objects an interface, then it is a "Realization". - * @param objA UML object as role A - * @param objB UML object as role B - * @return flag whether association is a realization - */ -bool UMLAssociation::isRealization(UMLObject* objA, UMLObject* objB) const -{ - bool aIsInterface = false; - if (objA && (objA->baseType() == UMLObject::ot_Interface)) { - aIsInterface = true; - } - bool bIsInterface = false; - if (objB && (objB->baseType() == UMLObject::ot_Interface)) { - bIsInterface = true; - } - return (m_AssocType == Uml::AssociationType::Generalization) && - (aIsInterface || bIsInterface); -} - -/** - * Common initializations at construction time. - * @param type The AssociationType::Enum to represent. - * @param roleAObj Pointer to the role A UMLObject. - * @param roleBObj Pointer to the role B UMLObject. - */ -void UMLAssociation::init(Uml::AssociationType::Enum type, UMLObject *roleAObj, UMLObject *roleBObj) -{ - m_AssocType = type; - m_BaseType = ot_Association; - m_Name = QString(); - m_bOldLoadMode = false; - nrof_parent_widgets = -1; - if (!UMLApp::app()->document()->loading()) { - m_pUMLPackage = UMLApp::app()->document()->currentRoot(); - } - m_pRole[RoleType::A] = new UMLRole (this, roleAObj, RoleType::A); - m_pRole[RoleType::B] = new UMLRole (this, roleBObj, RoleType::B); -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/association.h umbrello-kf6-15.08.1/umbrello/association.h --- umbrello-kf6-15.08.1.orig/umbrello/association.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/association.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,102 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef ASSOCIATION_H -#define ASSOCIATION_H - -#include "basictypes.h" -#include "umlobject.h" - -#include -#include - -class UMLRole; - -/** - * This class contains the non-graphic representation of an association. - * An association can be a generalization, realization, simple association, - * directed association, aggregation, or composition. - * - * @short Sets up association information. - * @author Oliver Kellogg - * @see UMLObject - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class UMLAssociation : public UMLObject -{ - Q_OBJECT - friend class AssociationWidget; - -public: - UMLAssociation(Uml::AssociationType::Enum type, UMLObject *roleA, UMLObject *roleB); - explicit UMLAssociation(Uml::AssociationType::Enum type = Uml::AssociationType::Unknown); - - virtual ~UMLAssociation(); - - bool operator==(const UMLAssociation &rhs) const; - - QString toString() const; - - UMLRole * getUMLRole(Uml::RoleType::Enum role) const; - Uml::ID::Type getObjectId(Uml::RoleType::Enum role) const; - Uml::ID::Type getRoleId(Uml::RoleType::Enum role) const; - - void setAssociationType(Uml::AssociationType::Enum assocType); - Uml::AssociationType::Enum getAssocType() const; - - void setObject(UMLObject *obj, Uml::RoleType::Enum role); - UMLObject* getObject(Uml::RoleType::Enum role) const; - - void setVisibility(Uml::Visibility::Enum value, Uml::RoleType::Enum role); - Uml::Visibility::Enum visibility(Uml::RoleType::Enum role) const; - - void setChangeability(Uml::Changeability::Enum value, Uml::RoleType::Enum role); - Uml::Changeability::Enum changeability(Uml::RoleType::Enum role) const; - - void setMultiplicity(const QString &multi, Uml::RoleType::Enum role); - QString getMultiplicity(Uml::RoleType::Enum role) const; - - void setRoleName(const QString &roleName, Uml::RoleType::Enum role); - QString getRoleName(Uml::RoleType::Enum role) const; - - void setRoleDoc(const QString &doc, Uml::RoleType::Enum role); - QString getRoleDoc(Uml::RoleType::Enum role) const; - - void setOldLoadMode(bool value = true); - bool getOldLoadMode() const; - - virtual UMLObject* clone() const { return NULL; } - - virtual bool resolveRef(); - - void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); - - virtual bool showPropertiesDialog(QWidget *parent = 0); - -protected: - - bool load(QDomElement& element); - - // keep track of number of parent widgets - int nrof_parent_widgets; - - void init(Uml::AssociationType::Enum type, UMLObject *roleAObj, UMLObject *roleBObj); - - UMLRole * m_pRole[2]; - Uml::AssociationType::Enum m_AssocType; - QString m_Name; - bool m_bOldLoadMode; - -private: - - bool isRealization(UMLObject* objA, UMLObject* objB) const; -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/attribute.cpp umbrello-kf6-15.08.1/umbrello/attribute.cpp --- umbrello-kf6-15.08.1.orig/umbrello/attribute.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/attribute.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,424 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "attribute.h" - -// app includes -#include "debug_utils.h" -#include "classifier.h" -#include "operation.h" -#include "umlobject.h" -#include "umldoc.h" -#include "uml.h" -#include "folder.h" -#include "umlattributedialog.h" -#include "object_factory.h" - -/** - * Sets up an attribute. - * - * @param parent The parent of this UMLAttribute. - * @param name The name of this UMLAttribute. - * @param id The unique id given to this UMLAttribute. - * @param s The visibility of the UMLAttribute. - * @param type The type of this UMLAttribute. - * @param iv The initial value of the attribute. - */ -UMLAttribute::UMLAttribute(UMLObject *parent, - const QString& name, Uml::ID::Type id, - Uml::Visibility::Enum s, - UMLObject *type, const QString& iv) - : UMLClassifierListItem(parent, name, id) -{ - m_InitialValue = iv; - m_BaseType = UMLObject::ot_Attribute; - m_visibility = s; - m_ParmKind = Uml::ParameterDirection::In; - /* CHECK: Do we need this: - if (type == NULL) { - type = Object_Factory::createUMLObject(Uml::ot_Datatype, "undef"); - } - */ - m_pSecondary = type; -} - -/** - * Sets up an attribute. - * - * @param parent The parent of this UMLAttribute. - */ -UMLAttribute::UMLAttribute(UMLObject *parent) : UMLClassifierListItem(parent) -{ - m_BaseType = UMLObject::ot_Attribute; - m_visibility = Uml::Visibility::Private; - m_ParmKind = Uml::ParameterDirection::In; -} - -/** - * Destructor. - */ -UMLAttribute::~UMLAttribute() -{ -} - -/** - * Reimplementation of method from UMLObject is required as - * an extra signal, attributeChanged(), is emitted. - */ -void UMLAttribute::setName(const QString &name) -{ - m_name = name; - emit attributeChanged(); - UMLObject::emitModified(); -} - -/** - * Reimplementation of method from UMLObject is required as - * an extra signal, attributeChanged(), is emitted. - */ -void UMLAttribute::setVisibility(Uml::Visibility::Enum s) -{ - m_visibility = s; - emit attributeChanged(); - UMLObject::emitModified(); -} - -/** - * Returns The initial value of the UMLAttribute. - * - * @return The initial value of the Atrtibute. - */ -QString UMLAttribute::getInitialValue() const -{ - return m_InitialValue; -} - -/** - * Sets the initial value of the UMLAttribute. - * - * @param iv The initial value of the UMLAttribute. - */ -void UMLAttribute::setInitialValue(const QString &iv) -{ - if(m_InitialValue != iv) { - m_InitialValue = iv; - UMLObject::emitModified(); - } -} - -void UMLAttribute::setParmKind (Uml::ParameterDirection::Enum pk) -{ - m_ParmKind = pk; -} - -Uml::ParameterDirection::Enum UMLAttribute::getParmKind() const -{ - return m_ParmKind; -} - -/** - * Returns a string representation of the UMLAttribute. - * - * @param sig If true will show the attribute type and initial value. - * @return Returns a string representation of the UMLAttribute. - */ -QString UMLAttribute::toString(Uml::SignatureType::Enum sig) -{ - QString s; - - if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::NoSig) { - s = Uml::Visibility::toString(m_visibility, true) + QLatin1Char(' '); - } - - if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::SigNoVis) { - // Determine whether the type name needs to be scoped. - UMLObject *owningObject = static_cast(parent()); - if (owningObject->baseType() == UMLObject::ot_Operation) { - // The immediate parent() is the UMLOperation but we want - // the UMLClassifier: - owningObject = static_cast(owningObject->parent()); - } - UMLClassifier *ownParent = dynamic_cast(owningObject); - if (ownParent == NULL) { - uError() << "parent " << owningObject->name() - << " is not a UMLClassifier"; - return QString(); - } - QString typeName; - UMLClassifier *type = UMLClassifierListItem::getType(); - if (type) { - UMLPackage *typeScope = type->umlPackage(); - if (typeScope != ownParent && typeScope != ownParent->umlPackage()) - typeName = type->fullyQualifiedName(); - else - typeName = type->name(); - } - // The default direction, "in", is not mentioned. - // Perhaps we should include a pd_Unspecified in - // Uml::ParameterDirection::Enum to have better control over this. - if (m_ParmKind == Uml::ParameterDirection::InOut) - s += QLatin1String("inout "); - else if (m_ParmKind == Uml::ParameterDirection::Out) - s += QLatin1String("out "); - // Construct the attribute text. - QString string = s + name() + QLatin1String(" : ") + typeName; - if (m_InitialValue.length() > 0) - string += QLatin1String(" = ") + m_InitialValue; - return string; - } - return s + name(); -} - -/** - * Reimplement method from UMLObject. - */ -QString UMLAttribute::getFullyQualifiedName(const QString& separator, - bool includeRoot /* = false */) const -{ - UMLOperation *op = NULL; - UMLObject *owningObject = static_cast(parent()); - if (owningObject->baseType() == UMLObject::ot_Operation) { - op = static_cast(owningObject); - owningObject = static_cast(owningObject->parent()); - } - UMLClassifier *ownParent = dynamic_cast(owningObject); - if (ownParent == NULL) { - uError() << name() << ": parent " << owningObject->name() - << " is not a UMLClassifier"; - return QString(); - } - QString tempSeparator = separator; - if (tempSeparator.isEmpty()) - tempSeparator = UMLApp::app()->activeLanguageScopeSeparator(); - QString fqn = ownParent->fullyQualifiedName(tempSeparator, includeRoot); - if (op) - fqn.append(tempSeparator + op->name()); - fqn.append(tempSeparator + name()); - return fqn; -} - -/** - * Overloaded '==' operator - */ -bool UMLAttribute::operator==(const UMLAttribute &rhs) const -{ - if(this == &rhs) - return true; - - if(!UMLObject::operator==(rhs)) - return false; - - // The type name is the only distinguishing criterion. - // (Some programming languages might support more, but others don't.) - if (m_pSecondary != rhs.m_pSecondary) - return false; - - return true; -} - -/** - * Copy the internal presentation of this object into the UMLAttribute - * object. - */ -void UMLAttribute::copyInto(UMLObject *lhs) const -{ - UMLAttribute *target = static_cast(lhs); - // call the parent first. - UMLClassifierListItem::copyInto(target); - - // Copy all datamembers - target->m_pSecondary = m_pSecondary; - target->m_SecondaryId = m_SecondaryId; - target->m_InitialValue = m_InitialValue; - target->m_ParmKind = m_ParmKind; -} - -/** - * Make a clone of the UMLAttribute. - */ -UMLObject* UMLAttribute::clone() const -{ - //FIXME: The new attribute should be slaved to the NEW parent not the old. - UMLAttribute *clone = new UMLAttribute(static_cast(parent())); - copyInto(clone); - - return clone; -} - -/** - * Creates the XMI element. - */ -void UMLAttribute::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) -{ - QDomElement attributeElement = UMLObject::save(QLatin1String("UML:Attribute"), qDoc); - if (m_pSecondary == NULL) { - uDebug() << name() << ": m_pSecondary is NULL, m_SecondaryId is '" - << m_SecondaryId << "'"; - } else { - attributeElement.setAttribute(QLatin1String("type"), Uml::ID::toString(m_pSecondary->id())); - } - if (! m_InitialValue.isEmpty()) - attributeElement.setAttribute(QLatin1String("initialValue"), m_InitialValue); - qElement.appendChild(attributeElement); -} - -/** - * Loads the XMI element. - */ -bool UMLAttribute::load(QDomElement & element) -{ - m_SecondaryId = element.attribute(QLatin1String("type")); - // We use the m_SecondaryId as a temporary store for the xmi.id - // of the attribute type model object. - // It is resolved later on, when all classes have been loaded. - // This deferred resolution is required because the xmi.id may - // be a forward reference, i.e. it may identify a model object - // that has not yet been loaded. - if (m_SecondaryId.isEmpty()) { - // Perhaps the type is stored in a child node: - QDomNode node = element.firstChild(); - while (!node.isNull()) { - if (node.isComment()) { - node = node.nextSibling(); - continue; - } - QDomElement tempElement = node.toElement(); - QString tag = tempElement.tagName(); - if (!UMLDoc::tagEq(tag, QLatin1String("type"))) { - node = node.nextSibling(); - continue; - } - m_SecondaryId = Model_Utils::getXmiId(tempElement); - if (m_SecondaryId.isEmpty()) - m_SecondaryId = tempElement.attribute(QLatin1String("xmi.idref")); - if (m_SecondaryId.isEmpty()) { - QString href = tempElement.attribute(QLatin1String("href")); - if (href.isEmpty()) { - QDomNode inner = node.firstChild(); - QDomElement tmpElem = inner.toElement(); - m_SecondaryId = Model_Utils::getXmiId(tmpElem); - if (m_SecondaryId.isEmpty()) - m_SecondaryId = tmpElem.attribute(QLatin1String("xmi.idref")); - } else { - int hashpos = href.lastIndexOf(QChar(QLatin1Char('#'))); - if (hashpos < 0) { - uDebug() << name() << ": cannot find type " << href; - } else { - QString typeName = href.mid(hashpos + 1); - UMLFolder *dtFolder = UMLApp::app()->document()->datatypeFolder(); - m_pSecondary = Model_Utils::findUMLObject(dtFolder->containedObjects(), - typeName, UMLObject::ot_Datatype); - if (!m_pSecondary) { - m_pSecondary = Object_Factory::createUMLObject(UMLObject::ot_Datatype, - typeName, dtFolder); - } - } - } - } - break; - } - if (m_SecondaryId.isEmpty()) { - uDebug() << name() << ": cannot find type."; - } - } - m_InitialValue = element.attribute(QLatin1String("initialValue")); - if (m_InitialValue.isEmpty()) { - // for backward compatibility - m_InitialValue = element.attribute(QLatin1String("value")); - } - return true; -} - -/** - * Display the properties configuration dialog for the attribute. - */ -bool UMLAttribute::showPropertiesDialog(QWidget* parent) -{ - UMLAttributeDialog dialog(parent, this); - return dialog.exec(); -} - -/** - * Puts in the param templateParamList all the template params that are in templateParam - */ -void UMLAttribute::setTemplateParams(const QString& templateParam, UMLClassifierList &templateParamList) -{ - if (templateParam.isEmpty()) - return; - QString type = templateParam.simplified(); - - int start = type.indexOf(QLatin1Char('<')); - if (start >= 0) { - int end = start; - int count = 1; - int len = type.length(); - while (count != 0 && ++end < len) { - QChar c = type.at(end); - if (c == QLatin1Char('<')) { - count++; - } - if (c == QLatin1Char('>')) { - count--; - } - } - if (count != 0) { - //The template is ill-formated, let's quit - return; - } - setTemplateParams(type.mid(start + 1, end - start - 1), templateParamList); - setTemplateParams(type.left(start) + type.right(len - end - 1), templateParamList); - } else { - QStringList paramsList = type.split(QLatin1Char(',')); - for (QStringList::Iterator it = paramsList.begin(); it != paramsList.end(); ++it) { - QString param = *it; - if (!param.isEmpty()) { - UMLDoc *pDoc = UMLApp::app()->document(); - UMLObject* obj = pDoc->findUMLObject(param); - if (obj == NULL) { - obj = pDoc->findUMLObject(param.remove(QLatin1Char(' '))); - } - if (obj != NULL) { - //We want to list only the params that already exist in this document - //If the param doesnt't already exist, we couldn't draw an association anyway - UMLClassifier* tmpClassifier = static_cast(obj); - if (templateParamList.indexOf(tmpClassifier) == -1) { - templateParamList.append(tmpClassifier); - } - } - } - } - } -} - -/** - * Returns all the template params (if any) that are in the type of this attribute - */ -UMLClassifierList UMLAttribute::getTemplateParams() -{ - UMLClassifierList templateParamList; - QString type = getType()->name(); - QString templateParam; - // Handle C++/D/Java template/generic parameters - const Uml::ProgrammingLanguage::Enum pl = UMLApp::app()->activeLanguage(); - if (pl == Uml::ProgrammingLanguage::Cpp || - pl == Uml::ProgrammingLanguage::Java || pl == Uml::ProgrammingLanguage::D) { - int start = type.indexOf(QLatin1Char('<')); - if (start >= 0) { - int end = type.lastIndexOf(QLatin1Char('>')); - if (end > start) { - templateParam = type.mid(start + 1, end - start - 1); - setTemplateParams(templateParam, templateParamList); - } - } - } - return templateParamList; -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/attribute.h umbrello-kf6-15.08.1/umbrello/attribute.h --- umbrello-kf6-15.08.1.orig/umbrello/attribute.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/attribute.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,84 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef ATTRIBUTE_H -#define ATTRIBUTE_H - -#include "basictypes.h" -#include "classifierlistitem.h" -#include "umlclassifierlist.h" - -/** - * This class is used to set up information for an attribute. This is like - * a programming attribute. It has a type, name, visibility and initial value. - * - * @short Sets up attribute information. - * @author Paul Hensgen - * @see UMLObject - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class UMLAttribute : public UMLClassifierListItem -{ - Q_OBJECT -public: - - UMLAttribute(UMLObject *parent, const QString& name, - Uml::ID::Type id = Uml::ID::None, - Uml::Visibility::Enum s = Uml::Visibility::Private, - UMLObject *type = 0, const QString& iv = QString()); - explicit UMLAttribute(UMLObject *parent); - - bool operator==(const UMLAttribute &rhs) const; - - virtual ~UMLAttribute(); - - virtual void copyInto(UMLObject *lhs) const; - - void setName(const QString &name); - - void setVisibility(Uml::Visibility::Enum s); - - virtual UMLObject* clone() const; - - QString getInitialValue() const; - void setInitialValue(const QString &iv); - - QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); - - QString getFullyQualifiedName(const QString& separator = QString(), - bool includeRoot = false) const; - - virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); - - virtual bool showPropertiesDialog(QWidget* parent = 0); - - void setParmKind(Uml::ParameterDirection::Enum pk); - Uml::ParameterDirection::Enum getParmKind() const; - - virtual UMLClassifierList getTemplateParams(); - -signals: - - void attributeChanged(); - -protected: - - bool load(QDomElement & element); - - QString m_InitialValue; ///< text for the attribute's initial value. - Uml::ParameterDirection::Enum m_ParmKind; - -private: - - void setTemplateParams(const QString& templateParam, UMLClassifierList &templateParamList); - -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/category.cpp umbrello-kf6-15.08.1/umbrello/category.cpp --- umbrello-kf6-15.08.1.orig/umbrello/category.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/category.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,101 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#include "category.h" - -/** - * Constructs a Category. - * - * @param name The name of the Category. - * @param id The unique id to assign to this Category. - */ -UMLCategory::UMLCategory(const QString & name, Uml::ID::Type id) - : UMLCanvasObject(name, id) -{ - init(); -} - -/** - * Standard destructor. - */ -UMLCategory::~UMLCategory() -{ -} - -/** - * Initializes key variables of the class. - */ -void UMLCategory::init() -{ - m_BaseType = UMLObject::ot_Category; - m_CategoryType = ct_Disjoint_Specialisation; -} - -/** - * Copy the internal presentation of this object into the new - * object. - */ -void UMLCategory::copyInto(UMLObject *lhs) const -{ - UMLCategory *target = static_cast(lhs); - - // call the parent first - UMLCanvasObject::copyInto(target); - - target->m_CategoryType = m_CategoryType; -} - -/** - * Make a clone of this object. - */ -UMLObject* UMLCategory::clone() const -{ - UMLCategory *clone = new UMLCategory(); - copyInto(clone); - return clone; -} - -/** - * Creates the XMI element. - */ -void UMLCategory::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) -{ - QDomElement categoryElement = UMLObject::save(QLatin1String("UML:Category"), qDoc); - categoryElement.setAttribute(QLatin1String("categoryType"), (int)m_CategoryType); - qElement.appendChild(categoryElement); -} - -/** - * Loads the XMI element (empty.) - */ -bool UMLCategory::load(QDomElement& element) -{ - m_CategoryType = (Category_Type)element.attribute(QLatin1String("categoryType"), - QLatin1String("0")).toInt(); - return true; -} - -/** - * Get the category type - */ -UMLCategory::Category_Type UMLCategory::getType() -{ - return m_CategoryType; -} - -/** - * Set the category type - */ -void UMLCategory::setType(Category_Type type) -{ - m_CategoryType = type; - emitModified(); -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/category.h umbrello-kf6-15.08.1/umbrello/category.h --- umbrello-kf6-15.08.1.orig/umbrello/category.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/category.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,62 +0,0 @@ -/*************************************************************************** - * * - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef CATEGORY_H -#define CATEGORY_H - -#include "umlcanvasobject.h" - -/** - * This class contains the non-graphical information required for a UML Category. - * This class inherits from @ref UMLCanvasObject which contains most of the - * information. - * The @ref UMLDoc class creates instances of this type. - * - * @short Information for a non-graphical UML Category. - * @author Sharan Rao - * @see UMLCanvasObject - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class UMLCategory : public UMLCanvasObject { - Q_OBJECT -public: - - enum Category_Type { - ct_Disjoint_Specialisation, - ct_Overlapping_Specialisation, - ct_Union - }; - - explicit UMLCategory(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); - ~UMLCategory(); - - virtual void init(); - - void copyInto(UMLObject *lhs) const; - - virtual UMLObject* clone() const; - - void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); - - UMLCategory::Category_Type getType(); - - void setType(Category_Type type); - -protected: - - bool load(QDomElement & element); - -private: - - Category_Type m_CategoryType; -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/checkconstraint.cpp umbrello-kf6-15.08.1/umbrello/checkconstraint.cpp --- umbrello-kf6-15.08.1.orig/umbrello/checkconstraint.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/checkconstraint.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,160 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -//own header -#include "checkconstraint.h" - -// app includes -#include "debug_utils.h" -#include "umlcheckconstraintdialog.h" - -/** - * Sets up a constraint. - * - * @param parent The parent of this UMLCheckConstraint. - * @param name The name of this UMLCheckConstraint. - * @param id The unique id given to this UMLCheckConstraint. - */ -UMLCheckConstraint::UMLCheckConstraint(UMLObject *parent, - const QString& name, Uml::ID::Type id) - : UMLEntityConstraint(parent, name, id) -{ - init(); -} - -/** - * Sets up a constraint. - * - * @param parent The parent of this UMLCheckConstraint. - */ -UMLCheckConstraint::UMLCheckConstraint(UMLObject *parent) - : UMLEntityConstraint(parent) -{ - init(); -} - -/** - * Overloaded '==' operator. - */ -bool UMLCheckConstraint::operator==(const UMLCheckConstraint &rhs) const -{ - if (this == &rhs) - return true; - - if (!UMLObject::operator==(rhs)) - return false; - - return true; -} - -/** - * Destructor. - */ -UMLCheckConstraint::~UMLCheckConstraint() -{ -} - -/** - * Copy the internal presentation of this object into the UMLCheckConstraint - * object. - */ -void UMLCheckConstraint::copyInto(UMLObject *lhs) const -{ - UMLCheckConstraint *target = static_cast(lhs); - - // call the parent first. - UMLEntityConstraint::copyInto(target); - - // Copy all datamembers - target->m_CheckCondition = m_CheckCondition; -} - -/** - * Make a clone of the UMLCheckConstraint. - */ -UMLObject* UMLCheckConstraint::clone() const -{ - //FIXME: The new attribute should be slaved to the NEW parent not the old. - UMLCheckConstraint *clone = new UMLCheckConstraint(static_cast(parent())); - copyInto(clone); - return clone; -} - -/** - * Returns a string representation of the UMLCheckConstraint. - * - * @param sig If true will show the attribute type and initial value. - * @return Returns a string representation of the UMLAttribute. - */ -QString UMLCheckConstraint::toString(Uml::SignatureType::Enum sig) -{ - QString s; - - if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::SigNoVis) { - s = name() ; - } - - return s; -} - -QString UMLCheckConstraint::getFullyQualifiedName(const QString& separator, - bool includeRoot) const -{ - Q_UNUSED(separator); Q_UNUSED(includeRoot); - return this->name(); -} - -/** - * Creates the XMI element. - */ -void UMLCheckConstraint::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) -{ - QDomElement checkConstraintElement = UMLObject::save(QLatin1String("UML:CheckConstraint"), qDoc); - - QDomNode checkCondition = qDoc.createTextNode(m_CheckCondition); - checkConstraintElement.appendChild(checkCondition); - - qElement.appendChild(checkConstraintElement); -} - -/** - * Display the properties configuration dialog for the attribute. - */ -bool UMLCheckConstraint::showPropertiesDialog(QWidget* parent) -{ - UMLCheckConstraintDialog dialog(parent, this); - return dialog.exec(); -} - -/** - * Loads the XMI element. - */ -bool UMLCheckConstraint::load(QDomElement & element) -{ - QDomNode node = element.firstChild(); - - QDomText checkConstraintText = node.toText(); - if (checkConstraintText.isNull()) - m_CheckCondition = QString(); - else - m_CheckCondition = checkConstraintText.data(); - - return true; -} - -/** - * Initialises Check Constraint - */ -void UMLCheckConstraint::init() -{ - m_BaseType = UMLObject::ot_CheckConstraint; - m_CheckCondition.clear(); -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/checkconstraint.h umbrello-kf6-15.08.1/umbrello/checkconstraint.h --- umbrello-kf6-15.08.1.orig/umbrello/checkconstraint.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/checkconstraint.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,71 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef CHECKCONSTRAINT_H -#define CHECKCONSTRAINT_H - -#include "basictypes.h" -#include "entityconstraint.h" - -/** - * This class is used to set up information for a unique entity constraint. - * - * @short Sets up Check Constraint information for UMLEntities. - * @author Sharan Rao - * @see UMLObject UMLClassifierListItem UMLEntityConstraint - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class UMLCheckConstraint : public UMLEntityConstraint -{ - Q_OBJECT -public: - - UMLCheckConstraint(UMLObject *parent, const QString& name, - Uml::ID::Type id = Uml::ID::None); - explicit UMLCheckConstraint(UMLObject *parent); - - bool operator==(const UMLCheckConstraint &rhs) const; - - virtual ~UMLCheckConstraint(); - - virtual void copyInto(UMLObject *lhs) const; - - virtual UMLObject* clone() const; - - QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); - - QString getFullyQualifiedName(const QString& separator = QString(), - bool includeRoot = false) const; - - void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); - - virtual bool showPropertiesDialog(QWidget* parent = 0); - - QString getCheckCondition() const { - return m_CheckCondition; - } - - void setCheckCondition(const QString& condition) { - m_CheckCondition = condition.trimmed(); - } - -protected: - - bool load(QDomElement & element); - -private: - - void init(); - - QString m_CheckCondition; ///< the check condition - -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/classifier.cpp umbrello-kf6-15.08.1/umbrello/classifier.cpp --- umbrello-kf6-15.08.1.orig/umbrello/classifier.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/classifier.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,1631 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ -#include "classifier.h" - -// app includes -#include "association.h" -#include "debug_utils.h" -#include "umlassociationlist.h" -#include "operation.h" -#include "attribute.h" -#include "template.h" -#include "enumliteral.h" -#include "entityattribute.h" -#include "enum.h" -#include "entity.h" -#include "stereotype.h" -#include "umldoc.h" -#include "uml.h" -#include "uniqueid.h" -#include "object_factory.h" -#include "model_utils.h" -#include "idchangelog.h" -#include "umloperationdialog.h" -#include "umlattributedialog.h" -#include "umltemplatedialog.h" -#include "optionstate.h" -#include "icon_utils.h" - -// kde includes -#include -#include - -// qt includes -#include - -using namespace Uml; - -/** - * @brief holds set of classifiers for recursive loop detection - */ -class UMLClassifierSet: public QSet { -public: - UMLClassifierSet() : level(0) - { - } - int level; -}; - -/** - * Sets up a Classifier. - * - * @param name The name of the Concept. - * @param id The unique id of the Concept. - */ -UMLClassifier::UMLClassifier(const QString & name, Uml::ID::Type id) - : UMLPackage(name, id) -{ - m_BaseType = UMLObject::ot_Class; // default value - m_pClassAssoc = NULL; - m_isRef = false; -} - -/** - * Standard deconstructor. - */ -UMLClassifier::~UMLClassifier() -{ -} - -/** - * Reimplementation of method from class UMLObject for controlling the - * exact type of this classifier: class, interface, or datatype. - * @param ot the base type to set - */ -void UMLClassifier::setBaseType(UMLObject::ObjectType ot) -{ - m_BaseType = ot; - Icon_Utils::IconType newIcon; - switch (ot) { - case ot_Interface: - UMLObject::setStereotypeCmd(QLatin1String("interface")); - UMLObject::m_bAbstract = true; - newIcon = Icon_Utils::it_Interface; - break; - case ot_Class: - UMLObject::setStereotypeCmd(QString()); - UMLObject::m_bAbstract = false; - newIcon = Icon_Utils::it_Class; - break; - case ot_Datatype: - UMLObject::setStereotypeCmd(QLatin1String("datatype")); - UMLObject::m_bAbstract = false; - newIcon = Icon_Utils::it_Datatype; - break; - case ot_Package: - UMLObject::setStereotypeCmd(QLatin1String("package")); - UMLObject::m_bAbstract = false; - newIcon = Icon_Utils::it_Package; - break; - default: - uError() << "cannot set to type " << ot; - return; - } - Model_Utils::treeViewChangeIcon(this, newIcon); -} - -/** - * Returns true if this classifier represents an interface. - */ -bool UMLClassifier::isInterface() const -{ - return (m_BaseType == ot_Interface); -} - -/** - * Returns true if this classifier represents a datatype. - */ -bool UMLClassifier::isDatatype() const -{ - return (m_BaseType == ot_Datatype); -} - -/** - * Checks whether an operation is valid based on its signature - - * An operation is "valid" if the operation's name and parameter list - * are unique in the classifier. - * - * @param name Name of the operation to check. - * @param opParams The operation's argument list. - * @param exemptOp Pointer to the exempt method (optional.) - * @return NULL if the signature is valid (ok), else return a pointer - * to the existing UMLOperation that causes the conflict. - */ -UMLOperation * UMLClassifier::checkOperationSignature( - const QString& name, - UMLAttributeList opParams, - UMLOperation *exemptOp) -{ - UMLOperationList list = findOperations(name); - if (list.count() == 0) { - return NULL; - } - const int inputParmCount = opParams.count(); - - // there is at least one operation with the same name... compare the parameter list - foreach (UMLOperation* test, list) { - if (test == exemptOp) { - continue; - } - UMLAttributeList testParams = test->getParmList(); - const int pCount = testParams.count(); - if (pCount != inputParmCount) { - continue; - } - int i = 0; - while (i < pCount) { - // The only criterion for equivalence is the parameter types. - // (Default values are not considered.) - if(testParams.at(i)->getTypeName() != opParams.at(i)->getTypeName()) - break; - i++; - } - if (i == pCount) { // all parameters matched->the signature is not unique - return test; - } - } - // we did not find an exact match, so the signature is unique (acceptable) - return NULL; -} - -/** - * Find an operation of the given name and parameter signature. - * - * @param name The name of the operation to find. - * @param params The parameter descriptors of the operation to find. - * - * @return The operation found. Will return 0 if none found. - */ -UMLOperation* UMLClassifier::findOperation(const QString& name, - Model_Utils::NameAndType_List params) -{ - UMLOperationList list = findOperations(name); - if (list.count() == 0) { - return NULL; - } - // if there are operation(s) with the same name then compare the parameter list - const int inputParmCount = params.count(); - - foreach (UMLOperation* test, list) { - UMLAttributeList testParams = test->getParmList(); - const int pCount = testParams.count(); - if (inputParmCount == 0 && pCount == 0) - return test; - if (inputParmCount != pCount) - continue; - int i = 0; - for (; i < pCount; ++i) { - Model_Utils::NameAndType_ListIt nt(params.begin() + i); - UMLClassifier *type = dynamic_cast((*nt).m_type); - UMLClassifier *testType = testParams.at(i)->getType(); - if (type == NULL && testType == NULL) { //no parameter type - continue; - } else if (type == NULL) { //template parameter - if (testType->name() != QLatin1String("class")) - break; - } else if (type != testType) - break; - } - if (i == pCount) - return test; // all parameters matched - } - return 0; -} - -/** - * Creates an operation in the current document. - * The new operation is initialized with name, id, etc. - * If a method with the given profile already exists in the classifier, - * no new method is created and the existing operation is returned. - * If no name is provided, or if the params are NULL, an Operation - * Dialog is shown to ask the user for a name and parameters. - * The operation's signature is checked for validity within the parent - * classifier. - * - * @param name The operation name (will be chosen internally if - * none given.) - * @param isExistingOp Optional pointer to bool. If supplied, the bool is - * set to true if an existing operation is returned. - * @param params Optional list of parameter names and types. - * If supplied, new operation parameters are - * constructed using this list. - * @return The new operation, or NULL if the operation could not be - * created because for example, the user canceled the dialog - * or no appropriate name can be found. - */ -UMLOperation* UMLClassifier::createOperation( - const QString &name /*=QString()*/, - bool *isExistingOp /*=NULL*/, - Model_Utils::NameAndType_List *params /*=NULL*/) -{ - bool nameNotSet = (name.isNull() || name.isEmpty()); - if (! nameNotSet) { - Model_Utils::NameAndType_List parList; - if (params) - parList = *params; - UMLOperation* existingOp = findOperation(name, parList); - if (existingOp != NULL) { - if (isExistingOp != NULL) - *isExistingOp = true; - return existingOp; - } - } - // we did not find an exact match, so the signature is unique - UMLOperation *op = new UMLOperation(this, name); - if (params) { - for (Model_Utils::NameAndType_ListIt it = params->begin(); it != params->end(); ++it) { - const Model_Utils::NameAndType &nt = *it; - UMLAttribute *par = new UMLAttribute(op, nt.m_name, Uml::ID::None, Uml::Visibility::Private, - nt.m_type, nt.m_initialValue); - par->setParmKind(nt.m_direction); - op->addParm(par); - } - } - - // Only show the operation dialog if no name was provided (allows quick-create - // from listview) - if (nameNotSet) { - op->setName(uniqChildName(UMLObject::ot_Operation)); - - while (true) { - QPointer operationDialog = new UMLOperationDialog(0, op); - if(operationDialog->exec() != QDialog::Accepted) { - delete op; - delete operationDialog; - return NULL; - } else if (checkOperationSignature(op->name(), op->getParmList())) { - KMessageBox::information(0, - i18n("An operation with the same name and signature already exists. You cannot add it again.")); - } else { - break; - } - delete operationDialog; - } - } - - // operation name is ok, formally add it to the classifier - if (! addOperation(op)) { - delete op; - return NULL; - } - - UMLDoc *umldoc = UMLApp::app()->document(); - umldoc->signalUMLObjectCreated(op); - return op; -} - -/** - * Appends an operation to the classifier. - * This function is mainly intended for the clipboard. - * - * @param op Pointer to the UMLOperation to add. - * @param position Inserted at the given position. - * @return True if the operation was added successfully. - */ -bool UMLClassifier::addOperation(UMLOperation* op, int position) -{ - Q_ASSERT(op); - if (m_List.indexOf(op) != -1) { - uDebug() << "findRef(" << op->name() << ") finds op (bad)"; - return false; - } - if (checkOperationSignature(op->name(), op->getParmList())) { - uDebug() << "checkOperationSignature(" << op->name() << ") op is non-unique"; - return false; - } - - if (position >= 0 && position <= m_List.count()) { - uDebug() << op->name() << ": inserting at position " << position; - m_List.insert(position, op); - UMLClassifierListItemList itemList = getFilteredList(UMLObject::ot_Operation); - QString buf; - foreach (UMLClassifierListItem* currentAtt, itemList) { - buf.append(QLatin1Char(' ') + currentAtt->name()); - } - uDebug() << " list after change: " << buf; - } - else { - m_List.append(op); - } - emit operationAdded(op); - UMLObject::emitModified(); - connect(op, SIGNAL(modified()), this, SIGNAL(modified())); - return true; -} - -/** - * Appends an operation to the classifier. - * @see bool addOperation(UMLOperation* Op, int position = -1) - * This function is mainly intended for the clipboard. - * - * @param op Pointer to the UMLOperation to add. - * @param log Pointer to the IDChangeLog. - * @return True if the operation was added successfully. - */ -bool UMLClassifier::addOperation(UMLOperation* op, IDChangeLog* log) -{ - if (addOperation(op, -1)) { - return true; - } - else if (log) { - log->removeChangeByNewID(op->id()); - } - return false; -} - -/** - * Remove an operation from the Classifier. - * The operation is not deleted so the caller is responsible for what - * happens to it after this. - * - * @param op The operation to remove. - * @return Count of the remaining operations after removal, or - * -1 if the given operation was not found. - */ -int UMLClassifier::removeOperation(UMLOperation *op) -{ - if (op == NULL) { - uDebug() << "called on NULL op"; - return -1; - } - if (!m_List.removeAll(op)) { - uDebug() << "cannot find op " << op->name() << " in list"; - return -1; - } - // disconnection needed. - // note that we don't delete the operation, just remove it from the Classifier - disconnect(op, SIGNAL(modified()), this, SIGNAL(modified())); - emit operationRemoved(op); - UMLObject::emitModified(); - return m_List.count(); -} - -/** - * Create and add a just created template. - * @param currentName the name of the template - * @return the template or NULL - */ -UMLObject* UMLClassifier::createTemplate(const QString& currentName /*= QString()*/) -{ - QString name = currentName; - bool goodName = !name.isEmpty(); - if (!goodName) { - name = uniqChildName(UMLObject::ot_Template); - } - UMLTemplate* newTemplate = new UMLTemplate(this, name); - - int button = QDialog::Accepted; - - while (button == QDialog::Accepted && !goodName) { - QPointer templateDialog = new UMLTemplateDialog(0, newTemplate); - button = templateDialog->exec(); - name = newTemplate->name(); - - if (name.length() == 0) { - KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); - } - else if (findChildObject(name) != NULL) { - KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name")); - } - else { - goodName = true; - } - delete templateDialog; - } - - if (button != QDialog::Accepted) { - return NULL; - } - - addTemplate(newTemplate); - - UMLDoc *umldoc = UMLApp::app()->document(); - umldoc->signalUMLObjectCreated(newTemplate); - return newTemplate; -} - -/** - * Returns the number of attributes for the class. - * - * @return The number of attributes for the class. - */ -int UMLClassifier::attributes() -{ - UMLClassifierListItemList atts = getFilteredList(UMLObject::ot_Attribute); - return atts.count(); -} - -/** - * Returns the attributes for the specified scope. - * @return List of true attributes for the class. - */ -UMLAttributeList UMLClassifier::getAttributeList() const -{ - UMLAttributeList attributeList; - foreach (UMLObject* listItem, m_List) { - uIgnoreZeroPointer(listItem); - if (listItem->baseType() == UMLObject::ot_Attribute) { - attributeList.append(static_cast(listItem)); - } - } - return attributeList; -} - -/** - * Returns the attributes for the specified scope. - * @param scope The scope of the attribute. - * @return List of true attributes for the class. - */ -UMLAttributeList UMLClassifier::getAttributeList(Visibility::Enum scope) const -{ - UMLAttributeList list; - if (!isInterface()) - { - UMLAttributeList atl = getAttributeList(); - foreach(UMLAttribute* at, atl) - { - uIgnoreZeroPointer(at); - if (! at->isStatic()) - { - if (scope == Uml::Visibility::Private) - { - if ((at->visibility() == Uml::Visibility::Private) || - (at->visibility() == Uml::Visibility::Implementation)) - { - list.append(at); - } - } - else if (scope == at->visibility()) - { - list.append(at); - } - } - } - } - return list; -} - -/** - * Returns the static attributes for the specified scope. - * - * @param scope The scope of the attribute. - * @return List of true attributes for the class. - */ -UMLAttributeList UMLClassifier::getAttributeListStatic(Visibility::Enum scope) const -{ - UMLAttributeList list; - if (!isInterface()) - { - UMLAttributeList atl = getAttributeList(); - foreach(UMLAttribute* at, atl) - { - uIgnoreZeroPointer(at); - if (at->isStatic()) - { - if (scope == Uml::Visibility::Private) - { - if ((at->visibility() == Uml::Visibility::Private) || - (at->visibility() == Uml::Visibility::Implementation)) - { - list.append(at); - } - } - else if (scope == at->visibility()) - { - list.append(at); - } - } - } - } - return list; -} - -/** - * Find a list of operations with the given name. - * - * @param n The name of the operation to find. - * @return The list of objects found; will be empty if none found. - */ -UMLOperationList UMLClassifier::findOperations(const QString &n) -{ - const bool caseSensitive = UMLApp::app()->activeLanguageIsCaseSensitive(); - UMLOperationList list; - foreach (UMLObject* obj, m_List) { - uIgnoreZeroPointer(obj); - if (obj->baseType() != UMLObject::ot_Operation) - continue; - UMLOperation *op = static_cast(obj); - if (caseSensitive) { - if (obj->name() == n) - list.append(op); - } else if (obj->name().toLower() == n.toLower()) { - list.append(op); - } - } - return list; -} - -/** - * Find the child object by the given id. - * @param id the id of the child object - * @param considerAncestors flag whether the ancestors should be considered during search - * @return the found child object or NULL - */ -UMLObject* UMLClassifier::findChildObjectById(Uml::ID::Type id, bool considerAncestors /* =false */) -{ - UMLObject *o = UMLCanvasObject::findChildObjectById(id); - if (o) { - return o; - } - if (considerAncestors) { - UMLClassifierList ancestors = findSuperClassConcepts(); - foreach (UMLClassifier *anc, ancestors) { - UMLObject *o = anc->findChildObjectById(id); - if (o) { - return o; - } - } - } - return NULL; -} - -/** - * Returns a list of concepts which inherit from this concept. - * - * @param type The ClassifierType to seek. - * @return List of UMLClassifiers that inherit from us. - */ -UMLClassifierList UMLClassifier::findSubClassConcepts (ClassifierType type) -{ - UMLClassifierList list = getSubClasses(); - UMLAssociationList rlist = getRealizations(); - - UMLClassifierList inheritingConcepts; - Uml::ID::Type myID = id(); - foreach(UMLClassifier *c, list) { - uIgnoreZeroPointer(c); - if (type == ALL || (!c->isInterface() && type == CLASS) - || (c->isInterface() && type == INTERFACE)) { - inheritingConcepts.append(c); - } - } - - foreach (UMLAssociation *a, rlist) { - uIgnoreZeroPointer(a); - if (a->getObjectId(RoleType::A) != myID) - { - UMLObject* obj = a->getObject(RoleType::A); - UMLClassifier *concept = dynamic_cast(obj); - if (concept && (type == ALL || (!concept->isInterface() && type == CLASS) - || (concept->isInterface() && type == INTERFACE)) - && (inheritingConcepts.indexOf(concept) == -1)) - { - inheritingConcepts.append(concept); - } - } - } - - return inheritingConcepts; -} - -/** - * Returns a list of concepts which this concept inherits from. - * - * @param type The ClassifierType to seek. - * @return List of UMLClassifiers we inherit from. - */ -UMLClassifierList UMLClassifier::findSuperClassConcepts (ClassifierType type) -{ - UMLClassifierList list = getSuperClasses(); - UMLAssociationList rlist = getRealizations(); - - UMLClassifierList parentConcepts; - Uml::ID::Type myID = id(); - foreach (UMLClassifier *concept, list) { - uIgnoreZeroPointer(concept); - if (type == ALL || (!concept->isInterface() && type == CLASS) - || (concept->isInterface() && type == INTERFACE)) - parentConcepts.append(concept); - } - - foreach (UMLAssociation *a, rlist) { - if (a->getObjectId(RoleType::A) == myID) - { - UMLObject* obj = a->getObject(RoleType::B); - UMLClassifier *concept = dynamic_cast(obj); - if (concept && (type == ALL || (!concept->isInterface() && type == CLASS) - || (concept->isInterface() && type == INTERFACE)) - && (parentConcepts.indexOf(concept) == -1)) - parentConcepts.append(concept); - } - } - - return parentConcepts; -} - -/** - * Overloaded '==' operator. - */ -bool UMLClassifier::operator==(const UMLClassifier & rhs) const -{ - return UMLCanvasObject::operator==(rhs); -} - -/** - * Copy the internal presentation of this object into the new - * object. - */ -void UMLClassifier::copyInto(UMLObject *lhs) const -{ - UMLClassifier *target = static_cast(lhs); - UMLCanvasObject::copyInto(target); - target->setBaseType(m_BaseType); - // CHECK: association property m_pClassAssoc is not copied - m_List.copyInto(&(target->m_List)); -} - -/** - * Make a clone of this object. - */ -UMLObject* UMLClassifier::clone() const -{ - UMLClassifier *clone = new UMLClassifier(); - copyInto(clone); - return clone; -} - -/** - * Needs to be called after all UML objects are loaded from file. - * Calls the parent resolveRef(), and calls resolveRef() on all - * UMLClassifierListItems. - * Overrides the method from UMLObject. - * - * @return true for success. - */ -bool UMLClassifier::resolveRef() -{ - bool success = UMLPackage::resolveRef(); - // Using reentrant iteration is a bare necessity here: - foreach (UMLObject* obj, m_List) { - uIgnoreZeroPointer(obj); - /**** For reference, here is the non-reentrant iteration scheme - - DO NOT USE THIS ! - for (UMLObject *obj = m_List.first(); obj; obj = m_List.next()) - { .... } - ****/ - if (obj->resolveRef()) { - UMLClassifierListItem *cli = static_cast(obj); - switch (cli->baseType()) { - case UMLObject::ot_Attribute: - emit attributeAdded(cli); - break; - case UMLObject::ot_Operation: - emit operationAdded(cli); - break; - case UMLObject::ot_Template: - emit templateAdded(cli); - break; - default: - break; - } - } - } - return success; -} - -/** - * Reimplemented from UMLObject. - */ -bool UMLClassifier::acceptAssociationType(AssociationType::Enum type) -{ - switch(type) - { - case AssociationType::Generalization: - case AssociationType::Aggregation: - case AssociationType::Relationship: - case AssociationType::Dependency: - case AssociationType::Association: - case AssociationType::Association_Self: - case AssociationType::Containment: - case AssociationType::Composition: - case AssociationType::Realization: - case AssociationType::UniAssociation: - return true; - default: - return false; - } - return false; //shutup compiler warning -} - -/** - * Creates an attribute for the class. - * - * @param name An optional name, used by when creating through UMLListView - * @param type An optional type, used by when creating through UMLListView - * @param vis An optional visibility, used by when creating through UMLListView - * @param init An optional initial value, used by when creating through UMLListView - * @return The UMLAttribute created - */ -UMLAttribute* UMLClassifier::createAttribute(const QString &name, - UMLObject *type, - Visibility::Enum vis, - const QString &init) -{ - Uml::ID::Type id = UniqueID::gen(); - QString currentName; - if (name.isNull()) { - currentName = uniqChildName(UMLObject::ot_Attribute); - } else { - currentName = name; - } - UMLAttribute* newAttribute = new UMLAttribute(this, currentName, id, vis, type, init); - - int button = QDialog::Accepted; - bool goodName = false; - - //check for name.isNull() stops dialog being shown - //when creating attribute via list view - while (button == QDialog::Accepted && !goodName && name.isNull()) { - QPointer attributeDialog = new UMLAttributeDialog(0, newAttribute); - button = attributeDialog->exec(); - QString name = newAttribute->name(); - - if(name.length() == 0) { - KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); - } else if (findChildObject(name) != NULL) { - KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name")); - } else { - goodName = true; - } - delete attributeDialog; - } - - if (button != QDialog::Accepted) { - delete newAttribute; - return NULL; - } - - addAttribute(newAttribute); - - UMLDoc *umldoc = UMLApp::app()->document(); - umldoc->signalUMLObjectCreated(newAttribute); - return newAttribute; -} - -/** - * Creates and adds an attribute for the class. - * - * @param name an optional name, used by when creating through UMLListView - * @param id an optional id - * @return the UMLAttribute created and added - */ - -UMLAttribute* UMLClassifier::addAttribute(const QString &name, Uml::ID::Type id /* = Uml::id_None */) -{ - foreach (UMLObject* obj, m_List) { - uIgnoreZeroPointer(obj); - if (obj->baseType() == UMLObject::ot_Attribute && obj->name() == name) - return static_cast(obj); - } - Uml::Visibility::Enum scope = Settings::optionState().classState.defaultAttributeScope; - UMLAttribute *a = new UMLAttribute(this, name, id, scope); - m_List.append(a); - emit attributeAdded(a); - UMLObject::emitModified(); - connect(a, SIGNAL(modified()), this, SIGNAL(modified())); - return a; -} - -/** - * Adds an already created attribute. - * The attribute object must not belong to any other concept. - * - * @param name the name of the attribute - * @param type the type of the attribute - * @param scope the visibility of the attribute - * @return the just created and added attribute - */ -UMLAttribute* UMLClassifier::addAttribute(const QString &name, UMLObject *type, Visibility::Enum scope) -{ - UMLAttribute *a = new UMLAttribute(this); - a->setName(name); - a->setVisibility(scope); - a->setID(UniqueID::gen()); - if (type) { - a->setType(type); - } - m_List.append(a); - emit attributeAdded(a); - UMLObject::emitModified(); - connect(a, SIGNAL(modified()), this, SIGNAL(modified())); - return a; -} - -/** - * Adds an already created attribute. - * The attribute object must not belong to any other concept. - * - * @param att Pointer to the UMLAttribute. - * @param log Pointer to the IDChangeLog (optional.) - * @param position Position index for the insertion (optional.) - * If the position is omitted, or if it is - * negative or too large, the attribute is added - * to the end of the list. - * @return True if the attribute was successfully added. - */ -bool UMLClassifier::addAttribute(UMLAttribute* att, IDChangeLog* log /* = 0 */, - int position /* = -1 */) -{ - Q_ASSERT(att); - if (findChildObject(att->name()) == NULL) { - att->setParent(this); - if (position >= 0 && position < (int)m_List.count()) { - m_List.insert(position, att); - } - else { - m_List.append(att); - } - emit attributeAdded(att); - UMLObject::emitModified(); - connect(att, SIGNAL(modified()), this, SIGNAL(modified())); - return true; - } else if (log) { - log->removeChangeByNewID(att->id()); - delete att; - } - return false; -} - -/** - * Removes an attribute from the class. - * - * @param att The attribute to remove. - * @return Count of the remaining attributes after removal. - * Returns -1 if the given attribute was not found. - */ -int UMLClassifier::removeAttribute(UMLAttribute* att) -{ - if (!m_List.removeAll(att)) { - uDebug() << "cannot find att given in list"; - return -1; - } - emit attributeRemoved(att); - UMLObject::emitModified(); - // If we are deleting the object, then we don't need to disconnect..this is done auto-magically - // for us by QObject. -b.t. - // disconnect(att, SIGNAL(modified()), this, SIGNAL(modified())); - delete att; - return m_List.count(); -} - -/** - * Sets the UMLAssociation for which this class shall act as an - * association class. - */ -void UMLClassifier::setClassAssoc(UMLAssociation *assoc) -{ - m_pClassAssoc = assoc; -} - -/** - * Returns the UMLAssociation for which this class acts as an - * association class. Returns NULL if this class does not act - * as an association class. - */ -UMLAssociation *UMLClassifier::getClassAssoc() const -{ - return m_pClassAssoc; -} - -/** - * Return true if this classifier has abstract operations. - */ -bool UMLClassifier::hasAbstractOps () -{ - UMLOperationList opl(getOpList()); - foreach(UMLOperation *op, opl) { - uIgnoreZeroPointer(op); - if (op->isAbstract()) { - return true; - } - } - return false; -} - -/** - * Counts the number of operations in the Classifier. - * - * @return The number of operations for the Classifier. - */ -int UMLClassifier::operations() -{ - return getOpList().count(); -} - - -/** - * Return a list of operations for the Classifier. - * - * @param includeInherited Includes operations from superclasses. - * @param alreadyTraversed internal used object to avoid recursive loops - * @return The list of operations for the Classifier. - */ -UMLOperationList UMLClassifier::getOpList(bool includeInherited, UMLClassifierSet *alreadyTraversed) -{ - UMLOperationList ops; - foreach (UMLObject* li, m_List) { - uIgnoreZeroPointer(li); - if (li->baseType() == ot_Operation) { - ops.append(static_cast(li)); - } - } - if (includeInherited) { - if (!alreadyTraversed) { - alreadyTraversed = new UMLClassifierSet; - } - else - alreadyTraversed->level++; - - if (!alreadyTraversed->contains(this)) - *alreadyTraversed << this; - - // get a list of parents of this class - UMLClassifierList parents = findSuperClassConcepts(); - foreach(UMLClassifier *c, parents) { - if (alreadyTraversed->contains(c)) { - uError() << "class " << c->name() << " is starting a dependency loop!"; - continue; - } - // get operations for each parent by recursive call - UMLOperationList pops = c->getOpList(true, alreadyTraversed); - // add these operations to operation list, but only if unique. - foreach (UMLOperation *po, pops) { - QString po_as_string(po->toString(Uml::SignatureType::SigNoVis)); - bool breakFlag = false; - foreach (UMLOperation* o, ops) { - if (o->toString(Uml::SignatureType::SigNoVis) == po_as_string) { - breakFlag = true; - break; - } - } - if (breakFlag == false) - ops.append(po); - } - // remember this node - *alreadyTraversed << c; - } - if (alreadyTraversed->level-- == 0) { - delete alreadyTraversed; - alreadyTraversed = 0; - } - } - return ops; -} - -/** - * Returns the entries in m_List that are of the requested type. - * If the requested type is UMLObject::ot_UMLObject then all entries - * are returned. - * @param ot the requested object type - * @return The list of true operations for the Concept. - */ -UMLClassifierListItemList UMLClassifier::getFilteredList(UMLObject::ObjectType ot) const -{ - UMLClassifierListItemList resultList; - foreach (UMLObject* o, m_List) { - uIgnoreZeroPointer(o); - if (!o || o->baseType() == UMLObject::ot_Association) { - continue; - } - UMLClassifierListItem *listItem = static_cast(o); - if (ot == UMLObject::ot_UMLObject || listItem->baseType() == ot) { - resultList.append(listItem); - } - } - return resultList; -} - -/** - * Adds an already created template. - * The template object must not belong to any other concept. - * - * @param name the name of the template - * @param id the id of the template - * @return the added template - */ -UMLTemplate* UMLClassifier::addTemplate(const QString &name, Uml::ID::Type id) -{ - UMLTemplate *templt = findTemplate(name); - if (templt) { - return templt; - } - templt = new UMLTemplate(this, name, id); - m_List.append(templt); - emit templateAdded(templt); - UMLObject::emitModified(); - connect(templt, SIGNAL(modified()), this, SIGNAL(modified())); - return templt; -} - -/** - * Adds an already created template. - * The template object must not belong to any other concept. - * - * @param newTemplate Pointer to the UMLTemplate object to add. - * @param log Pointer to the IDChangeLog. - * @return True if the template was successfully added. - */ -bool UMLClassifier::addTemplate(UMLTemplate* newTemplate, IDChangeLog* log /* = 0*/) -{ - QString name = newTemplate->name(); - if (findChildObject(name) == NULL) { - newTemplate->setParent(this); - m_List.append(newTemplate); - emit templateAdded(newTemplate); - UMLObject::emitModified(); - connect(newTemplate, SIGNAL(modified()), this, SIGNAL(modified())); - return true; - } - else if (log) { - log->removeChangeByNewID(newTemplate->id()); - delete newTemplate; - } - return false; -} - -/** - * Adds an template to the class. - * The template object must not belong to any other class. - * TODO: If the param IDChangeLog from the method above is not being used, - * give position a default value of -1 and the method can replace the above one. - * @param templt Pointer to the UMLTemplate to add. - * @param position The position of the template in the list. - * A value of -1 will add the template at the end. - * @return True if the template was successfully added. - */ -bool UMLClassifier::addTemplate(UMLTemplate* templt, int position) -{ - Q_ASSERT(templt); - QString name = templt->name(); - if (findChildObject(name) == NULL) { - templt->setParent(this); - if (position >= 0 && position <= (int)m_List.count()) { - m_List.insert(position, templt); - } - else { - m_List.append(templt); - } - emit templateAdded(templt); - UMLObject::emitModified(); - connect(templt, SIGNAL(modified()), this, SIGNAL(modified())); - return true; - } - //else - return false; -} - -/** - * Removes a template from the class. - * - * @param umltemplate The template to remove. - * @return Count of the remaining templates after removal. - * Returns -1 if the given template was not found. - */ -int UMLClassifier::removeTemplate(UMLTemplate* umltemplate) -{ - if (!m_List.removeAll(umltemplate)) { - uWarning() << "cannot find att given in list"; - return -1; - } - emit templateRemoved(umltemplate); - UMLObject::emitModified(); - disconnect(umltemplate, SIGNAL(modified()), this, SIGNAL(modified())); - return m_List.count(); -} - -/** - * Seeks the template parameter of the given name. - * @param name the template name - * @return the found template or 0 - */ -UMLTemplate *UMLClassifier::findTemplate(const QString& name) -{ - UMLTemplateList templParams = getTemplateList(); - foreach (UMLTemplate *templt, templParams) { - if (templt->name() == name) { - return templt; - } - } - return 0; -} - -/** - * Returns the number of templates for the class. - * - * @return The number of templates for the class. - */ -int UMLClassifier::templates() -{ - UMLClassifierListItemList tempList = getFilteredList(UMLObject::ot_Template); - return tempList.count(); -} - -/** - * Returns the templates. - * Same as UMLClassifier::getFilteredList(ot_Template) but - * return type is a true UMLTemplateList. - * - * @return Pointer to the list of true templates for the class. - */ -UMLTemplateList UMLClassifier::getTemplateList() const -{ - UMLTemplateList templateList; - foreach (UMLObject* listItem, m_List) { - uIgnoreZeroPointer(listItem); - if (listItem->baseType() == UMLObject::ot_Template) { - templateList.append(static_cast(listItem)); - } - } - return templateList; -} - -/** - * Take and return a subordinate item from this classifier. - * Ownership of the item is passed to the caller. - * - * @param item Subordinate item to take. - * @return Index in m_List of the item taken. - * Return -1 if the item is not found in m_List. - */ -int UMLClassifier::takeItem(UMLClassifierListItem *item) -{ - QString buf; - foreach (UMLObject* currentAtt, m_List) { - uIgnoreZeroPointer(currentAtt); - QString txt = currentAtt->name(); - if (txt.isEmpty()) { - txt = QLatin1String("Type-") + QString::number((int) currentAtt->baseType()); - } - buf.append(QLatin1Char(' ') + currentAtt->name()); - } - uDebug() << " UMLClassifier::takeItem (before): m_List is " << buf; - - int index = m_List.indexOf(item); - if (index == -1) { - return -1; - } - switch (item->baseType()) { - case UMLObject::ot_Operation: { - if (removeOperation(dynamic_cast(item)) < 0) { - index = -1; - } - break; - } - case UMLObject::ot_Attribute: { - UMLAttribute *retval = dynamic_cast(m_List.takeAt(index).data()); - if (retval) { - emit attributeRemoved(retval); - UMLObject::emitModified(); - } else { - index = -1; - } - break; - } - case UMLObject::ot_Template: { - UMLTemplate *templt = dynamic_cast(m_List.takeAt(index).data()); - if (templt) { - emit templateRemoved(templt); - UMLObject::emitModified(); - } else { - index = -1; - } - break; - } - case UMLObject::ot_EnumLiteral: { - UMLEnumLiteral *el = dynamic_cast(m_List.takeAt(index).data()); - if (el) { - UMLEnum *e = static_cast(this); - e->signalEnumLiteralRemoved(el); - UMLObject::emitModified(); - } else { - index = -1; - } - break; - } - case UMLObject::ot_EntityAttribute: { - UMLEntityAttribute* el = dynamic_cast(m_List.takeAt(index).data()); - if (el) { - UMLEntity *e = static_cast(this); - e->signalEntityAttributeRemoved(el); - UMLObject::emitModified(); - } else { - index = -1; - } - break; - } - default: - index = -1; - break; - } - return index; -} - -/** - * Set the origin type (in case of e.g. typedef) - * @param origType the origin type to set - */ -void UMLClassifier::setOriginType(UMLClassifier *origType) -{ - m_pSecondary = origType; -} - -/** - * Get the origin type (in case of e.g. typedef) - * @return the origin type - */ -UMLClassifier * UMLClassifier::originType() const -{ - return dynamic_cast(m_pSecondary.data()); -} - -/** - * Set the m_isRef flag (true when dealing with a pointer type) - * @param isRef the flag to set - */ -void UMLClassifier::setIsReference(bool isRef) -{ - m_isRef = isRef; -} - -/** - * Get the m_isRef flag. - * @return true if is reference, otherwise false - */ -bool UMLClassifier::isReference() const -{ - return m_isRef; -} - -/** - * Return true if this classifier has associations. - * @return true if classifier has associations - */ -bool UMLClassifier::hasAssociations() -{ - return getSpecificAssocs(AssociationType::Association).count() > 0 - || getAggregations().count() > 0 - || getCompositions().count() > 0 - || getUniAssociationToBeImplemented().count() > 0; -} - -/** - * Return true if this classifier has attributes. - */ -bool UMLClassifier::hasAttributes() -{ - return getAttributeList(Uml::Visibility::Public).count() > 0 - || getAttributeList(Uml::Visibility::Protected).count() > 0 - || getAttributeList(Uml::Visibility::Private).count() > 0 - || getAttributeListStatic(Uml::Visibility::Public).count() > 0 - || getAttributeListStatic(Uml::Visibility::Protected).count() > 0 - || getAttributeListStatic(Uml::Visibility::Private).count() > 0; -} - -/** - * Return true if this classifier has static attributes. - */ -bool UMLClassifier::hasStaticAttributes() -{ - return getAttributeListStatic(Uml::Visibility::Public).count() > 0 - || getAttributeListStatic(Uml::Visibility::Protected).count() > 0 - || getAttributeListStatic(Uml::Visibility::Private).count() > 0; -} - -/** - * Return true if this classifier has accessor methods. - */ -bool UMLClassifier::hasAccessorMethods() -{ - return hasAttributes() || hasAssociations(); -} - -/** - * Return true if this classifier has operation methods. - */ -bool UMLClassifier::hasOperationMethods() -{ - return getOpList().last() ? true : false; -} - -/** - * Return true if this classifier has methods. - */ -bool UMLClassifier::hasMethods() -{ - return hasOperationMethods() || hasAccessorMethods(); -} - -// this is a bit too simplistic..some associations are for -// SINGLE objects, and WONT be declared as Vectors, so this -// is a bit overly inclusive (I guess that's better than the other way around) - -/** - * Return true if this classifier has vector fields. - */ -bool UMLClassifier::hasVectorFields() -{ - return hasAssociations(); -} - -/** - * Return the list of unidirectional association that should show up in the code - */ -UMLAssociationList UMLClassifier::getUniAssociationToBeImplemented() -{ - UMLAssociationList associations = getSpecificAssocs(AssociationType::UniAssociation); - UMLAssociationList uniAssocListToBeImplemented; - - foreach (UMLAssociation *a, associations) { - uIgnoreZeroPointer(a); - if (a->getObjectId(RoleType::B) == id()) { - continue; // we need to be at the A side - } - QString roleNameB = a->getRoleName(RoleType::B); - if (!roleNameB.isEmpty()) { - UMLAttributeList atl = getAttributeList(); - bool found = false; - //make sure that an attribute with the same name doesn't already exist - foreach (UMLAttribute *at, atl) { - uIgnoreZeroPointer(a); - if (at->name() == roleNameB) { - found = true; - break; - } - } - if (!found) { - uniAssocListToBeImplemented.append(a); - } - } - } - return uniAssocListToBeImplemented; -} - -/** - * Creates XML tag , , or - * depending on m_BaseType. - * Saves possible template parameters, generalizations, attributes, - * operations, and contained objects to the given QDomElement. - */ -void UMLClassifier::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) -{ - QString tag; - switch (m_BaseType) { - case UMLObject::ot_Class: - tag = QLatin1String("UML:Class"); - break; - case UMLObject::ot_Interface: - tag = QLatin1String("UML:Interface"); - break; - case UMLObject::ot_Datatype: - tag = QLatin1String("UML:DataType"); - break; - case UMLObject::ot_Package: - UMLPackage::saveToXMI(qDoc, qElement); - return; - break; - default: - uError() << "internal error: basetype is " << m_BaseType; - return; - } - QDomElement classifierElement = UMLObject::save(tag, qDoc); - if (m_BaseType == UMLObject::ot_Datatype && m_pSecondary != NULL) - classifierElement.setAttribute(QLatin1String("elementReference"), - Uml::ID::toString(m_pSecondary->id())); - - //save templates - UMLClassifierListItemList list = getFilteredList(UMLObject::ot_Template); - if (list.count()) { - QDomElement tmplElement = qDoc.createElement(QLatin1String("UML:ModelElement.templateParameter")); - foreach (UMLClassifierListItem *tmpl, list) { - tmpl->saveToXMI(qDoc, tmplElement); - } - classifierElement.appendChild(tmplElement); - } - - //save generalizations (we are the subclass, the other end is the superclass) - UMLAssociationList generalizations = getSpecificAssocs(AssociationType::Generalization); - if (generalizations.count()) { - QDomElement genElement = qDoc.createElement(QLatin1String("UML:GeneralizableElement.generalization")); - foreach (UMLAssociation *a, generalizations) { - // We are the subclass if we are at the role A end. - if (m_nId != a->getObjectId(RoleType::A)) { - continue; - } - QDomElement gElem = qDoc.createElement(QLatin1String("UML:Generalization")); - gElem.setAttribute(QLatin1String("xmi.idref"), Uml::ID::toString(a->id())); - genElement.appendChild(gElem); - } - if (genElement.hasChildNodes()) { - classifierElement.appendChild(genElement); - } - } - - // save attributes - QDomElement featureElement = qDoc.createElement(QLatin1String("UML:Classifier.feature")); - UMLClassifierListItemList attList = getFilteredList(UMLObject::ot_Attribute); - foreach (UMLClassifierListItem *pAtt, attList) { - pAtt->saveToXMI(qDoc, featureElement); - } - - // save operations - UMLOperationList opList = getOpList(); - foreach (UMLOperation *pOp, opList) { - pOp->saveToXMI(qDoc, featureElement); - } - if (featureElement.hasChildNodes()) { - classifierElement.appendChild(featureElement); - } - - // save contained objects - if (m_objects.count()) { - QDomElement ownedElement = qDoc.createElement(QLatin1String("UML:Namespace.ownedElement")); - foreach (UMLObject* obj, m_objects) { - uIgnoreZeroPointer(obj); - obj->saveToXMI (qDoc, ownedElement); - } - classifierElement.appendChild(ownedElement); - } - qElement.appendChild(classifierElement); -} - -/** - * Create a new ClassifierListObject (attribute, operation, template) - * according to the given XMI tag. - * Returns NULL if the string given does not contain one of the tags - * , , or . - * Used by the clipboard for paste operation. - */ -UMLClassifierListItem* UMLClassifier::makeChildObject(const QString& xmiTag) -{ - UMLClassifierListItem* pObject = NULL; - if (UMLDoc::tagEq(xmiTag, QLatin1String("Operation")) || - UMLDoc::tagEq(xmiTag, QLatin1String("ownedOperation"))) { - pObject = new UMLOperation(this); - } else if (UMLDoc::tagEq(xmiTag, QLatin1String("Attribute")) || - UMLDoc::tagEq(xmiTag, QLatin1String("ownedAttribute"))) { - if (baseType() != UMLObject::ot_Class) - return NULL; - pObject = new UMLAttribute(this); - } else if (UMLDoc::tagEq(xmiTag, QLatin1String("TemplateParameter"))) { - pObject = new UMLTemplate(this); - } - return pObject; -} - -/** - * Auxiliary to loadFromXMI: - * The loading of operations is implemented here. - * Calls loadSpecialized() for any other tag. - * Child classes can override the loadSpecialized method - * to load its additional tags. - */ -bool UMLClassifier::load(QDomElement& element) -{ - UMLClassifierListItem *child = NULL; - m_SecondaryId = element.attribute(QLatin1String("elementReference")); - if (!m_SecondaryId.isEmpty()) { - // @todo We do not currently support composition. - m_isRef = true; - } - bool totalSuccess = true; - for (QDomNode node = element.firstChild(); !node.isNull(); - node = node.nextSibling()) { - if (node.isComment()) - continue; - element = node.toElement(); - QString tag = element.tagName(); - QString stereotype = element.attribute(QLatin1String("stereotype")); - if (UMLDoc::tagEq(tag, QLatin1String("ModelElement.templateParameter")) || - UMLDoc::tagEq(tag, QLatin1String("Classifier.feature")) || - UMLDoc::tagEq(tag, QLatin1String("Namespace.ownedElement")) || - UMLDoc::tagEq(tag, QLatin1String("Element.ownedElement")) || // Embarcadero's Describe - UMLDoc::tagEq(tag, QLatin1String("Namespace.contents"))) { - load(element); - // Not evaluating the return value from load() - // because we want a best effort. - - } else if ((child = makeChildObject(tag)) != NULL) { - if (child->loadFromXMI(element)) { - switch (child->baseType()) { - case UMLObject::ot_Template: - addTemplate(static_cast(child)); - break; - case UMLObject::ot_Operation: - if (! addOperation(static_cast(child))) { - uError() << "error from addOperation(op)"; - delete child; - totalSuccess = false; - } - break; - case UMLObject::ot_Attribute: - addAttribute(static_cast(child)); - break; - default: - break; - } - } else { - uWarning() << "failed to load " << tag; - delete child; - totalSuccess = false; - } - } else if (!Model_Utils::isCommonXMIAttribute(tag)) { - UMLObject *pObject = Object_Factory::makeObjectFromXMI(tag, stereotype); - if (pObject == NULL) { - // Not setting totalSuccess to false - // because we want a best effort. - continue; - } - pObject->setUMLPackage(this); - if (! pObject->loadFromXMI(element)) { - removeObject(pObject); - delete pObject; - totalSuccess = false; - } - } - } - return totalSuccess; -} - -/* -UMLClassifierList UMLClassifier::getPlainAssocChildClassifierList() -{ - UMLAssociationList plainAssociations = getSpecificAssocs(Uml::AssociationType::Association); - return findAssocClassifierObjsInRoles(&plainAssociations); -} - -UMLClassifierList UMLClassifier::getAggregateChildClassifierList() -{ - UMLAssociationList aggregations = getAggregations(); - return findAssocClassifierObjsInRoles(&aggregations); -} - -UMLClassifierList UMLClassifier::getCompositionChildClassifierList() -{ - UMLAssociationList compositions = getCompositions(); - return findAssocClassifierObjsInRoles(&compositions); -} - -UMLClassifierList UMLClassifier::findAssocClassifierObjsInRoles (UMLAssociationList * list) -{ - UMLClassifierList classifiers; - - for (UMLAssociationListIt alit(*list); alit.hasNext(); ) { - UMLAssociation* a = alit.next(); - // DON'T accept a classifier IF the association role is empty, by - // convention, that means to ignore the classifier on that end of - // the association. - // We also ignore classifiers which are the same as the current one - // (e.g. id matches), we only want the "other" classifiers - if (a->getObjectId(RoleType::A) == id() && !a->getRoleName(RoleType::B).isEmpty()) { - UMLClassifier *c = dynamic_cast(a->getObject(RoleType::B)); - if(c) - classifiers.append(c); - } else if (a->getObjectId(RoleType::B) == id() && !a->getRoleName(RoleType::A).isEmpty()) { - UMLClassifier *c = dynamic_cast(a->getObject(RoleType::A)); - if(c) - classifiers.append(c); - } - } - - return classifiers; -} -*/ - - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/classifier.h umbrello-kf6-15.08.1/umbrello/classifier.h --- umbrello-kf6-15.08.1.orig/umbrello/classifier.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/classifier.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,199 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ -#ifndef CLASSIFIER_H -#define CLASSIFIER_H - -#include "package.h" -#include "umlattributelist.h" -#include "umloperationlist.h" -#include "umlclassifierlistitemlist.h" -#include "classifierlistitem.h" -#include "umltemplatelist.h" -#include "model_utils.h" - -// forward declarations -class UMLAssociation; -class IDChangeLog; -class UMLClassifierSet; - -/** - * This class defines the non-graphical information required for a - * UML Classifier (ie a class or interface). - * This class inherits from @ref UMLPackage which allows classifiers - * to also act as namespaces, i.e. it allows classifiers to nest. - * - * NOTE: There is a unit test available for this class. - * Please, use and adapt it when necessary. - * - * @short Information for a non-graphical Concept/Class. - * @author Paul Hensgen - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class UMLClassifier : public UMLPackage -{ - Q_OBJECT -public: - - /** - * Enumeration identifying the type of classifier. - */ - enum ClassifierType { ALL = 0, CLASS, INTERFACE, DATATYPE }; - - explicit UMLClassifier(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); - virtual ~UMLClassifier(); - - bool operator==(const UMLClassifier & rhs) const; - - virtual void copyInto(UMLObject *lhs) const; - - UMLObject* clone() const; - - virtual UMLAttribute* createAttribute(const QString &name = QString(), - UMLObject *type = 0, - Uml::Visibility::Enum vis = Uml::Visibility::Private, - const QString &init = QString()); - - UMLAttribute* addAttribute(const QString &name, Uml::ID::Type id = Uml::ID::None); - UMLAttribute* addAttribute(const QString &name, UMLObject *type, Uml::Visibility::Enum scope); - - bool addAttribute(UMLAttribute* att, IDChangeLog* log = 0, - int position = -1); - - int removeAttribute(UMLAttribute *att); - - int attributes() ; - - UMLAttributeList getAttributeList() const; - UMLAttributeList getAttributeList(Uml::Visibility::Enum scope) const; - UMLAttributeList getAttributeListStatic(Uml::Visibility::Enum scope) const; - - UMLOperation* createOperation(const QString &name = QString(), - bool *isExistingOp = NULL, - Model_Utils::NameAndType_List *params = NULL); - - bool addOperation(UMLOperation* op, int position = -1); - bool addOperation(UMLOperation* op, IDChangeLog* log); - - UMLOperation * checkOperationSignature(const QString& name, - UMLAttributeList opParams, - UMLOperation *exemptOp = NULL); - - int removeOperation(UMLOperation *op); - - int operations(); - - UMLOperationList getOpList(bool includeInherited = false, UMLClassifierSet *alreadyTraversed = 0); - - UMLObject* createTemplate(const QString& name = QString()); - - UMLTemplate* addTemplate(const QString &name, Uml::ID::Type id = Uml::ID::None); - - bool addTemplate(UMLTemplate* newTemplate, IDChangeLog* log = 0); - bool addTemplate(UMLTemplate* templt, int position); - - int removeTemplate(UMLTemplate* umltemplate); - - UMLTemplate *findTemplate(const QString& name); - - int templates(); - - UMLTemplateList getTemplateList() const; - - int takeItem(UMLClassifierListItem* item); - - virtual UMLClassifierListItemList getFilteredList(UMLObject::ObjectType ot) const; - - virtual bool resolveRef(); - - UMLOperationList findOperations(const QString &n); - - virtual UMLObject* findChildObjectById(Uml::ID::Type id, bool considerAncestors = false); - - UMLOperation* findOperation(const QString& name, - Model_Utils::NameAndType_List params); - - UMLClassifierList findSuperClassConcepts(ClassifierType type = ALL); - - UMLClassifierList findSubClassConcepts(ClassifierType type = ALL); - - virtual bool acceptAssociationType(Uml::AssociationType::Enum type); - - void setClassAssoc(UMLAssociation *assoc); - UMLAssociation *getClassAssoc() const; - - void setBaseType(UMLObject::ObjectType ot); - - bool isInterface() const; - - bool isDatatype() const; - - void setOriginType(UMLClassifier *origType); - UMLClassifier * originType() const; - - void setIsReference(bool isRef = true); - bool isReference() const; - - bool hasAbstractOps(); - bool hasAssociations(); - bool hasAttributes(); - bool hasStaticAttributes(); - bool hasMethods(); - bool hasAccessorMethods(); - bool hasOperationMethods(); - bool hasVectorFields(); - - /** - * utility functions to allow easy determination of what classifiers - * are "owned" by the current one via named association type (e.g. - * plain, aggregate or compositions). - */ -// UMLClassifierList getPlainAssocChildClassifierList(); -// UMLClassifierList getAggregateChildClassifierList(); -// UMLClassifierList getCompositionChildClassifierList(); - - virtual UMLClassifierListItem* makeChildObject(const QString& xmiTag); - - virtual UMLAssociationList getUniAssociationToBeImplemented(); - -signals: - - void operationAdded(UMLClassifierListItem *); - void operationRemoved(UMLClassifierListItem *); - - void templateAdded(UMLClassifierListItem*); - void templateRemoved(UMLClassifierListItem*); - - // only applies when (m_Type == ot_Class) - void attributeAdded(UMLClassifierListItem*); - void attributeRemoved(UMLClassifierListItem*); - -private: - - UMLAssociation *m_pClassAssoc; - - bool m_isRef; - - /** - * Utility method called by "get*ChildClassfierList()" methods. It basically - * finds all the classifiers named in each association in the given association list - * which aren't the current one. Useful for finding which classifiers are "owned" by the - * current one via declared associations such as in aggregations/compositions. - */ -// UMLClassifierList findAssocClassifierObjsInRoles (UMLAssociationList * list); - -protected: - - void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); - - virtual bool load(QDomElement& element); - -}; - -#endif // CLASSIFIER_H diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/classifierlistitem.cpp umbrello-kf6-15.08.1/umbrello/classifierlistitem.cpp --- umbrello-kf6-15.08.1.orig/umbrello/classifierlistitem.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/classifierlistitem.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,159 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "classifierlistitem.h" - -// local includes -#include "debug_utils.h" -#include "classifier.h" -#include "model_utils.h" -#include "object_factory.h" -#include "uml.h" -#include "umldoc.h" - -// kde includes -#include - -/** - * Constructor. - * - * @param parent The parent to this operation. - * At first sight it would appear that the type of the - * parent should be UMLClassifier. However, the class - * UMLAttribute is also used for the parameters of - * operations, and in this case the UMLOperation is the - * parent. - * @param name The name of the operation. - * @param id The id of the operation. - */ -UMLClassifierListItem::UMLClassifierListItem(UMLObject *parent, - const QString& name, Uml::ID::Type id) - : UMLObject(parent, name, id) -{ - UMLObject *parentObj = const_cast(parent); - UMLClassifier *pc = dynamic_cast(parentObj); - if (pc) - UMLObject::setUMLPackage(pc); -} - -/** - * Constructor. - * - * @param parent The parent to this operation. - * At first sight it would appear that the type of the - * parent should be UMLClassifier. However, the class - * UMLAttribute is also used for the parameters of - * operations, and in this case the UMLOperation is the - * parent. - */ -UMLClassifierListItem::UMLClassifierListItem(UMLObject *parent) - : UMLObject(parent) -{ - UMLObject *parentObj = const_cast(parent); - UMLClassifier *pc = dynamic_cast(parentObj); - if (pc) - UMLObject::setUMLPackage(pc); -} - -/** - * Destructor. Empty. - */ -UMLClassifierListItem::~UMLClassifierListItem() -{ -} - -/** - * Copy the internal presentation of this object into the new - * object. - */ -void UMLClassifierListItem::copyInto(UMLObject *lhs) const -{ - // Call the parent. - UMLObject::copyInto(lhs); -} - -/** - * Returns a string representation of the list item. - * - * @param sig What type of operation string to show. - * @return The string representation of the operation. - */ -QString UMLClassifierListItem::toString(Uml::SignatureType::Enum sig) -{ - Q_UNUSED(sig); - return name(); -} - -/** - * Returns the type of the UMLClassifierListItem. - * - * @return The type of the UMLClassifierListItem. - */ -UMLClassifier * UMLClassifierListItem::getType() const -{ - return dynamic_cast(m_pSecondary.data()); -} - -/** - * Returns the type name of the UMLClassifierListItem. - * - * @return The type name of the UMLClassifierListItem. - */ -QString UMLClassifierListItem::getTypeName() const -{ - if (m_pSecondary == NULL) - return m_SecondaryId; - const UMLPackage *typePkg = m_pSecondary->umlPackage(); - if (typePkg != NULL && typePkg != m_pUMLPackage) - return m_pSecondary->fullyQualifiedName(); - return m_pSecondary->name(); -} - -/** - * Sets the type of the UMLAttribute. - * - * @param type Pointer to the UMLObject of the type. - */ -void UMLClassifierListItem::setType(UMLObject *type) -{ - if (m_pSecondary != type) { - m_pSecondary = type; - UMLObject::emitModified(); - } -} - -/** - * Sets the type name of the UMLClassifierListItem. - * DEPRECATED - use setType() instead. - * - * @param type The type name of the UMLClassifierListItem. - */ -void UMLClassifierListItem::setTypeName(const QString &type) -{ - if (type.isEmpty() || type == QLatin1String("void")) { - m_pSecondary = NULL; - m_SecondaryId.clear(); - return; - } - UMLDoc *pDoc = UMLApp::app()->document(); - m_pSecondary = pDoc->findUMLObject(type); - if (m_pSecondary == NULL) { - // Make data type for easily identified cases - if (Model_Utils::isCommonDataType(type) || type.contains(QLatin1Char('*'))) { - m_pSecondary = Object_Factory::createUMLObject(UMLObject::ot_Datatype, type); - uDebug() << "created datatype for " << type; - } else { - m_SecondaryId = type; - } - } - UMLObject::emitModified(); -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/classifierlistitem.h umbrello-kf6-15.08.1/umbrello/classifierlistitem.h --- umbrello-kf6-15.08.1.orig/umbrello/classifierlistitem.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/classifierlistitem.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,58 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef CLASSIFIERLISTITEM_H -#define CLASSIFIERLISTITEM_H - -#include "umlobject.h" - -// forward declaration -class UMLClassifier; - -/** - * Classifiers (classes, interfaces) have lists of operations, - * attributes, templates and others. This is a base class for - * the items in this list. This abstraction should remove - * duplication of dialogs and allow for stereotypes in lists. - * - * @short A base class for classifier list items (e.g. attributes) - * @author Jonathan Riddell - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class UMLClassifierListItem : public UMLObject -{ - Q_OBJECT -public: - - UMLClassifierListItem(UMLObject *parent, - const QString& name, - Uml::ID::Type id = Uml::ID::None); - explicit UMLClassifierListItem(UMLObject *parent); - virtual ~UMLClassifierListItem(); - - virtual void setType(UMLObject *type); - UMLClassifier * getType() const; - - void setTypeName(const QString &type); - virtual QString getTypeName() const; - - virtual QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); - - virtual void copyInto(UMLObject *lhs) const; - - /** - * The abstract method UMLObject::clone() must be implemented - * by the classes inheriting from UMLClassifierListItem. - */ - virtual UMLObject* clone() const = 0; - -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/CMakeLists.txt umbrello-kf6-15.08.1/umbrello/CMakeLists.txt --- umbrello-kf6-15.08.1.orig/umbrello/CMakeLists.txt 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/CMakeLists.txt 2015-10-08 11:48:59.486089026 +0300 @@ -56,7 +56,8 @@ ${CMAKE_CURRENT_SOURCE_DIR}/docgenerators/ ${CMAKE_CURRENT_SOURCE_DIR}/finder/ ${CMAKE_CURRENT_SOURCE_DIR}/refactoring/ - ${CMAKE_CURRENT_SOURCE_DIR}/widgets/ + ${CMAKE_CURRENT_SOURCE_DIR}/umlmodel/ + ${CMAKE_CURRENT_SOURCE_DIR}/umlwidgets/ ${CMAKE_SOURCE_DIR}/lib/cppparser/ ${CMAKE_SOURCE_DIR}/lib/interfaces/ ) @@ -343,47 +344,47 @@ cmds/widget/cmd_setTxt.cpp ) -set(libwidgets_SRCS - widgets/activitywidget.cpp - widgets/actorwidget.cpp - widgets/artifactwidget.cpp - widgets/associationline.cpp - widgets/associationwidget.cpp - widgets/boxwidget.cpp - widgets/categorywidget.cpp - widgets/classifierwidget.cpp - widgets/combinedfragmentwidget.cpp - widgets/componentwidget.cpp - widgets/datatypewidget.cpp - widgets/entitywidget.cpp - widgets/enumwidget.cpp - widgets/floatingdashlinewidget.cpp - widgets/floatingtextwidget.cpp - widgets/forkjoinwidget.cpp - widgets/layoutgrid.cpp - widgets/linkwidget.cpp - widgets/messagewidget.cpp - widgets/nodewidget.cpp - widgets/notewidget.cpp - widgets/objectnodewidget.cpp - widgets/objectwidget.cpp - widgets/packagewidget.cpp - widgets/pinportbase.cpp - widgets/pinwidget.cpp - widgets/portwidget.cpp - widgets/preconditionwidget.cpp - widgets/regionwidget.cpp - widgets/seqlinewidget.cpp - widgets/signalwidget.cpp - widgets/statewidget.cpp - widgets/toolbarstateonewidget.cpp - widgets/umlwidget.cpp - widgets/usecasewidget.cpp - widgets/widget_factory.cpp - widgets/widget_utils.cpp - widgets/widgetbase.cpp - widgets/widgetlist_utils.cpp - widgets/statusbartoolbutton.cpp +set(libumlwidgets_SRCS + umlwidgets/activitywidget.cpp + umlwidgets/actorwidget.cpp + umlwidgets/artifactwidget.cpp + umlwidgets/associationline.cpp + umlwidgets/associationwidget.cpp + umlwidgets/boxwidget.cpp + umlwidgets/categorywidget.cpp + umlwidgets/classifierwidget.cpp + umlwidgets/combinedfragmentwidget.cpp + umlwidgets/componentwidget.cpp + umlwidgets/datatypewidget.cpp + umlwidgets/entitywidget.cpp + umlwidgets/enumwidget.cpp + umlwidgets/floatingdashlinewidget.cpp + umlwidgets/floatingtextwidget.cpp + umlwidgets/forkjoinwidget.cpp + umlwidgets/layoutgrid.cpp + umlwidgets/linkwidget.cpp + umlwidgets/messagewidget.cpp + umlwidgets/nodewidget.cpp + umlwidgets/notewidget.cpp + umlwidgets/objectnodewidget.cpp + umlwidgets/objectwidget.cpp + umlwidgets/packagewidget.cpp + umlwidgets/pinportbase.cpp + umlwidgets/pinwidget.cpp + umlwidgets/portwidget.cpp + umlwidgets/preconditionwidget.cpp + umlwidgets/regionwidget.cpp + umlwidgets/seqlinewidget.cpp + umlwidgets/signalwidget.cpp + umlwidgets/statewidget.cpp + umlwidgets/toolbarstateonewidget.cpp + umlwidgets/umlwidget.cpp + umlwidgets/usecasewidget.cpp + umlwidgets/widget_factory.cpp + umlwidgets/widget_utils.cpp + umlwidgets/widgetbase.cpp + umlwidgets/widgetlist_utils.cpp + umlwidgets/statusbartoolbutton.cpp ) set(libfinder_SRCS @@ -394,47 +395,60 @@ finder/umlscenefinder.cpp ) -########### next target ############### +set(libuml_SRCS + umlmodel/actor.cpp + umlmodel/artifact.cpp + umlmodel/association.cpp + umlmodel/attribute.cpp + umlmodel/category.cpp + umlmodel/checkconstraint.cpp + umlmodel/classifier.cpp + umlmodel/classifierlistitem.cpp + umlmodel/component.cpp + umlmodel/entity.cpp + umlmodel/entityattribute.cpp + umlmodel/entityconstraint.cpp + umlmodel/enum.cpp + umlmodel/enumliteral.cpp + umlmodel/folder.cpp + umlmodel/foreignkeyconstraint.cpp + umlmodel/node.cpp + umlmodel/operation.cpp + umlmodel/package.cpp + umlmodel/port.cpp + umlmodel/stereotype.cpp + umlmodel/template.cpp + umlmodel/umlattributelist.cpp + umlmodel/umlcanvasobject.cpp + umlmodel/umlclassifierlistitemlist.cpp + umlmodel/umlentityattributelist.cpp + umlmodel/umlentityconstraintlist.cpp + umlmodel/umlobject.cpp + umlmodel/umlobjectlist.cpp + umlmodel/umlrole.cpp + umlmodel/usecase.cpp + umlmodel/uniqueconstraint.cpp +) set(umbrello-kf6base_SRCS - actor.cpp - artifact.cpp - association.cpp assocrules.cpp - attribute.cpp basictypes.cpp birdview.cpp - category.cpp - checkconstraint.cpp - classifier.cpp - classifierlistitem.cpp cmdlineexportallviewsevent.cpp - component.cpp docwindow.cpp dotgenerator.cpp - entity.cpp - entityattribute.cpp - entityconstraint.cpp - enum.cpp - enumliteral.cpp - folder.cpp - foreignkeyconstraint.cpp icon_utils.cpp import_argo.cpp import_rose.cpp layoutgenerator.cpp listpopupmenu.cpp model_utils.cpp - node.cpp object_factory.cpp - operation.cpp optionstate.cpp - package.cpp petalnode.cpp petaltree2uml.cpp - port.cpp - stereotype.cpp - template.cpp + stereotypeswindow.cpp + stereotypesmodel.cpp toolbarstatearrow.cpp toolbarstateassociation.cpp toolbarstate.cpp @@ -443,26 +457,16 @@ toolbarstateother.cpp toolbarstatepool.cpp umlappprivate.cpp - umlattributelist.cpp - umlcanvasobject.cpp - umlclassifierlistitemlist.cpp uml.cpp umldoc.cpp - umlentityattributelist.cpp - umlentityconstraintlist.cpp umllistview.cpp umllistviewitem.cpp - umlobject.cpp - umlobjectlist.cpp - umlrole.cpp umlscene.cpp umlview.cpp umlviewimageexporterall.cpp umlviewimageexporter.cpp umlviewimageexportermodel.cpp - uniqueconstraint.cpp uniqueid.cpp - usecase.cpp worktoolbar.cpp ) @@ -482,7 +486,8 @@ ${libcodegenerator_SRCS} ${libdocgenerator_SRCS} ${libcmds_SRCS} - ${libwidgets_SRCS} + ${libuml_SRCS} + ${libumlwidgets_SRCS} ${umbrello-kf6base_SRCS} ) diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/component.cpp umbrello-kf6-15.08.1/umbrello/component.cpp --- umbrello-kf6-15.08.1.orig/umbrello/component.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/component.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,127 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "component.h" -// app includes -#include "association.h" -#include "debug_utils.h" -#include "object_factory.h" -#include "model_utils.h" -#include "clipboard/idchangelog.h" -#include "umldoc.h" -// kde includes -#include - -/** - * Sets up a Component. - * @param name The name of the Concept. - * @param id The unique id of the Concept. - */ -UMLComponent::UMLComponent(const QString & name, Uml::ID::Type id) - : UMLPackage(name, id), - m_executable(false) -{ - m_BaseType = UMLObject::ot_Component; -} - -/** - * Destructor. - */ -UMLComponent::~UMLComponent() -{ -} - -/** - * Make a clone of this object. - */ -UMLObject* UMLComponent::clone() const -{ - UMLComponent *clone = new UMLComponent(); - UMLObject::copyInto(clone); - return clone; -} - -/** - * Creates the UML:Component element including its operations, - * attributes and templates - */ -void UMLComponent::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) -{ - QDomElement componentElement = UMLObject::save(QLatin1String("UML:Component"), qDoc); - componentElement.setAttribute(QLatin1String("executable"), m_executable); - // Save contained components if any. - if (m_objects.count()) { - QDomElement ownedElement = qDoc.createElement(QLatin1String("UML:Namespace.ownedElement")); - for (UMLObjectListIt objectsIt(m_objects); objectsIt.hasNext();) { - UMLObject* obj = objectsIt.next(); - uIgnoreZeroPointer(obj); - obj->saveToXMI (qDoc, ownedElement); - } - componentElement.appendChild(ownedElement); - } - qElement.appendChild(componentElement); -} - -/** - * Loads the UML:Component element including its ports et al. - */ -bool UMLComponent::load(QDomElement& element) -{ - QString executable = element.attribute(QLatin1String("executable"), QLatin1String("0")); - m_executable = (bool)executable.toInt(); - for (QDomNode node = element.firstChild(); !node.isNull(); - node = node.nextSibling()) { - if (node.isComment()) - continue; - QDomElement tempElement = node.toElement(); - QString type = tempElement.tagName(); - if (Model_Utils::isCommonXMIAttribute(type)) - continue; - if (UMLDoc::tagEq(type, QLatin1String("Namespace.ownedElement")) || - UMLDoc::tagEq(type, QLatin1String("Namespace.contents"))) { - //CHECK: umbrello-kf6 currently assumes that nested elements - // are ownedElements anyway. - // Therefore these tags are not further interpreted. - if (! load(tempElement)) - return false; - continue; - } - UMLObject *pObject = Object_Factory::makeObjectFromXMI(type); - if (!pObject) { - uWarning() << "Unknown type of umlobject to create: " << type; - continue; - } - pObject->setUMLPackage(this); - if (pObject->loadFromXMI(tempElement)) { - addObject(pObject); - } else { - delete pObject; - } - } - return true; -} - -/** - * Sets m_executable. - */ -void UMLComponent::setExecutable(bool executable) -{ - m_executable = executable; -} - -/** - * Returns the value of m_executable. - */ -bool UMLComponent::getExecutable() -{ - return m_executable; -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/component.h umbrello-kf6-15.08.1/umbrello/component.h --- umbrello-kf6-15.08.1.orig/umbrello/component.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/component.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,48 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef COMPONENT_H -#define COMPONENT_H - -#include "package.h" - -/** - * This class contains the non-graphical information required for a - * UML Component. - * This class inherits from @ref UMLPackage which contains most - * of the information. - * - * @short Non-graphical information for a Component. - * @author Jonathan Riddell - * @see UMLCanvasObject - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class UMLComponent : public UMLPackage -{ - Q_OBJECT -public: - explicit UMLComponent(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); - virtual ~UMLComponent(); - - virtual UMLObject* clone() const; - - void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); - - void setExecutable(bool executable); - bool getExecutable(); - -protected: - bool load(QDomElement & element); - -private: - bool m_executable; ///< holds whether this is an executable component or not -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/dialogs/notedialog.cpp umbrello-kf6-15.08.1/umbrello/dialogs/notedialog.cpp --- umbrello-kf6-15.08.1.orig/umbrello/dialogs/notedialog.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/dialogs/notedialog.cpp 2015-10-08 11:48:59.497089026 +0300 @@ -36,6 +36,7 @@ QVBoxLayout *layout = new QVBoxLayout(frame); layout->addWidget(m_docWidget, 10); setMinimumSize(600, 250); + m_docWidget->setFocus(); } /** diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/dialogs/widgets/documentationwidget.cpp umbrello-kf6-15.08.1/umbrello/dialogs/widgets/documentationwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/dialogs/widgets/documentationwidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/dialogs/widgets/documentationwidget.cpp 2015-10-08 11:48:59.499089026 +0300 @@ -67,6 +67,8 @@ m_editField->setLineWrapMode(QTextEdit::WidgetWidth); m_editField->setWordWrapMode(QTextOption::WordWrap); m_editField->setText(text); + setFocusProxy(m_editField); + QHBoxLayout *layout = new QHBoxLayout(m_box); layout->addWidget(m_editField); layout->setMargin(fontMetrics().height()); diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/docwindow.cpp umbrello-kf6-15.08.1/umbrello/docwindow.cpp --- umbrello-kf6-15.08.1.orig/umbrello/docwindow.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/docwindow.cpp 2015-10-08 11:48:59.499089026 +0300 @@ -91,6 +91,7 @@ statusLayout->addWidget(m_modifiedWidget, 0, 5, 1, 1); m_docTE = new KTextEdit(this); m_docTE->setText(QString()); + setFocusProxy(m_docTE); //m_docTE->setWordWrapMode(QTextEdit::WidgetWidth); QVBoxLayout* docLayout = new QVBoxLayout(this); docLayout->addLayout(statusLayout); @@ -461,5 +462,6 @@ tab->setCurrentIndex(i); } } + m_docTE->setFocus(); } diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/entityattribute.cpp umbrello-kf6-15.08.1/umbrello/entityattribute.cpp --- umbrello-kf6-15.08.1.orig/umbrello/entityattribute.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/entityattribute.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,280 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "entityattribute.h" - -// app includes -#include "debug_utils.h" -//#include "umlcanvasobject.h" -#include "umldoc.h" -#include "uml.h" -#include "umlentityattributedialog.h" -#include "object_factory.h" - -// qt includes -#include - -/** - * Sets up an entityattribute. - * @param parent The parent of this UMLEntityAttribute. - * @param name The name of this UMLEntityAttribute. - * @param id The unique id given to this UMLEntityAttribute. - * @param s The visibility of the UMLEntityAttribute. - * @param type The type of this UMLEntityAttribute. - * @param iv The initial value of the entityattribute. - */ -UMLEntityAttribute::UMLEntityAttribute(UMLObject *parent, const QString& name, - Uml::ID::Type id, Uml::Visibility::Enum s, - UMLObject *type, const QString& iv) - : UMLAttribute(parent, name, id, s, type, iv) -{ - init(); - if (m_pSecondary) { - m_pSecondary->setBaseType(UMLObject::ot_Entity); - } -} - -/** - * Sets up an entityattribute. - * @param parent The parent of this UMLEntityAttribute. - */ -UMLEntityAttribute::UMLEntityAttribute(UMLObject *parent) - : UMLAttribute(parent) -{ - init(); -} - -/** - * Destructor. - */ -UMLEntityAttribute::~UMLEntityAttribute() -{ -} - -/** - * Initialize members of this class. - * Auxiliary method used by constructors. - */ -void UMLEntityAttribute::init() -{ - m_BaseType = UMLObject::ot_EntityAttribute; - m_indexType = UMLEntityAttribute::None; - m_autoIncrement = false; - m_null = false; -} - -/** - * Returns the value of the UMLEntityAttribute's attributes property. - * @return The value of the UMLEntityAttribute's attributes property. - */ -QString UMLEntityAttribute::getAttributes() const -{ - return m_attributes; -} - -/** - * Sets the UMLEntityAttribute's attributes property. - * @param attributes The new value for the attributes property. - */ -void UMLEntityAttribute::setAttributes(const QString& attributes) -{ - m_attributes = attributes; -} - -/** - * Returns the UMLEntityAttribute's length/values property. - * @return The new value of the length/values property. - */ -QString UMLEntityAttribute::getValues() const -{ - return m_values; -} - -/** - * Sets the UMLEntityAttribute's length/values property. - * @param values The new value of the length/values property. - */ -void UMLEntityAttribute::setValues(const QString& values) -{ - m_values = values; -} - -/** - * Returns the UMLEntityAttribute's auto_increment boolean - * @return The UMLEntityAttribute's auto_increment boolean - */ -bool UMLEntityAttribute::getAutoIncrement() const -{ - return m_autoIncrement; -} - -/** - * Sets the UMLEntityAttribute's auto_increment boolean - * @param autoIncrement The UMLEntityAttribute's auto_increment boolean - */ -void UMLEntityAttribute::setAutoIncrement(const bool autoIncrement) -{ - m_autoIncrement = autoIncrement; -} - -/** - * Returns the UMLEntityAttribute's index type property. - * @return The value of the UMLEntityAttribute's index type property. - */ -UMLEntityAttribute::DBIndex_Type UMLEntityAttribute::indexType() const -{ - return m_indexType; -} - -/** - * Sets the initial value of the UMLEntityAttribute's index type property. - * @param indexType The initial value of the UMLEntityAttribute's index type property. - */ -void UMLEntityAttribute::setIndexType(const UMLEntityAttribute::DBIndex_Type indexType) -{ - m_indexType = indexType; -} - -/** - * Returns the UMLEntityAttribute's allow null value. - * @return The UMLEntityAttribute's allow null value. - */ -bool UMLEntityAttribute::getNull() const -{ - return m_null; -} - -/** - * Sets the initial value of the UMLEntityAttribute's allow null value. - * @param nullIn The initial value of the UMLEntityAttribute's allow null value. - */ -void UMLEntityAttribute::setNull(const bool nullIn) -{ - m_null = nullIn; -} - -/** - * Returns a string representation of the UMLEntityAttribute. - * @param sig If true will show the entityattribute type and initial value. - * @return Returns a string representation of the UMLEntityAttribute. - */ -QString UMLEntityAttribute::toString(Uml::SignatureType::Enum sig) -{ - QString s; - //FIXME - - if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::NoSig) { - s = Uml::Visibility::toString(m_visibility, true) + QLatin1Char(' '); - } - - if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::SigNoVis) { - QString string = s + name() + QLatin1String(" : ") + getTypeName(); - if(m_InitialValue.length() > 0) - string += QLatin1String(" = ") + m_InitialValue; - return string; - } else - return s + name(); -} - -/** - * Overloaded '==' operator - */ -bool UMLEntityAttribute::operator==(const UMLEntityAttribute &rhs) const -{ - if(this == &rhs) - return true; - - if(!UMLObject::operator==(rhs)) - return false; - - // The type name is the only distinguishing criterion. - // (Some programming languages might support more, but others don't.) - if (m_pSecondary != rhs.m_pSecondary) - return false; - - return true; -} - -/** - * Copy the internal presentation of this object into the UMLEntityAttribute - * object. - */ -void UMLEntityAttribute::copyInto(UMLObject *lhs) const -{ - UMLEntityAttribute *target = static_cast(lhs); - - // call the parent first. - UMLClassifierListItem::copyInto(target); - - // Copy all datamembers - target->m_pSecondary = m_pSecondary; - target->m_SecondaryId = m_SecondaryId; - target->m_InitialValue = m_InitialValue; - target->m_ParmKind = m_ParmKind; -} - -/** - * Make a clone of the UMLEntityAttribute. - */ -UMLObject* UMLEntityAttribute::clone() const -{ - UMLEntityAttribute* clone = new UMLEntityAttribute((UMLEntityAttribute*)parent()); - copyInto(clone); - - return clone; -} - -/** - * Creates the XMI element. - */ -void UMLEntityAttribute::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) -{ - QDomElement entityattributeElement = UMLObject::save(QLatin1String("UML:EntityAttribute"), qDoc); - if (m_pSecondary == NULL) { - uDebug() << name() << ": m_pSecondary is NULL, using local name " << m_SecondaryId; - entityattributeElement.setAttribute(QLatin1String("type"), m_SecondaryId); - } else { - entityattributeElement.setAttribute(QLatin1String("type"), Uml::ID::toString(m_pSecondary->id())); - } - entityattributeElement.setAttribute(QLatin1String("initialValue"), m_InitialValue); - entityattributeElement.setAttribute(QLatin1String("dbindex_type"), m_indexType); - entityattributeElement.setAttribute(QLatin1String("values"), m_values); - entityattributeElement.setAttribute(QLatin1String("attributes"), m_attributes); - entityattributeElement.setAttribute(QLatin1String("auto_increment"), m_autoIncrement); - entityattributeElement.setAttribute(QLatin1String("allow_null"), m_null); - qElement.appendChild(entityattributeElement); -} - -/** - * Loads the XMI element. - */ -bool UMLEntityAttribute::load(QDomElement & element) -{ - if (! UMLAttribute::load(element)) - return false; - int indexType = element.attribute(QLatin1String("dbindex_type"), QLatin1String("1100")).toInt(); - m_indexType = (UMLEntityAttribute::DBIndex_Type)indexType; - m_values = element.attribute(QLatin1String("values")); - m_attributes = element.attribute(QLatin1String("attributes")); - m_autoIncrement = (bool)element.attribute(QLatin1String("auto_increment")).toInt(); - m_null = (bool)element.attribute(QLatin1String("allow_null")).toInt(); - return true; -} - -/** - * Display the properties configuration dialog for the entityattribute. - */ -bool UMLEntityAttribute::showPropertiesDialog(QWidget* parent) -{ - UMLEntityAttributeDialog dialog(parent, this); - return dialog.exec(); -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/entityattribute.h umbrello-kf6-15.08.1/umbrello/entityattribute.h --- umbrello-kf6-15.08.1.orig/umbrello/entityattribute.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/entityattribute.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,85 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef ENTITYATTRIBUTE_H -#define ENTITYATTRIBUTE_H - -#include "attribute.h" -#include "basictypes.h" - -/** - * This class is used to set up information for an entityattribute. This is a database field - * It has a type, name, index type and default value. - * - * @short Sets up entityattribute information. - * @author Jonathan Riddell - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class UMLEntityAttribute : public UMLAttribute -{ - Q_OBJECT - Q_ENUMS(DBIndex_Type) -public: - enum DBIndex_Type - { - None = 1100, - Primary, - Index, - Unique - }; - - UMLEntityAttribute(UMLObject* parent, const QString& name, - Uml::ID::Type id = Uml::ID::None, - Uml::Visibility::Enum s = Uml::Visibility::Private, - UMLObject *type = 0, const QString& iv = QString()); - explicit UMLEntityAttribute(UMLObject* parent); - virtual ~UMLEntityAttribute(); - - bool operator==(const UMLEntityAttribute& rhs) const; - - virtual void copyInto(UMLObject *lhs) const; - - virtual UMLObject* clone() const; - - void setAttributes(const QString& attributes); - QString getAttributes() const; - - void setIndexType(const DBIndex_Type indexType); - DBIndex_Type indexType() const; - - void setValues(const QString& values); - QString getValues() const; - - void setAutoIncrement(const bool autoIncrement); - bool getAutoIncrement() const; - - void setNull(const bool null); - bool getNull() const; - - QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); - - virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); - - virtual bool showPropertiesDialog(QWidget* parent = 0); - -protected: - void init(); - - bool load(QDomElement& element); - -private: - DBIndex_Type m_indexType; - QString m_values; - QString m_attributes; - bool m_autoIncrement; - bool m_null; -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/entityconstraint.cpp umbrello-kf6-15.08.1/umbrello/entityconstraint.cpp --- umbrello-kf6-15.08.1.orig/umbrello/entityconstraint.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/entityconstraint.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,76 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -//own header -#include "entityconstraint.h" - -// app includes -#include "umlobject.h" -#include "umldoc.h" -#include "uml.h" - -// qt includes -#include - -/** - * Sets up a constraint. - * @param parent The parent of this UMLEntityConstraint. - * @param name The name of this UMLEntityConstraint. - * @param id The unique id given to this UMLEntityConstraint. - */ -UMLEntityConstraint::UMLEntityConstraint(UMLObject *parent, - const QString& name, Uml::ID::Type id) - : UMLClassifierListItem(parent, name, id) -{ - m_BaseType = UMLObject::ot_EntityConstraint; -} - -/** - * Sets up a constraint. - * @param parent The parent of this UMLEntityConstraint. - */ -UMLEntityConstraint::UMLEntityConstraint(UMLObject *parent) - : UMLClassifierListItem(parent) -{ - m_BaseType = UMLObject::ot_EntityConstraint; -} - -/** - * Overloaded '==' operator - */ -bool UMLEntityConstraint::operator==(const UMLEntityConstraint &rhs) const -{ - if(this == &rhs) - return true; - - if(!UMLObject::operator==(rhs)) - return false; - - return true; -} - -/** - * destructor. - */ -UMLEntityConstraint::~UMLEntityConstraint() -{ -} - -/** - * Copy the internal presentation of this object into the UMLEntityConstraint - * object. - */ -void UMLEntityConstraint::copyInto(UMLObject *lhs) const -{ - // call the parent first. - UMLClassifierListItem::copyInto(lhs); -} - - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/entityconstraint.h umbrello-kf6-15.08.1/umbrello/entityconstraint.h --- umbrello-kf6-15.08.1.orig/umbrello/entityconstraint.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/entityconstraint.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,49 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef ENTITYCONSTRAINT_H -#define ENTITYCONSTRAINT_H - -#include "basictypes.h" -#include "classifierlistitem.h" -#include "umlclassifierlist.h" - -/** - * This class is used to set up information for a entity constraint. - * - * @short Sets up entity constraint information. - * @author Sharan Rao - * @see UMLObject UMLClassifierListItem - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class UMLEntityConstraint : public UMLClassifierListItem -{ - Q_OBJECT - -public: - UMLEntityConstraint(UMLObject *parent, const QString& name, - Uml::ID::Type id = Uml::ID::None); - - explicit UMLEntityConstraint(UMLObject *parent); - - bool operator==(const UMLEntityConstraint &rhs) const; - - virtual ~UMLEntityConstraint(); - - virtual void copyInto(UMLObject *lhs) const; - - /** - * Make a clone of the UMLEntityConstraint. - */ - virtual UMLObject* clone() const = 0; - -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/entity.cpp umbrello-kf6-15.08.1/umbrello/entity.cpp --- umbrello-kf6-15.08.1.orig/umbrello/entity.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/entity.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,719 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "entity.h" - -// app includes -#include "debug_utils.h" -#include "entityattribute.h" -#include "uniqueconstraint.h" -#include "foreignkeyconstraint.h" -#include "checkconstraint.h" -#include "umldoc.h" -#include "uml.h" -#include "uniqueid.h" -#include "umlentityattributelist.h" -#include "umlentityconstraintlist.h" -#include "idchangelog.h" -#include "umlentityattributedialog.h" -#include "umluniqueconstraintdialog.h" -#include "umlforeignkeyconstraintdialog.h" -#include "umlcheckconstraintdialog.h" - -// kde includes -#include -#include - -// qt includes -#include - -/** - * Constructor. - */ -UMLEntity::UMLEntity(const QString& name, Uml::ID::Type id) - : UMLClassifier(name, id), - m_PrimaryKey(0) -{ - m_BaseType = UMLObject::ot_Entity; - connect(this, SIGNAL(entityAttributeRemoved(UMLClassifierListItem*)), - this, SLOT(slotEntityAttributeRemoved(UMLClassifierListItem*))); -} - -/** - * Standard destructor. - */ -UMLEntity::~UMLEntity() -{ - m_List.clear(); -} - -/** - * Overloaded '==' operator. - */ -bool UMLEntity::operator==(const UMLEntity& rhs) const -{ - return UMLClassifier::operator==(rhs); -} - -/** - * Copy the internal presentation of this object into the new - * object. - */ -void UMLEntity::copyInto(UMLObject *lhs) const -{ - UMLEntity *target = static_cast(lhs); - - // call base class copy function - UMLClassifier::copyInto(target); - - // copy local data items - target->m_PrimaryKey = m_PrimaryKey; -} - -/** - * Make a clone of this object. - */ -UMLObject* UMLEntity::clone() const -{ - UMLEntity* clone = new UMLEntity(); - copyInto(clone); - - return clone; -} - -/** - * Create an UMLAttribute. - * @param name an optional name for the attribute - * @param type an optional type object for the attribute - * @param vis the visibility of the attribute - * @param iv the initial value for the attribute - * @return the just created attribute or null - */ -UMLAttribute* UMLEntity::createAttribute(const QString &name /*= QString()*/, UMLObject *type /*= 0*/, - Uml::Visibility::Enum vis /* = Uml::Visibility::Private*/, - const QString& iv /* = QString()*/) -{ - Uml::ID::Type id = UniqueID::gen(); - QString currentName; - if (name.isNull()) { - currentName = uniqChildName(UMLObject::ot_EntityAttribute); - } else { - currentName = name; - } - - UMLEntityAttribute* newAttribute = new UMLEntityAttribute(this, currentName, id, vis, type, iv); - - int button = QDialog::Accepted; - bool goodName = false; - - //check for name.isNull() stops dialog being shown - //when creating attribute via list view - while (button == QDialog::Accepted && !goodName && name.isNull()) { - QPointer dialog = new UMLEntityAttributeDialog(0, newAttribute); - button = dialog->exec(); - QString name = newAttribute->name(); - - if (name.length() == 0) { - KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); - } else if (findChildObject(name) != NULL) { - KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name")); - } else { - goodName = true; - } - delete dialog; - } - - if (button != QDialog::Accepted) { - delete newAttribute; - return 0; - } - - addEntityAttribute(newAttribute); - - UMLDoc *umldoc = UMLApp::app()->document(); - umldoc->signalUMLObjectCreated(newAttribute); - return newAttribute; -} - -/** - * Creates a Unique Constraint for this Entity. - * @param name an optional name - * @return the UniqueConstraint created - */ -UMLUniqueConstraint* UMLEntity::createUniqueConstraint(const QString &name) -{ - Uml::ID::Type id = UniqueID::gen(); - QString currentName; - if (name.isNull()) { - - /** - * @todo check parameter - */ - currentName = uniqChildName(UMLObject::ot_UniqueConstraint); - } else { - currentName = name; - } - - UMLUniqueConstraint* newUniqueConstraint = new UMLUniqueConstraint(this, currentName, id); - - int button = QDialog::Accepted; - bool goodName = false; - - //check for name.isNull() stops dialog being shown - //when creating attribute via list view - while (button == QDialog::Accepted && !goodName && name.isNull()) { - QPointer dialog = new UMLUniqueConstraintDialog(0, newUniqueConstraint); - button = dialog->exec(); - QString name = newUniqueConstraint->name(); - - if (name.length() == 0) { - KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); - } else if (findChildObject(name) != NULL) { - KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name")); - } else { - goodName = true; - } - delete dialog; - } - - if (button != QDialog::Accepted) { - delete newUniqueConstraint; - return NULL; - } - - addConstraint(newUniqueConstraint); - - UMLDoc *umldoc = UMLApp::app()->document(); - umldoc->signalUMLObjectCreated(newUniqueConstraint); - emitModified(); - return newUniqueConstraint; -} - -/** - * Creates a Foreign Key Constraint for this Entity. - * @param name an optional name - * @return the ForeignKeyConstraint created - */ -UMLForeignKeyConstraint* UMLEntity::createForeignKeyConstraint(const QString &name) -{ - Uml::ID::Type id = UniqueID::gen(); - QString currentName; - if (name.isNull()) { - currentName = uniqChildName(UMLObject::ot_ForeignKeyConstraint); - } else { - currentName = name; - } - - UMLForeignKeyConstraint* newForeignKeyConstraint = new UMLForeignKeyConstraint(this, currentName, id); - - int button = QDialog::Accepted; - bool goodName = false; - - //check for name.isNull() stops dialog being shown - //when creating attribute via list view - while (button == QDialog::Accepted && !goodName && name.isNull()) { - QPointer dialog = new UMLForeignKeyConstraintDialog(0, newForeignKeyConstraint); - button = dialog->exec(); - QString name = newForeignKeyConstraint->name(); - - if (name.length() == 0) { - KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); - } else if (findChildObject(name) != NULL) { - KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name")); - } else { - goodName = true; - } - delete dialog; - } - - if (button != QDialog::Accepted) { - return NULL; - } - - addConstraint(newForeignKeyConstraint); - - UMLDoc *umldoc = UMLApp::app()->document(); - umldoc->signalUMLObjectCreated(newForeignKeyConstraint); - emitModified(); - return newForeignKeyConstraint; -} - -/** - * Creates a Check Constraint for this Entity. - * @param name an optional name - * @return the CheckConstraint created - */ -UMLCheckConstraint* UMLEntity::createCheckConstraint(const QString &name) -{ - Uml::ID::Type id = UniqueID::gen(); - QString currentName; - if (name.isNull()) { - currentName = uniqChildName(UMLObject::ot_CheckConstraint); - } else { - currentName = name; - } - - UMLCheckConstraint* newCheckConstraint = new UMLCheckConstraint(this, currentName, id); - - int button = QDialog::Accepted; - bool goodName = false; - - //check for name.isNull() stops dialog being shown - //when creating attribute via list view - while (button == QDialog::Accepted && !goodName && name.isNull()) { - QPointer dialog = new UMLCheckConstraintDialog(0, newCheckConstraint); - button = dialog->exec(); - QString name = newCheckConstraint->name(); - - if (name.length() == 0) { - KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); - } else if (findChildObject(name) != NULL) { - KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name")); - } else { - goodName = true; - } - delete dialog; - } - - if (button != QDialog::Accepted) { - return NULL; - } - - addConstraint(newCheckConstraint); - - UMLDoc *umldoc = UMLApp::app()->document(); - umldoc->signalUMLObjectCreated(newCheckConstraint); - emitModified(); - return newCheckConstraint; -} - -/** - * Adds an entityAttribute. - * The entityAttribute object must not belong to any other concept. - * @param name name of the UMLEntityAttribute - * @param id id of the UMLEntityAttribute - * @return True if the entityAttribute was successfully added. - */ -UMLObject* UMLEntity::addEntityAttribute(const QString& name, Uml::ID::Type id) -{ - UMLEntityAttribute* literal = new UMLEntityAttribute(this, name, id); - m_List.append(literal); - emit entityAttributeAdded(literal); - UMLObject::emitModified(); - connect(literal, SIGNAL(modified()), this, SIGNAL(modified())); - return literal; -} - -/** - * Adds an already created entityAttribute. - * The entityAttribute object must not belong to any other concept. - * @param att Pointer to the UMLEntityAttribute. - * @param log Pointer to the IDChangeLog. - * @return True if the entityAttribute was successfully added. - */ -bool UMLEntity::addEntityAttribute(UMLEntityAttribute* att, IDChangeLog* log /* = 0*/) -{ - QString name = (QString)att->name(); - if (findChildObject(name) == NULL) { - att->setParent(this); - m_List.append(att); - emit entityAttributeAdded(att); - UMLObject::emitModified(); - connect(att, SIGNAL(modified()), this, SIGNAL(modified())); - return true; - } else if (log) { - log->removeChangeByNewID(att->id()); - delete att; - } - return false; -} - -/** - * Adds an entityAttribute to the entity, at the given position. - * If position is negative or too large, the entityAttribute is added - * to the end of the list. - * TODO: give default value -1 to position (append) - now it conflicts with the method above.. - * @param att Pointer to the UMLEntityAttribute. - * @param position Position index for the insertion. - * @return True if the entityAttribute was successfully added. - */ -bool UMLEntity::addEntityAttribute(UMLEntityAttribute* att, int position) -{ - Q_ASSERT(att); - QString name = (QString)att->name(); - if (findChildObject(name) == NULL) { - att->setParent(this); - if (position >= 0 && position <= (int)m_List.count()) { - m_List.insert(position, att); - } else { - m_List.append(att); - } - emit entityAttributeAdded(att); - UMLObject::emitModified(); - connect(att, SIGNAL(modified()), this, SIGNAL(modified())); - return true; - } - return false; -} - -/** - * Removes an entityAttribute from the class. - * @param att The entityAttribute to remove. - * @return Count of the remaining entityAttributes after removal. - * Returns -1 if the given entityAttribute was not found. - */ -int UMLEntity::removeEntityAttribute(UMLClassifierListItem* att) -{ - if (!m_List.removeAll((UMLEntityAttribute*)att)) { - uDebug() << "cannot find att given in list"; - return -1; - } - emit entityAttributeRemoved(att); - UMLObject::emitModified(); - // If we are deleting the object, then we don't need to disconnect..this is done auto-magically - // for us by QObject. -b.t. - // disconnect(att, SIGNAL(modified()), this, SIGNAL(modified())); - delete att; - return m_List.count(); -} - -/** - * Returns the number of entityAttributes for the class. - * @return The number of entityAttributes for the class. - */ -int UMLEntity::entityAttributes() -{ - UMLClassifierListItemList entityAttributes = getFilteredList(UMLObject::ot_EntityAttribute); - return entityAttributes.count(); -} - -/** - * Emit the entityAttributeRemoved signal. - */ -void UMLEntity::signalEntityAttributeRemoved(UMLClassifierListItem *eattr) -{ - emit entityAttributeRemoved(eattr); -} - -/** - * Resolve the types referenced by our UMLEntityAttributes. - * Reimplements the method from UMLClassifier. - */ -bool UMLEntity::resolveRef() -{ - bool success = UMLClassifier::resolveRef(); - for (UMLObjectListIt oit(m_List); oit.hasNext();) { - UMLObject* obj = oit.next(); - if (obj->resolveRef()) { - UMLClassifierListItem *cli = static_cast(obj); - switch (cli->baseType()) { - case UMLObject::ot_EntityAttribute: - emit entityAttributeAdded(cli); - break; - case UMLObject::ot_UniqueConstraint: - case UMLObject::ot_ForeignKeyConstraint: - emit entityConstraintAdded(cli); - break; - default: - break; - } - } - } - return success; -} - -/** - * Creates the element including its entityliterals. - */ -void UMLEntity::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) -{ - QDomElement entityElement = UMLObject::save(QLatin1String("UML:Entity"), qDoc); - //save operations - UMLClassifierListItemList entityAttributes = getFilteredList(UMLObject::ot_EntityAttribute); - UMLClassifierListItem* pEntityAttribute = 0; - foreach (pEntityAttribute, entityAttributes) { - pEntityAttribute->saveToXMI(qDoc, entityElement); - } - - UMLClassifierListItemList entityConstraints = getFilteredList(UMLObject::ot_EntityConstraint); - foreach(UMLClassifierListItem* cli, entityConstraints) { - cli->saveToXMI(qDoc, entityElement); - } - - qElement.appendChild(entityElement); -} - -/** - * Loads the element including its entityAttributes. - */ -bool UMLEntity::load(QDomElement& element) -{ - QDomNode node = element.firstChild(); - while(!node.isNull()) { - if (node.isComment()) { - node = node.nextSibling(); - continue; - } - QDomElement tempElement = node.toElement(); - QString tag = tempElement.tagName(); - if (UMLDoc::tagEq(tag, QLatin1String("EntityAttribute"))) { // for backward compatibility - UMLEntityAttribute* pEntityAttribute = new UMLEntityAttribute(this); - if(!pEntityAttribute->loadFromXMI(tempElement)) { - return false; - } - m_List.append(pEntityAttribute); - } else if (UMLDoc::tagEq(tag, QLatin1String("UniqueConstraint"))) { - UMLUniqueConstraint* pUniqueConstraint = new UMLUniqueConstraint(this); - if (!pUniqueConstraint->loadFromXMI(tempElement)) { - return false; - } - addConstraint(pUniqueConstraint); - } else if (UMLDoc::tagEq(tag, QLatin1String("ForeignKeyConstraint"))) { - UMLForeignKeyConstraint* pForeignKeyConstraint = new UMLForeignKeyConstraint(this); - if (!pForeignKeyConstraint->loadFromXMI(tempElement)) { - return false; - } - - addConstraint(pForeignKeyConstraint); - } else if (UMLDoc::tagEq(tag, QLatin1String("CheckConstraint"))) { - - UMLCheckConstraint* pCheckConstraint = new UMLCheckConstraint(this); - if (!pCheckConstraint->loadFromXMI(tempElement)) { - return false; - } - - addConstraint(pCheckConstraint); - } else if (tag == QLatin1String("stereotype")) { - uDebug() << name() << ": losing old-format stereotype."; - } else { - uWarning() << "unknown child type in UMLEntity::load"; - } - node = node.nextSibling(); - }//end while - return true; -} - -/** - * Sets the UniqueConstraint passed as the Primary Key of this Entity - * If the UniqueConstraint exists, then it is made a primary key - * Else the UniqueConstraint is added and set as PrimaryKey - * @param uconstr The Unique Constraint that is to be set as Primary Key - * @return true if Primary key could be set successfully - */ -bool UMLEntity::setAsPrimaryKey(UMLUniqueConstraint* uconstr) -{ - if (uconstr == NULL) { - uDebug() << "NULL value passed. To unset a Primary Key use " - << "unsetPrimaryKey()"; - return false; - } - - if (static_cast(uconstr->parent()) != this) { - - uDebug() << "Parent of " << uconstr->name() - << " does not match with current entity"; - return false; - } - - // check if this constraint already exists as a unique constraint for this entity - UMLUniqueConstraint* uuc = static_cast(findChildObjectById(uconstr->id())); - if (uuc == NULL) { - addConstraint(uconstr); - uuc = uconstr; - } - - UMLUniqueConstraint* oldPrimaryKey = m_PrimaryKey; - - m_PrimaryKey = uuc; - - if (oldPrimaryKey != NULL) - oldPrimaryKey->emitModified(); - - uuc->emitModified(); - emitModified(); - return true; -} - -/** - * Unset a Primary Key Constraint if it exists, else does nothing - * This function will make the primary key into just another UniqueConstraint - * if it exists - */ -void UMLEntity::unsetPrimaryKey() -{ - m_PrimaryKey = 0; -} - -/** - * Checks if This UMLEntity has a primary key set. - * @return true if a Primary Key Exists for this UMLEntity - */ -bool UMLEntity::hasPrimaryKey() const -{ - if (m_PrimaryKey) { - return true; - } - - return false; -} - -/** - * Adds a Constraint to this UMLEntity. - * To set a UMLUniqueConstraint as Primary Key use setAsPrimaryKey. - * @param constr The UMLEntityConstraint that is to be added - * @return true if the constraint could be added successfully - */ -bool UMLEntity::addConstraint(UMLEntityConstraint* constr) -{ - if (findChildObjectById(constr->id()) != NULL) { - uDebug() << "Constraint with id " << Uml::ID::toString(constr->id()) - << " already exists "; - return false; - } - - m_List.append(constr); - - emit entityConstraintAdded(constr); - UMLObject::emitModified(); - connect(constr, SIGNAL(modified()), this, SIGNAL(modified())); - - return true; -} - -/** - * Removes an existing constraint from this UMLEntity. - * If the Contraint is a Primary Key, this Entity will no longer have a PrimaryKey. - * @param constr the constraint to be removed - * @return true if the constraint could be removed successfully - */ -bool UMLEntity::removeConstraint(UMLEntityConstraint* constr) -{ - if (findChildObjectById(constr->id()) == NULL) { - uDebug() << "Constraint with id " << Uml::ID::toString(constr->id()) - << " does not exist "; - return false; - } - - if (m_PrimaryKey == constr) { - unsetPrimaryKey(); - } - - m_List.removeAll(constr); - - emit entityConstraintRemoved(constr); - UMLObject::emitModified(); - - delete constr; - return true; -} - -/** - * Slot for entity attribute removed. - */ -void UMLEntity::slotEntityAttributeRemoved(UMLClassifierListItem* cli) -{ - // this function does some cleanjobs related to this entity when the attribute is - // removed, like, removing the attribute from all constraints - - UMLEntityAttribute* entAtt = static_cast(cli); - if (cli) { - UMLClassifierListItemList ual = this->getFilteredList(UMLObject::ot_UniqueConstraint); - - foreach(UMLClassifierListItem* ucli, ual) { - UMLUniqueConstraint* uuc = static_cast(ucli); - if (uuc->hasEntityAttribute(entAtt)) { - uuc->removeEntityAttribute(entAtt); - } - } - } - -} - -/** - * Reimplementation of getFilteredList to support ot=UMLObject::ot_EntityConstraint. - */ -UMLClassifierListItemList UMLEntity::getFilteredList(UMLObject::ObjectType ot) const -{ - if (ot == UMLObject::ot_EntityConstraint) { - UMLClassifierListItemList ucList, fcList, ccList, rcList; - ucList = UMLClassifier::getFilteredList(UMLObject::ot_UniqueConstraint); - fcList = UMLClassifier::getFilteredList(UMLObject::ot_ForeignKeyConstraint); - ccList = UMLClassifier::getFilteredList(UMLObject::ot_CheckConstraint); - - // append the lists to rcList - // first the Unique Constraints - foreach(UMLClassifierListItem* ucli, ucList) { - rcList.append(ucli); - } - - // then the Foreign Key Constraints - foreach(UMLClassifierListItem* ucli, fcList) { - rcList.append(ucli); - } - - foreach(UMLClassifierListItem* ucli, ccList) { - rcList.append(ucli); - } - - return rcList; - } else { - return UMLClassifier::getFilteredList(ot); - } -} - -/** - * Checks if a given Unique Constraint is primary key of this entity - * @param uConstr a Unique Constraint - * @return bool true if passed parameter is a primary key of this entity - */ -bool UMLEntity::isPrimaryKey(UMLUniqueConstraint* uConstr) const -{ - if (uConstr == m_PrimaryKey) { - return true; - } - - return false; -} - -/** - * Returns the Entity Attributes. - * Same as getFilteredList(UMLObject::ot_EntityAttribute). - */ -UMLEntityAttributeList UMLEntity::getEntityAttributes() const -{ - UMLEntityAttributeList entityAttributeList; - for (UMLObjectListIt lit(m_List); lit.hasNext();) { - UMLObject *listItem = lit.next(); - if (listItem->baseType() == UMLObject::ot_EntityAttribute) { - entityAttributeList.append(static_cast(listItem)); - } - } - return entityAttributeList; -} - - -/** - * Create a new ClassifierListObject (entityattribute) - * according to the given XMI tag. - * Returns NULL if the string given does not contain one of the tags - * - * Used by the clipboard for paste operation. - * Reimplemented from UMLClassifier for UMLEntity - */ -UMLClassifierListItem* UMLEntity::makeChildObject(const QString& xmiTag) -{ - UMLClassifierListItem* pObject = NULL; - if (UMLDoc::tagEq(xmiTag, QLatin1String("EntityAttribute"))) { - pObject = new UMLEntityAttribute(this); - } - return pObject; -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/entity.h umbrello-kf6-15.08.1/umbrello/entity.h --- umbrello-kf6-15.08.1.orig/umbrello/entity.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/entity.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,108 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef ENTITY_H -#define ENTITY_H - -#include "classifier.h" - -// forward declarations -class UMLEntityAttribute; -class UMLEntityConstraint; -class UMLUniqueConstraint; -class UMLForeignKeyConstraint; -class UMLCheckConstraint; -class UMLEntityAttributeList; - -/** - * This class contains the non-graphical information required for a UML - * Entity. - * This class inherits from @ref UMLClassifier which contains most of the - * information. - * - * @short Non-graphical Information for an Entity. - * @author Jonathan Riddell - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class UMLEntity : public UMLClassifier -{ - Q_OBJECT -public: - explicit UMLEntity(const QString& name = QString(), Uml::ID::Type id = Uml::ID::None); - virtual ~UMLEntity(); - - bool operator==(const UMLEntity& rhs) const; - - virtual void copyInto(UMLObject *lhs) const; - - virtual UMLObject* clone() const; - - virtual UMLAttribute* createAttribute(const QString &name = QString(), - UMLObject *type = 0, Uml::Visibility::Enum vis = Uml::Visibility::Private, - const QString &init = QString()); - - UMLUniqueConstraint* createUniqueConstraint(const QString &name = QString()); - UMLForeignKeyConstraint* createForeignKeyConstraint(const QString &name = QString()); - UMLCheckConstraint* createCheckConstraint(const QString &name = QString()); - - UMLObject* addEntityAttribute(const QString &name, Uml::ID::Type id = Uml::ID::None); - bool addEntityAttribute(UMLEntityAttribute* att, IDChangeLog* log = 0); - bool addEntityAttribute(UMLEntityAttribute* att, int position); - - int removeEntityAttribute(UMLClassifierListItem* att); - - void signalEntityAttributeRemoved(UMLClassifierListItem *eattr); - - int entityAttributes() ; - - bool setAsPrimaryKey(UMLUniqueConstraint* uconstr); - void unsetPrimaryKey(); - bool hasPrimaryKey() const; - bool isPrimaryKey(UMLUniqueConstraint* uConstr) const; - - bool addConstraint(UMLEntityConstraint* constr); - bool removeConstraint(UMLEntityConstraint* constr); - - virtual bool resolveRef(); - - virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); - - UMLClassifierListItemList getFilteredList(UMLObject::ObjectType ot) const; - - UMLEntityAttributeList getEntityAttributes() const; - - virtual UMLClassifierListItem* makeChildObject(const QString& xmiTag); - -private slots: - void slotEntityAttributeRemoved(UMLClassifierListItem*); - -signals: - void entityAttributeAdded(UMLClassifierListItem*); - void entityAttributeRemoved(UMLClassifierListItem*); - void entityConstraintAdded(UMLClassifierListItem*); - void entityConstraintRemoved(UMLClassifierListItem*); - -protected: - bool load(QDomElement& element); - -private: - - /** - * Primary Key of this Entity - * This is a pointer kept for easy access to the primary key, and to distinguish it - * from all other UniqueConstraints. It is also there in m_List (inherited from - * UMLCanvasObject) - */ - UMLUniqueConstraint* m_PrimaryKey; - -}; - -#endif // ENTITY_H - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/enum.cpp umbrello-kf6-15.08.1/umbrello/enum.cpp --- umbrello-kf6-15.08.1.orig/umbrello/enum.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/enum.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,302 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "enum.h" - -// app includes -#include "debug_utils.h" -#include "enumliteral.h" -#include "umldoc.h" -#include "uml.h" -#include "uniqueid.h" -#include "idchangelog.h" - -// kde includes -#include -#include - -/** - * Sets up an enum. - * @param name The name of the Enum. - * @param id The unique id of the Enum. - */ -UMLEnum::UMLEnum(const QString& name, Uml::ID::Type id) : UMLClassifier(name, id) -{ - init(); -} - -/** - * Standard destructor. - */ -UMLEnum::~UMLEnum() -{ - m_List.clear(); -} - -/** - * Overloaded '==' operator. - */ -bool UMLEnum::operator==(const UMLEnum & rhs) const -{ - return UMLClassifier::operator==(rhs); -} - -/** - * Copy the internal presentation of this object into the new - * object. - */ -void UMLEnum::copyInto(UMLObject *lhs) const -{ - UMLClassifier::copyInto(lhs); -} - -/** - * Make a clone of this object. - */ -UMLObject* UMLEnum::clone() const -{ - UMLEnum *clone = new UMLEnum(); - copyInto(clone); - - return clone; -} - -/** - * Initializes key variables of the class. - */ -void UMLEnum::init() -{ - m_BaseType = UMLObject::ot_Enum; - setStereotypeCmd(QLatin1String("enum")); -} - -/** - * Creates a literal for the enum. - * @return The UMLEnum created - */ -UMLObject* UMLEnum::createEnumLiteral(const QString& name) -{ - Uml::ID::Type id = UniqueID::gen(); - QString currentName; - if (name.isNull()) { - currentName = uniqChildName(UMLObject::ot_EnumLiteral); - } else { - currentName = name; - } - - UMLEnumLiteral* newEnumLiteral = new UMLEnumLiteral(this, currentName); - - bool ok = true; - bool goodName = false; - - //check for name.isNull() stops dialog being shown - //when creating enum literal via list view - while (ok && !goodName && name.isNull()) { - ok = newEnumLiteral->showPropertiesDialog(UMLApp::app()); - QString name = newEnumLiteral->name(); - - if(name.length() == 0) { - KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); - } else { - goodName = true; - } - } - - if (!ok) { - delete newEnumLiteral; - return NULL; - } - - addEnumLiteral(newEnumLiteral); - - UMLDoc *umldoc = UMLApp::app()->document(); - umldoc->signalUMLObjectCreated(newEnumLiteral); - return newEnumLiteral; -} - -/** - * Adds an enumliteral to the enum. - * @param name The name of the enumliteral. - * @param id The id of the enumliteral (optional.) - * If omitted a new ID is assigned internally. - * @return Pointer to the UMLEnumliteral created. - */ -UMLObject* UMLEnum::addEnumLiteral(const QString &name, Uml::ID::Type id) -{ - UMLObject *el = UMLCanvasObject::findChildObject(name); - if (el != NULL) { - uDebug() << name << " is already present"; - return el; - } - UMLEnumLiteral* literal = new UMLEnumLiteral(this, name, id); - m_List.append(literal); - UMLObject::emitModified(); - emit enumLiteralAdded(literal); - connect(literal, SIGNAL(modified()), this, SIGNAL(modified())); - return literal; -} - -/** - * Adds an already created enumliteral. - * The enumliteral object must not belong to any other concept. - * @param literal Pointer to the UMLEnumLiteral. - * @param Log Pointer to the IDChangeLog. - * @return True if the enumliteral was successfully added. - */ -bool UMLEnum::addEnumLiteral(UMLEnumLiteral* literal, IDChangeLog* Log /* = 0*/) -{ - QString name = (QString)literal->name(); - if (findChildObject(name) == NULL) { - literal->setParent(this); - m_List.append(literal); - UMLObject::emitModified(); - emit enumLiteralAdded(literal); - connect(literal, SIGNAL(modified()), this, SIGNAL(modified())); - return true; - } else if (Log) { - Log->removeChangeByNewID(literal->id()); - delete literal; - } - return false; -} - -/** - * Adds an enumliteral to the enum, at the given position. - * If position is negative or too large, the enumliteral is added - * to the end of the list. - * TODO: give default value -1 to position (append) - now it conflicts with the method above.. - * @param literal Pointer to the UMLEnumLiteral. - * @param position Position index for the insertion. - * @return True if the enumliteral was successfully added. - */ -bool UMLEnum::addEnumLiteral(UMLEnumLiteral* literal, int position) -{ - Q_ASSERT(literal); - QString name = (QString)literal->name(); - if (findChildObject(name) == NULL) { - literal->setParent(this); - if (position >= 0 && position <= (int)m_List.count()) { - m_List.insert(position, literal); - } else { - m_List.append(literal); - } - UMLObject::emitModified(); - emit enumLiteralAdded(literal); - connect(literal, SIGNAL(modified()), this, SIGNAL(modified())); - return true; - } - return false; -} - -/** - * Removes an enumliteral from the class. - * @param literal The enumliteral to remove. - * @return Count of the remaining enumliterals after removal. - * Returns -1 if the given enumliteral was not found. - */ -int UMLEnum::removeEnumLiteral(UMLEnumLiteral* literal) -{ - if (!m_List.removeAll(literal)) { - uDebug() << "cannot find att given in list"; - return -1; - } - emit enumLiteralRemoved(literal); - UMLObject::emitModified(); - // If we are deleting the object, then we don't need to disconnect..this is done auto-magically - // for us by QObject. -b.t. - // disconnect(a, SIGNAL(modified()), this, SIGNAL(modified())); - delete literal; - return m_List.count(); -} - -/** - * Returns the number of enumliterals for the class. - * @return The number of enumliterals for the class. - */ -int UMLEnum::enumLiterals() -{ - return m_List.count(); -} - -/** - * Emit the enumLiteralRemoved signal. - */ -void UMLEnum::signalEnumLiteralRemoved(UMLClassifierListItem *elit) -{ - emit enumLiteralRemoved(elit); -} - -/** - * Creates the element including its enumliterals. - */ -void UMLEnum::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) -{ - QDomElement enumElement = UMLObject::save(QLatin1String("UML:Enumeration"), qDoc); - // save enum literals - UMLClassifierListItemList enumLiterals = getFilteredList(UMLObject::ot_EnumLiteral); - foreach (UMLClassifierListItem* pEnumLiteral, enumLiterals) { - pEnumLiteral->saveToXMI(qDoc, enumElement); - } - qElement.appendChild(enumElement); -} - -/** - * Loads the element including its enumliterals. - */ -bool UMLEnum::load(QDomElement& element) -{ - QDomNode node = element.firstChild(); - while(!node.isNull()) { - if (node.isComment()) { - node = node.nextSibling(); - continue; - } - QDomElement tempElement = node.toElement(); - QString tag = tempElement.tagName(); - if (UMLDoc::tagEq(tag, QLatin1String("EnumerationLiteral")) || - UMLDoc::tagEq(tag, QLatin1String("ownedLiteral")) || - UMLDoc::tagEq(tag, QLatin1String("EnumLiteral"))) { // for backward compatibility - UMLEnumLiteral* pEnumLiteral = new UMLEnumLiteral(this); - if(!pEnumLiteral->loadFromXMI(tempElement)) { - return false; - } - m_List.append(pEnumLiteral); - } else if (UMLDoc::tagEq(tag, QLatin1String("Enumeration.literal"))) { // Embarcadero's Describe - if (! load(tempElement)) - return false; - } else if (tag == QLatin1String("stereotype")) { - uDebug() << name() << ": losing old-format stereotype."; - } else { - uWarning() << "unknown child type: " << tag; - } - node = node.nextSibling(); - }//end while - return true; -} - -/** - * Create a new ClassifierListObject (enumLiteral) - * according to the given XMI tag. - * Returns NULL if the string given does not contain one of the tags - * - * Used by the clipboard for paste operation. - * Reimplemented from UMLClassifier for UMLEnum - */ -UMLClassifierListItem* UMLEnum::makeChildObject(const QString& xmiTag) -{ - UMLClassifierListItem* pObject = NULL; - if (UMLDoc::tagEq(xmiTag, QLatin1String("EnumerationLiteral")) || - UMLDoc::tagEq(xmiTag, QLatin1String("EnumLiteral"))) { - pObject = new UMLEnumLiteral(this); - } - return pObject; -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/enum.h umbrello-kf6-15.08.1/umbrello/enum.h --- umbrello-kf6-15.08.1.orig/umbrello/enum.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/enum.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,72 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef ENUM_H -#define ENUM_H - -#include "classifier.h" - -class UMLEnumLiteral; - -/** - * This class contains the non-graphical information required for a UML - * Enum. - * This class inherits from @ref UMLClassifier which contains most of the - * information. - * - * @short Non-graphical Information for an Enum. - * @author Jonathan Riddell - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class UMLEnum : public UMLClassifier -{ - Q_OBJECT -public: - explicit UMLEnum(const QString& name = QString(), Uml::ID::Type id = Uml::ID::None); - - virtual ~UMLEnum(); - - bool operator==(const UMLEnum& rhs) const; - - virtual void copyInto(UMLObject *lhs) const; - - virtual UMLObject* clone() const; - - UMLObject* createEnumLiteral(const QString& name = QString()); - - UMLObject* addEnumLiteral(const QString &name, Uml::ID::Type id = Uml::ID::None); - - bool addEnumLiteral(UMLEnumLiteral* literal, IDChangeLog* Log = 0); - bool addEnumLiteral(UMLEnumLiteral* literal, int position); - - int removeEnumLiteral(UMLEnumLiteral* literal); - - int enumLiterals(); - - void signalEnumLiteralRemoved(UMLClassifierListItem *elit); - - virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); - - virtual UMLClassifierListItem* makeChildObject(const QString& xmiTag); - -signals: - void enumLiteralAdded(UMLClassifierListItem*); - void enumLiteralRemoved(UMLClassifierListItem*); - -protected: - bool load(QDomElement & element); - -private: - void init(); - -}; - -#endif // ENUM_H - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/enumliteral.cpp umbrello-kf6-15.08.1/umbrello/enumliteral.cpp --- umbrello-kf6-15.08.1.orig/umbrello/enumliteral.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/enumliteral.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,126 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#include "enumliteral.h" - -// kde includes -#if QT_VERSION < 0x050000 -#include -#endif -#include - -// qt includes -#if QT_VERSION >= 0x050000 -#include -#endif - -/** - * Sets up an enum literal. - * @param parent The parent of this UMLEnumLiteral. - * @param name The name of this UMLEnumLiteral. - * @param id The unique id given to this UMLEnumLiteral. - */ -UMLEnumLiteral::UMLEnumLiteral(UMLObject *parent, - const QString& name, Uml::ID::Type id) - : UMLClassifierListItem(parent, name, id) -{ - m_BaseType = UMLObject::ot_EnumLiteral; -} - -/** - * Sets up an enum literal. - * @param parent The parent of this UMLEnumLiteral. - */ -UMLEnumLiteral::UMLEnumLiteral(UMLObject *parent) - : UMLClassifierListItem(parent) -{ - m_BaseType = UMLObject::ot_EnumLiteral; -} - -/** - * Destructor. - */ -UMLEnumLiteral::~UMLEnumLiteral() -{ -} - -/** - * Overloaded '==' operator - */ -bool UMLEnumLiteral::operator==(const UMLEnumLiteral& rhs) const -{ - if (this == &rhs) { - return true; - } - if (!UMLObject::operator==(rhs)) { - return false; - } - return true; -} - -/** - * Copy the internal presentation of this object into the new - * object. - */ -void UMLEnumLiteral::copyInto(UMLObject *lhs) const -{ - UMLClassifierListItem::copyInto(lhs); -} - -/** - * Make a clone of this object. - */ -UMLObject* UMLEnumLiteral::clone() const -{ - UMLEnumLiteral *clone = new UMLEnumLiteral((UMLObject *) parent()); - copyInto(clone); - - return clone; -} - -/** - * Creates the XMI element. - */ -void UMLEnumLiteral::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) -{ - QDomElement attributeElement = UMLObject::save(QLatin1String("UML:EnumerationLiteral"), qDoc); - qElement.appendChild(attributeElement); -} - -/** - * Loads the XMI element (empty.) - */ -bool UMLEnumLiteral::load(QDomElement& element) -{ - Q_UNUSED(element); - return true; -} - -/** - * Display the properties configuration dialog for the enum literal. - */ -bool UMLEnumLiteral::showPropertiesDialog(QWidget* parent) -{ - bool ok; -#if QT_VERSION >= 0x050000 - QString enumName = QInputDialog::getText(parent, - i18nc("enum name", "Name"), i18n("Enter name:"), - QLineEdit::Normal, - name(), &ok); -#else - QString enumName = KInputDialog::getText(i18nc("enum name", "Name"), i18n("Enter name:"), name(), &ok, parent); -#endif - if (ok && !enumName.isEmpty()) { - setName(enumName); - return true; - } else { - return false; - } -} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/enumliteral.h umbrello-kf6-15.08.1/umbrello/enumliteral.h --- umbrello-kf6-15.08.1.orig/umbrello/enumliteral.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/enumliteral.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,49 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef ENUMLITERAL_H -#define ENUMLITERAL_H - -#include "classifierlistitem.h" - -/** - * This class is used to set up information for an enum literal. Enum - * literals are the values that enums can be set to. - * - * @short Sets up attribute information. - * @author Paul Hensgen - * @see UMLObject - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class UMLEnumLiteral : public UMLClassifierListItem -{ -public: - UMLEnumLiteral(UMLObject* parent, - const QString& name, Uml::ID::Type id = Uml::ID::None); - explicit UMLEnumLiteral(UMLObject* parent); - - bool operator==(const UMLEnumLiteral &rhs) const; - - virtual void copyInto(UMLObject *lhs) const; - - virtual UMLObject* clone() const; - - virtual ~UMLEnumLiteral(); - - virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); - - virtual bool showPropertiesDialog(QWidget* parent = 0); - -protected: - bool load(QDomElement& element); - -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/folder.cpp umbrello-kf6-15.08.1/umbrello/folder.cpp --- umbrello-kf6-15.08.1.orig/umbrello/folder.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/folder.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,558 +0,0 @@ -/*************************************************************************** - * 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) 2006-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "folder.h" - -// app includes -#include "debug_utils.h" -#include "model_utils.h" -#include "object_factory.h" -#include "optionstate.h" -#include "uml.h" -#include "umldoc.h" -#include "umlscene.h" -#include "umlview.h" - -// kde includes -#include -#include - -// qt includes -#include - -/** - * Sets up a Folder. - * @param name The name of the Folder. - * @param id The unique id of the Folder. A new ID will be generated - * if this argument is left away. - */ -UMLFolder::UMLFolder(const QString & name, Uml::ID::Type id) - : UMLPackage(name, id) -{ - m_BaseType = UMLObject::ot_Folder; - UMLObject::setStereotypeCmd(QLatin1String("folder")); -} - -/** - * Empty destructor. - */ -UMLFolder::~UMLFolder() -{ - qDeleteAll(m_diagrams); - m_diagrams.clear(); -} - -/** - * Make a clone of this object. - */ -UMLObject* UMLFolder::clone() const -{ - UMLFolder *clone = new UMLFolder(); - UMLObject::copyInto(clone); - return clone; -} - -/** - * Set the localized name of this folder. - * This is set for the predefined root views (Logical, - * UseCase, Component, Deployment, EntityRelationship, - * and the Datatypes folder inside the Logical View.) - */ -void UMLFolder::setLocalName(const QString& localName) -{ - m_localName = localName; -} - -/** - * Return the localized name of this folder. - * Only useful for the predefined root folders. - */ -QString UMLFolder::localName() const -{ - return m_localName; -} - -/** - * Add a view to the diagram list. - */ -void UMLFolder::addView(UMLView *view) -{ - m_diagrams.append(view); -} - -/** - * Remove a view from the diagram list. - */ -void UMLFolder::removeView(UMLView *view) -{ - m_diagrams.removeAll(view); - delete view; -} - -/** - * Append the views in this folder to the given diagram list. - * @param viewList The UMLViewList to which to append the diagrams. - * @param includeNested Whether to include diagrams from nested folders - * (default: true.) - */ -void UMLFolder::appendViews(UMLViewList& viewList, bool includeNested) -{ - if (includeNested) { - foreach (UMLObject* o, m_objects) { - uIgnoreZeroPointer(o); - if (o->baseType() == UMLObject::ot_Folder) { - UMLFolder *f = static_cast(o); - f->appendViews(viewList); - } - } - } - foreach (UMLView* v, m_diagrams) { - viewList.append(v); - } -} - -/** - * Acivate the views in this folder. - * "Activation": Some widgets require adjustments after loading from file, - * those are done here. - */ -void UMLFolder::activateViews() -{ - foreach (UMLObject* o, m_objects) { - uIgnoreZeroPointer(o); - if (o->baseType() == UMLObject::ot_Folder) { - UMLFolder *f = static_cast(o); - f->activateViews(); - } - } - - foreach (UMLView* v, m_diagrams) { - v->umlScene()->activateAfterLoad(); - } - // Make sure we have a treeview item for each diagram. - // It may happen that we are missing them after switching off tabbed widgets. - Settings::OptionState optionState = Settings::optionState(); - if (optionState.generalState.tabdiagrams) { - return; - } - Model_Utils::treeViewAddViews(m_diagrams); -} - -/** - * Seek a view of the given ID in this folder. - * @param id ID of the view to find. - * @return Pointer to the view if found, NULL if no view found. - */ -UMLView *UMLFolder::findView(Uml::ID::Type id) -{ - foreach (UMLView* v, m_diagrams) { - if (v->umlScene()->ID() == id) { - return v; - } - } - - UMLView* v = 0; - UMLPackageList packages; - appendPackages(packages); - foreach (UMLPackage *o, packages) { - if (o->baseType() != UMLObject::ot_Folder) { - continue; - } - UMLFolder *f = static_cast(o); - v = f->findView(id); - if (v) { - break; - } - } - return v; -} - -/** - * Seek a view by the type and name given. - * @param type The type of view to find. - * @param name The name of the view to find. - * @param searchAllScopes Search in all subfolders (default: true.) - * @return Pointer to the view found, or NULL if not found. - */ -UMLView *UMLFolder::findView(Uml::DiagramType::Enum type, const QString &name, bool searchAllScopes) -{ - foreach (UMLView* v, m_diagrams) { - if (v->umlScene()->type() == type && v->umlScene()->name() == name) { - return v; - } - } - - UMLView* v = 0; - if (searchAllScopes) { - foreach (UMLObject* o, m_objects) { - uIgnoreZeroPointer(o); - if (o->baseType() != UMLObject::ot_Folder) { - continue; - } - UMLFolder *f = static_cast(o); - v = f->findView(type, name, searchAllScopes); - if (v) { - break; - } - } - } - return v; -} - -/** - * Set the options for the views in this folder. - */ -void UMLFolder::setViewOptions(const Settings::OptionState& optionState) -{ - // for each view update settings - foreach (UMLView* v, m_diagrams) { - v->umlScene()->setOptionState(optionState); - } -} - -/** - * Remove all views in this folder. - */ -void UMLFolder::removeAllViews() -{ - foreach (UMLObject* o, m_objects) { - uIgnoreZeroPointer(o); - if (o->baseType() != UMLObject::ot_Folder) - continue; - UMLFolder *f = static_cast(o); - f->removeAllViews(); - } - - foreach (UMLView* v, m_diagrams) { - // TODO ------------------ check this code - bad: calling back to UMLDoc::removeView() - v->umlScene()->removeAllAssociations(); // note : It may not be apparent, but when we remove all associations - // from a view, it also causes any UMLAssociations that lack parent - // association widgets (but once had them) to remove themselves from - // this document. - uDebug() << "removing " << v->umlScene()->name(); - UMLApp::app()->document()->removeView(v, false); - } - - qDeleteAll(m_diagrams); - m_diagrams.clear(); -} - -/** - * Set the folder file name for a separate submodel. - */ -void UMLFolder::setFolderFile(const QString& fileName) -{ - m_folderFile = fileName; -} - -/** - * Get the folder file name for a separate submodel. - */ -QString UMLFolder::folderFile() const -{ - return m_folderFile; -} - -/** - * Auxiliary to saveToXMI(): Save the contained objects and diagrams. - * Can be used regardless of whether saving to the main model file - * or to an external folder file (see m_folderFile.) - */ -void UMLFolder::saveContents(QDomDocument& qDoc, QDomElement& qElement) -{ - QDomElement ownedElement = qDoc.createElement(QLatin1String("UML:Namespace.ownedElement")); - UMLObject *obj = 0; - // Save contained objects if any. - for (UMLObjectListIt oit(m_objects); oit.hasNext();) { - obj = oit.next(); - uIgnoreZeroPointer(obj); - obj->saveToXMI (qDoc, ownedElement); - } - // Save asscociations if any. - for (UMLObjectListIt ait(m_List); ait.hasNext();) { - obj = ait.next(); - obj->saveToXMI (qDoc, ownedElement); - } - qElement.appendChild(ownedElement); - // Save diagrams to `extension'. - if (m_diagrams.count()) { - QDomElement diagramsElement = qDoc.createElement(QLatin1String("diagrams")); - - foreach (UMLView* pView, m_diagrams) { - pView->umlScene()->saveToXMI(qDoc, diagramsElement); - } - QDomElement extension = qDoc.createElement(QLatin1String("XMI.extension")); - extension.setAttribute(QLatin1String("xmi.extender"), QLatin1String("umbrello-kf6")); - extension.appendChild(diagramsElement); - qElement.appendChild(extension); - } -} - -/** - * Auxiliary to saveToXMI(): Creates a element when saving - * a predefined modelview, or a element when saving a - * user created folder. Invokes saveContents() with the newly created - * element. - */ -void UMLFolder::save(QDomDocument& qDoc, QDomElement& qElement) -{ - UMLDoc *umldoc = UMLApp::app()->document(); - QString elementName(QLatin1String("UML:Package")); - const Uml::ModelType::Enum mt = umldoc->rootFolderType(this); - if (mt != Uml::ModelType::N_MODELTYPES) { - elementName = QLatin1String("UML:Model"); - } - QDomElement folderElement = UMLObject::save(elementName, qDoc); - saveContents(qDoc, folderElement); - qElement.appendChild(folderElement); -} - -/** - * Creates a UML:Model or UML:Package element: - * UML:Model is created for the predefined fixed folders, - * UML:Package with stereotype "folder" is created for all else. - */ -void UMLFolder::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) -{ - if (m_folderFile.isEmpty()) { - save(qDoc, qElement); - return; - } - // See if we can create the external file. - // If not then internalize the folder. - UMLDoc *umldoc = UMLApp::app()->document(); -#if QT_VERSION >= 0x050000 - QString fileName = umldoc->url().adjusted(QUrl::RemoveFilename).path() + m_folderFile; -#else - QString fileName = umldoc->url().directory() + QLatin1Char('/') + m_folderFile; -#endif - QFile file(fileName); - if (!file.open(QIODevice::WriteOnly)) { - uError() << m_folderFile << QLatin1String(": ") - << "cannot create file, contents will be saved in main model file"; - m_folderFile.clear(); - save(qDoc, qElement); - return; - } - // Okay, external file is writable. Wrap up main file. - QDomElement folderElement = UMLObject::save(QLatin1String("UML:Package"), qDoc); - QDomElement extension = qDoc.createElement(QLatin1String("XMI.extension")); - extension.setAttribute(QLatin1String("xmi.extender"), QLatin1String("umbrello-kf6")); - QDomElement fileElement = qDoc.createElement(QLatin1String("external_file")); - fileElement.setAttribute(QLatin1String("name"), m_folderFile); - extension.appendChild(fileElement); - folderElement.appendChild(extension); - qElement.appendChild(folderElement); - - // Save folder to external file. - QDomDocument folderDoc; - QDomElement folderRoot; - QDomProcessingInstruction xmlHeading = - folderDoc.createProcessingInstruction(QLatin1String("xml"), - QString::fromLatin1("version=\"1.0\" encoding=\"UTF-8\"")); - folderDoc.appendChild(xmlHeading); - folderRoot = folderDoc.createElement(QLatin1String("external_file")); - folderRoot.setAttribute(QLatin1String("name"), name()); - folderRoot.setAttribute(QLatin1String("filename"), m_folderFile); - folderRoot.setAttribute(QLatin1String("mainModel"), umldoc->url().fileName()); - folderRoot.setAttribute(QLatin1String("parentId"), Uml::ID::toString(m_pUMLPackage->id())); - folderRoot.setAttribute(QLatin1String("parent"), m_pUMLPackage->fullyQualifiedName(QLatin1String("::"), true)); - saveContents(folderDoc, folderRoot); - folderDoc.appendChild(folderRoot); - QTextStream stream(&file); - stream.setCodec("UTF-8"); - stream << folderDoc.toString(); - file.close(); -} - -/** - * Auxiliary to load(): - * Load the diagrams from the "diagrams" in the - */ -bool UMLFolder::loadDiagramsFromXMI(QDomNode& diagrams) -{ - const Settings::OptionState optionState = Settings::optionState(); - UMLDoc *umldoc = UMLApp::app()->document(); - bool totalSuccess = true; - for (QDomElement diagram = diagrams.toElement(); !diagram.isNull(); - diagrams = diagrams.nextSibling(), diagram = diagrams.toElement()) { - QString tag = diagram.tagName(); - if (tag != QLatin1String("diagram")) { - uDebug() << "ignoring " << tag << " in "; - continue; - } - UMLView * pView = new UMLView(this); - pView->umlScene()->setOptionState(optionState); - if (pView->umlScene()->loadFromXMI(diagram)) { - pView->hide(); - umldoc->addView(pView); - } else { - delete pView; - totalSuccess = false; - } - } - return totalSuccess; -} - -/** - * Folders in the listview can be marked such that their contents - * are saved to a separate file. - * This method loads the separate folder file. - * CAVEAT: This is not XMI standard compliant. - * If standard compliance is an issue then avoid folder files. - * @param path Fully qualified file name, i.e. absolute directory - * plus file name. - * @return True for success. - */ -bool UMLFolder::loadFolderFile(const QString& path) -{ - QFile file(path); - if (!file.exists()) { - KMessageBox::error(0, i18n("The folderfile %1 does not exist.", path), i18n("Load Error")); - return false; - } - if (!file.open(QIODevice::ReadOnly)) { - KMessageBox::error(0, i18n("The folderfile %1 cannot be opened.", path), i18n("Load Error")); - return false; - } - QTextStream stream(&file); - QString data = stream.readAll(); - file.close(); - QDomDocument doc; - QString error; - int line; - if (!doc.setContent(data, false, &error, &line)) { - uError() << "Cannot set content:" << error << " line:" << line; - return false; - } - QDomNode rootNode = doc.firstChild(); - while (rootNode.isComment() || rootNode.isProcessingInstruction()) { - rootNode = rootNode.nextSibling(); - } - if (rootNode.isNull()) { - uError() << "Root node is Null"; - return false; - } - QDomElement element = rootNode.toElement(); - QString type = element.tagName(); - if (type != QLatin1String("external_file")) { - uError() << "Root node has unknown type " << type; - return false; - } - return load(element); -} - -/** - * Loads the owned elements of the . - */ -bool UMLFolder::load(QDomElement& element) -{ - UMLDoc *umldoc = UMLApp::app()->document(); - bool totalSuccess = true; - for (QDomNode node = element.firstChild(); !node.isNull(); - node = node.nextSibling()) { - if (node.isComment()) - continue; - QDomElement tempElement = node.toElement(); - QString type = tempElement.tagName(); - if (Model_Utils::isCommonXMIAttribute(type)) - continue; - if (UMLDoc::tagEq(type, QLatin1String("Namespace.ownedElement")) || - UMLDoc::tagEq(type, QLatin1String("Namespace.contents"))) { - //CHECK: umbrello-kf6 currently assumes that nested elements - // are ownedElements anyway. - // Therefore these tags are not further interpreted. - if (! load(tempElement)) { - uDebug() << "An error happened while loading the " << type - << " of the " << name(); - totalSuccess = false; - } - continue; - } else if (UMLDoc::tagEq(type, QLatin1String("packagedElement")) || - UMLDoc::tagEq(type, QLatin1String("ownedElement"))) { - type = tempElement.attribute(QLatin1String("xmi:type")); - } else if (type == QLatin1String("XMI.extension")) { - for (QDomNode xtnode = node.firstChild(); !xtnode.isNull(); - xtnode = xtnode.nextSibling()) { - QDomElement el = xtnode.toElement(); - const QString xtag = el.tagName(); - if (xtag == QLatin1String("diagrams")) { - QDomNode diagramNode = xtnode.firstChild(); - if (!loadDiagramsFromXMI(diagramNode)) - totalSuccess = false; - } else if (xtag == QLatin1String("external_file")) { -#if QT_VERSION >= 0x050000 - const QString rootDir(umldoc->url().adjusted(QUrl::RemoveFilename).path()); -#else - const QString rootDir(umldoc->url().directory()); -#endif - QString fileName = el.attribute(QLatin1String("name")); - const QString path(rootDir + QLatin1Char('/') + fileName); - if (loadFolderFile(path)) - m_folderFile = fileName; - } else { - uDebug() << name() << ": ignoring XMI.extension " << xtag; - continue; - } - } - continue; - } - // Do not re-create the predefined Datatypes folder in the Logical View, - // it already exists. - UMLFolder *logicalView = umldoc->rootFolder(Uml::ModelType::Logical); - if (this == logicalView && UMLDoc::tagEq(type, QLatin1String("Package"))) { - QString thisName = tempElement.attribute(QLatin1String("name")); - if (thisName == QLatin1String("Datatypes")) { - UMLFolder *datatypeFolder = umldoc->datatypeFolder(); - if (!datatypeFolder->loadFromXMI(tempElement)) - totalSuccess = false; - continue; - } - } - UMLObject *pObject = 0; - // Avoid duplicate creation of forward declared object - QString idStr = Model_Utils::getXmiId(tempElement); - if (!idStr.isEmpty()) { - Uml::ID::Type id = Uml::ID::fromString(idStr); - pObject = umldoc->findObjectById(id); - if (pObject) { - uDebug() << "object " << idStr << "already exists"; - } - } - if (pObject == 0) { - QString stereoID = tempElement.attribute(QLatin1String("stereotype")); - pObject = Object_Factory::makeObjectFromXMI(type, stereoID); - if (!pObject) { - uWarning() << "Unknown type of umlobject to create: " << type; - continue; - } - } - pObject->setUMLPackage(this); - if (!pObject->loadFromXMI(tempElement)) { - removeObject(pObject); - delete pObject; - totalSuccess = false; - } - } - return totalSuccess; -} - -/** - * Overloading operator for debugging output. - */ -QDebug operator<<(QDebug out, const UMLFolder& item) -{ - out.nospace() << "UMLFolder: localName=" << item.m_localName - << ", folderFile=" << item.m_folderFile - << ", diagrams=" << item.m_diagrams.count(); - return out.space(); -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/folder.h umbrello-kf6-15.08.1/umbrello/folder.h --- umbrello-kf6-15.08.1.orig/umbrello/folder.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/folder.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,92 +0,0 @@ -/*************************************************************************** - * 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) 2006-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef UMLFOLDER_H -#define UMLFOLDER_H - -#include "package.h" -#include "umlviewlist.h" -#include "optionstate.h" - -/** - * This class manages the UMLObjects and UMLViews of a Folder. - * This class inherits from UMLPackage which contains most - * of the information. - * - * The UMLDoc class allocates a fixed instance of this class for - * each of the predefined Logical, UseCase, Component, Deployment, and - * Entity-Relationship folders. Further instances are created on demand - * for user folders. - * - * @short Non-graphical management of objects and diagrams of a Folder - * @author Oliver Kellogg - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - * - * TODO: This whole class needs a relook regarding view/scene. - */ -class UMLFolder : public UMLPackage -{ - Q_OBJECT -public: - explicit UMLFolder(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); - virtual ~UMLFolder(); - - virtual UMLObject* clone() const; - - void setLocalName(const QString& localName); - QString localName() const; - - void addView(UMLView *view); - - void removeView(UMLView *view); - - void appendViews(UMLViewList& viewList, bool includeNested = true); - - void activateViews(); - - UMLView* findView(Uml::ID::Type id); - UMLView* findView(Uml::DiagramType::Enum type, const QString &name, bool searchAllScopes = true); - - void setViewOptions(const Settings::OptionState& optionState); - - void removeAllViews(); - - void setFolderFile(const QString& fileName); - QString folderFile() const; - - void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); - - friend QDebug operator<<(QDebug out, const UMLFolder& item); - -protected: - void saveContents(QDomDocument& qDoc, QDomElement& qElement); - - void save(QDomDocument& qDoc, QDomElement& qElement); - - bool loadDiagramsFromXMI(QDomNode& diagrams); - - bool loadFolderFile(const QString& path); - - bool load(QDomElement & element); - -private: - QString m_localName; ///< i18n name, only used for predefined root folders - /** - * If m_folderFile is not empty then it contains a file name to which - * this folder is saved. - * In this case the folder file acts as a physically separate submodel. - * What is saved in the main model is not the folder contents but a - * reference to the folder file. - */ - QString m_folderFile; - UMLViewList m_diagrams; -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/foreignkeyconstraint.cpp umbrello-kf6-15.08.1/umbrello/foreignkeyconstraint.cpp --- umbrello-kf6-15.08.1.orig/umbrello/foreignkeyconstraint.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/foreignkeyconstraint.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,444 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -//own header -#include "foreignkeyconstraint.h" - -// app includes -#include "debug_utils.h" -#include "entity.h" -#include "entityattribute.h" -#include "umlobject.h" -#include "umldoc.h" -#include "uml.h" -#include "umlforeignkeyconstraintdialog.h" -#include "object_factory.h" - -/** - * Sets up a constraint. - * @param parent The parent of this UMLForeignKeyConstraint. - * @param name The name of this UMLForeignKeyConstraint. - * @param id The unique id given to this UMLForeignKeyConstraint. - */ -UMLForeignKeyConstraint::UMLForeignKeyConstraint(UMLObject *parent, - const QString& name, Uml::ID::Type id) - : UMLEntityConstraint(parent, name, id) -{ - init(); -} - -/** - * Sets up a constraint. - * @param parent The parent of this UMLForeignKeyConstraint. - */ -UMLForeignKeyConstraint::UMLForeignKeyConstraint(UMLObject *parent) - : UMLEntityConstraint(parent) -{ - init(); -} - -/** - * Initialisation of common variables - */ -void UMLForeignKeyConstraint::init() -{ - // initialise attributes - m_BaseType = UMLObject::ot_ForeignKeyConstraint; - - // should be NULL actually - // self referencing assigned to protect default behaviour - m_ReferencedEntity = static_cast(parent()); - - m_UpdateAction = uda_NoAction; - m_DeleteAction = uda_NoAction; - - // connecte signals and slots - connect(this, SIGNAL(sigReferencedEntityChanged()), this, SLOT(slotReferencedEntityChanged())); -} - -/** - * Overloaded '==' operator - */ -bool UMLForeignKeyConstraint::operator==(const UMLForeignKeyConstraint &rhs) const -{ - if(this == &rhs) - return true; - - if(!UMLObject::operator==(rhs)) - return false; - - return true; -} - -/** - * Destructor. - */ -UMLForeignKeyConstraint::~UMLForeignKeyConstraint() -{ -} - -/** - * Copy the internal presentation of this object into the UMLForeignKeyConstraint - * object. - */ -void UMLForeignKeyConstraint::copyInto(UMLObject *lhs) const -{ - UMLForeignKeyConstraint *target = static_cast(lhs); - - // call the parent first. - UMLEntityConstraint::copyInto(target); - - // Copy all datamembers - target->m_ReferencedEntity = m_ReferencedEntity; - target->m_AttributeMap = m_AttributeMap; - target->m_DeleteAction = m_DeleteAction; - target->m_UpdateAction = m_UpdateAction; -} - -/** - * Make a clone of the UMLForeignKeyConstraint. - */ -UMLObject* UMLForeignKeyConstraint::clone() const -{ - //FIXME: The new attribute should be slaved to the NEW parent not the old. - UMLForeignKeyConstraint *clone = new UMLForeignKeyConstraint(static_cast(parent())); - copyInto(clone); - return clone; -} - -/** - * Returns a string representation of the UMLForeignKeyConstraint. - * @param sig If true will show the attribute type and initial value. - * @return Returns a string representation of the UMLAttribute. - */ -QString UMLForeignKeyConstraint::toString(Uml::SignatureType::Enum sig) -{ - QString s; - - if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::SigNoVis) { - s = name() + QLatin1Char(':'); - s += QLatin1String(" Foreign Key ("); - QList keys = m_AttributeMap.keys(); - bool first = true; - foreach(UMLEntityAttribute* key, keys) { - if (first) { - first = false; - } else - s += QLatin1Char(','); - s += key->name(); - } - s += QLatin1Char(')'); - } - - return s; -} - -/** - * Creates the XMI element. - */ -void UMLForeignKeyConstraint::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) -{ - QDomElement foreignKeyConstraintElement = UMLObject::save(QLatin1String("UML:ForeignKeyConstraint"), qDoc); - - foreignKeyConstraintElement.setAttribute(QLatin1String("referencedEntity"), Uml::ID::toString(m_ReferencedEntity->id())); - - int updateAction = (int)m_UpdateAction; - int deleteAction = (int)m_DeleteAction; - - foreignKeyConstraintElement.setAttribute(QLatin1String("updateAction"), updateAction); - foreignKeyConstraintElement.setAttribute(QLatin1String("deleteAction"), deleteAction); - - QMap::iterator i; - for (i = m_AttributeMap.begin(); i!= m_AttributeMap.end() ; ++i) { - QDomElement mapElement = qDoc.createElement(QLatin1String("AttributeMap")); - mapElement.setAttribute(QLatin1String("key"), Uml::ID::toString((i.key())->id())); - mapElement.setAttribute(QLatin1String("value"), Uml::ID::toString((i.value())->id())); - foreignKeyConstraintElement.appendChild(mapElement); - } - - qElement.appendChild(foreignKeyConstraintElement); -} - -/** - * Display the properties configuration dialog for the attribute. - */ -bool UMLForeignKeyConstraint::showPropertiesDialog(QWidget* parent) -{ - UMLForeignKeyConstraintDialog dialog(parent, this); - return dialog.exec(); -} - -/** - * Adds the attribute pair to the attributeMap - * @param pAttr The Attribute of the Parent Entity - * @param rAttr The Attribute of the Referenced Entity - * @return true if the attribute pair could be added successfully - */ -bool UMLForeignKeyConstraint::addEntityAttributePair(UMLEntityAttribute* pAttr, UMLEntityAttribute* rAttr) -{ - UMLEntity *owningParent = dynamic_cast(parent()); - - if (pAttr == NULL || rAttr == NULL) { - uError() << "null values passed to function"; - return false; - } - // check for sanity of pAttr (parent entity attribute) - if (owningParent == NULL) { - uError() << name() << ": parent is not a UMLEntity"; - return false; - } - - if (owningParent->findChildObjectById(pAttr->id()) == NULL) { - uError() << " parent " << owningParent->name() - << " does not contain attribute " << pAttr->name(); - return false; - } - - //check for sanity of rAttr (referenced entity attribute) - if (m_ReferencedEntity != NULL) { - if (m_ReferencedEntity->findChildObjectById(rAttr->id()) == NULL) { - uError() << " parent " << m_ReferencedEntity->name() - << " does not contain attribute " << rAttr->name(); - return false; - } - } else { - uError() << "Referenced Table Not set. Not Adding Pair "; - return false; - } - - // check if key takes part in some mapping - if (m_AttributeMap.contains(pAttr) == true) - return false; - - // check if value takes part in some mapping (no direct function) - foreach(UMLEntityAttribute* attr, m_AttributeMap.values()) { - if (rAttr == attr) - return false; - } - - // passed all checks, insert now - m_AttributeMap.insert(pAttr, rAttr); - - QMap::iterator i; - for (i = m_AttributeMap.begin(); i != m_AttributeMap.end(); ++i) - uDebug() << i.key()->name() << QLatin1String(" ") << i.key()->baseType() - << QLatin1String(" ") << i.value()->name() << QLatin1String(" ") << i.value()->baseType(); - - return true; -} - -/** - * Removes an Attribute pair - * @param pAttr The Attribute of the Parent Entity in the map. This attribute is the - key of the map. - * @return true of the attribute pair could be removed successfully - */ -bool UMLForeignKeyConstraint::removeEntityAttributePair(UMLEntityAttribute* /*key*/ pAttr) -{ - bool state = m_AttributeMap.remove(pAttr); - - return state; -} - -/** - * Check if a attribute pair already exists - * @param pAttr The Attribute of the Parent Entity - * @param rAttr The Attribute of the Referenced Entity - * @return true if the attribute pair could be found. - */ -bool UMLForeignKeyConstraint::hasEntityAttributePair(UMLEntityAttribute* pAttr, UMLEntityAttribute* rAttr) const -{ - if (m_AttributeMap.contains(pAttr)) { - if (m_AttributeMap.value(pAttr) == rAttr) { - return true; - } - } - - return false; -} - -/** - * Loads the XMI element. - */ -bool UMLForeignKeyConstraint::load(QDomElement & element) -{ - UMLDoc* doc = UMLApp::app()->document(); - - Uml::ID::Type referencedEntityId = Uml::ID::fromString(element.attribute(QLatin1String("referencedEntity"))); - - UMLObject* obj = doc->findObjectById(referencedEntityId); - m_ReferencedEntity = static_cast(obj); - - if (m_ReferencedEntity == NULL) { - // save for resolving later - m_pReferencedEntityID = referencedEntityId; - } - - m_UpdateAction = (UpdateDeleteAction)element.attribute(QLatin1String("updateAction")).toInt(); - m_DeleteAction = (UpdateDeleteAction)element.attribute(QLatin1String("deleteAction")).toInt(); - - QDomNode node = element.firstChild(); - while (!node.isNull()) { - if (node.isComment()) { - node = node.nextSibling(); - continue; - } - QDomElement tempElement = node.toElement(); - QString tag = tempElement.tagName(); - if (UMLDoc::tagEq(tag, QLatin1String("AttributeMap"))) { - - QString xmiKey = tempElement.attribute(QLatin1String("key")); - QString xmiValue = tempElement.attribute(QLatin1String("value")); - Uml::ID::Type keyId = Uml::ID::fromString(xmiKey); - Uml::ID::Type valueId = Uml::ID::fromString(xmiValue); - - UMLEntity* parentEntity = static_cast(parent()); - UMLObject* keyObj = parentEntity->findChildObjectById(keyId); - UMLEntityAttribute* key = static_cast(keyObj); - - if (keyObj == NULL) { - uWarning() << "unable to resolve foreign key referencing attribute " << xmiKey; - } else if (m_ReferencedEntity == NULL) { - // if referenced entity is null, then we won't find its attributes even - // save for resolving later - m_pEntityAttributeIDMap.insert(key, valueId); - } else { - UMLObject* valueObj = m_ReferencedEntity->findChildObjectById(valueId); - if (valueObj == NULL) { - uWarning() << "unable to resolve foreign key referenced attribute" << xmiValue; - } else { - m_AttributeMap[key] = static_cast(valueObj); - } - } - - } else { - uWarning() << "unknown child type in UMLForeignKeyConstraint::load"; - } - - node = node.nextSibling(); - } - - return true; -} - -/** - * Set the Referenced Entity. - * @param ent The Entity to Reference - */ -void UMLForeignKeyConstraint::setReferencedEntity(UMLEntity* ent) -{ - if (ent == m_ReferencedEntity) - return; - - m_ReferencedEntity = ent; - - emit sigReferencedEntityChanged(); -} - -/** - * Get the Referenced Entity. - * @return the UML entity object - */ -UMLEntity* UMLForeignKeyConstraint::getReferencedEntity() const -{ - return m_ReferencedEntity; -} - -/** - * Slot for referenced entity changed. - */ -void UMLForeignKeyConstraint::slotReferencedEntityChanged() -{ - // clear all mappings - m_AttributeMap.clear(); -} - -/** - * Clears all mappings between local and referenced attributes - */ -void UMLForeignKeyConstraint::clearMappings() -{ - m_AttributeMap.clear(); -} - -/** - * Remimplementation from base classes - * Used to resolve forward references to referenced entities in xmi - */ -bool UMLForeignKeyConstraint::resolveRef() -{ - // resolve referenced entity first - UMLDoc* doc = UMLApp::app()->document(); - - bool success = true; - - //resolve the referenced entity - if (!Uml::ID::toString(m_pReferencedEntityID).isEmpty()) { - UMLObject* obj = doc->findObjectById(m_pReferencedEntityID); - m_ReferencedEntity = static_cast(obj); - if (m_ReferencedEntity == NULL) { - success = false; - } - } - - QMap::iterator i; - for (i = m_pEntityAttributeIDMap.begin(); i!= m_pEntityAttributeIDMap.end() ; ++i) { - if (!Uml::ID::toString(i.value()).isEmpty()) { - UMLObject* obj = doc->findObjectById(i.value()); - m_AttributeMap[i.key()] = static_cast(obj); - if (m_AttributeMap[i.key()] == NULL) { - success = false; - } - } - } - - return success; -} - -/** - * Retrieve all Pairs of Attributes. - */ -QMap UMLForeignKeyConstraint::getEntityAttributePairs() -{ - return m_AttributeMap; -} - -/** - * Get the Delete Action. - */ -UMLForeignKeyConstraint::UpdateDeleteAction UMLForeignKeyConstraint::getDeleteAction() const -{ - return m_DeleteAction; -} - -/** - * Get the Update Action. - */ -UMLForeignKeyConstraint::UpdateDeleteAction UMLForeignKeyConstraint::getUpdateAction() const -{ - return m_UpdateAction; -} - -/** - * Set the Delete Action to the specified UpdateDeleteAction. - */ -void UMLForeignKeyConstraint::setDeleteAction(UpdateDeleteAction uda) -{ - m_DeleteAction = uda; -} - -/** - * Set the Update Action to the specified UpdateDeleteAction - */ -void UMLForeignKeyConstraint::setUpdateAction(UpdateDeleteAction uda) -{ - m_UpdateAction = uda; -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/foreignkeyconstraint.h umbrello-kf6-15.08.1/umbrello/foreignkeyconstraint.h --- umbrello-kf6-15.08.1.orig/umbrello/foreignkeyconstraint.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/foreignkeyconstraint.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,120 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef FOREIGNKEYCONSTRAINT_H -#define FOREIGNKEYCONSTRAINT_H - -// appl includes -#include "basictypes.h" -#include "entityconstraint.h" - -// qt includes -#include - -//forward declarations -class UMLEntityAttribute; -class UMLEntity; - -/** - * This class is used to set up information for a foreign key entity constraint. - * @short Sets up Foreign Key entity constraint information. - * @author Sharan Rao - * @see UMLObject UMLClassifierListItem UMLEntityConstraint - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class UMLForeignKeyConstraint : public UMLEntityConstraint -{ - Q_OBJECT - -public: - - /** - * Update/Delete Action: Action to be taken on Update or Delete of a referenced attribute - * is either, No Action, Restrict, Cascade, Set NULL, Set Default. - */ - enum UpdateDeleteAction { uda_NoAction = 0, - uda_Restrict, - uda_Cascade, - uda_SetNull, - uda_SetDefault }; - - UMLForeignKeyConstraint(UMLObject *parent, const QString& name, - Uml::ID::Type id = Uml::ID::None); - explicit UMLForeignKeyConstraint(UMLObject *parent); - - bool operator==(const UMLForeignKeyConstraint &rhs) const; - - virtual ~UMLForeignKeyConstraint(); - - virtual void copyInto(UMLObject *lhs) const; - - virtual UMLObject* clone() const; - - QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); - - void setReferencedEntity(UMLEntity* ent); - UMLEntity* getReferencedEntity() const; - - void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); - - virtual bool showPropertiesDialog(QWidget* parent = 0); - - bool addEntityAttributePair(UMLEntityAttribute* pAttr, UMLEntityAttribute* rAttr); - - bool removeEntityAttributePair(UMLEntityAttribute* /*key*/ pAttr); - - bool hasEntityAttributePair(UMLEntityAttribute* pAttr, UMLEntityAttribute* rAttr) const; - - QMap getEntityAttributePairs(); - - void setDeleteAction(UpdateDeleteAction uda); - UpdateDeleteAction getDeleteAction() const; - - void setUpdateAction(UpdateDeleteAction uda); - UpdateDeleteAction getUpdateAction() const; - - void clearMappings(); - - bool resolveRef(); - -signals: - void sigReferencedEntityChanged(); - -private slots: - void slotReferencedEntityChanged(); - -protected: - bool load(QDomElement & element); - -private: - - Uml::ID::Type m_pReferencedEntityID; ///< Used to resolve forward references to UMLEntity. - - /** - * Used to resolve forward references to UMLEntityAttributes - * Key -> The local attribute - * Value -> Id of the attribute it is mapping to - */ - QMap m_pEntityAttributeIDMap; - - void init(); - - UMLEntity* m_ReferencedEntity; ///< The UMLEntity that this foreign key references. - - /** - * Stores the Mapping of attributes between parent table and referenced table - */ - QMap m_AttributeMap; - - UpdateDeleteAction m_UpdateAction; ///< What to do on Update of referenced attributes. - UpdateDeleteAction m_DeleteAction; ///< What to do on Deletion of referenced attributes. -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/listpopupmenu.cpp umbrello-kf6-15.08.1/umbrello/listpopupmenu.cpp --- umbrello-kf6-15.08.1.orig/umbrello/listpopupmenu.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/listpopupmenu.cpp 2015-10-08 11:48:59.500089026 +0300 @@ -1195,7 +1195,6 @@ void ListPopupMenu::makeClassifierShowPopup(ClassifierWidget *c) { WidgetBase::WidgetType type = c->baseType(); - ClassifierWidget *cls = NULL; #if QT_VERSION >= 0x050000 QMenu* show = new QMenu(i18n("Show"), this); @@ -1208,9 +1207,8 @@ setActionChecked(mt_Show_Documentation, c->visualProperty(ClassifierWidget::ShowDocumentation)); #endif if (type == WidgetBase::wt_Class) { - cls = static_cast(c); insert(mt_Show_Attributes, show, i18n("Attributes"), CHECKABLE); - setActionChecked(mt_Show_Attributes, cls->visualProperty(ClassifierWidget::ShowAttributes)); + setActionChecked(mt_Show_Attributes, c->visualProperty(ClassifierWidget::ShowAttributes)); } insert(mt_Show_Operations, show, i18n("Operations"), CHECKABLE); setActionChecked(mt_Show_Operations, c->visualProperty(ClassifierWidget::ShowOperations)); @@ -1224,16 +1222,14 @@ setActionChecked(mt_Show_Operation_Signature, sig); if (type == WidgetBase::wt_Class) { insert(mt_Show_Attribute_Signature, show, i18n("Attribute Signature"), CHECKABLE); - sig = (cls->attributeSignature() == Uml::SignatureType::SigNoVis || - cls->attributeSignature() == Uml::SignatureType::ShowSig); + sig = (c->attributeSignature() == Uml::SignatureType::SigNoVis || + c->attributeSignature() == Uml::SignatureType::ShowSig); setActionChecked(mt_Show_Attribute_Signature, sig); } insert(mt_Show_Packages, show, i18n("Package"), CHECKABLE); setActionChecked(mt_Show_Packages, c->visualProperty(ClassifierWidget::ShowPackage)); - if (type == WidgetBase::wt_Class) { - insert(mt_Show_Stereotypes, show, i18n("Stereotype"), CHECKABLE); - setActionChecked(mt_Show_Stereotypes, cls->visualProperty(ClassifierWidget::ShowStereotype)); - } + insert(mt_Show_Stereotypes, show, i18n("Stereotype"), CHECKABLE); + setActionChecked(mt_Show_Stereotypes, c->visualProperty(ClassifierWidget::ShowStereotype)); addMenu(show); } diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/node.cpp umbrello-kf6-15.08.1/umbrello/node.cpp --- umbrello-kf6-15.08.1.orig/umbrello/node.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/node.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,68 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#include "node.h" - -#include - -/** - * Sets up a Node. - * - * @param name The name of the Concept. - * @param id The unique id of the Concept. - */ -UMLNode::UMLNode(const QString & name, Uml::ID::Type id) - : UMLCanvasObject(name, id) -{ - init(); -} - -/** - * Destructor. - */ -UMLNode::~UMLNode() -{ -} - -/** - * Initializes key variables of the class. - */ -void UMLNode::init() -{ - m_BaseType = UMLObject::ot_Node; -} - -/** - * Make a clone of this object. - */ -UMLObject* UMLNode::clone() const -{ - UMLNode *clone = new UMLNode(); - UMLObject::copyInto(clone); - return clone; -} - -/** - * Creates the XMI element. - */ -void UMLNode::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) -{ - QDomElement nodeElement = UMLObject::save(QLatin1String("UML:Node"), qDoc); - qElement.appendChild(nodeElement); -} - -/** - * Loads the XMI element (empty.) - */ -bool UMLNode::load(QDomElement&) -{ - return true; -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/node.h umbrello-kf6-15.08.1/umbrello/node.h --- umbrello-kf6-15.08.1.orig/umbrello/node.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/node.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,46 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef NODE_H -#define NODE_H - -#include "umlcanvasobject.h" - -/** - * This class contains the non-graphical information required for a UML Node. - * This class inherits from @ref UMLCanvasObject which contains most of the - * information. - * - * @short Non-graphical information for a Node. - * @author Jonathan Riddell - * @see UMLCanvasObject - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class UMLNode : public UMLCanvasObject -{ - Q_OBJECT -public: - - explicit UMLNode(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); - virtual ~UMLNode(); - - virtual void init(); - - virtual UMLObject* clone() const; - - void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); - -protected: - - bool load(QDomElement & element); - -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/operation.cpp umbrello-kf6-15.08.1/umbrello/operation.cpp --- umbrello-kf6-15.08.1.orig/umbrello/operation.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/operation.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,611 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "operation.h" - -// app includes -#include "attribute.h" -#include "classifier.h" -#include "model_utils.h" -#include "debug_utils.h" -#include "uml.h" -#include "umldoc.h" -#include "uniqueid.h" -#include "umloperationdialog.h" -#include "codegenerator.h" -#include "codedocument.h" -#include "codeblock.h" - -// kde includes -#include - -// qt includes -#include - -/** - * Constructs an UMLOperation. - * Not intended for general use: The operation is not tied in with - * umbrello-kf6's Qt signalling for object creation. - * If you want to create an Operation use the method in UMLDoc instead. - * - * @param parent the parent to this operation - * @param name the name of the operation - * @param id the id of the operation - * @param s the visibility of the operation - * @param rt the return type of the operation - */ -UMLOperation::UMLOperation(UMLClassifier *parent, const QString& name, - Uml::ID::Type id, Uml::Visibility::Enum s, UMLObject *rt) - : UMLClassifierListItem(parent, name, id) -{ - if (rt) - m_returnId = UniqueID::gen(); - else - m_returnId = Uml::ID::None; - m_pSecondary = rt; - m_visibility = s; - m_BaseType = UMLObject::ot_Operation; - m_bConst = false; - m_Code.clear(); -} - -/** - * Constructs an UMLOperation. - * Not intended for general use: The operation is not tied in with - * umbrello-kf6's Qt signalling for object creation. - * If you want to create an Operation use the method in UMLDoc instead. - * - * @param parent the parent to this operation - */ -UMLOperation::UMLOperation(UMLClassifier * parent) - : UMLClassifierListItem (parent) -{ - m_BaseType = UMLObject::ot_Operation; - m_bConst = false; - m_Code.clear(); -} - -/** - * Destructor. - */ -UMLOperation::~UMLOperation() -{ -} - -/** - * Reimplement method from UMLClassifierListItem. - * - * @param type pointer to the type object - */ -void UMLOperation::setType(UMLObject* type) -{ - UMLClassifierListItem::setType(type); - if (m_returnId == Uml::ID::None) - m_returnId = UniqueID::gen(); -} - -/** - * Move a parameter one position to the left. - * - * @param a the parameter to move - */ -void UMLOperation::moveParmLeft(UMLAttribute * a) -{ - if (a == NULL) { - uDebug() << "called on NULL attribute"; - return; - } - uDebug() << "called for " << a->name(); - disconnect(a, SIGNAL(modified()), this, SIGNAL(modified())); - int idx; - if ((idx=m_List.indexOf(a)) == -1) { - uDebug() << "Error move parm left " << a->name(); - return; - } - if (idx == 0) - return; - m_List.removeAll(a); - m_List.insert(idx-1, a); -} - -/** - * Move a parameter one position to the right. - * - * @param a the parameter to move - */ -void UMLOperation::moveParmRight(UMLAttribute * a) -{ - if (a == NULL) { - uDebug() << "called on NULL attribute"; - return; - } - uDebug() << "called for " << a->name(); - disconnect(a, SIGNAL(modified()), this, SIGNAL(modified())); - int idx; - if ((idx=m_List.indexOf(a)) == -1) { - uDebug() << "Error move parm right " << a->name(); - return; - } - int count = m_List.count(); - if (idx == count-1) - return; - m_List.removeAll(a); - m_List.insert(idx+1, a); -} - -/** - * Remove a parameter from the operation. - * - * @param a the parameter to remove - * @param emitModifiedSignal whether to emit the "modified" signal - * which creates an entry in the Undo stack for the - * removal, default: true - */ -void UMLOperation::removeParm(UMLAttribute * a, bool emitModifiedSignal /* =true */) -{ - if (a == NULL) { - uDebug() << "called on NULL attribute"; - return; - } - uDebug() << "called for " << a->name(); - disconnect(a, SIGNAL(modified()), this, SIGNAL(modified())); - if(!m_List.removeAll(a)) - uDebug() << "Error removing parm " << a->name(); - - if (emitModifiedSignal) - emit modified(); -} - -/** - * Returns a list of parameters. - * - * @return a list of the parameters in the operation - */ -UMLAttributeList UMLOperation::getParmList() const -{ - return m_List; -} - -/** - * Finds a parameter of the operation. - * - * @param name the parameter name to search for - * @return the found parameter, 0 if not found - */ -UMLAttribute* UMLOperation::findParm(const QString &name) -{ - UMLAttribute * obj=0; - foreach (obj, m_List) { - if (obj->name() == name) - return obj; - } - return 0; -} - -/** - * Returns a string representation of the operation. - * - * @param sig what type of operation string to show - * @return the string representation of the operation - */ -QString UMLOperation::toString(Uml::SignatureType::Enum sig) -{ - QString s; - - if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::NoSig) - s = Uml::Visibility::toString(m_visibility, true) + QLatin1Char(' '); - - s += name(); - Uml::ProgrammingLanguage::Enum pl = UMLApp::app()->activeLanguage(); - bool parameterlessOpNeedsParentheses = - (pl != Uml::ProgrammingLanguage::Pascal && pl != Uml::ProgrammingLanguage::Ada); - - if (sig == Uml::SignatureType::NoSig || sig == Uml::SignatureType::NoSigNoVis) { - if (parameterlessOpNeedsParentheses) - s.append(QLatin1String("()")); - return s; - } - int last = m_List.count(); - if (last) { - s.append(QLatin1String("(")); - int i = 0; - foreach (UMLAttribute *param, m_List) { - i++; - s.append(param->toString(Uml::SignatureType::SigNoVis)); - if (i < last) - s.append(QLatin1String(", ")); - } - s.append(QLatin1String(")")); - } else if (parameterlessOpNeedsParentheses) { - s.append(QLatin1String("()")); - } - UMLClassifier *ownParent = static_cast(parent()); - QString returnType; - UMLClassifier *retType = UMLClassifierListItem::getType(); - if (retType) { - UMLPackage *retVisibility = retType->umlPackage(); - if (retVisibility != ownParent && retVisibility != ownParent->umlPackage()) - returnType = retType->fullyQualifiedName(); - else - returnType = retType->name(); - } - if (returnType.length() > 0 && returnType != QLatin1String("void")) { - s.append(QLatin1String(" : ")); - - if (returnType.startsWith(QLatin1String(QLatin1String("virtual ")))) { - s += returnType.mid(8); - } else { - s += returnType; - } - } - return s; -} - -/** - * Add a parameter to the operation. - * - * @param parameter the parameter to add - * @param position the position in the parameter list. - * If position = -1 the parameter will be - * appended to the list. - */ -void UMLOperation::addParm(UMLAttribute *parameter, int position) -{ - if(position >= 0 && position <= (int)m_List.count()) - m_List.insert(position, parameter); - else - m_List.append(parameter); - UMLObject::emitModified(); - connect(parameter, SIGNAL(modified()), this, SIGNAL(modified())); -} - -/** - * Returns an unused parameter name for a new parameter. - */ -QString UMLOperation::getUniqueParameterName() -{ - QString currentName = i18n("new_parameter"); - QString name = currentName; - for (int number = 1; findParm(name); ++number) { - name = currentName + QLatin1Char('_') + QString::number(number); - } - return name; -} - -/** - * Overloaded '==' operator. - */ -bool UMLOperation::operator==(const UMLOperation & rhs) const -{ - if (this == &rhs) - return true; - - if (!UMLObject::operator==(rhs)) - return false; - - if (getTypeName() != rhs.getTypeName()) - return false; - - if (m_List.count() != rhs.m_List.count()) - return false; - - if (!(m_List == rhs.m_List)) - return false; - - return true; -} - -/** - * Copy the internal presentation of this object into the new - * object. - */ -void UMLOperation::copyInto(UMLObject *lhs) const -{ - UMLOperation *target = static_cast(lhs); - - UMLClassifierListItem::copyInto(target); - - m_List.copyInto(&(target->m_List)); -} - -/** - * Make a clone of this object. - */ -UMLObject* UMLOperation::clone() const -{ - //FIXME: The new operation should be slaved to the NEW parent not the old. - UMLOperation *clone = new UMLOperation(static_cast(parent())); - copyInto(clone); - - return clone; -} - -/** - * Calls resolveRef() on all parameters. - * Needs to be called after all UML objects are loaded from file. - * - * @return true for success - */ -bool UMLOperation::resolveRef() -{ - bool overallSuccess = UMLObject::resolveRef(); - // See remark on iteration style in UMLClassifier::resolveRef() - foreach (UMLAttribute* pAtt, m_List) { - if (! pAtt->resolveRef()) - overallSuccess = false; - } - return overallSuccess; -} - -/** - * Returns whether this operation is a constructor. - * - * @return true if this operation is a constructor - */ -bool UMLOperation::isConstructorOperation() -{ - // if an operation has the stereotype constructor - // return true - if (stereotype() == QLatin1String("constructor")) - return true; - - UMLClassifier * c = static_cast(this->parent()); - QString cName = c->name(); - QString opName = name(); - // It's a constructor operation if the operation name - // matches that of the parent classifier. - return (cName == opName); -} - -/** - * Returns whether this operation is a destructor. - * - * @return true if this operation is a destructor - */ -bool UMLOperation::isDestructorOperation() -{ - if (stereotype() == QLatin1String("destructor")) - return true; - UMLClassifier * c = static_cast(this->parent()); - - QString cName = c->name(); - QString opName = name(); - // Special support for C++ syntax: - // It's a destructor operation if the operation name begins - // with "~" followed by the name of the parent classifier. - if (! opName.startsWith(QLatin1Char('~'))) - return false; - opName.remove(QRegExp(QLatin1String("^~\\s*"))); - return (cName == opName); -} - -/** - * Shortcut for (isConstructorOperation() || isDestructorOperation()). - * - * @return true if this operation is a constructor or destructor - */ -bool UMLOperation::isLifeOperation() -{ - return (isConstructorOperation() || isDestructorOperation()); -} - -/** - * Sets whether this operation is a query (C++ "const"). - */ -void UMLOperation::setConst(bool b) -{ - m_bConst = b; -} - -/** - * Returns whether this operation is a query (C++ "const"). - */ -bool UMLOperation::getConst() const -{ - return m_bConst; -} - -/** - * Display the properties configuration dialog for the template. - * - * @param parent the parent for the dialog - */ -bool UMLOperation::showPropertiesDialog(QWidget* parent) -{ - UMLOperationDialog dialog(parent, this); - return dialog.exec(); -} - -/** - * Sets the source code for this operation. - * - * @param code the body of this operation - */ -void UMLOperation::setSourceCode(const QString& code) -{ - m_Code = code; -} - -/** - * Returns the source code for this operation. - */ -QString UMLOperation::getSourceCode() const -{ - return m_Code; -} - -/** - * Saves to the XMI element. - */ -void UMLOperation::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) -{ - QDomElement operationElement = UMLObject::save(QLatin1String("UML:Operation"), qDoc); - operationElement.setAttribute(QLatin1String("isQuery"), m_bConst ? QLatin1String("true") : QLatin1String("false")); - QDomElement featureElement = qDoc.createElement(QLatin1String("UML:BehavioralFeature.parameter")); - if (m_pSecondary) { - QDomElement retElement = qDoc.createElement(QLatin1String("UML:Parameter")); - if (m_returnId == Uml::ID::None) { - uDebug() << name() << ": m_returnId is not set, setting it now."; - m_returnId = UniqueID::gen(); - } - retElement.setAttribute(QLatin1String("xmi.id"), Uml::ID::toString(m_returnId)); - retElement.setAttribute(QLatin1String("type"), Uml::ID::toString(m_pSecondary->id())); - retElement.setAttribute(QLatin1String("kind"), QLatin1String("return")); - featureElement.appendChild(retElement); - } else { - uDebug() << "m_SecondaryId is " << m_SecondaryId; - } - - //save each attribute here, type different - foreach(UMLAttribute* pAtt, m_List) { - QDomElement attElement = pAtt->UMLObject::save(QLatin1String("UML:Parameter"), qDoc); - UMLClassifier *attrType = pAtt->getType(); - if (attrType) { - attElement.setAttribute(QLatin1String("type"), Uml::ID::toString(attrType->id())); - } else { - attElement.setAttribute(QLatin1String("type"), pAtt->getTypeName()); - } - attElement.setAttribute(QLatin1String("value"), pAtt->getInitialValue()); - - Uml::ParameterDirection::Enum kind = pAtt->getParmKind(); - if (kind == Uml::ParameterDirection::Out) - attElement.setAttribute(QLatin1String("kind"), QLatin1String("out")); - else if (kind == Uml::ParameterDirection::InOut) - attElement.setAttribute(QLatin1String("kind"), QLatin1String("inout")); - // The default for the parameter kind is "in". - - featureElement.appendChild(attElement); - } - if (featureElement.hasChildNodes()) { - operationElement.appendChild(featureElement); - } - qElement.appendChild(operationElement); -} - -/** - * Loads a XMI element. - */ -bool UMLOperation::load(QDomElement & element) -{ - m_SecondaryId = element.attribute(QLatin1String("type")); - QString isQuery = element.attribute(QLatin1String("isQuery")); - if (!isQuery.isEmpty()) { - // We need this extra test for isEmpty() because load() might have been - // called again by the processing for BehavioralFeature.parameter (see below) - m_bConst = (isQuery == QLatin1String("true")); - } - QDomNode node = element.firstChild(); - if (node.isComment()) - node = node.nextSibling(); - QDomElement attElement = node.toElement(); - while (!attElement.isNull()) { - QString tag = attElement.tagName(); - if (UMLDoc::tagEq(tag, QLatin1String("BehavioralFeature.parameter")) || - UMLDoc::tagEq(tag, QLatin1String("Element.ownedElement"))) { // Embarcadero's Describe - if (! load(attElement)) - return false; - } else if (UMLDoc::tagEq(tag, QLatin1String("Parameter"))) { - QString kind = attElement.attribute(QLatin1String("kind")); - if (kind.isEmpty()) { - kind = attElement.attribute(QLatin1String("direction")); // Embarcadero's Describe - if (kind.isEmpty()) { - // Perhaps the kind is stored in a child node: - for (QDomNode n = attElement.firstChild(); !n.isNull(); n = n.nextSibling()) { - if (n.isComment()) - continue; - QDomElement tempElement = n.toElement(); - QString tag = tempElement.tagName(); - if (!UMLDoc::tagEq(tag, QLatin1String("kind"))) - continue; - kind = tempElement.attribute(QLatin1String("xmi.value")); - break; - } - } - if (kind.isEmpty()) { - kind = QLatin1String("in"); - } - } - if (kind == QLatin1String("return") || - kind == QLatin1String("result")) { // Embarcadero's Describe - QString returnId = Model_Utils::getXmiId(attElement); - if (!returnId.isEmpty()) - m_returnId = Uml::ID::fromString(returnId); - m_SecondaryId = attElement.attribute(QLatin1String("type")); - if (m_SecondaryId.isEmpty()) { - // Perhaps the type is stored in a child node: - QDomNode node = attElement.firstChild(); - while (!node.isNull()) { - if (node.isComment()) { - node = node.nextSibling(); - continue; - } - QDomElement tempElement = node.toElement(); - QString tag = tempElement.tagName(); - if (!UMLDoc::tagEq(tag, QLatin1String("type"))) { - node = node.nextSibling(); - continue; - } - m_SecondaryId = Model_Utils::getXmiId(tempElement); - if (m_SecondaryId.isEmpty()) - m_SecondaryId = tempElement.attribute(QLatin1String("xmi.idref")); - if (m_SecondaryId.isEmpty()) { - QDomNode inner = node.firstChild(); - QDomElement tmpElem = inner.toElement(); - m_SecondaryId = Model_Utils::getXmiId(tmpElem); - if (m_SecondaryId.isEmpty()) - m_SecondaryId = tmpElem.attribute(QLatin1String("xmi.idref")); - } - break; - } - if (m_SecondaryId.isEmpty()) { - uError() << name() << ": cannot find return type."; - } - } - // Use deferred xmi.id resolution. - m_pSecondary = NULL; - } else { - UMLAttribute * pAtt = new UMLAttribute(this); - if(!pAtt->loadFromXMI(attElement)) { - delete pAtt; - return false; - } - if (kind == QLatin1String("out")) - pAtt->setParmKind(Uml::ParameterDirection::Out); - else if (kind == QLatin1String("inout")) - pAtt->setParmKind(Uml::ParameterDirection::InOut); - else - pAtt->setParmKind(Uml::ParameterDirection::In); - m_List.append(pAtt); - } - } - node = node.nextSibling(); - if (node.isComment()) - node = node.nextSibling(); - attElement = node.toElement(); - - // loading the source code which was entered in the 'classpropdlg' dialog is not done - // with the following code, because there is no CodeDocument. - /* - CodeGenerator* codegen = UMLApp::app()->getGenerator(); - if (codegen) { - uDebug() << "CodeDocument searching with id=" << Uml::ID::toString(UMLObject::ID()); - CodeDocument* codeDoc = codegen->findCodeDocumentByID(Uml::ID::toString(UMLObject::ID())); - if (codeDoc) { - uDebug() << "CodeDocument found:\n" << codeDoc; - } - } - */ - // it is done in the code generators by calling CodeGenerator::loadFromXMI(...). - - }//end while - return true; -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/operation.h umbrello-kf6-15.08.1/umbrello/operation.h --- umbrello-kf6-15.08.1.orig/umbrello/operation.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/operation.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,84 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef OPERATION_H -#define OPERATION_H - -#include "umlattributelist.h" -#include "classifierlistitem.h" - -class UMLClassifier; - -/** - * This class represents an operation in the UML model. - * - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class UMLOperation : public UMLClassifierListItem -{ - Q_OBJECT -public: - UMLOperation(UMLClassifier * parent, const QString& name, - Uml::ID::Type id = Uml::ID::None, - Uml::Visibility::Enum s = Uml::Visibility::Public, - UMLObject *rt = 0); - explicit UMLOperation(UMLClassifier * parent); - virtual ~UMLOperation(); - - bool operator==(const UMLOperation & rhs) const; - - virtual void copyInto(UMLObject *lhs) const; - - virtual UMLObject* clone() const; - - void setType(UMLObject* type); - - void moveParmLeft(UMLAttribute *a); - void moveParmRight(UMLAttribute *a); - - void removeParm(UMLAttribute *a, bool emitModifiedSignal = true); - - UMLAttributeList getParmList() const; - - UMLAttribute * findParm(const QString &name); - - QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); - - void addParm(UMLAttribute *parameter, int position = -1); - - bool resolveRef(); - - QString getUniqueParameterName(); - - virtual bool showPropertiesDialog(QWidget* parent = 0); - - bool isConstructorOperation(); - bool isDestructorOperation(); - bool isLifeOperation(); - - void setConst(bool b); - bool getConst() const; - - void setSourceCode(const QString& code); - QString getSourceCode() const; - - void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); - -protected: - bool load(QDomElement & element); - -private: - Uml::ID::Type m_returnId; ///< Holds the xmi.id of the - UMLAttributeList m_List; ///< Parameter list - bool m_bConst; ///< Holds the isQuery attribute of the - QString m_Code; ///< Holds the entered source code -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/org.kde.umbrello-kf6.appdata.xml umbrello-kf6-15.08.1/umbrello/org.kde.umbrello-kf6.appdata.xml --- umbrello-kf6-15.08.1.orig/umbrello/org.kde.umbrello-kf6.appdata.xml 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/org.kde.umbrello-kf6.appdata.xml 2015-10-08 11:48:59.501089026 +0300 @@ -0,0 +1,136 @@ + + + org.kde.umbrello-kf6.desktop + CC0-1.0 + GPL-2.0+ + umbrello-kf6 + umbrello-kf6 + umbrello-kf6 + umbrello-kf6 + umbrello-kf6 + umbrello-kf6 + umbrello-kf6 + umbrello-kf6 + umbrello-kf6 + umbrello-kf6 + umbrello-kf6 + umbrello-kf6 + umbrello-kf6 + umbrello-kf6 + umbrello-kf6 + umbrello-kf6 + umbrello-kf6 + umbrello-kf6 + xxumbrello-kf6xx + UML Modeller + Modelador UML + UML modelář + UML-Modeller + UML Modeller + Modelador UML + UML-i modelleerimise rakendus + UML-mallinnusohjelma + Modelador de UML + Modellatore UML + UML-modeller + Program do modelowania UML + Modelador de UML + Modelador de UML + Modelár UML + Modelirnik UML + UML-modellering + Засіб моделювання UML + xxUML Modellerxx + +

+ umbrello-kf6 is a Unified Modelling Language (UML) modelling tool and code generator. + It can create diagrams of software and other systems in the industry-standard UML format, and can also generate code from UML diagrams + in a variety of programming languages. +

+

L'umbrello-kf6 és una eina de modelatge de Llenguatge Unificat de Modelatge (UML) i generador de codi. Pot crear diagrames de programari i altres sistemes en el format UML estàndard de la indústria, i també pot generar codi des de diagrames UML en diversos llenguatges de programació.

+

umbrello-kf6 is a Unified Modelling Language (UML) modelling tool and code generator. It can create diagrams of software and other systems in the industry-standard UML format, and can also generate code from UML diagrams in a variety of programming languages.

+

umbrello-kf6 es una herramienta de modelado y de generación de código para el lenguaje unificado de modelado (UML). Puede crear diagramas de software y de otros sistemas en el formato estándar de la industria UML, además de generar código a partir de diagramas UML en diversos lenguajes de programación.

+

umbrello-kf6 on unifitseeritud modelleerimiskeele UML modelleerimistööriist ja koodi genereerija. See võib luua tarkvara ja muude süsteemide skeeme standardses UML-vormingus, samuti genereerida UML-skeemide põhjal koodi mitmes programmeerimiskeeles.

+

umbrello-kf6 on UML-mallinnusohjelma. umbrello-kf6lla voi luoda kaavioita ohjelmistoista ja muista järjestelmistä käyttäen standardia UML-muotoa. Sillä voi myös luoda koodin UML-kaavioiden perusteella useille ohjelmointikielille.

+

umbrello-kf6 é unha ferramenta de modelaxe e xerador de código baseado na linguaxe de modelaxe UML. Pode crear diagramas de software e doutros sistemas usando o formato estándar da industria, UML, e pode tamén xerar código a partir de diagramas UML en varios linguaxes de programación.

+

umbrello-kf6 è uno strumento per diagrammi UML e un generatore di codice. Può creare diagrammi di software e altri sistemi nello standard industriale UML, e può anche generare codice partendo dai diagrammi UML in diversi linguaggi di programmazione.

+

umbrello-kf6 is een Unified Modelling Language (UML) hulpmiddel voor modellering en generator van code. Het kan diagrammen van software en andere systemen maken in het industrie-standaard UML-formaat en kan ook code genereren uit UML diagrammen in een verscheidenheid van programmeertalen.

+

umbrello-kf6 jest Unified Modelling Language (UML) (z ang. Językiem do Jednolitego Modelowania) i generatorem kodu. Może tworzyć diagramy oprogramowania i innych systemów w formacie standardu przemysłowego UML, a także generować kod z diagramów UML w wielu językach programowania.

+

O umbrello-kf6 é uma ferramenta de modelação em UML (Unified Modelling Language) e gerador de código. Poderá criar diagramas de aplicações e outros sistemas, usando o formato-padrão da indústria UML, podendo também gerar código a partir de diagramas UML, numa grande variedade de linguagens de programação.

+

umbrello-kf6 é uma ferramenta de modelação de UML (Unified Modelling Language) e gerador de código. Ele pode criar diagramas de softwares e outros sistemas, usando o formato de UML padrão da indústria, assim como gerar código a partir de diagramas UML, em uma grande variedade de linguagens de programação.

+

umbrello-kf6 je nástroj na modelovania v UML a generátor kódu. Dokáže vytvárať diagramy softvéru a iných systémov v priemyselnom štandarde UML a tiež generovať kód z UML diagramov v množstve programovacích jazykov.

+

umbrello-kf6 je orodje za modeliranje v poenotenem jeziku za modeliranje (UML) in ustvarjalnik kode. Ustvari lahko diagrame programov in drugih sistemov v industrijski standardizirani obliki UML, iz diagramov UML pa lahko ustvari tudi kodo v različnih programskih jezikih.

+

umbrello-kf6 är ett modelleringsverktyg för Unified Modelling Language och kodgenerator. Det kan skapa diagram av programvara och andra system med industristandardformatet UML, och kan också skapa kod från UML-diagram på ett antal olika programspråk.

+

umbrello-kf6 — засіб моделювання уніфікованою мовою моделювання (UML) та інструмент для створення шаблонів коду. Програма здатна створювати діаграми систем програмного забезпечення та інших систем у стандартному форматі UML та реалізовувати діаграми UML у програмному коді багатьма мовами програмування.

+

xxumbrello-kf6 is a Unified Modelling Language (UML) modelling tool and code generator. It can create diagrams of software and other systems in the industry-standard UML format, and can also generate code from UML diagrams in a variety of programming languages.xx

+

Features:

+

Característiques:

+

Vlastnosti:

+

Funktionen:

+

Features:

+

Funciones:

+

Omadused:

+

Ominaisuuksia:

+

Funcionalidades:

+

Funzionalità:

+

Kenmerken:

+

Możliwości:

+

Funcionalidades:

+

Funcionalidades:

+

Funkcie:

+

Zmožnosti:

+

Funktioner:

+

Можливості:

+

xxFeatures:xx

+
    +
  • Supported formats: XMI
  • +
  • Formats acceptats: XMI
  • +
  • Podporované formáty: XMI
  • +
  • Unterstützte Formate: XMI
  • +
  • Supported formats: XMI
  • +
  • Formatos permitidos: XMI
  • +
  • Toetatud vormingud: XMI
  • +
  • Tukee XMI-tiedostomuotoa
  • +
  • Formatos compatíbeis: XMI.
  • +
  • Formati supportati: XMI
  • +
  • Ondersteunde formaten: XMI
  • +
  • Obsługiwane formaty: XMI
  • +
  • Formatos suportados: XMI
  • +
  • Formatos suportados: XMI
  • +
  • Podporované formáty: XMI
  • +
  • Podprte oblike: XMI
  • +
  • Format som stöds: XMI
  • +
  • Підтримувані формати: XMI
  • +
  • xxSupported formats: XMIxx
  • +
  • Several type of diagrams supported: use case, class, sequence, collaboration, state, activity, component, deployment, entity relationship
  • +
  • Es permeten diversos tipus de diagrames: cas d'ús, classe, seqüència, col·laboració, estat, activitat, component, desplegament, entitat relació
  • +
  • Several type of diagrams supported: use case, class, sequence, collaboration, state, activity, component, deployment, entity relationship
  • +
  • Permite usar varios tipos de diagramas: casos de uso, clase, secuencia, colaboración, estado, actividad, componente, despliegue y relación de entidades
  • +
  • Toetatud on mitut tüüpi skeemid: kasutus, klass, järgnevus, koostöö, olek, tegevus, komponent, evitus, olem-seos
  • +
  • Tukee monenlaisia kaavioita: käyttötapauskaavio, luokkakaavio, sekvenssikaavio, yhteistyökaavio, tilakaavio, aktiviteettikaavio, komponenttikaavio, sijoittelukaavio, käsitekaavio
  • +
  • Permite traballar con varios tipos de diagramas: caso de uso, clase, secuencia, colaboración, estado, actividade, compoñente, distribución, e entidade-relación.
  • +
  • Diversi tipi di diagrammi supportati: casi d'uso, classe, sequenza, collaborazione, stato, attività, componente, dispiegamento, relazione tra entità
  • +
  • Verschillende typen diagrammen worden ondersteund: use case, klassen, volgorde, samenwerking, status, activiteit, component, deployment, relaties tussen eenheden
  • +
  • Kilka obsługiwanych rodzajów diagramów: przypadki użycia, klasy, sekwencje, kolaboracje, stany, aktywności, składniki, zastosowanie, współzależności obiektów
  • +
  • Diversos tipos de diagramas suportados: casos de uso, classe, sequência, colaboração, estado, actividade, componente, entrada em produção, entidade-associação
  • +
  • Há suporte para diversos tipos de diagramas: casos de uso, classe, sequência, colaboração, estado, atividade, componente, distribuição, relacionamento de entidade
  • +
  • Podporovaných je niekoľko typov diagramov: prípady použitia, triedy, sekvencie, stavy, aktivity, nasadenie, vzžahy entít
  • +
  • Podprte so številne vrste diagramov: primer uporabe, razred, zaporedje, sodelovanje, stanje, dejavnost, sestavni del, namestitev, odvisnost entitete
  • +
  • Flera diagramtyper stöds: användningsfall, klass, sekvens, samarbete, tillstånd, aktivitet, komponent, utplacering, objektsamband
  • +
  • Підтримка декількох типів діаграм: випадків використання, класів, послідовності, співпраці, станів, компонент, розміщення та взаємозв’язку компонентів.
  • +
  • xxSeveral type of diagrams supported: use case, class, sequence, collaboration, state, activity, component, deployment, entity relationshipxx
  • +
+
+ http://umbrello-kf6.kde.org + https://bugs.kde.org/enter_bug.cgi?format=guided&product=umbrello-kf6 + http://docs.kde.org/stable/en/kdesdk/umbrello/index.html + + + http://kde.org/images/screenshots/umbrello-kf6.png + + + KDE + + umbrello-kf6 + +
diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/package.cpp umbrello-kf6-15.08.1/umbrello/package.cpp --- umbrello-kf6-15.08.1.orig/umbrello/package.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/package.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,461 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header file -#include "package.h" - -// local includes -#include "debug_utils.h" -#include "dialog_utils.h" -#include "uml.h" -#include "umldoc.h" -#include "classifier.h" -#include "association.h" -#include "entity.h" -#include "object_factory.h" -#include "model_utils.h" - -// kde includes -#if QT_VERSION < 0x050000 -#include -#endif -#include -#include - -// qt includes -#if QT_VERSION >= 0x050000 -#include -#endif - -using namespace Uml; - -/** - * Sets up a Package. - * @param name The name of the Concept. - * @param id The unique id of the Concept. - */ -UMLPackage::UMLPackage(const QString & name, Uml::ID::Type id) - : UMLCanvasObject(name, id) -{ - m_BaseType = ot_Package; -} - -/** - * Destructor. - */ -UMLPackage::~UMLPackage() -{ -} - -/** - * Copy the internal presentation of this object into the new object. - */ -void UMLPackage::copyInto(UMLObject *lhs) const -{ - UMLPackage *target = static_cast(lhs); - - UMLCanvasObject::copyInto(target); - - m_objects.copyInto(&(target->m_objects)); -} - -/** - * Make a clone of this object. - */ -UMLObject* UMLPackage::clone() const -{ - UMLPackage *clone = new UMLPackage(); - copyInto(clone); - - return clone; -} - -/** - * Adds an existing association to the matching concept in the list of concepts. - * The selection of the matching concept depends on the association type: - * For generalizations, the assoc is added to the concept that matches role A. - * For aggregations and compositions, the assoc is added to the concept - * that matches role B. - * @param assoc the association to add - */ -void UMLPackage::addAssocToConcepts(UMLAssociation* assoc) -{ - if (! AssociationType::hasUMLRepresentation(assoc->getAssocType())) - return; - Uml::ID::Type AId = assoc->getObjectId(Uml::RoleType::A); - Uml::ID::Type BId = assoc->getObjectId(Uml::RoleType::B); - UMLObject *o = NULL; - for (UMLObjectListIt oit(m_objects); oit.hasNext();) { - o = oit.next(); - UMLCanvasObject *c = dynamic_cast(o); - if (c == NULL) - continue; - if (AId == c->id() || (BId == c->id())) { - if (c->hasAssociation(assoc)) - uDebug() << c->name() << " already has association id=" << Uml::ID::toString(assoc->id()); - else - c->addAssociationEnd(assoc); - } - UMLPackage *pkg = dynamic_cast(c); - if (pkg) - pkg->addAssocToConcepts(assoc); - } -} - -/** - * Remove the association from the participating concepts. - * @param assoc the association to remove - */ -void UMLPackage::removeAssocFromConcepts(UMLAssociation *assoc) -{ - UMLObject *o = 0; - for (UMLObjectListIt oit(m_objects); oit.hasNext();) { - o = oit.next(); - UMLCanvasObject *c = dynamic_cast(o); - if (c) { - if (c->hasAssociation(assoc)) - c->removeAssociationEnd(assoc); - UMLPackage *pkg = dynamic_cast(c); - if (pkg) - pkg->removeAssocFromConcepts(assoc); - } - } -} - -/** - * Adds an object in this package. - * - * @param pObject Pointer to the UMLObject to add. - * @return True if the object was actually added. - */ -bool UMLPackage::addObject(UMLObject *pObject) -{ - if (pObject == NULL) { - uError() << "is called with a NULL object"; - return false; - } - if (pObject == this) { - uError() << "adding myself as child is not allowed"; - return false; - } - - if (m_objects.indexOf(pObject) != -1) { - uDebug() << pObject->name() << " is already there"; - return false; - } - if (pObject->baseType() == UMLObject::ot_Association) { - UMLAssociation *assoc = static_cast(pObject); - // Adding the UMLAssociation at the participating concepts is done - // again later (in UMLAssociation::resolveRef()) if they are not yet - // known right here. - if (assoc->getObject(Uml::RoleType::A) && assoc->getObject(Uml::RoleType::B)) { - UMLPackage *pkg = pObject->umlPackage(); - if (pkg != this) { - uError() << "UMLPackage " << name() << " addObject: " - << "assoc's UMLPackage is " << pkg->name(); - } - addAssocToConcepts(assoc); - } - } - else { - QString name = pObject->name(); - QString oldName = name; - while (findObject(name) != NULL) { - QString prevName = name; - name = Model_Utils::uniqObjectName(pObject->baseType(), this); - bool ok = Dialog_Utils::askName(i18nc("object name", "Name"), - i18n("An object with the name %1\nalready exists in the package %2.\nPlease enter a new name:", prevName, this->name()), - name); - if (!ok) { - name = oldName; - continue; - } - if (name.length() == 0) { - KMessageBox::error(0, i18n("That is an invalid name."), - i18n("Invalid Name")); - continue; - } - } - if (oldName != name) { - pObject->setName(name); - } - } - m_objects.append(pObject); - return true; -} - -/** - * Removes an object from this package. - * Does not physically delete the object. - * - * @param pObject Pointer to the UMLObject to be removed. - */ -void UMLPackage::removeObject(UMLObject *pObject) -{ - if (pObject->baseType() == UMLObject::ot_Association) { - UMLObject *o = const_cast(pObject); - UMLAssociation *assoc = static_cast(o); - removeAssocFromConcepts(assoc); - } - if (m_objects.indexOf(pObject) == -1) - uDebug() << name() << " removeObject: object with id=" - << Uml::ID::toString(pObject->id()) << "not found."; - else - m_objects.removeAll(pObject); -} - -/** - * Removes all objects from this package. - * Inner containers (e.g. nested packages) are removed recursively. - */ -void UMLPackage::removeAllObjects() -{ - UMLCanvasObject::removeAllChildObjects(); - UMLObject *o = NULL; - - while (!m_objects.isEmpty() && (o = m_objects.first()) != NULL) { - UMLPackage *pkg = dynamic_cast(o); - if (pkg) - pkg->removeAllObjects(); - removeObject(o); - delete o; - } -} - -/** - * Returns the list of objects contained in this package. - */ -UMLObjectList UMLPackage::containedObjects() -{ - return m_objects; -} - -/** - * Find the object of the given name in the list of contained objects. - * - * @param name The name to seek. - * @return Pointer to the UMLObject found or NULL if not found. - */ -UMLObject * UMLPackage::findObject(const QString &name) -{ - const bool caseSensitive = UMLApp::app()->activeLanguageIsCaseSensitive(); - for (UMLObjectListIt oit(m_objects); oit.hasNext();) { - UMLObject *obj = oit.next(); - if (!obj) - continue; - if (caseSensitive) { - if (obj->name() == name) - return obj; - } else if (obj->name().toLower() == name.toLower()) { - return obj; - } - } - return NULL; -} - -/** - * Find the object of the given ID in the list of contained objects. - * - * @param id The ID to seek. - * @return Pointer to the UMLObject found or NULL if not found. - */ -UMLObject * UMLPackage::findObjectById(Uml::ID::Type id) -{ - return Model_Utils::findObjectInList(id, m_objects); -} - -/** - * Append all packages from this package (and those from nested packages) - * to the given UMLPackageList. - * - * @param packages The list to append to - * @param includeNested Whether to include the packages from nested packages - * (default:true) - */ -void UMLPackage::appendPackages(UMLPackageList& packages, bool includeNested) -{ - for (UMLObjectListIt oit(m_objects); oit.hasNext();) { - UMLObject *o = oit.next(); - uIgnoreZeroPointer(o); - ObjectType ot = o->baseType(); - if (ot == ot_Package || ot == ot_Folder) { - packages.append(static_cast(o)); - if (includeNested) { - UMLPackage *inner = static_cast(o); - inner->appendPackages(packages); - } - } - } -} - -/** - * Append all classifiers from this package (and those from - * nested packages) to the given UMLClassifierList. - * - * @param classifiers The list to append to. - * @param includeNested Whether to include the classifiers from - * nested packages (default: true.) - */ -void UMLPackage::appendClassifiers(UMLClassifierList& classifiers, - bool includeNested /* = true */) -{ - for (UMLObjectListIt oit(m_objects); oit.hasNext();) { - UMLObject *o = oit.next(); - uIgnoreZeroPointer(o); - ObjectType ot = o->baseType(); - if (ot == ot_Class || ot == ot_Interface || - ot == ot_Datatype || ot == ot_Enum || ot == ot_Entity) { - classifiers.append((UMLClassifier *)o); - } else if (includeNested && (ot == ot_Package || ot == ot_Folder)) { - UMLPackage *inner = static_cast(o); - inner->appendClassifiers(classifiers); - } - } -} - -/** - * Append all entities from this package (and those - * from nested packages) to the given UMLEntityList. - * - * @param entities The list to append to. - * @param includeNested Whether to include the entities from - * nested packages (default: true.) - */ -void UMLPackage::appendEntities(UMLEntityList& entities, - bool includeNested /* = true */) -{ - for (UMLObjectListIt oit(m_objects); oit.hasNext();) { - UMLObject *o = oit.next(); - uIgnoreZeroPointer(o); - ObjectType ot = o->baseType(); - if (ot == ot_Entity) { - UMLEntity *c = static_cast(o); - entities.append(c); - } else if (includeNested && (ot == ot_Package || ot == ot_Folder)) { - UMLPackage *inner = static_cast(o); - inner->appendEntities(entities); - } - } -} - -/** - * Append all classes and interfaces from this package (and those - * from nested packages) to the given UMLClassifierList. - * - * @param classifiers The list to append to. - * @param includeNested Whether to include the classifiers from - * nested packages (default: true.) - */ -void UMLPackage::appendClassesAndInterfaces(UMLClassifierList& classifiers, - bool includeNested /* = true */) -{ - for (UMLObjectListIt oit(m_objects); oit.hasNext();) { - UMLObject *o = oit.next(); - uIgnoreZeroPointer(o); - ObjectType ot = o->baseType(); - if (ot == ot_Class || ot == ot_Interface) { - UMLClassifier *c = static_cast(o); - classifiers.append(c); - } else if (includeNested && (ot == ot_Package || ot == ot_Folder)) { - UMLPackage *inner = static_cast(o); - inner->appendClassesAndInterfaces(classifiers); - } - } -} - -/** - * Resolve types. Required when dealing with foreign XMI files. - * Needs to be called after all UML objects are loaded from file. - * Overrides the method from UMLObject. - * Calls resolveRef() on each contained object. - * - * @return True for overall success. - */ -bool UMLPackage::resolveRef() -{ - bool overallSuccess = UMLCanvasObject::resolveRef(); - for (UMLObjectListIt oit(m_objects); oit.hasNext();) { - UMLObject *obj = oit.next(); - uIgnoreZeroPointer(obj); - if (! obj->resolveRef()) { - UMLObject::ObjectType ot = obj->baseType(); - if (ot != UMLObject::ot_Package && ot != UMLObject::ot_Folder) - m_objects.removeAll(obj); - overallSuccess = false; - } - } - return overallSuccess; -} - -/** - * Creates the XMI element. - */ -void UMLPackage::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) -{ - QDomElement packageElement = UMLObject::save(QLatin1String("UML:Package"), qDoc); - QDomElement ownedElement = qDoc.createElement(QLatin1String("UML:Namespace.ownedElement")); - UMLObject *obj = NULL; - // save classifiers etc. - for (UMLObjectListIt oit(m_objects); oit.hasNext();) { - obj = oit.next(); - uIgnoreZeroPointer(obj); - obj->saveToXMI (qDoc, ownedElement); - } - // save associations - for (UMLObjectListIt ait(m_List); ait.hasNext();) { - obj = ait.next(); - obj->saveToXMI (qDoc, ownedElement); - } - - packageElement.appendChild(ownedElement); - qElement.appendChild(packageElement); -} - -/** - * Loads the XMI element. - * Auxiliary to UMLObject::loadFromXMI. - */ -bool UMLPackage::load(QDomElement& element) -{ - for (QDomNode node = element.firstChild(); !node.isNull(); - node = node.nextSibling()) { - if (node.isComment()) - continue; - QDomElement tempElement = node.toElement(); - QString type = tempElement.tagName(); - if (Model_Utils::isCommonXMIAttribute(type)) - continue; - if (UMLDoc::tagEq(type, QLatin1String("Namespace.ownedElement")) || - UMLDoc::tagEq(type, QLatin1String("Element.ownedElement")) || // Embarcadero's Describe - UMLDoc::tagEq(type, QLatin1String("Namespace.contents"))) { - //CHECK: umbrello-kf6 currently assumes that nested elements - // are ownedElements anyway. - // Therefore these tags are not further interpreted. - if (! load(tempElement)) - return false; - continue; - } else if (UMLDoc::tagEq(type, QLatin1String("packagedElement")) || - UMLDoc::tagEq(type, QLatin1String("ownedElement"))) { - type = tempElement.attribute(QLatin1String("xmi:type")); - } - UMLObject *pObject = Object_Factory::makeObjectFromXMI(type); - if(!pObject) { - uWarning() << "Unknown type of umlobject to create: " << type; - continue; - } - pObject->setUMLPackage(this); - if (!pObject->loadFromXMI(tempElement)) { - removeObject(pObject); - delete pObject; - } - } - return true; -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/package.h umbrello-kf6-15.08.1/umbrello/package.h --- umbrello-kf6-15.08.1.orig/umbrello/package.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/package.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,79 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef PACKAGE_H -#define PACKAGE_H - -#include "umlcanvasobject.h" -#include "umlclassifierlist.h" -#include "umlentitylist.h" - -// forward declarations -class UMLAssociation; - -/** - * This class contains the non-graphical information required for a UML - * Package. - * This class inherits from @ref UMLCanvasObject which contains most of the - * information. - * - * @short Non-graphical information for a Package. - * @author Jonathan Riddell - * @see UMLCanvasObject - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class UMLPackage : public UMLCanvasObject -{ - Q_OBJECT -public: - explicit UMLPackage(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); - virtual ~UMLPackage(); - - virtual void copyInto(UMLObject *lhs) const; - - virtual UMLObject* clone() const; - - bool addObject(UMLObject *pObject); - void removeObject(UMLObject *pObject); - - virtual void removeAllObjects(); - - UMLObjectList containedObjects(); - - void addAssocToConcepts(UMLAssociation* assoc); - void removeAssocFromConcepts(UMLAssociation *assoc); - - UMLObject * findObject(const QString &name); - UMLObject * findObjectById(Uml::ID::Type id); - - void appendPackages(UMLPackageList& packages, bool includeNested = true); - void appendClassifiers(UMLClassifierList& classifiers, - bool includeNested = true); - void appendClassesAndInterfaces(UMLClassifierList& classifiers, - bool includeNested = true); - void appendEntities(UMLEntityList& entities, - bool includeNested = true); - - virtual bool resolveRef(); - - virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); - -protected: - virtual bool load(QDomElement& element); - - /** - * References to the objects contained in this package. - * The UMLPackage is the owner of the objects. - */ - UMLObjectList m_objects; - -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/port.cpp umbrello-kf6-15.08.1/umbrello/port.cpp --- umbrello-kf6-15.08.1.orig/umbrello/port.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/port.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,68 +0,0 @@ -/*************************************************************************** - * 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) 2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#include "port.h" - -#include - -/** - * Sets up a Port. - * - * @param name The name of the Concept. - * @param id The unique id of the Concept. - */ -UMLPort::UMLPort(const QString & name, Uml::ID::Type id) - : UMLCanvasObject(name, id) -{ - init(); -} - -/** - * Destructor. - */ -UMLPort::~UMLPort() -{ -} - -/** - * Initializes key variables of the class. - */ -void UMLPort::init() -{ - m_BaseType = UMLObject::ot_Port; -} - -/** - * Make a clone of this object. - */ -UMLObject* UMLPort::clone() const -{ - UMLPort *clone = new UMLPort(); - UMLObject::copyInto(clone); - return clone; -} - -/** - * Creates the XMI element. - */ -void UMLPort::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) -{ - QDomElement portElement = UMLObject::save(QLatin1String("UML:Port"), qDoc); - qElement.appendChild(portElement); -} - -/** - * Loads the XMI element (empty.) - */ -bool UMLPort::load(QDomElement&) -{ - return true; -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/port.h umbrello-kf6-15.08.1/umbrello/port.h --- umbrello-kf6-15.08.1.orig/umbrello/port.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/port.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,46 +0,0 @@ -/*************************************************************************** - * 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) 2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef PORT_H -#define PORT_H - -#include "umlcanvasobject.h" - -/** - * This class contains the non-graphical information required for a UML Port. - * This class inherits from @ref UMLCanvasObject which contains most of the - * information. - * - * @short Non-graphical information for a Port. - * @author Oliver Kellogg - * @see UMLCanvasObject - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class UMLPort : public UMLCanvasObject -{ - Q_OBJECT -public: - - explicit UMLPort(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); - virtual ~UMLPort(); - - virtual void init(); - - virtual UMLObject* clone() const; - - void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); - -protected: - - bool load(QDomElement & element); - -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/stereotype.cpp umbrello-kf6-15.08.1/umbrello/stereotype.cpp --- umbrello-kf6-15.08.1.orig/umbrello/stereotype.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/stereotype.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,164 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "stereotype.h" - -// local includes -#include "debug_utils.h" -#include "umldoc.h" -#include "uml.h" - -// kde includes -#if QT_VERSION < 0x050000 -#include -#endif -#include - -// qt includes -#if QT_VERSION >= 0x050000 -#include -#endif - -/** - * Sets up a stereotype. - * - * @param name The name of this UMLStereotype. - * @param id The unique id given to this UMLStereotype. - */ -UMLStereotype::UMLStereotype(const QString &name, Uml::ID::Type id /* = Uml::id_None */) - : UMLObject(name, id) -{ - m_BaseType = UMLObject::ot_Stereotype; - UMLStereotype * existing = UMLApp::app()->document()->findStereotype(name); - if (existing) { - uError() << "UMLStereotype constructor: " << name << " already exists"; - } - m_refCount = 0; -} - -/** - * Sets up a stereotype. - */ -UMLStereotype::UMLStereotype() - : UMLObject() -{ - m_BaseType = UMLObject::ot_Stereotype; - m_refCount = 0; -} - -/** - * Destructor. - */ -UMLStereotype::~UMLStereotype() -{ -} - -/** - * Overloaded '==' operator. - */ -bool UMLStereotype::operator==(const UMLStereotype &rhs) const -{ - if (this == &rhs) { - return true; - } - - if (!UMLObject::operator==(rhs)) { - return false; - } - - return true; -} - -/** - * Copy the internal presentation of this object into the new - * object. - */ -void UMLStereotype::copyInto(UMLObject *lhs) const -{ - UMLObject::copyInto(lhs); -} - -/** - * Make a clone of this object. - */ -UMLObject* UMLStereotype::clone() const -{ - UMLStereotype *clone = new UMLStereotype(); - copyInto(clone); - - return clone; -} - -/** - * Saves to the XMI element. - */ -void UMLStereotype::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) -{ - //FIXME: uml13.dtd compliance - QDomElement stereotypeElement = UMLObject::save(QLatin1String("UML:Stereotype"), qDoc); - qElement.appendChild(stereotypeElement); -} - -/** - * Display the properties configuration dialog for the stereotype - * (just a line edit). - */ -bool UMLStereotype::showPropertiesDialog(QWidget* parent) -{ - bool ok; -#if QT_VERSION >= 0x050000 - QString stereoTypeName = QInputDialog::getText(parent, - i18n("Stereotype"), i18n("Enter name:"), - QLineEdit::Normal, - name(), &ok); -#else - QString stereoTypeName = KInputDialog::getText(i18n("Stereotype"), i18n("Enter name:"), name(), &ok, parent); -#endif - if (ok) { - setName(stereoTypeName); - } - return ok; -} - -/** - * Increments the reference count for this stereotype. - */ -void UMLStereotype::incrRefCount() -{ - m_refCount++; -} - -/** - * Decrements the reference count for this stereotype. - */ -void UMLStereotype::decrRefCount() -{ - m_refCount--; -} - -/** - * Returns the reference count for this stereotype. - */ -int UMLStereotype::refCount() const -{ - return m_refCount; -} - -/** - * Returns the name as string - */ -QString UMLStereotype::name(bool includeAdornments) const -{ - if (includeAdornments) - return QString::fromUtf8("«") + UMLObject::name() + QString::fromUtf8("»"); - else - return UMLObject::name(); -} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/stereotype.h umbrello-kf6-15.08.1/umbrello/stereotype.h --- umbrello-kf6-15.08.1.orig/umbrello/stereotype.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/stereotype.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,71 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef STEREOTYPE_H -#define STEREOTYPE_H - -#include "umlobject.h" - -/** - * This class is used to set up information for a stereotype. - * Stereotypes are used essentially as properties of - * attributes and operations etc. - * - * Each stereotype object is reference counted, i.e. client code - * manages it such that it comes into existence as soon as there is - * at least one user, and ceases existing when the number of users - * drops to 0. - * m_refCount reflects the number of users. It is externally managed, - * i.e. client code must take care to call incrRefCount() and - * decrRefCount() as appropriate. - * - * The one and only owner of all stereotypes is the UMLDoc, and the - * ownership is specially managed (umlPackage() returns NULL for a - * UMLStereotype.) The reason for this special treatment is that - * class UMLDoc does not inherit from class UMLPackage, and therefore - * setUMLPackage() cannot be used for stereotypes. - * - * @short Sets up stereotype information. - * @author Jonathan Riddell - * @author Oliver Kellogg - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class UMLStereotype : public UMLObject -{ - Q_OBJECT -public: - explicit UMLStereotype(const QString &name, Uml::ID::Type id = Uml::ID::None); - UMLStereotype(); - - virtual ~UMLStereotype(); - - bool operator==(const UMLStereotype &rhs) const; - - virtual void copyInto(UMLObject *lhs) const; - - virtual UMLObject* clone() const; - - void incrRefCount(); - void decrRefCount(); - - int refCount() const; - - QString name(bool includeAdornments=false) const; - - void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); - - virtual bool showPropertiesDialog(QWidget* parent); - -protected: - int m_refCount; - -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/stereotypesmodel.cpp umbrello-kf6-15.08.1/umbrello/stereotypesmodel.cpp --- umbrello-kf6-15.08.1.orig/umbrello/stereotypesmodel.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/stereotypesmodel.cpp 2015-10-08 11:48:59.505089026 +0300 @@ -0,0 +1,121 @@ +/*************************************************************************** + * 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) 2015 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#include "stereotypesmodel.h" + +// app includes +#include "stereotype.h" +#include "uml.h" +#include "umldoc.h" + +// kde includes +#include + +// qt includes +#include + +StereotypesModel::StereotypesModel(UMLStereotypeList *stereotypes) + : m_count(0), + m_stereotypes(stereotypes) +{ +} + +int StereotypesModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + + int count = m_stereotypes->count(); + return count; +} + +int StereotypesModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + + return 2; +} + +QVariant StereotypesModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (section < 0) + return QVariant(); + + if (role != Qt::DisplayRole) + return QVariant(); + + if (orientation == Qt::Vertical) + return section + 1; + if (section == 0) + return QVariant(i18n("Name")); + else if (section == 1) + return QVariant(i18n("Usage")); + else return QVariant(); +} + +QVariant StereotypesModel::data(const QModelIndex & index, int role) const +{ + if (role == Qt::UserRole && index.column() == 0) { + QVariant v; + v.setValue(m_stereotypes->at(index.row())); + return v; + } + + if (role != Qt::DisplayRole) + return QVariant(); + + int cCount = columnCount(index); + if (index.column() >= cCount) + return QVariant(); + + UMLStereotype *s = m_stereotypes->at(index.row()); + if (cCount == 1) { + QString a = s->name() + QString(QLatin1String(" (%1)")).arg(s->refCount()); + return a; + } + + // table view + if (index.column() == 0) + return s->name(); + else + return s->refCount(); +} + +bool StereotypesModel::addStereotype(UMLStereotype *stereotype) +{ + if (m_stereotypes->contains(stereotype)) + return false; + int index = m_stereotypes->count(); + beginInsertRows(QModelIndex(), index, index); + m_stereotypes->append(stereotype); + endInsertRows(); + return true; +} + +bool StereotypesModel::removeStereotype(UMLStereotype *stereotype) +{ + if (!m_stereotypes->contains(stereotype)) + return false; + int index = m_stereotypes->indexOf(stereotype); + beginRemoveRows(QModelIndex(), index, index); + m_stereotypes->removeAll(stereotype); + endRemoveRows(); + return true; +} + +void StereotypesModel::emitDataChanged(const QModelIndex &index) +{ + emit dataChanged(index, index); +} + +void StereotypesModel::emitDataChanged(int index) +{ + QModelIndex mi = createIndex(index,0); + emit dataChanged(mi, mi); +} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/stereotypesmodel.h umbrello-kf6-15.08.1/umbrello/stereotypesmodel.h --- umbrello-kf6-15.08.1.orig/umbrello/stereotypesmodel.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/stereotypesmodel.h 2015-10-08 11:48:59.505089026 +0300 @@ -0,0 +1,47 @@ +/*************************************************************************** + * 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) 2015 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef STEREOTYPESMODEL_H +#define STEREOTYPESMODEL_H + +// app includes +#include "umlstereotypelist.h" + +// qt includes +#include + +class UMLStereotype; + +Q_DECLARE_METATYPE(UMLStereotype*); + +class StereotypesModel : public QAbstractTableModel +{ + Q_OBJECT +public: + StereotypesModel(UMLStereotypeList *stereotypes); + + int rowCount(const QModelIndex &parent) const; + int columnCount(const QModelIndex &parent) const; + + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const; + + bool addStereotype(UMLStereotype *stereotype); + bool removeStereotype(UMLStereotype *stereotype); + + void emitDataChanged(const QModelIndex &index); + void emitDataChanged(int index); + +protected: + int m_count; + UMLStereotypeList *m_stereotypes; +}; + +#endif // STEREOTYPESMODEL_H diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/stereotypeswindow.cpp umbrello-kf6-15.08.1/umbrello/stereotypeswindow.cpp --- umbrello-kf6-15.08.1.orig/umbrello/stereotypeswindow.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/stereotypeswindow.cpp 2015-10-08 11:48:59.506089026 +0300 @@ -0,0 +1,72 @@ +/*************************************************************************** + * 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) 2015 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#include "stereotypeswindow.h" + +// app includes +#include "stereotype.h" +#include "stereotypesmodel.h" +#include "uml.h" +#include "umldoc.h" + +// kde includes +#include + +// qt includes +#include +#include +#include +#include + +StereotypesWindow::StereotypesWindow(QWidget *parent) + : QDockWidget(i18n("&Stereotypes"), parent) +{ + setObjectName(QLatin1String("StereotypesWindow")); + + QSortFilterProxyModel *proxy = new QSortFilterProxyModel; + proxy->setSourceModel(UMLApp::app()->document()->stereotypesModel()); + proxy->setSortCaseSensitivity(Qt::CaseInsensitive); + m_stereotypesTree = new QTableView; + m_stereotypesTree->setModel(proxy); + m_stereotypesTree->setSortingEnabled(true); + m_stereotypesTree->verticalHeader()->setDefaultSectionSize(20); + m_stereotypesTree->verticalHeader()->setVisible(false); +#if QT_VERSION >= 0x050000 + m_stereotypesTree->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); +#else + m_stereotypesTree->horizontalHeader()->setResizeMode(QHeaderView::Stretch); +#endif + setWidget(m_stereotypesTree); + + connect(m_stereotypesTree, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(slotStereotypesDoubleClicked(QModelIndex))); +} + +StereotypesWindow::~StereotypesWindow() +{ + delete m_stereotypesTree; +} + +void StereotypesWindow::modified() +{ + UMLStereotype *o = static_cast(QObject::sender()); + if (!o) + return; + int index = UMLApp::app()->document()->stereotypes().indexOf(o); + UMLApp::app()->document()->stereotypesModel()->emitDataChanged(index); +} + +void StereotypesWindow::slotStereotypesDoubleClicked(QModelIndex index) +{ + QVariant v = UMLApp::app()->document()->stereotypesModel()->data(index, Qt::UserRole); + if (v.canConvert()) { + UMLStereotype *s = v.value(); + s->showPropertiesDialog(this); + } +} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/stereotypeswindow.h umbrello-kf6-15.08.1/umbrello/stereotypeswindow.h --- umbrello-kf6-15.08.1.orig/umbrello/stereotypeswindow.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/stereotypeswindow.h 2015-10-08 11:48:59.506089026 +0300 @@ -0,0 +1,38 @@ +/*************************************************************************** + * 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) 2015 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef STEREOTYPESWINDOW_H +#define STEREOTYPESWINDOW_H + +#include +#include + +class QTableView; + +class StereotypesWindow : public QDockWidget +{ + Q_OBJECT +public: + explicit StereotypesWindow(QWidget *parent = 0); + ~StereotypesWindow(); + +signals: + +public slots: + void modified(); + +protected slots: + void slotStereotypesDoubleClicked(QModelIndex index); + +protected: + QTableView *m_stereotypesTree; +}; + +#endif // STEREOTYPESWINDOW_H diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/template.cpp umbrello-kf6-15.08.1/umbrello/template.cpp --- umbrello-kf6-15.08.1.orig/umbrello/template.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/template.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,146 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "template.h" - -// app includes -#include "debug_utils.h" -#include "uml.h" -#include "umldoc.h" -#include "umltemplatedialog.h" - -/** - * Sets up a template. - * - * @param parent The parent of this UMLTemplate (i.e. its concept). - * @param name The name of this UMLTemplate. - * @param id The unique id given to this UMLTemplate. - * @param type The type of this UMLTemplate. - */ -UMLTemplate::UMLTemplate(UMLObject *parent, const QString& name, - Uml::ID::Type id, const QString& type) - : UMLClassifierListItem(parent, name, id) -{ - setTypeName(type); - m_BaseType = UMLObject::ot_Template; -} - -/** - * Sets up a template. - * - * @param parent The parent of this UMLTemplate (i.e. its concept). - */ -UMLTemplate::UMLTemplate(UMLObject *parent) - : UMLClassifierListItem(parent) -{ - m_BaseType = UMLObject::ot_Template; -} - -/** - * Destructor. - */ -UMLTemplate::~UMLTemplate() -{ -} - -QString UMLTemplate::toString(Uml::SignatureType::Enum sig) -{ - Q_UNUSED(sig); - if (m_pSecondary == NULL || m_pSecondary->name() == QLatin1String("class")) { - return name(); - } else { - return name() + QLatin1String(" : ") + m_pSecondary->name(); - } -} - -/** - * Overrides method from UMLClassifierListItem. - * Returns the type name of the UMLTemplate. - * If the template parameter is a class, there is no separate - * type object. In this case, getTypeName() returns "class". - * - * @return The type name of the UMLClassifierListItem. - */ -QString UMLTemplate::getTypeName() const -{ - if (m_pSecondary == NULL) - return QLatin1String("class"); - return m_pSecondary->name(); -} - -/** - * Overloaded '==' operator. - */ -bool UMLTemplate::operator==(const UMLTemplate &rhs) const -{ - if (this == &rhs) { - return true; - } - if (!UMLObject::operator==(rhs)) { - return false; - } - if (m_pSecondary != rhs.m_pSecondary) { - return false; - } - return true; -} - -/** - * Copy the internal presentation of this object into the new - * object. - */ -void UMLTemplate::copyInto(UMLObject *lhs) const -{ - UMLClassifierListItem::copyInto(lhs); -} - -/** - * Make a clone of this object. - */ -UMLObject* UMLTemplate::clone() const -{ - UMLTemplate *clone = new UMLTemplate((UMLTemplate*) parent()); - copyInto(clone); - - return clone; -} - -/** - * Writes the XMI element. - */ -void UMLTemplate::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) -{ - //FIXME: uml13.dtd compliance - QDomElement attributeElement = UMLObject::save(QLatin1String("UML:TemplateParameter"), qDoc); - if (m_pSecondary) - attributeElement.setAttribute(QLatin1String("type"), Uml::ID::toString(m_pSecondary->id())); - qElement.appendChild(attributeElement); -} - -/** - * Loads the XMI element. - */ -bool UMLTemplate::load(QDomElement& element) -{ - m_SecondaryId = element.attribute(QLatin1String("type")); - return true; -} - -/** - * Display the properties configuration dialog for the template. - * - * @return Success status. - */ -bool UMLTemplate::showPropertiesDialog(QWidget* parent) -{ - UMLTemplateDialog dialog(parent, this); - return dialog.exec(); -} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/template.h umbrello-kf6-15.08.1/umbrello/template.h --- umbrello-kf6-15.08.1.orig/umbrello/template.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/template.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,57 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef TEMPLATE_H -#define TEMPLATE_H - -#include "classifierlistitem.h" - -/** - * This class holds information used by template classes, called - * paramaterised class in UML and a generic in Java. It has a - * type (usually just "class") and name. - * - * @short Sets up template information. - * @author Jonathan Riddell - * @see UMLObject - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class UMLTemplate : public UMLClassifierListItem -{ -public: - - UMLTemplate(UMLObject *parent, const QString& name, - Uml::ID::Type id = Uml::ID::None, const QString& type = QLatin1String("class")); - - explicit UMLTemplate(UMLObject *parent); - - bool operator==(const UMLTemplate &rhs) const; - - virtual void copyInto(UMLObject *lhs) const; - - virtual UMLObject* clone() const; - - virtual ~UMLTemplate(); - - QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); - - virtual QString getTypeName() const; - - virtual bool showPropertiesDialog(QWidget* parent); - - void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); - -protected: - - bool load(QDomElement & element); - -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umbrello-kf6ui.rc umbrello-kf6-15.08.1/umbrello/umbrello-kf6ui.rc --- umbrello-kf6-15.08.1.orig/umbrello/umbrello-kf6ui.rc 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/umbrello-kf6ui.rc 2015-10-08 11:48:59.506089026 +0300 @@ -85,6 +85,7 @@ + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlappprivate.h umbrello-kf6-15.08.1/umbrello/umlappprivate.h --- umbrello-kf6-15.08.1.orig/umbrello/umlappprivate.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/umlappprivate.h 2015-10-08 11:48:59.506089026 +0300 @@ -15,8 +15,11 @@ #include "finddialog.h" #include "findresults.h" #include "uml.h" +#include "stereotypeswindow.h" // kde includes +#include +#include #include #include #include @@ -43,16 +46,18 @@ { Q_OBJECT public: - QWidget *parent; + UMLApp *parent; FindDialog findDialog; FindResults findResults; QListWidget *logWindow; ///< Logging window. + KToggleAction *viewStereotypesWindow; + StereotypesWindow *stereotypesWindow; ktexteditor-kf6::Editor *editor; ktexteditor-kf6::View *view; ktexteditor-kf6::Document *document; - explicit UMLAppPrivate(QWidget *_parent) + explicit UMLAppPrivate(UMLApp *_parent) : parent(_parent), findDialog(_parent), view(0), @@ -101,6 +106,18 @@ delete dialog; delete document; } + + void createStereotypesWindow() + { + // create the tree viewer + stereotypesWindow = new StereotypesWindow(parent); + parent->addDockWidget(Qt::LeftDockWidgetArea, stereotypesWindow); + + viewStereotypesWindow = parent->actionCollection()->add(QLatin1String("view_stereotypes_window")); + viewStereotypesWindow->setText(i18n("Stereotypes")); + connect(viewStereotypesWindow, SIGNAL(triggered(bool)), stereotypesWindow, SLOT(setVisible(bool))); + } + }; #endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlassociationlist.h umbrello-kf6-15.08.1/umbrello/umlassociationlist.h --- umbrello-kf6-15.08.1.orig/umbrello/umlassociationlist.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/umlassociationlist.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,23 +0,0 @@ -/*************************************************************************** - * * - * 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) 2004-2007 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef UMLASSOCIATIONLIST_H -#define UMLASSOCIATIONLIST_H - -#include - -// forward declaration -class UMLAssociation; - -typedef QList UMLAssociationList; -typedef QListIterator UMLAssociationListIt; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlattributelist.cpp umbrello-kf6-15.08.1/umbrello/umlattributelist.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlattributelist.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/umlattributelist.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,61 +0,0 @@ -/*************************************************************************** - * 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) 2004-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#include "umlattributelist.h" - -#include "attribute.h" - -#include - -UMLAttributeList::UMLAttributeList() -{ -} - -UMLAttributeList::UMLAttributeList(const UMLAttributeList& other) - : QList(other) -{ -} - -UMLAttributeList::~UMLAttributeList() -{ -} - -/** - * Copy the internal presentation of this object into the new - * object. - */ -void UMLAttributeList::copyInto(UMLAttributeList *rhs) const -{ - // Don't copy yourself. - if (rhs == this) return; - - rhs->clear(); - - // Suffering from const; we shall not modify our object. - UMLAttributeList *tmp = new UMLAttributeList(*this); - - UMLAttribute *item; - for (UMLAttributeListIt ait(*tmp); ait.hasNext() ;) - { - item = ait.next(); - rhs->append((UMLAttribute*)item->clone()); - } - delete tmp; -} - -/** - * Make a clone of this object. - */ -UMLAttributeList* UMLAttributeList::clone() const -{ - UMLAttributeList *clone = new UMLAttributeList(); - copyInto(clone); - return clone; -} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlattributelist.h umbrello-kf6-15.08.1/umbrello/umlattributelist.h --- umbrello-kf6-15.08.1.orig/umbrello/umlattributelist.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/umlattributelist.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,42 +0,0 @@ -/*************************************************************************** - * * - * 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) 2004-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef UMLATTRIBUTELIST_H -#define UMLATTRIBUTELIST_H - -#include - -#include "attribute.h" - -//typedef QPtrList UMLAttributeList; -typedef QListIterator UMLAttributeListIt; - -/** - * This sub-class adds copyInto and clone to the QPtrList - * base class. - */ -class UMLAttributeList : public QList -{ -public: - - UMLAttributeList(); - - UMLAttributeList(const UMLAttributeList&); - - virtual ~UMLAttributeList(); - - virtual void copyInto(UMLAttributeList *rhs) const; - - virtual UMLAttributeList* clone() const; -}; - - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlcanvasobject.cpp umbrello-kf6-15.08.1/umbrello/umlcanvasobject.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlcanvasobject.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/umlcanvasobject.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,464 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "umlcanvasobject.h" - -// local includes -#include "debug_utils.h" -#include "uml.h" -#include "umldoc.h" -#include "classifier.h" -#include "association.h" -#include "attribute.h" -#include "operation.h" -#include "template.h" -#include "stereotype.h" -#include "idchangelog.h" - -// kde includes -#include - -DEBUG_REGISTER_DISABLED(UMLCanvasObject) - -/** - * Sets up a UMLCanvasObject. - * - * @param name The name of the Concept. - * @param id The unique id of the Concept. - */ -UMLCanvasObject::UMLCanvasObject(const QString & name, Uml::ID::Type id) - : UMLObject(name, id) -{ -} - -/** - * Standard deconstructor. - */ -UMLCanvasObject::~UMLCanvasObject() -{ - //removeAllAssociations(); - // No! This is way too late to do that. - // It should have been called explicitly before destructing the - // UMLCanvasObject. - if (associations()) - DEBUG(DBG_SRC) << "UMLCanvasObject destructor: FIXME: there are still associations()"; -} - -/** - * Return the subset of m_List that matches the given type. - * - * @param assocType The AssociationType::Enum to match. - * @return The list of associations that match assocType. - */ -UMLAssociationList UMLCanvasObject::getSpecificAssocs(Uml::AssociationType::Enum assocType) -{ - UMLAssociationList list; - UMLObject *o = NULL; - for (UMLObjectListIt oit(m_List); oit.hasNext();) { - o = oit.next(); - uIgnoreZeroPointer(o); - if (o->baseType() != UMLObject::ot_Association) - continue; - UMLAssociation *a = static_cast(o); - if (a->getAssocType() == assocType) - list.append(a); - } - return list; -} - -/** - * Adds an association end to m_List. - * - * @param assoc The association to add. - * @todo change param type to UMLRole - */ -bool UMLCanvasObject::addAssociationEnd(UMLAssociation* assoc) -{ - Q_ASSERT(assoc); - // add association only if not already present in list - if (!hasAssociation(assoc)) - { - m_List.append(assoc); - - // Don't emit signals during load from XMI - UMLObject::emitModified(); - emit sigAssociationEndAdded(assoc); - return true; - } - return false; -} - -/** - * Determine if this canvasobject has the given association. - * - * @param assoc The association to check. - */ -bool UMLCanvasObject::hasAssociation(UMLAssociation* assoc) -{ - uint cnt = m_List.count(assoc); - DEBUG(DBG_SRC) << "count is " << cnt; - return (cnt > 0); -} - -/** - * Remove an association end from the CanvasObject. - * - * @param assoc The association to remove. - * @todo change param type to UMLRole - */ -int UMLCanvasObject::removeAssociationEnd(UMLAssociation * assoc) -{ - if (!hasAssociation(assoc) || !m_List.removeAll(assoc)) { - DEBUG(DBG_SRC) << "cannot find given assoc " << assoc << " in list"; - return -1; - } - UMLApp::app()->document()->removeAssociation(assoc, false); - UMLObject::emitModified(); - emit sigAssociationEndRemoved(assoc); - return m_List.count(); -} - -/** - * Remove all association ends from the CanvasObject. - */ -void UMLCanvasObject::removeAllAssociationEnds() -{ - for (int i = 0; i < m_List.count(); i++) { - UMLObject *o = m_List.at(i); - uIgnoreZeroPointer(o); - if (o->baseType() != UMLObject::ot_Association) { - continue; - } - UMLAssociation *assoc = static_cast(o); - //umldoc->slotRemoveUMLObject(assoc); - UMLObject* objA = assoc->getObject(Uml::RoleType::A); - UMLObject* objB = assoc->getObject(Uml::RoleType::B); - UMLCanvasObject *roleAObj = dynamic_cast(objA); - if (roleAObj) { - roleAObj->removeAssociationEnd(assoc); - } else if (objA) { - DEBUG(DBG_SRC) << name() << ": objA " << objA->name() << " is not a UMLCanvasObject"; - } else - DEBUG(DBG_SRC) << name() << "): objA is NULL"; - UMLCanvasObject *roleBObj = dynamic_cast(objB); - if (roleBObj) { - roleBObj->removeAssociationEnd(assoc); - } else if (objB) { - DEBUG(DBG_SRC) << name() << "): objB " << objB->name() << " is not a UMLCanvasObject"; - } else - DEBUG(DBG_SRC) << name() << "): objB is NULL"; - } -} - -/** - * Remove all child objects. - * Just clear list, objects must be deleted where they were created - * (or we have bad crashes). - */ -void UMLCanvasObject::removeAllChildObjects() -{ - if (!m_List.isEmpty()) { - removeAllAssociationEnds(); - m_List.clear(); - } -} - -/** - * Returns a name for the new association, operation, template - * or attribute appended with a number if the default name is - * taken e.g. new_association, new_association_1 etc. - * - * @param type The object type for which to make a name. - * @param prefix Optional prefix to use for the name. - * If not given then uniqChildName() will choose the prefix - * internally based on the object type. - * @return Unique name string for the ObjectType given. - */ -QString UMLCanvasObject::uniqChildName(const UMLObject::ObjectType type, - const QString &prefix /* = QString() */) -{ - QString currentName; - currentName = prefix; - if (currentName.isEmpty()) { - switch (type) { - case UMLObject::ot_Association: - currentName = i18n("new_association"); - break; - case UMLObject::ot_Attribute: - currentName = i18n("new_attribute"); - break; - case UMLObject::ot_Template: - currentName = i18n("new_template"); - break; - case UMLObject::ot_Operation: - currentName = i18n("new_operation"); - break; - case UMLObject::ot_EnumLiteral: - currentName = i18n("new_literal"); - break; - case UMLObject::ot_EntityAttribute: - currentName = i18n("new_field"); - break; - case UMLObject::ot_UniqueConstraint: - currentName = i18n("new_unique_constraint"); - break; - case UMLObject::ot_ForeignKeyConstraint: - currentName = i18n("new_fkey_constraint"); - break; - case UMLObject::ot_CheckConstraint: - currentName = i18n("new_check_constraint"); - break; - default: - uWarning() << "uniqChildName() called for unknown child type " << UMLObject::toString(type); - return QLatin1String("ERROR_in_UMLCanvasObject_uniqChildName"); - } - } - - QString name = currentName; - for (int number = 1; findChildObject(name); ++number) { - name = currentName + QLatin1Char('_') + QString::number(number); - } - return name; -} - -/** - * Find a child object with the given name. - * - * @param n The name of the object to find. - * @param t The type to find (optional.) If not given then - * any object type will match. - * @return Pointer to the object found; NULL if none found. - */ -UMLObject * UMLCanvasObject::findChildObject(const QString &n, UMLObject::ObjectType t) -{ - const bool caseSensitive = UMLApp::app()->activeLanguageIsCaseSensitive(); - UMLObject *obj = NULL; - for (UMLObjectListIt oit(m_List); oit.hasNext();) { - obj = oit.next(); - uIgnoreZeroPointer(obj); - if (t != UMLObject::ot_UMLObject && obj->baseType() != t) - continue; - if (caseSensitive) { - if (obj->name() == n) - return obj; - } else if (obj->name().toLower() == n.toLower()) { - return obj; - } - } - return NULL; -} - -/** - * Find an association. - * - * @param id The id of the object to find. - * @param considerAncestors boolean switch to consider ancestors while searching - * @return Pointer to the object found (NULL if not found.) - */ -UMLObject* UMLCanvasObject::findChildObjectById(Uml::ID::Type id, bool considerAncestors) -{ - Q_UNUSED(considerAncestors); - UMLObject *o = NULL; - for (UMLObjectListIt oit(m_List); oit.hasNext();) { - o = oit.next(); - uIgnoreZeroPointer(o); - if (o->id() == id) - return o; - } - return 0; -} - -/** - * Overloaded '==' operator - */ -bool UMLCanvasObject::operator==(const UMLCanvasObject& rhs) const -{ - if (this == &rhs) { - return true; - } - if (!UMLObject::operator==(rhs)) { - return false; - } - if (m_List.count() != rhs.m_List.count()) { - return false; - } - if (&m_List != &(rhs.m_List)) { - return false; - } - return true; -} - -/** - * Copy the internal presentation of this object into the new - * object. - */ -void UMLCanvasObject::copyInto(UMLObject *lhs) const -{ - UMLObject::copyInto(lhs); - - // TODO Associations are not copied at the moment. This because - // the duplicate function (on umlwidgets) do not copy the associations. - // - //target->m_List = m_List; -} - -/** - * Returns the number of associations for the CanvasObject. - * This is the sum of the aggregations and compositions. - * - * @return The number of associations for the Concept. - */ -int UMLCanvasObject::associations() -{ - int count = 0; - UMLObject *obj = NULL; - for (UMLObjectListIt oit(m_List); oit.hasNext();) { - obj = oit.next(); - uIgnoreZeroPointer(obj); - if (obj->baseType() == UMLObject::ot_Association) - count++; - } - return count; -} - -/** - * Return the list of associations for the CanvasObject. - * - * @return The list of associations for the CanvasObject. - */ -UMLAssociationList UMLCanvasObject::getAssociations() -{ - UMLAssociationList assocs; - UMLObject *o = NULL; - for (UMLObjectListIt oit(m_List); oit.hasNext() ;) { - o = oit.next(); - uIgnoreZeroPointer(o); - if (o->baseType() != UMLObject::ot_Association) - continue; - UMLAssociation *assoc = static_cast(o); - assocs.append(assoc); - } - return assocs; -} - -/** - * Return a list of the superclasses of this concept. - * TODO: This overlaps with UMLClassifier::findSuperClassConcepts(), - * see if we can merge the two. - * - * @param withRealizations include realizations in the returned list (default=yes) - * @return The list of superclasses for the concept. - */ -UMLClassifierList UMLCanvasObject::getSuperClasses(bool withRealizations) -{ - UMLClassifierList list; - UMLAssociationList assocs = getAssociations(); - foreach (UMLAssociation* a, assocs) { - uIgnoreZeroPointer(a); - if ((a->getAssocType() != Uml::AssociationType::Generalization && - a->getAssocType() != Uml::AssociationType::Realization) || - (!withRealizations && a->getAssocType() == Uml::AssociationType::Realization) || - a->getObjectId(Uml::RoleType::A) != id()) - continue; - UMLClassifier *c = dynamic_cast(a->getObject(Uml::RoleType::B)); - if (c) - list.append(c); - else - DEBUG(DBG_SRC) << name() << ": generalization's other end is not a " - << "UMLClassifier (id= " << Uml::ID::toString(a->getObjectId(Uml::RoleType::B)) << ")"; - } - return list; -} - -/** - * Return a list of the classes that inherit from this concept. - * TODO: This overlaps with UMLClassifier::findSubClassConcepts(), - * see if we can merge the two. - * - * @return The list of classes inheriting from the concept. - */ -UMLClassifierList UMLCanvasObject::getSubClasses() -{ - UMLClassifierList list; - UMLAssociationList assocs = getAssociations(); - foreach (UMLAssociation* a, assocs) { - uIgnoreZeroPointer(a); - if ((a->getAssocType() != Uml::AssociationType::Generalization && - a->getAssocType() != Uml::AssociationType::Realization) || - a->getObjectId(Uml::RoleType::B) != id()) - continue; - UMLClassifier *c = dynamic_cast(a->getObject(Uml::RoleType::A)); - if (c) - list.append(c); - else - DEBUG(DBG_SRC) << "specialization's other end is not a UMLClassifier" - << " (id=" << Uml::ID::toString(a->getObjectId(Uml::RoleType::A)) << ")"; - } - return list; -} - -/** - * Shorthand for getSpecificAssocs(Uml::at_Realization) - * - * @return The list of realizations for the Concept. - */ -UMLAssociationList UMLCanvasObject::getRealizations() -{ - return getSpecificAssocs(Uml::AssociationType::Realization); -} - -/** - * Shorthand for getSpecificAssocs(Uml::at_Aggregation) - * - * @return The list of aggregations for the Concept. - */ -UMLAssociationList UMLCanvasObject::getAggregations() -{ - return getSpecificAssocs(Uml::AssociationType::Aggregation); -} - -/** - * Shorthand for getSpecificAssocs(Uml::at_Composition) - * - * @return The list of compositions for the Concept. - */ -UMLAssociationList UMLCanvasObject::getCompositions() -{ - return getSpecificAssocs(Uml::AssociationType::Composition); -} - -/** - * Shorthand for getSpecificAssocs(Uml::at_Relationship) - * - * @return The list of relationships for the entity. - */ -UMLAssociationList UMLCanvasObject::getRelationships() -{ - return getSpecificAssocs(Uml::AssociationType::Relationship); -} - -/** - * Reimplementation of UMLObject method. - */ -bool UMLCanvasObject::resolveRef() -{ - bool overallSuccess = UMLObject::resolveRef(); - for (UMLObjectListIt ait(m_List); ait.hasNext();) { - UMLObject *obj = ait.next(); - uIgnoreZeroPointer(obj); - if (! obj->resolveRef()) { - m_List.removeAll(obj); - overallSuccess = false; - } - } - return overallSuccess; -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlcanvasobject.h umbrello-kf6-15.08.1/umbrello/umlcanvasobject.h --- umbrello-kf6-15.08.1.orig/umbrello/umlcanvasobject.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/umlcanvasobject.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,108 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef CANVASOBJECT_H -#define CANVASOBJECT_H - -#include "umlobject.h" -#include "umlobjectlist.h" -#include "umlclassifierlist.h" -#include "umlassociationlist.h" - -/** - * This class contains the non-graphical information required for UMLObjects - * which appear as moveable widgets on the scene. - * - * This class inherits from @ref UMLObject which contains most of the - * information. - * It is not instantiated itself, it's just used as a super class for - * actual model objects. - * - * @short Non-graphical information for a UMLCanvasObject. - * @author Jonathan Riddell - * @see UMLObject - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class UMLCanvasObject : public UMLObject -{ - Q_OBJECT - -public: - explicit UMLCanvasObject(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); - virtual ~UMLCanvasObject(); - - bool operator==(const UMLCanvasObject& rhs) const; - - virtual void copyInto(UMLObject *lhs) const; - - // The abstract method UMLObject::clone() is implemented - // in the classes inheriting from UMLCanvasObject. - - bool addAssociationEnd(UMLAssociation* assoc); - - bool hasAssociation(UMLAssociation* assoc); - - int removeAssociationEnd(UMLAssociation *assoc); - - void removeAllAssociationEnds(); - - int associations(); - - UMLAssociationList getAssociations(); - - UMLAssociationList getSpecificAssocs(Uml::AssociationType::Enum assocType); - - UMLClassifierList getSuperClasses(bool withRealizations = true); - UMLClassifierList getSubClasses(); - - virtual UMLAssociationList getRealizations(); - - UMLAssociationList getAggregations(); - UMLAssociationList getCompositions(); - UMLAssociationList getRelationships(); - - virtual UMLObject *findChildObject(const QString &n, - UMLObject::ObjectType t = UMLObject::ot_UMLObject); - virtual UMLObject *findChildObjectById(Uml::ID::Type id, bool considerAncestors = false); - - virtual QString uniqChildName(const UMLObject::ObjectType type, - const QString &prefix = QString()); - - virtual void removeAllChildObjects(); - - UMLObjectList subordinates() const { - return m_List; - } - - virtual bool resolveRef(); - - // The abstract method UMLObject::saveToXMI() is implemented - // in the classes inheriting from UMLCanvasObject. - -protected: - - /** - * List of all the associations in this object. - * Inheriting classes add more types of objects that are possible in this list; - * for example, UMLClassifier adds operations, attributes, and templates. - * - * @todo Only a pointer to the appropriate assocation end object - * (UMLRole) should be saved here, not the entire UMLAssociation. - */ - UMLObjectList m_List; - -signals: - - void sigAssociationEndAdded(UMLAssociation * assoc); - void sigAssociationEndRemoved(UMLAssociation * assoc); - -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlclassifierlist.h umbrello-kf6-15.08.1/umbrello/umlclassifierlist.h --- umbrello-kf6-15.08.1.orig/umbrello/umlclassifierlist.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/umlclassifierlist.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,22 +0,0 @@ -/*************************************************************************** - * 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-2010 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef UMLCLASSIFIERLIST_H -#define UMLCLASSIFIERLIST_H - -#include - -// forward declaration -class UMLClassifier; - -typedef QList UMLClassifierList; -typedef QListIterator UMLClassifierListIt; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlclassifierlistitemlist.cpp umbrello-kf6-15.08.1/umbrello/umlclassifierlistitemlist.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlclassifierlistitemlist.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/umlclassifierlistitemlist.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,60 +0,0 @@ -/*************************************************************************** - * 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) 2004-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#include "umlclassifierlistitemlist.h" - -#include "classifierlistitem.h" - -#include - -UMLClassifierListItemList::UMLClassifierListItemList() -{ -} - -UMLClassifierListItemList::UMLClassifierListItemList(const UMLClassifierListItemList& other) - : QList(other) -{ -} - -UMLClassifierListItemList::~UMLClassifierListItemList() -{ -} - -/** - * Copy the internal presentation of this object into the new - * object. - */ -void UMLClassifierListItemList::copyInto(UMLClassifierListItemList *rhs) const -{ - // Prevent copying to yourself. (Can cause serious injuries) - if (rhs == this) return; - - rhs->clear(); - - // Suffering from const; we shall not modify our object. - UMLClassifierListItemList *tmp = new UMLClassifierListItemList(*this); - - UMLClassifierListItem *item; - for (UMLClassifierListItemListIt clit(*tmp); clit.hasNext() ;) { - item = clit.next(); - rhs->append((UMLClassifierListItem*)item->clone()); - } - delete tmp; -} - -/** - * Make a clone of this object. - */ -UMLClassifierListItemList* UMLClassifierListItemList::clone() const -{ - UMLClassifierListItemList *clone = new UMLClassifierListItemList(); - copyInto(clone); - return clone; -} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlclassifierlistitemlist.h umbrello-kf6-15.08.1/umbrello/umlclassifierlistitemlist.h --- umbrello-kf6-15.08.1.orig/umbrello/umlclassifierlistitemlist.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/umlclassifierlistitemlist.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,41 +0,0 @@ -/*************************************************************************** - * 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) 2004-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef UMLCLASSIFIERLISTITEMLIST_H -#define UMLCLASSIFIERLISTITEMLIST_H - -#include - -// forward declaration -class UMLClassifierListItem; - -//typedef QPtrList UMLClassifierListItemList; -typedef QListIterator UMLClassifierListItemListIt; - -/** - * This sub-class adds copyInto and clone to the QPtrList - * base class. - */ -class UMLClassifierListItemList : public QList -{ -public: - - UMLClassifierListItemList(); - UMLClassifierListItemList(const UMLClassifierListItemList& other); - - virtual ~UMLClassifierListItemList(); - - virtual void copyInto (UMLClassifierListItemList *rhs) const; - - virtual UMLClassifierListItemList* clone() const; - -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/uml.cpp umbrello-kf6-15.08.1/umbrello/uml.cpp --- umbrello-kf6-15.08.1.orig/umbrello/uml.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/uml.cpp 2015-10-08 11:48:59.506089026 +0300 @@ -240,15 +240,15 @@ delete m_clipTimer; delete m_copyTimer; delete m_commoncodegenpolicy; - delete m_d; - delete m_doc; delete m_imageExporterAll; - delete m_listView; delete m_printer; delete m_policyext; delete m_pUndoStack; delete m_refactoringAssist; delete m_xhtmlGenerator; + delete m_listView; + delete m_doc; + delete m_d; } /** @@ -918,6 +918,8 @@ widget->setLayout(m_layout); setCentralWidget(widget); + m_d->createStereotypesWindow(); + // create the tree viewer m_listDock = new QDockWidget(i18n("&Tree View"), this); m_listDock->setObjectName(QLatin1String("TreeViewDock")); diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umldoc.cpp umbrello-kf6-15.08.1/umbrello/umldoc.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umldoc.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/umldoc.cpp 2015-10-08 11:48:59.506089026 +0300 @@ -44,6 +44,7 @@ #include "umlscene.h" #include "version.h" #include "worktoolbar.h" +#include "stereotypesmodel.h" // kde includes #include @@ -113,7 +114,8 @@ m_nViewID(Uml::ID::None), m_bTypesAreResolved(true), m_pCurrentRoot(0), - m_bClosing(false) + m_bClosing(false), + m_stereotypesModel(new StereotypesModel(&m_stereoList)) { for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) m_root[i] = 0; @@ -190,6 +192,7 @@ } delete m_pChangeLog; qDeleteAll(m_stereoList); + delete m_stereotypesModel; } /** @@ -402,18 +405,19 @@ // @fixme With advanced code generation enabled, this crashes. removeAllObjects(); + // Remove any stereotypes. + if (stereotypes().count() > 0) { + foreach(UMLStereotype *s, stereotypes()) { + m_stereotypesModel->removeStereotype(s); + delete s; + } + m_stereoList.clear(); + } + // Restore the datatype folder, it has been deleted above. createDatatypeFolder(); // this creates to much items only Logical View should be created listView->init(); - /* Remove any stereotypes. - if (m_stereoList.count() > 0) { - UMLStereotype *s; - for (UMLStereotypeListIt sit(m_stereoList); (s = sit.current()) != 0; ++sit) - delete s; - m_stereoList.clear(); - } - */ } m_bClosing = false; } @@ -1268,9 +1272,8 @@ */ void UMLDoc::addStereotype(UMLStereotype *s) { - if (! m_stereoList.contains(s)) { - m_stereoList.append(s); - } + if (m_stereotypesModel->addStereotype(s)) + emit sigObjectCreated(s); } /** @@ -1279,9 +1282,8 @@ */ void UMLDoc::removeStereotype(UMLStereotype *s) { - if (m_stereoList.contains(s)) { - m_stereoList.removeAll(s); - } + if (m_stereotypesModel->removeStereotype(s)) + emit sigObjectRemoved(s); } /** @@ -2444,6 +2446,11 @@ qApp->processEvents(); // give UI events a chance } +StereotypesModel *UMLDoc::stereotypesModel() +{ + return m_stereotypesModel; +} + /** * Ensures the XMI file is a valid UML file. * Currently only checks for metamodel=UML. diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umldoc.h umbrello-kf6-15.08.1/umbrello/umldoc.h --- umbrello-kf6-15.08.1.orig/umbrello/umldoc.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/umldoc.h 2015-10-08 11:48:59.506089026 +0300 @@ -48,6 +48,7 @@ class QPrinter; class IDChangeLog; +class StereotypesModel; class UMLPackage; class UMLFolder; class DiagramPrintPage; @@ -233,6 +234,8 @@ void resolveTypes(); + StereotypesModel *stereotypesModel(); + private: void initSaveTimer(); void createDatatypeFolder(); @@ -308,6 +311,8 @@ */ bool m_bClosing; + StereotypesModel *m_stereotypesModel; + public slots: void slotRemoveUMLObject(UMLObject*o); void slotAutoSave(); diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlentityattributelist.cpp umbrello-kf6-15.08.1/umbrello/umlentityattributelist.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlentityattributelist.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/umlentityattributelist.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,60 +0,0 @@ -/*************************************************************************** - * 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) 2004-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#include "umlentityattributelist.h" - -#include "entityattribute.h" - -#include - -UMLEntityAttributeList::UMLEntityAttributeList() -{ -} - -UMLEntityAttributeList::UMLEntityAttributeList(const UMLEntityAttributeList& other) - : QList(other) -{ -} - -UMLEntityAttributeList::~UMLEntityAttributeList() -{ -} - -/** - * Copy the internal presentation of this object into the new - * object. - */ -void UMLEntityAttributeList::copyInto(UMLEntityAttributeList* rhs) const -{ - // Don't copy yourself. - if (rhs == this) return; - - rhs->clear(); - - // Suffering from const; we shall not modify our object. - UMLEntityAttributeList* tmp = new UMLEntityAttributeList(*this); - - UMLEntityAttribute* item; - for (UMLEntityAttributeListIt eait(*tmp); eait.hasNext() ;) { - item = eait.next(); - rhs->append((UMLEntityAttribute*)item->clone()); - } - delete tmp; -} - -/** - * Make a clone of this object. - */ -UMLEntityAttributeList* UMLEntityAttributeList::clone() const -{ - UMLEntityAttributeList *clone = new UMLEntityAttributeList(); - copyInto(clone); - return clone; -} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlentityattributelist.h umbrello-kf6-15.08.1/umbrello/umlentityattributelist.h --- umbrello-kf6-15.08.1.orig/umbrello/umlentityattributelist.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/umlentityattributelist.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,41 +0,0 @@ -/*************************************************************************** - * * - * 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) 2004-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef UMLENTITYATTRIBUTELIST_H -#define UMLENTITYATTRIBUTELIST_H - -#include -#include "entityattribute.h" - -//typedef QPtrList UMLEntityAttributeList; -typedef QListIterator UMLEntityAttributeListIt; - -/** - * This sub-class adds copyInto and clone to the QPtrList - * base class. - */ -class UMLEntityAttributeList : public QList -{ -public: - - UMLEntityAttributeList(); - - UMLEntityAttributeList(const UMLEntityAttributeList&); - - virtual ~UMLEntityAttributeList(); - - virtual void copyInto (UMLEntityAttributeList* rhs) const; - - virtual UMLEntityAttributeList* clone() const; -}; - - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlentityconstraintlist.cpp umbrello-kf6-15.08.1/umbrello/umlentityconstraintlist.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlentityconstraintlist.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/umlentityconstraintlist.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,60 +0,0 @@ -/*************************************************************************** - * 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) 2004-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#include "umlentityconstraintlist.h" - -#include "entityconstraint.h" - -#include - -UMLEntityConstraintList::UMLEntityConstraintList() -{ -} - -UMLEntityConstraintList::UMLEntityConstraintList(const UMLEntityConstraintList& other) - : QList(other) -{ -} - -UMLEntityConstraintList::~UMLEntityConstraintList() -{ -} - -/** - * Copy the internal presentation of this object into the new - * object. - */ -void UMLEntityConstraintList::copyInto(UMLEntityConstraintList* rhs) const -{ - // Don't copy yourself. - if (rhs == this) return; - - rhs->clear(); - - // Suffering from const; we shall not modify our object. - UMLEntityConstraintList* tmp = new UMLEntityConstraintList(*this); - - UMLEntityConstraint* item; - for (UMLEntityConstraintListIt ecit(*tmp); ecit.hasNext() ;) { - item = ecit.next(); - rhs->append((UMLEntityConstraint*)item->clone()); - } - delete tmp; -} - -/** - * Make a clone of this object. - */ -UMLEntityConstraintList* UMLEntityConstraintList::clone() const -{ - UMLEntityConstraintList *clone = new UMLEntityConstraintList(); - copyInto(clone); - return clone; -} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlentityconstraintlist.h umbrello-kf6-15.08.1/umbrello/umlentityconstraintlist.h --- umbrello-kf6-15.08.1.orig/umbrello/umlentityconstraintlist.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/umlentityconstraintlist.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,43 +0,0 @@ -/*************************************************************************** - * * - * 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) 2004-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef UMLENTITYCONSTRAINTLIST_H -#define UMLENTITYCONSTRAINTLIST_H - -#include - -// forward declaration -class UMLEntityConstraint; - - -typedef QListIterator UMLEntityConstraintListIt; - -/** - * This sub-class adds copyInto and clone to the QPtrList - * base class. - */ -class UMLEntityConstraintList : public QList -{ -public: - - UMLEntityConstraintList(); - - UMLEntityConstraintList(const UMLEntityConstraintList&); - - virtual ~UMLEntityConstraintList(); - - virtual void copyInto (UMLEntityConstraintList* rhs) const; - - virtual UMLEntityConstraintList* clone() const; -}; - - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlentitylist.h umbrello-kf6-15.08.1/umbrello/umlentitylist.h --- umbrello-kf6-15.08.1.orig/umbrello/umlentitylist.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/umlentitylist.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,22 +0,0 @@ -/*************************************************************************** - * 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-2010 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef UMLENTITYLIST_H -#define UMLENTITYLIST_H - -#include - -// forward declaration -class UMLEntity; - -typedef QList UMLEntityList; -typedef QListIterator UMLEntityListIt; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlenumliterallist.h umbrello-kf6-15.08.1/umbrello/umlenumliterallist.h --- umbrello-kf6-15.08.1.orig/umbrello/umlenumliterallist.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/umlenumliterallist.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,23 +0,0 @@ -/*************************************************************************** - * * - * 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) 2004-2007 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef UMLENUMLITERALLIST_H -#define UMLENUMLITERALLIST_H - -#include - -// forward declaration -class UMLEnumLiteral; - -typedef QList UMLEnumLiteralList; -typedef QListIterator UMLEnumLiteralListIt; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umllistview.cpp umbrello-kf6-15.08.1/umbrello/umllistview.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umllistview.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/umllistview.cpp 2015-10-08 11:48:59.506089026 +0300 @@ -2161,6 +2161,11 @@ QString name = classifier->uniqChildName(objectType); UMLObject* object = Object_Factory::createChildObject(classifier, objectType, name); + if (object == 0) { + // creation was cancelled by the user + return; + } + // Handle primary key constraints (mark the unique constraint as PK on // the parent entity) if (type == UMLListViewItem::lvt_PrimaryKeyConstraint) { diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/actor.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/actor.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/actor.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/actor.cpp 2015-10-08 11:48:59.506089026 +0300 @@ -0,0 +1,67 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#include "actor.h" + +/** + * Constructs an Actor. + * + * @param name The name of the Actor. + * @param id The unique id to assign to this Actor. + */ +UMLActor::UMLActor(const QString & name, Uml::ID::Type id) + : UMLCanvasObject(name, id) +{ + init(); +} + +/** + * Standard destructor. + */ +UMLActor::~UMLActor() +{ +} + +/** + * Initializes key variables of the class. + */ +void UMLActor::init() +{ + m_BaseType = UMLObject::ot_Actor; +} + +/** + * Make a clone of this object. + */ +UMLObject* UMLActor::clone() const +{ + UMLActor *clone = new UMLActor(); + UMLObject::copyInto(clone); + return clone; +} + +/** + * Creates the XMI element. + */ +void UMLActor::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +{ + QDomElement actorElement = UMLObject::save(QLatin1String("UML:Actor"), qDoc); + qElement.appendChild(actorElement); +} + +/** + * Loads the XMI element (empty). + */ +bool UMLActor::load(QDomElement& element) +{ + Q_UNUSED(element); + return true; +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/actor.h umbrello-kf6-15.08.1/umbrello/umlmodel/actor.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/actor.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/actor.h 2015-10-08 11:48:59.506089026 +0300 @@ -0,0 +1,44 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef ACTOR_H +#define ACTOR_H + +#include "umlcanvasobject.h" + +/** + * This class contains the non-graphical information required for a UML Actor. + * This class inherits from @ref UMLCanvasObject which contains most of the + * information. + * The @ref UMLDoc class creates instances of this type. + * + * @short Information for a non-graphical UML Actor. + * @author Paul Hensgen + * @see UMLCanvasObject + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class UMLActor : public UMLCanvasObject +{ + Q_OBJECT +public: + explicit UMLActor(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); + virtual ~UMLActor(); + + virtual void init(); + + virtual UMLObject* clone() const; + + void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); + +protected: + bool load(QDomElement & element); +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/artifact.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/artifact.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/artifact.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/artifact.cpp 2015-10-08 11:48:59.506089026 +0300 @@ -0,0 +1,90 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#include "artifact.h" +#include "association.h" +#include "clipboard/idchangelog.h" + +#include + +/** + * Sets up an Artifact. + * @param name The name of the Concept. + * @param id The unique id of the Concept. + */ +UMLArtifact::UMLArtifact(const QString & name, Uml::ID::Type id) + : UMLPackage(name, id), + m_drawAsType(defaultDraw) +{ + m_BaseType = UMLObject::ot_Artifact; +} + +/** + * Standard deconstructor. + */ +UMLArtifact::~UMLArtifact() +{ +} + +/** + * Make a clone of this object. + * @return the cloned object + */ +UMLObject* UMLArtifact::clone() const +{ + UMLArtifact *clone = new UMLArtifact(); + UMLObject::copyInto(clone); + return clone; +} + +/** + * Creates the UML:Artifact element including its operations, + * attributes and templates + * @param qDoc the xml document + * @param qElement the xml element + */ +void UMLArtifact::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +{ + QDomElement artifactElement = UMLObject::save(QLatin1String("UML:Artifact"), qDoc); + artifactElement.setAttribute(QLatin1String("drawas"), m_drawAsType); + qElement.appendChild(artifactElement); +} + +/** + * Loads the UML:Artifact element including its operations, + * attributes and templates. + * @param element the xml element to load + * @return the success status of the operation + */ +bool UMLArtifact::load(QDomElement& element) +{ + QString drawAs = element.attribute(QLatin1String("drawas"), QLatin1String("0")); + m_drawAsType = (Draw_Type)drawAs.toInt(); + return true; +} + +/** + * Sets m_drawAsType for which method to draw the artifact as. + * @param type the draw type + */ +void UMLArtifact::setDrawAsType(Draw_Type type) +{ + m_drawAsType = type; +} + +/** + * Returns the value of m_drawAsType. + * @return the value of the draw type attribute + */ +UMLArtifact::Draw_Type UMLArtifact::getDrawAsType() +{ + return m_drawAsType; +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/artifact.h umbrello-kf6-15.08.1/umbrello/umlmodel/artifact.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/artifact.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/artifact.h 2015-10-08 11:48:59.506089026 +0300 @@ -0,0 +1,66 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef ARTIFACT_H +#define ARTIFACT_H + +#include "package.h" + +/** + * This class contains the non-graphical information required for a UML + * Artifact. + * This class inherits from @ref UMLCanvasObject which contains most of the + * information. + * + * @short Non-graphical information for a Artifact. + * @author Jonathan Riddell + * @see UMLCanvasObject + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class UMLArtifact : public UMLPackage +{ + Q_OBJECT +public: + + /** + * Artifacts can be drawn using one of several icons. + */ + enum Draw_Type { + defaultDraw, + file, + library, + table + }; + + explicit UMLArtifact(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); + virtual ~UMLArtifact(); + + virtual UMLObject* clone() const; + + void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); + + void setDrawAsType(Draw_Type type); + + Draw_Type getDrawAsType(); + +protected: + + bool load(QDomElement & element); + +private: + + /** + * Artifacts can be drawn as one of several different icons, + * this value choosing how to draw them. + */ + Draw_Type m_drawAsType; +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/association.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/association.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/association.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/association.cpp 2015-10-08 11:48:59.506089026 +0300 @@ -0,0 +1,742 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "association.h" + +// app includes +#include "debug_utils.h" +#include "classifier.h" +#include "classpropertiesdialog.h" +#include "folder.h" +#include "uml.h" +#include "umldoc.h" +#include "umlrole.h" +#include "uniqueid.h" +#include "model_utils.h" +#include "cmds.h" + +// kde includes +#include + +// qt includes +#include +#include + +using namespace Uml; + +DEBUG_REGISTER(UMLAssociation) + +/** + * Sets up an association. + * A new unique ID is assigned internally. + * @param type The AssociationType::Enum to construct. + * @param roleA Pointer to the UMLObject in role A. + * @param roleB Pointer to the UMLObject in role B. + */ +UMLAssociation::UMLAssociation(Uml::AssociationType::Enum type, + UMLObject * roleA, UMLObject * roleB) + : UMLObject(QString()) +{ + init(type, roleA, roleB); + + m_pRole[RoleType::A]->setID(UniqueID::gen()); + m_pRole[RoleType::B]->setID(UniqueID::gen()); +} + +/** + * Constructs an association - for loading only. + * This constructor should not normally be used as it constructs + * an incomplete association (i.e. the role objects are missing.) + * @param type The AssociationType::Enum to construct. + * Default: Unknown. + */ +UMLAssociation::UMLAssociation(Uml::AssociationType::Enum type) + : UMLObject(QString(), Uml::ID::Reserved) +{ + init(type, NULL, NULL); +} + +/** + * Standard destructor. + */ +UMLAssociation::~UMLAssociation() +{ + if (m_pRole[RoleType::A] == NULL) { + uError() << "UMLAssociation destructor: m_pRole[A] is NULL already"; + } else { + delete m_pRole[RoleType::A]; + m_pRole[RoleType::A] = NULL; + } + if (m_pRole[RoleType::B] == NULL) { + uError() << "UMLAssociation destructor: m_pRole[B] is NULL already"; + } else { + delete m_pRole[RoleType::B]; + m_pRole[RoleType::B] = NULL; + } +} + +/** + * Overloaded '==' operator + */ +bool UMLAssociation::operator==(const UMLAssociation &rhs) const +{ + if (this == &rhs) { + return true; + } + return (UMLObject::operator== (rhs) && + m_AssocType == rhs.m_AssocType && + m_Name == rhs.m_Name && + m_pRole[RoleType::A] == rhs.m_pRole[RoleType::A] && + m_pRole[RoleType::B] == rhs.m_pRole[RoleType::B]); +} + +/** + * Returns the AssociationType::Enum of the UMLAssociation. + * @return The AssociationType::Enum of the UMLAssociation. + */ +Uml::AssociationType::Enum UMLAssociation::getAssocType() const +{ + return m_AssocType; +} + +/** + * Returns a String representation of this UMLAssociation. + */ +QString UMLAssociation::toString() const +{ + QString string; + if(m_pRole[RoleType::A]) + { + string += m_pRole[RoleType::A]->object()->name(); + string += QLatin1Char(':'); + string += m_pRole[RoleType::A]->name(); + } + string += QLatin1Char(':') + Uml::AssociationType::toStringI18n(m_AssocType) + QLatin1Char(':'); + if(m_pRole[RoleType::B]) + { + string += m_pRole[RoleType::B]->object()->name(); + string += QLatin1Char(':'); + string += m_pRole[RoleType::B]->name(); + } + return string; +} + +/** + * Resolve types. Required when dealing with foreign XMI files. + * Needs to be called after all UML objects are loaded from file. + * Overrides the method from UMLObject. + * Calls resolveRef() for each role. + * @return True for success. + */ +bool UMLAssociation::resolveRef() +{ + bool successA = getUMLRole(RoleType::A)->resolveRef(); + bool successB = getUMLRole(RoleType::B)->resolveRef(); + if (successA && successB) { + UMLObject *objA = getUMLRole(RoleType::A)->object(); + UMLObject *objB = getUMLRole(RoleType::B)->object(); + // Check if need to change the assoc type to Realization + if (isRealization(objA, objB)) { + m_AssocType = Uml::AssociationType::Realization; + } + m_pUMLPackage->addAssocToConcepts(this); + return true; + } + return false; +} + +/** + * Creates the or XMI element + * including its role objects. + */ +void UMLAssociation::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +{ + if (m_AssocType == Uml::AssociationType::Generalization) { + QDomElement assocElement = UMLObject::save(QLatin1String("UML:Generalization"), qDoc); + assocElement.setAttribute(QLatin1String("discriminator"), QString()); + assocElement.setAttribute(QLatin1String("child"), Uml::ID::toString(getObjectId(RoleType::A))); + assocElement.setAttribute(QLatin1String("parent"), Uml::ID::toString(getObjectId(RoleType::B))); + qElement.appendChild(assocElement); + return; + } + if (m_AssocType == Uml::AssociationType::Realization) { + QDomElement assocElement = UMLObject::save(QLatin1String("UML:Abstraction"), qDoc); + assocElement.setAttribute(QLatin1String("client"), Uml::ID::toString(getObjectId(RoleType::A))); + assocElement.setAttribute(QLatin1String("supplier"), Uml::ID::toString(getObjectId(RoleType::B))); + qElement.appendChild(assocElement); + return; + } + if (m_AssocType == Uml::AssociationType::Dependency) { + QDomElement assocElement = UMLObject::save(QLatin1String("UML:Dependency"), qDoc); + assocElement.setAttribute(QLatin1String("client"), Uml::ID::toString(getObjectId(RoleType::A))); + assocElement.setAttribute(QLatin1String("supplier"), Uml::ID::toString(getObjectId(RoleType::B))); + qElement.appendChild(assocElement); + return; + } + if (m_AssocType == Uml::AssociationType::Child2Category) { + QDomElement assocElement = UMLObject::save(QLatin1String("UML:Child2Category"), qDoc); + assocElement.setAttribute(QLatin1String("client"), Uml::ID::toString(getObjectId(RoleType::A))); + assocElement.setAttribute(QLatin1String("supplier"), Uml::ID::toString(getObjectId(RoleType::B))); + qElement.appendChild(assocElement); + return; + } + if (m_AssocType == Uml::AssociationType::Category2Parent) { + QDomElement assocElement = UMLObject::save(QLatin1String("UML:Category2Parent"), qDoc); + assocElement.setAttribute(QLatin1String("client"), Uml::ID::toString(getObjectId(RoleType::A))); + assocElement.setAttribute(QLatin1String("supplier"), Uml::ID::toString(getObjectId(RoleType::B))); + qElement.appendChild(assocElement); + return; + } + + QDomElement associationElement = UMLObject::save(QLatin1String("UML:Association"), qDoc); + QDomElement connElement = qDoc.createElement(QLatin1String("UML:Association.connection")); + getUMLRole(RoleType::A)->saveToXMI (qDoc, connElement); + getUMLRole(RoleType::B)->saveToXMI (qDoc, connElement); + associationElement.appendChild (connElement); + qElement.appendChild(associationElement); +} + +bool UMLAssociation::showPropertiesDialog(QWidget *parent) +{ + QPointer dlg = new ClassPropertiesDialog(parent, this, true); + bool modified = false; + if (dlg->exec()) { + modified = true; + } + dlg->close(); + delete dlg; + return modified; +} + +/** + * Creates the or XMI element + * including its role objects. + */ +bool UMLAssociation::load(QDomElement & element) +{ + if (id() == Uml::ID::None) + return false; // old style XMI file. No real info in this association. + + UMLDoc * doc = UMLApp::app()->document(); + UMLObject * obj[2] = { NULL, NULL }; + if (m_AssocType == Uml::AssociationType::Generalization || + m_AssocType == Uml::AssociationType::Realization || + m_AssocType == Uml::AssociationType::Dependency || + m_AssocType == Uml::AssociationType::Child2Category || + m_AssocType == Uml::AssociationType::Category2Parent) { + QString general = element.attribute(QLatin1String("general")); + if (!general.isEmpty()) { + UMLClassifier *owningClassifier = dynamic_cast(m_pUMLPackage); + if (owningClassifier == NULL){ + uWarning() << "Cannot load UML2 generalization: m_pUMLPackage is expected " + << "to be the owning classifier (=client)"; + return false; + } + m_pRole[RoleType::A]->setObject(owningClassifier); + m_pRole[RoleType::B]->setSecondaryId(general); // defer resolution to resolveRef() + owningClassifier->addAssociationEnd(this); + m_pUMLPackage = m_pUMLPackage->umlPackage(); // reparent + m_pUMLPackage->addObject(this); + return true; + } + for (unsigned r = RoleType::A; r <= RoleType::B; ++r) { + const QString fetch = (m_AssocType == Uml::AssociationType::Generalization ? + r == RoleType::A ? QLatin1String("child") : QLatin1String("parent") + : r == RoleType::A ? QLatin1String("client") : QLatin1String("supplier")); + QString roleIdStr = element.attribute(fetch); + if (roleIdStr.isEmpty()) { + // Might be given as a child node instead - see below. + continue; + } + + // set umlobject of role if possible (else defer resolution) + obj[r] = doc->findObjectById(Uml::ID::fromString(roleIdStr)); + Uml::RoleType::Enum role = Uml::RoleType::fromInt(r); + if (obj[r] == NULL) { + m_pRole[role]->setSecondaryId(roleIdStr); // defer to resolveRef() + } else { + m_pRole[role]->setObject(obj[r]); + if (m_pUMLPackage == NULL) { + Uml::ModelType::Enum mt = Model_Utils::convert_OT_MT(obj[r]->baseType()); + m_pUMLPackage = doc->rootFolder(mt); + DEBUG(DBG_SRC) << "assoctype " << m_AssocType + << ": setting model type " << Uml::ModelType::toString(mt); + } + } + } + if (obj[RoleType::A] == NULL || obj[RoleType::B] == NULL) { + for (QDomNode node = element.firstChild(); !node.isNull(); + node = node.nextSibling()) { + if (node.isComment()) + continue; + QDomElement tempElement = node.toElement(); + QString tag = tempElement.tagName(); + if (Model_Utils::isCommonXMIAttribute(tag)) + continue; + // Permitted tag names: + // roleA: "child" "subtype" "client" + // roleB: "parent" "supertype" "supplier" + QString idStr = tempElement.attribute(QLatin1String("xmi.id")); + if (idStr.isEmpty()) + idStr = tempElement.attribute(QLatin1String("xmi.idref")); + if (idStr.isEmpty()) { + QDomNode inner = node.firstChild(); + QDomElement tmpElem = inner.toElement(); + idStr = tmpElem.attribute(QLatin1String("xmi.id")); + if (idStr.isEmpty()) + idStr = tmpElem.attribute(QLatin1String("xmi.idref")); + } + if (idStr.isEmpty()) { + uError() << "type " << m_AssocType + << ", id " << Uml::ID::toString(id()) << ": " + << "xmi id not given for " << tag; + continue; + } + // Since we know for sure that we're dealing with a non + // umbrello-kf6 file, use deferred resolution unconditionally. + if (UMLDoc::tagEq(tag, QLatin1String("child")) || + UMLDoc::tagEq(tag, QLatin1String("subtype")) || + UMLDoc::tagEq(tag, QLatin1String("client"))) { + getUMLRole(RoleType::A)->setSecondaryId(idStr); + } else { + getUMLRole(RoleType::B)->setSecondaryId(idStr); + } + } + } + + // it is a realization if either endpoint is an interface + if (isRealization(obj[RoleType::A], obj[RoleType::B])) { + m_AssocType = Uml::AssociationType::Realization; + } + return true; + } + + for (QDomNode node = element.firstChild(); !node.isNull(); + node = node.nextSibling()) { + // uml13.dtd compliant format (new style) + if (node.isComment()) + continue; + QDomElement tempElement = node.toElement(); + QString tag = tempElement.tagName(); + if (Model_Utils::isCommonXMIAttribute(tag)) + continue; + if (!UMLDoc::tagEq(tag, QLatin1String("Association.connection")) && + !UMLDoc::tagEq(tag, QLatin1String("Association.end")) && // Embarcadero's Describe + !UMLDoc::tagEq(tag, QLatin1String("Namespace.ownedElement")) && + !UMLDoc::tagEq(tag, QLatin1String("Namespace.contents"))) { + uWarning() << "unknown child node " << tag; + continue; + } + // Load role A. + QDomNode nodeA = tempElement.firstChild(); + while (nodeA.isComment()) + nodeA = nodeA.nextSibling(); + tempElement = nodeA.toElement(); + if (tempElement.isNull()) { + uWarning() << "UML:Association : element (A) is Null"; + return false; + } + tag = tempElement.tagName(); + if (UMLDoc::tagEq(tag, QLatin1String("NavigableEnd"))) { // Embarcadero's Describe + m_AssocType = Uml::AssociationType::UniAssociation; + } else if (!UMLDoc::tagEq(tag, QLatin1String("AssociationEndRole")) && + !UMLDoc::tagEq(tag, QLatin1String("AssociationEnd"))) { + uWarning() << "unknown child (A) tag " << tag; + return false; + } + if (! getUMLRole(RoleType::A)->loadFromXMI(tempElement)) + return false; + // Load role B. + QDomNode nodeB = nodeA.nextSibling(); + while (nodeB.isComment()) + nodeB = nodeB.nextSibling(); + tempElement = nodeB.toElement(); + if (tempElement.isNull()) { + uWarning() << "UML:Association : element (B) is Null"; + return false; + } + tag = tempElement.tagName(); + if (UMLDoc::tagEq(tag, QLatin1String("NavigableEnd"))) { // Embarcadero's Describe + m_AssocType = Uml::AssociationType::UniAssociation; + } else if (!UMLDoc::tagEq(tag, QLatin1String("AssociationEndRole")) && + !UMLDoc::tagEq(tag, QLatin1String("AssociationEnd"))) { + uWarning() << "unknown child (B) tag " << tag; + return false; + } + if (! getUMLRole(RoleType::B)->loadFromXMI(tempElement)) + return false; + + if (m_pUMLPackage == NULL) { + Uml::ModelType::Enum mt = Model_Utils::convert_OT_MT(getObject(RoleType::B)->baseType()); + m_pUMLPackage = doc->rootFolder(mt); + DEBUG(DBG_SRC) << "setting model type " << Uml::ModelType::toString(mt); + } + + // setting the association type: + // + // In the old days, we could just record this on the association, + // and be done with it. But thats not how the UML13.dtd does things. + // As a result, we are checking roleA for information about the + // parent association (!) which by this point in the parse, should + // be set. However, the information that the roles are allowed to have + // is not complete, so we need to finish the analysis here. + + // find self-associations + if (m_AssocType == Uml::AssociationType::Association && getObjectId(RoleType::A) == getObjectId(RoleType::B)) + m_AssocType = Uml::AssociationType::Association_Self; + + // fall-back default type + if (m_AssocType == Uml::AssociationType::Unknown) { + m_AssocType = Uml::AssociationType::Association; + } + + return true; + } + + // From here on it's old-style stuff. + QString assocTypeStr = element.attribute(QLatin1String("assoctype"), QLatin1String("-1")); + Uml::AssociationType::Enum assocType = Uml::AssociationType::Unknown; + if (assocTypeStr[0] >= QLatin1Char('a') && assocTypeStr[0] <= QLatin1Char('z')) { + // In an earlier version, the natural assoctype names were saved. + const char *assocTypeString[] = { + "generalization", // Uml::AssociationType::Generalization + "aggregation", // Uml::AssociationType::Aggregation + "dependency", // Uml::AssociationType::Dependency + "association", // Uml::AssociationType::Association + "associationself", // Uml::AssociationType::Association_Self + "collmessage", // Uml::AssociationType::Coll_Message + "seqmessage", // Uml::AssociationType::Seq_Message + "collmessageself", // Uml::AssociationType::Coll_Message_Self + "seqmessageself", // Uml::AssociationType::Seq_Message_Self + "implementation", // Uml::AssociationType::Implementation + "composition", // Uml::AssociationType::Composition + "realization", // Uml::AssociationType::Realization + "uniassociation", // Uml::AssociationType::UniAssociation + "anchor", // Uml::AssociationType::Anchor + "state", // Uml::AssociationType::State + "activity", // Uml::AssociationType::Activity + "exception", // Uml::AssociationType::Exception + "category2parent" // Uml::AssociationType::Category2Parent + "child2category" // Uml::AssociationType::Child2Category + "relationship" // Uml::AssociationType::Relationship + }; + const int arraySize = sizeof(assocTypeString) / sizeof(char*); + DEBUG(DBG_SRC) << "AssociationType string array size = " << arraySize; + + int index; + for (index = 0; index < arraySize; ++index) + if (assocTypeStr == QString::fromLatin1(assocTypeString[index])) + break; + if (index < arraySize) + assocType = Uml::AssociationType::fromInt(index); + } else { + int assocTypeNum = assocTypeStr.toInt(); + if (assocTypeNum < (int)Uml::AssociationType::Generalization || // first enum + assocTypeNum >= (int)Uml::AssociationType::Reserved) { // last enum + uWarning() << "bad assoctype of UML:AssociationType::Enum " << Uml::ID::toString(id()); + return false; + } + assocType = Uml::AssociationType::fromInt(assocTypeNum); + } + setAssociationType(assocType); + + Uml::ID::Type roleAObjID = Uml::ID::fromString(element.attribute(QLatin1String("rolea"), QLatin1String("-1"))); + Uml::ID::Type roleBObjID = Uml::ID::fromString(element.attribute(QLatin1String("roleb"), QLatin1String("-1"))); + if (assocType == Uml::AssociationType::Aggregation || + assocType == Uml::AssociationType::Composition) { + // Flip roles to compensate for changed diamond logic in AssociationLine. + // For further explanations see AssociationWidget::loadFromXMI. + Uml::ID::Type tmp = roleAObjID; + roleAObjID = roleBObjID; + roleBObjID = tmp; + } + + UMLObject * objA = doc->findObjectById(roleAObjID); + UMLObject * objB = doc->findObjectById(roleBObjID); + + if(objA) + getUMLRole(RoleType::A)->setObject(objA); + else + return false; + + if(objB) + getUMLRole(RoleType::B)->setObject(objB); + else + return false; + + setMultiplicity(element.attribute(QLatin1String("multia")), RoleType::A); + setMultiplicity(element.attribute(QLatin1String("multib")), RoleType::B); + + setRoleName(element.attribute(QLatin1String("namea")), RoleType::A); + setRoleName(element.attribute(QLatin1String("nameb")), RoleType::B); + + setRoleDoc(element.attribute(QLatin1String("doca")), RoleType::A); + setRoleDoc(element.attribute(QLatin1String("docb")), RoleType::B); + + // Visibility defaults to Public if it cant set it here.. + QString visibilityA = element.attribute(QLatin1String("visibilitya"), QLatin1String("0")); + QString visibilityB = element.attribute(QLatin1String("visibilityb"), QLatin1String("0")); + int vis = visibilityA.toInt(); + if (vis >= 200) // bkwd compat. + vis -= 200; + setVisibility((Uml::Visibility::Enum)vis, RoleType::A); + vis = visibilityB.toInt(); + if (vis >= 200) // bkwd compat. + vis -= 200; + setVisibility((Uml::Visibility::Enum)vis, RoleType::B); + + // Changeability defaults to Changeable if it cant set it here.. + QString changeabilityA = element.attribute(QLatin1String("changeabilitya"), QLatin1String("0")); + QString changeabilityB = element.attribute(QLatin1String("changeabilityb"), QLatin1String("0")); + if (changeabilityA.toInt() > 0) + setChangeability(Uml::Changeability::fromInt(changeabilityA.toInt()), RoleType::A); + if (changeabilityB.toInt() > 0) + setChangeability(Uml::Changeability::fromInt(changeabilityB.toInt()), RoleType::B); + + return true; +} + +/** + * Returns the UMLObject assigned to the given role. + * @return Pointer to the UMLObject in the given role. + */ +UMLObject* UMLAssociation::getObject(Uml::RoleType::Enum role) const +{ + if (m_pRole[role] == NULL) + return NULL; + return m_pRole[role]->object(); +} + +/** + * Returns the ID of the UMLObject assigned to the given role. + * Shorthand for getObject(role)->ID(). + * @return ID of the UMLObject in the given role. + */ +Uml::ID::Type UMLAssociation::getObjectId(Uml::RoleType::Enum role) const +{ + UMLRole *roleObj = m_pRole[role]; + if (roleObj == NULL) + return Uml::ID::None; + UMLObject *o = roleObj->object(); + if (o == NULL) { + QString auxID = roleObj->secondaryId(); + if (auxID.isEmpty()) { + uError() << "role " << role << ": getObject returns NULL"; + return Uml::ID::None; + } else { + DEBUG(DBG_SRC) << "role " << role << ": using secondary ID " << auxID; + return Uml::ID::fromString(auxID); + } + } + return o->id(); +} + +/** + * Returns the ID of the UMLObject assigned to the given role. + * CURRENTLY UNUSED. + * @return ID of the UMLObject of the given role. + */ +Uml::ID::Type UMLAssociation::getRoleId(RoleType::Enum role) const +{ + return m_pRole[role]->id(); +} + +/** + * Returns the changeability. + */ +Uml::Changeability::Enum UMLAssociation::changeability(Uml::RoleType::Enum role) const +{ + return m_pRole[role]->changeability(); +} + +/** + * Returns the Visibility of the given role. + * @return Visibility of the given role. + */ +Uml::Visibility::Enum UMLAssociation::visibility(Uml::RoleType::Enum role) const +{ + return m_pRole[role]->visibility(); +} + +/** + * Returns the multiplicity assigned to the given role. + * @return The multiplicity assigned to the given role. + */ +QString UMLAssociation::getMultiplicity(Uml::RoleType::Enum role) const +{ + return m_pRole[role]->multiplicity(); +} + +/** + * Returns the name assigned to the role A. + * @return The name assigned to the given role. + */ +QString UMLAssociation::getRoleName(Uml::RoleType::Enum role) const +{ + return m_pRole[role]->name(); +} + +/** + * Returns the documentation assigned to the given role. + * @return Documentation text of given role. + */ +QString UMLAssociation::getRoleDoc(Uml::RoleType::Enum role) const +{ + return m_pRole[role]->doc(); +} + +/** + * Get the underlying UMLRole object for the given role. + * @return Pointer to the UMLRole object for the given role. + */ +UMLRole * UMLAssociation::getUMLRole(Uml::RoleType::Enum role) const +{ + return m_pRole[role]; +} + +/** + * Set the attribute m_bOldLoadMode. + * @param value the new value to set + */ +void UMLAssociation::setOldLoadMode(bool value /* = true */) +{ + m_bOldLoadMode = value; +} + +/** + * Return the backward compatibility flag for loading files. + */ +bool UMLAssociation::getOldLoadMode() const +{ + return m_bOldLoadMode; +} + +/** + * Sets the assocType of the UMLAssociation. + * @param assocType The AssociationType::Enum of the UMLAssociation. + */ +void UMLAssociation::setAssociationType(Uml::AssociationType::Enum assocType) +{ + m_AssocType = assocType; + if (m_AssocType == Uml::AssociationType::UniAssociation) + { + // In this case we need to auto-set the multiplicity/rolenames + // of the roles +#ifdef VERBOSE_DEBUGGING + DEBUG(DBG_SRC) << " A new uni-association has been created."; +#endif + } + UMLObject::emitModified(); +} + +/** + * Sets the UMLObject playing the given role in the association. + * @param obj Pointer to the UMLObject of the given role. + * @param role The Uml::RoleType::Enum played by the association + */ +void UMLAssociation::setObject(UMLObject *obj, Uml::RoleType::Enum role) +{ + m_pRole[role]->setObject(obj); +} + +/** + * Sets the visibility of the given role of the UMLAssociation. + * @param value Visibility of role. + * @param role The Uml::RoleType::Enum to which the visibility is being applied + */ +void UMLAssociation::setVisibility(Visibility::Enum value, Uml::RoleType::Enum role) +{ + m_pRole[role]->setVisibility(value); +} + +/** + * Sets the changeability of the given role of the UMLAssociation. + * @param value Changeability_Type of the given role. + * @param role The Uml::RoleType::Enum to which the changeability is being set + */ +void UMLAssociation::setChangeability(Uml::Changeability::Enum value, Uml::RoleType::Enum role) +{ + m_pRole[role]->setChangeability(value); +} + +/** + * Sets the multiplicity of the given role of the UMLAssociation. + * @param multi The multiplicity of the given role. + * @param role The Uml::RoleType::Enum to which the multiplicity is being applied + */ +void UMLAssociation::setMultiplicity(const QString &multi, Uml::RoleType::Enum role) +{ + if (m_pRole[role]->multiplicity() != multi) { + UMLApp::app()->executeCommand(new CmdChangeMultiplicity(m_pRole[role], multi)); + } +} + +/** + * Sets the name of the given role of the UMLAssociation. + * @param roleName The name to set for the given role. + * @param role The Uml::RoleType::Enum for which to set the name. + */ +void UMLAssociation::setRoleName(const QString &roleName, Uml::RoleType::Enum role) +{ + m_pRole[role]->setName(roleName); +} + +/** + * Sets the documentation on the given role in the association. + * @param doc The string with the documentation. + * @param role The Uml::RoleType::Enum to which the documentation is being applied + */ +void UMLAssociation::setRoleDoc(const QString &doc, Uml::RoleType::Enum role) +{ + m_pRole[role]->setDoc(doc); +} + +/** + * When the association type is "Generalization" and at least one of the + * given objects an interface, then it is a "Realization". + * @param objA UML object as role A + * @param objB UML object as role B + * @return flag whether association is a realization + */ +bool UMLAssociation::isRealization(UMLObject* objA, UMLObject* objB) const +{ + bool aIsInterface = false; + if (objA && (objA->baseType() == UMLObject::ot_Interface)) { + aIsInterface = true; + } + bool bIsInterface = false; + if (objB && (objB->baseType() == UMLObject::ot_Interface)) { + bIsInterface = true; + } + return (m_AssocType == Uml::AssociationType::Generalization) && + (aIsInterface || bIsInterface); +} + +/** + * Common initializations at construction time. + * @param type The AssociationType::Enum to represent. + * @param roleAObj Pointer to the role A UMLObject. + * @param roleBObj Pointer to the role B UMLObject. + */ +void UMLAssociation::init(Uml::AssociationType::Enum type, UMLObject *roleAObj, UMLObject *roleBObj) +{ + m_AssocType = type; + m_BaseType = ot_Association; + m_Name = QString(); + m_bOldLoadMode = false; + nrof_parent_widgets = -1; + if (!UMLApp::app()->document()->loading()) { + m_pUMLPackage = UMLApp::app()->document()->currentRoot(); + } + m_pRole[RoleType::A] = new UMLRole (this, roleAObj, RoleType::A); + m_pRole[RoleType::B] = new UMLRole (this, roleBObj, RoleType::B); +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/association.h umbrello-kf6-15.08.1/umbrello/umlmodel/association.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/association.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/association.h 2015-10-08 11:48:59.506089026 +0300 @@ -0,0 +1,102 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef ASSOCIATION_H +#define ASSOCIATION_H + +#include "basictypes.h" +#include "umlobject.h" + +#include +#include + +class UMLRole; + +/** + * This class contains the non-graphic representation of an association. + * An association can be a generalization, realization, simple association, + * directed association, aggregation, or composition. + * + * @short Sets up association information. + * @author Oliver Kellogg + * @see UMLObject + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class UMLAssociation : public UMLObject +{ + Q_OBJECT + friend class AssociationWidget; + +public: + UMLAssociation(Uml::AssociationType::Enum type, UMLObject *roleA, UMLObject *roleB); + explicit UMLAssociation(Uml::AssociationType::Enum type = Uml::AssociationType::Unknown); + + virtual ~UMLAssociation(); + + bool operator==(const UMLAssociation &rhs) const; + + QString toString() const; + + UMLRole * getUMLRole(Uml::RoleType::Enum role) const; + Uml::ID::Type getObjectId(Uml::RoleType::Enum role) const; + Uml::ID::Type getRoleId(Uml::RoleType::Enum role) const; + + void setAssociationType(Uml::AssociationType::Enum assocType); + Uml::AssociationType::Enum getAssocType() const; + + void setObject(UMLObject *obj, Uml::RoleType::Enum role); + UMLObject* getObject(Uml::RoleType::Enum role) const; + + void setVisibility(Uml::Visibility::Enum value, Uml::RoleType::Enum role); + Uml::Visibility::Enum visibility(Uml::RoleType::Enum role) const; + + void setChangeability(Uml::Changeability::Enum value, Uml::RoleType::Enum role); + Uml::Changeability::Enum changeability(Uml::RoleType::Enum role) const; + + void setMultiplicity(const QString &multi, Uml::RoleType::Enum role); + QString getMultiplicity(Uml::RoleType::Enum role) const; + + void setRoleName(const QString &roleName, Uml::RoleType::Enum role); + QString getRoleName(Uml::RoleType::Enum role) const; + + void setRoleDoc(const QString &doc, Uml::RoleType::Enum role); + QString getRoleDoc(Uml::RoleType::Enum role) const; + + void setOldLoadMode(bool value = true); + bool getOldLoadMode() const; + + virtual UMLObject* clone() const { return NULL; } + + virtual bool resolveRef(); + + void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); + + virtual bool showPropertiesDialog(QWidget *parent = 0); + +protected: + + bool load(QDomElement& element); + + // keep track of number of parent widgets + int nrof_parent_widgets; + + void init(Uml::AssociationType::Enum type, UMLObject *roleAObj, UMLObject *roleBObj); + + UMLRole * m_pRole[2]; + Uml::AssociationType::Enum m_AssocType; + QString m_Name; + bool m_bOldLoadMode; + +private: + + bool isRealization(UMLObject* objA, UMLObject* objB) const; +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/attribute.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/attribute.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/attribute.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/attribute.cpp 2015-10-08 11:48:59.506089026 +0300 @@ -0,0 +1,424 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "attribute.h" + +// app includes +#include "debug_utils.h" +#include "classifier.h" +#include "operation.h" +#include "umlobject.h" +#include "umldoc.h" +#include "uml.h" +#include "folder.h" +#include "umlattributedialog.h" +#include "object_factory.h" + +/** + * Sets up an attribute. + * + * @param parent The parent of this UMLAttribute. + * @param name The name of this UMLAttribute. + * @param id The unique id given to this UMLAttribute. + * @param s The visibility of the UMLAttribute. + * @param type The type of this UMLAttribute. + * @param iv The initial value of the attribute. + */ +UMLAttribute::UMLAttribute(UMLObject *parent, + const QString& name, Uml::ID::Type id, + Uml::Visibility::Enum s, + UMLObject *type, const QString& iv) + : UMLClassifierListItem(parent, name, id) +{ + m_InitialValue = iv; + m_BaseType = UMLObject::ot_Attribute; + m_visibility = s; + m_ParmKind = Uml::ParameterDirection::In; + /* CHECK: Do we need this: + if (type == NULL) { + type = Object_Factory::createUMLObject(Uml::ot_Datatype, "undef"); + } + */ + m_pSecondary = type; +} + +/** + * Sets up an attribute. + * + * @param parent The parent of this UMLAttribute. + */ +UMLAttribute::UMLAttribute(UMLObject *parent) : UMLClassifierListItem(parent) +{ + m_BaseType = UMLObject::ot_Attribute; + m_visibility = Uml::Visibility::Private; + m_ParmKind = Uml::ParameterDirection::In; +} + +/** + * Destructor. + */ +UMLAttribute::~UMLAttribute() +{ +} + +/** + * Reimplementation of method from UMLObject is required as + * an extra signal, attributeChanged(), is emitted. + */ +void UMLAttribute::setName(const QString &name) +{ + m_name = name; + emit attributeChanged(); + UMLObject::emitModified(); +} + +/** + * Reimplementation of method from UMLObject is required as + * an extra signal, attributeChanged(), is emitted. + */ +void UMLAttribute::setVisibility(Uml::Visibility::Enum s) +{ + m_visibility = s; + emit attributeChanged(); + UMLObject::emitModified(); +} + +/** + * Returns The initial value of the UMLAttribute. + * + * @return The initial value of the Atrtibute. + */ +QString UMLAttribute::getInitialValue() const +{ + return m_InitialValue; +} + +/** + * Sets the initial value of the UMLAttribute. + * + * @param iv The initial value of the UMLAttribute. + */ +void UMLAttribute::setInitialValue(const QString &iv) +{ + if(m_InitialValue != iv) { + m_InitialValue = iv; + UMLObject::emitModified(); + } +} + +void UMLAttribute::setParmKind (Uml::ParameterDirection::Enum pk) +{ + m_ParmKind = pk; +} + +Uml::ParameterDirection::Enum UMLAttribute::getParmKind() const +{ + return m_ParmKind; +} + +/** + * Returns a string representation of the UMLAttribute. + * + * @param sig If true will show the attribute type and initial value. + * @return Returns a string representation of the UMLAttribute. + */ +QString UMLAttribute::toString(Uml::SignatureType::Enum sig) +{ + QString s; + + if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::NoSig) { + s = Uml::Visibility::toString(m_visibility, true) + QLatin1Char(' '); + } + + if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::SigNoVis) { + // Determine whether the type name needs to be scoped. + UMLObject *owningObject = static_cast(parent()); + if (owningObject->baseType() == UMLObject::ot_Operation) { + // The immediate parent() is the UMLOperation but we want + // the UMLClassifier: + owningObject = static_cast(owningObject->parent()); + } + UMLClassifier *ownParent = dynamic_cast(owningObject); + if (ownParent == NULL) { + uError() << "parent " << owningObject->name() + << " is not a UMLClassifier"; + return QString(); + } + QString typeName; + UMLClassifier *type = UMLClassifierListItem::getType(); + if (type) { + UMLPackage *typeScope = type->umlPackage(); + if (typeScope != ownParent && typeScope != ownParent->umlPackage()) + typeName = type->fullyQualifiedName(); + else + typeName = type->name(); + } + // The default direction, "in", is not mentioned. + // Perhaps we should include a pd_Unspecified in + // Uml::ParameterDirection::Enum to have better control over this. + if (m_ParmKind == Uml::ParameterDirection::InOut) + s += QLatin1String("inout "); + else if (m_ParmKind == Uml::ParameterDirection::Out) + s += QLatin1String("out "); + // Construct the attribute text. + QString string = s + name() + QLatin1String(" : ") + typeName; + if (m_InitialValue.length() > 0) + string += QLatin1String(" = ") + m_InitialValue; + return string; + } + return s + name(); +} + +/** + * Reimplement method from UMLObject. + */ +QString UMLAttribute::getFullyQualifiedName(const QString& separator, + bool includeRoot /* = false */) const +{ + UMLOperation *op = NULL; + UMLObject *owningObject = static_cast(parent()); + if (owningObject->baseType() == UMLObject::ot_Operation) { + op = static_cast(owningObject); + owningObject = static_cast(owningObject->parent()); + } + UMLClassifier *ownParent = dynamic_cast(owningObject); + if (ownParent == NULL) { + uError() << name() << ": parent " << owningObject->name() + << " is not a UMLClassifier"; + return QString(); + } + QString tempSeparator = separator; + if (tempSeparator.isEmpty()) + tempSeparator = UMLApp::app()->activeLanguageScopeSeparator(); + QString fqn = ownParent->fullyQualifiedName(tempSeparator, includeRoot); + if (op) + fqn.append(tempSeparator + op->name()); + fqn.append(tempSeparator + name()); + return fqn; +} + +/** + * Overloaded '==' operator + */ +bool UMLAttribute::operator==(const UMLAttribute &rhs) const +{ + if(this == &rhs) + return true; + + if(!UMLObject::operator==(rhs)) + return false; + + // The type name is the only distinguishing criterion. + // (Some programming languages might support more, but others don't.) + if (m_pSecondary != rhs.m_pSecondary) + return false; + + return true; +} + +/** + * Copy the internal presentation of this object into the UMLAttribute + * object. + */ +void UMLAttribute::copyInto(UMLObject *lhs) const +{ + UMLAttribute *target = static_cast(lhs); + // call the parent first. + UMLClassifierListItem::copyInto(target); + + // Copy all datamembers + target->m_pSecondary = m_pSecondary; + target->m_SecondaryId = m_SecondaryId; + target->m_InitialValue = m_InitialValue; + target->m_ParmKind = m_ParmKind; +} + +/** + * Make a clone of the UMLAttribute. + */ +UMLObject* UMLAttribute::clone() const +{ + //FIXME: The new attribute should be slaved to the NEW parent not the old. + UMLAttribute *clone = new UMLAttribute(static_cast(parent())); + copyInto(clone); + + return clone; +} + +/** + * Creates the XMI element. + */ +void UMLAttribute::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +{ + QDomElement attributeElement = UMLObject::save(QLatin1String("UML:Attribute"), qDoc); + if (m_pSecondary == NULL) { + uDebug() << name() << ": m_pSecondary is NULL, m_SecondaryId is '" + << m_SecondaryId << "'"; + } else { + attributeElement.setAttribute(QLatin1String("type"), Uml::ID::toString(m_pSecondary->id())); + } + if (! m_InitialValue.isEmpty()) + attributeElement.setAttribute(QLatin1String("initialValue"), m_InitialValue); + qElement.appendChild(attributeElement); +} + +/** + * Loads the XMI element. + */ +bool UMLAttribute::load(QDomElement & element) +{ + m_SecondaryId = element.attribute(QLatin1String("type")); + // We use the m_SecondaryId as a temporary store for the xmi.id + // of the attribute type model object. + // It is resolved later on, when all classes have been loaded. + // This deferred resolution is required because the xmi.id may + // be a forward reference, i.e. it may identify a model object + // that has not yet been loaded. + if (m_SecondaryId.isEmpty()) { + // Perhaps the type is stored in a child node: + QDomNode node = element.firstChild(); + while (!node.isNull()) { + if (node.isComment()) { + node = node.nextSibling(); + continue; + } + QDomElement tempElement = node.toElement(); + QString tag = tempElement.tagName(); + if (!UMLDoc::tagEq(tag, QLatin1String("type"))) { + node = node.nextSibling(); + continue; + } + m_SecondaryId = Model_Utils::getXmiId(tempElement); + if (m_SecondaryId.isEmpty()) + m_SecondaryId = tempElement.attribute(QLatin1String("xmi.idref")); + if (m_SecondaryId.isEmpty()) { + QString href = tempElement.attribute(QLatin1String("href")); + if (href.isEmpty()) { + QDomNode inner = node.firstChild(); + QDomElement tmpElem = inner.toElement(); + m_SecondaryId = Model_Utils::getXmiId(tmpElem); + if (m_SecondaryId.isEmpty()) + m_SecondaryId = tmpElem.attribute(QLatin1String("xmi.idref")); + } else { + int hashpos = href.lastIndexOf(QChar(QLatin1Char('#'))); + if (hashpos < 0) { + uDebug() << name() << ": cannot find type " << href; + } else { + QString typeName = href.mid(hashpos + 1); + UMLFolder *dtFolder = UMLApp::app()->document()->datatypeFolder(); + m_pSecondary = Model_Utils::findUMLObject(dtFolder->containedObjects(), + typeName, UMLObject::ot_Datatype); + if (!m_pSecondary) { + m_pSecondary = Object_Factory::createUMLObject(UMLObject::ot_Datatype, + typeName, dtFolder); + } + } + } + } + break; + } + if (m_SecondaryId.isEmpty()) { + uDebug() << name() << ": cannot find type."; + } + } + m_InitialValue = element.attribute(QLatin1String("initialValue")); + if (m_InitialValue.isEmpty()) { + // for backward compatibility + m_InitialValue = element.attribute(QLatin1String("value")); + } + return true; +} + +/** + * Display the properties configuration dialog for the attribute. + */ +bool UMLAttribute::showPropertiesDialog(QWidget* parent) +{ + UMLAttributeDialog dialog(parent, this); + return dialog.exec(); +} + +/** + * Puts in the param templateParamList all the template params that are in templateParam + */ +void UMLAttribute::setTemplateParams(const QString& templateParam, UMLClassifierList &templateParamList) +{ + if (templateParam.isEmpty()) + return; + QString type = templateParam.simplified(); + + int start = type.indexOf(QLatin1Char('<')); + if (start >= 0) { + int end = start; + int count = 1; + int len = type.length(); + while (count != 0 && ++end < len) { + QChar c = type.at(end); + if (c == QLatin1Char('<')) { + count++; + } + if (c == QLatin1Char('>')) { + count--; + } + } + if (count != 0) { + //The template is ill-formated, let's quit + return; + } + setTemplateParams(type.mid(start + 1, end - start - 1), templateParamList); + setTemplateParams(type.left(start) + type.right(len - end - 1), templateParamList); + } else { + QStringList paramsList = type.split(QLatin1Char(',')); + for (QStringList::Iterator it = paramsList.begin(); it != paramsList.end(); ++it) { + QString param = *it; + if (!param.isEmpty()) { + UMLDoc *pDoc = UMLApp::app()->document(); + UMLObject* obj = pDoc->findUMLObject(param); + if (obj == NULL) { + obj = pDoc->findUMLObject(param.remove(QLatin1Char(' '))); + } + if (obj != NULL) { + //We want to list only the params that already exist in this document + //If the param doesnt't already exist, we couldn't draw an association anyway + UMLClassifier* tmpClassifier = static_cast(obj); + if (templateParamList.indexOf(tmpClassifier) == -1) { + templateParamList.append(tmpClassifier); + } + } + } + } + } +} + +/** + * Returns all the template params (if any) that are in the type of this attribute + */ +UMLClassifierList UMLAttribute::getTemplateParams() +{ + UMLClassifierList templateParamList; + QString type = getType()->name(); + QString templateParam; + // Handle C++/D/Java template/generic parameters + const Uml::ProgrammingLanguage::Enum pl = UMLApp::app()->activeLanguage(); + if (pl == Uml::ProgrammingLanguage::Cpp || + pl == Uml::ProgrammingLanguage::Java || pl == Uml::ProgrammingLanguage::D) { + int start = type.indexOf(QLatin1Char('<')); + if (start >= 0) { + int end = type.lastIndexOf(QLatin1Char('>')); + if (end > start) { + templateParam = type.mid(start + 1, end - start - 1); + setTemplateParams(templateParam, templateParamList); + } + } + } + return templateParamList; +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/attribute.h umbrello-kf6-15.08.1/umbrello/umlmodel/attribute.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/attribute.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/attribute.h 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,84 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef ATTRIBUTE_H +#define ATTRIBUTE_H + +#include "basictypes.h" +#include "classifierlistitem.h" +#include "umlclassifierlist.h" + +/** + * This class is used to set up information for an attribute. This is like + * a programming attribute. It has a type, name, visibility and initial value. + * + * @short Sets up attribute information. + * @author Paul Hensgen + * @see UMLObject + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class UMLAttribute : public UMLClassifierListItem +{ + Q_OBJECT +public: + + UMLAttribute(UMLObject *parent, const QString& name, + Uml::ID::Type id = Uml::ID::None, + Uml::Visibility::Enum s = Uml::Visibility::Private, + UMLObject *type = 0, const QString& iv = QString()); + explicit UMLAttribute(UMLObject *parent); + + bool operator==(const UMLAttribute &rhs) const; + + virtual ~UMLAttribute(); + + virtual void copyInto(UMLObject *lhs) const; + + void setName(const QString &name); + + void setVisibility(Uml::Visibility::Enum s); + + virtual UMLObject* clone() const; + + QString getInitialValue() const; + void setInitialValue(const QString &iv); + + QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); + + QString getFullyQualifiedName(const QString& separator = QString(), + bool includeRoot = false) const; + + virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); + + virtual bool showPropertiesDialog(QWidget* parent = 0); + + void setParmKind(Uml::ParameterDirection::Enum pk); + Uml::ParameterDirection::Enum getParmKind() const; + + virtual UMLClassifierList getTemplateParams(); + +signals: + + void attributeChanged(); + +protected: + + bool load(QDomElement & element); + + QString m_InitialValue; ///< text for the attribute's initial value. + Uml::ParameterDirection::Enum m_ParmKind; + +private: + + void setTemplateParams(const QString& templateParam, UMLClassifierList &templateParamList); + +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/category.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/category.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/category.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/category.cpp 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,101 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#include "category.h" + +/** + * Constructs a Category. + * + * @param name The name of the Category. + * @param id The unique id to assign to this Category. + */ +UMLCategory::UMLCategory(const QString & name, Uml::ID::Type id) + : UMLCanvasObject(name, id) +{ + init(); +} + +/** + * Standard destructor. + */ +UMLCategory::~UMLCategory() +{ +} + +/** + * Initializes key variables of the class. + */ +void UMLCategory::init() +{ + m_BaseType = UMLObject::ot_Category; + m_CategoryType = ct_Disjoint_Specialisation; +} + +/** + * Copy the internal presentation of this object into the new + * object. + */ +void UMLCategory::copyInto(UMLObject *lhs) const +{ + UMLCategory *target = static_cast(lhs); + + // call the parent first + UMLCanvasObject::copyInto(target); + + target->m_CategoryType = m_CategoryType; +} + +/** + * Make a clone of this object. + */ +UMLObject* UMLCategory::clone() const +{ + UMLCategory *clone = new UMLCategory(); + copyInto(clone); + return clone; +} + +/** + * Creates the XMI element. + */ +void UMLCategory::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +{ + QDomElement categoryElement = UMLObject::save(QLatin1String("UML:Category"), qDoc); + categoryElement.setAttribute(QLatin1String("categoryType"), (int)m_CategoryType); + qElement.appendChild(categoryElement); +} + +/** + * Loads the XMI element (empty.) + */ +bool UMLCategory::load(QDomElement& element) +{ + m_CategoryType = (Category_Type)element.attribute(QLatin1String("categoryType"), + QLatin1String("0")).toInt(); + return true; +} + +/** + * Get the category type + */ +UMLCategory::Category_Type UMLCategory::getType() +{ + return m_CategoryType; +} + +/** + * Set the category type + */ +void UMLCategory::setType(Category_Type type) +{ + m_CategoryType = type; + emitModified(); +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/category.h umbrello-kf6-15.08.1/umbrello/umlmodel/category.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/category.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/category.h 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,62 @@ +/*************************************************************************** + * * + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef CATEGORY_H +#define CATEGORY_H + +#include "umlcanvasobject.h" + +/** + * This class contains the non-graphical information required for a UML Category. + * This class inherits from @ref UMLCanvasObject which contains most of the + * information. + * The @ref UMLDoc class creates instances of this type. + * + * @short Information for a non-graphical UML Category. + * @author Sharan Rao + * @see UMLCanvasObject + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class UMLCategory : public UMLCanvasObject { + Q_OBJECT +public: + + enum Category_Type { + ct_Disjoint_Specialisation, + ct_Overlapping_Specialisation, + ct_Union + }; + + explicit UMLCategory(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); + ~UMLCategory(); + + virtual void init(); + + void copyInto(UMLObject *lhs) const; + + virtual UMLObject* clone() const; + + void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); + + UMLCategory::Category_Type getType(); + + void setType(Category_Type type); + +protected: + + bool load(QDomElement & element); + +private: + + Category_Type m_CategoryType; +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/checkconstraint.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/checkconstraint.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/checkconstraint.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/checkconstraint.cpp 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,160 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +//own header +#include "checkconstraint.h" + +// app includes +#include "debug_utils.h" +#include "umlcheckconstraintdialog.h" + +/** + * Sets up a constraint. + * + * @param parent The parent of this UMLCheckConstraint. + * @param name The name of this UMLCheckConstraint. + * @param id The unique id given to this UMLCheckConstraint. + */ +UMLCheckConstraint::UMLCheckConstraint(UMLObject *parent, + const QString& name, Uml::ID::Type id) + : UMLEntityConstraint(parent, name, id) +{ + init(); +} + +/** + * Sets up a constraint. + * + * @param parent The parent of this UMLCheckConstraint. + */ +UMLCheckConstraint::UMLCheckConstraint(UMLObject *parent) + : UMLEntityConstraint(parent) +{ + init(); +} + +/** + * Overloaded '==' operator. + */ +bool UMLCheckConstraint::operator==(const UMLCheckConstraint &rhs) const +{ + if (this == &rhs) + return true; + + if (!UMLObject::operator==(rhs)) + return false; + + return true; +} + +/** + * Destructor. + */ +UMLCheckConstraint::~UMLCheckConstraint() +{ +} + +/** + * Copy the internal presentation of this object into the UMLCheckConstraint + * object. + */ +void UMLCheckConstraint::copyInto(UMLObject *lhs) const +{ + UMLCheckConstraint *target = static_cast(lhs); + + // call the parent first. + UMLEntityConstraint::copyInto(target); + + // Copy all datamembers + target->m_CheckCondition = m_CheckCondition; +} + +/** + * Make a clone of the UMLCheckConstraint. + */ +UMLObject* UMLCheckConstraint::clone() const +{ + //FIXME: The new attribute should be slaved to the NEW parent not the old. + UMLCheckConstraint *clone = new UMLCheckConstraint(static_cast(parent())); + copyInto(clone); + return clone; +} + +/** + * Returns a string representation of the UMLCheckConstraint. + * + * @param sig If true will show the attribute type and initial value. + * @return Returns a string representation of the UMLAttribute. + */ +QString UMLCheckConstraint::toString(Uml::SignatureType::Enum sig) +{ + QString s; + + if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::SigNoVis) { + s = name() ; + } + + return s; +} + +QString UMLCheckConstraint::getFullyQualifiedName(const QString& separator, + bool includeRoot) const +{ + Q_UNUSED(separator); Q_UNUSED(includeRoot); + return this->name(); +} + +/** + * Creates the XMI element. + */ +void UMLCheckConstraint::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +{ + QDomElement checkConstraintElement = UMLObject::save(QLatin1String("UML:CheckConstraint"), qDoc); + + QDomNode checkCondition = qDoc.createTextNode(m_CheckCondition); + checkConstraintElement.appendChild(checkCondition); + + qElement.appendChild(checkConstraintElement); +} + +/** + * Display the properties configuration dialog for the attribute. + */ +bool UMLCheckConstraint::showPropertiesDialog(QWidget* parent) +{ + UMLCheckConstraintDialog dialog(parent, this); + return dialog.exec(); +} + +/** + * Loads the XMI element. + */ +bool UMLCheckConstraint::load(QDomElement & element) +{ + QDomNode node = element.firstChild(); + + QDomText checkConstraintText = node.toText(); + if (checkConstraintText.isNull()) + m_CheckCondition = QString(); + else + m_CheckCondition = checkConstraintText.data(); + + return true; +} + +/** + * Initialises Check Constraint + */ +void UMLCheckConstraint::init() +{ + m_BaseType = UMLObject::ot_CheckConstraint; + m_CheckCondition.clear(); +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/checkconstraint.h umbrello-kf6-15.08.1/umbrello/umlmodel/checkconstraint.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/checkconstraint.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/checkconstraint.h 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,71 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef CHECKCONSTRAINT_H +#define CHECKCONSTRAINT_H + +#include "basictypes.h" +#include "entityconstraint.h" + +/** + * This class is used to set up information for a unique entity constraint. + * + * @short Sets up Check Constraint information for UMLEntities. + * @author Sharan Rao + * @see UMLObject UMLClassifierListItem UMLEntityConstraint + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class UMLCheckConstraint : public UMLEntityConstraint +{ + Q_OBJECT +public: + + UMLCheckConstraint(UMLObject *parent, const QString& name, + Uml::ID::Type id = Uml::ID::None); + explicit UMLCheckConstraint(UMLObject *parent); + + bool operator==(const UMLCheckConstraint &rhs) const; + + virtual ~UMLCheckConstraint(); + + virtual void copyInto(UMLObject *lhs) const; + + virtual UMLObject* clone() const; + + QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); + + QString getFullyQualifiedName(const QString& separator = QString(), + bool includeRoot = false) const; + + void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); + + virtual bool showPropertiesDialog(QWidget* parent = 0); + + QString getCheckCondition() const { + return m_CheckCondition; + } + + void setCheckCondition(const QString& condition) { + m_CheckCondition = condition.trimmed(); + } + +protected: + + bool load(QDomElement & element); + +private: + + void init(); + + QString m_CheckCondition; ///< the check condition + +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/classifier.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/classifier.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/classifier.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/classifier.cpp 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,1631 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ +#include "classifier.h" + +// app includes +#include "association.h" +#include "debug_utils.h" +#include "umlassociationlist.h" +#include "operation.h" +#include "attribute.h" +#include "template.h" +#include "enumliteral.h" +#include "entityattribute.h" +#include "enum.h" +#include "entity.h" +#include "stereotype.h" +#include "umldoc.h" +#include "uml.h" +#include "uniqueid.h" +#include "object_factory.h" +#include "model_utils.h" +#include "idchangelog.h" +#include "umloperationdialog.h" +#include "umlattributedialog.h" +#include "umltemplatedialog.h" +#include "optionstate.h" +#include "icon_utils.h" + +// kde includes +#include +#include + +// qt includes +#include + +using namespace Uml; + +/** + * @brief holds set of classifiers for recursive loop detection + */ +class UMLClassifierSet: public QSet { +public: + UMLClassifierSet() : level(0) + { + } + int level; +}; + +/** + * Sets up a Classifier. + * + * @param name The name of the Concept. + * @param id The unique id of the Concept. + */ +UMLClassifier::UMLClassifier(const QString & name, Uml::ID::Type id) + : UMLPackage(name, id) +{ + m_BaseType = UMLObject::ot_Class; // default value + m_pClassAssoc = NULL; + m_isRef = false; +} + +/** + * Standard deconstructor. + */ +UMLClassifier::~UMLClassifier() +{ +} + +/** + * Reimplementation of method from class UMLObject for controlling the + * exact type of this classifier: class, interface, or datatype. + * @param ot the base type to set + */ +void UMLClassifier::setBaseType(UMLObject::ObjectType ot) +{ + m_BaseType = ot; + Icon_Utils::IconType newIcon; + switch (ot) { + case ot_Interface: + UMLObject::setStereotypeCmd(QLatin1String("interface")); + UMLObject::m_bAbstract = true; + newIcon = Icon_Utils::it_Interface; + break; + case ot_Class: + UMLObject::setStereotypeCmd(QString()); + UMLObject::m_bAbstract = false; + newIcon = Icon_Utils::it_Class; + break; + case ot_Datatype: + UMLObject::setStereotypeCmd(QLatin1String("datatype")); + UMLObject::m_bAbstract = false; + newIcon = Icon_Utils::it_Datatype; + break; + case ot_Package: + UMLObject::setStereotypeCmd(QString()); + UMLObject::m_bAbstract = false; + newIcon = Icon_Utils::it_Package; + break; + default: + uError() << "cannot set to type " << ot; + return; + } + Model_Utils::treeViewChangeIcon(this, newIcon); +} + +/** + * Returns true if this classifier represents an interface. + */ +bool UMLClassifier::isInterface() const +{ + return (m_BaseType == ot_Interface); +} + +/** + * Returns true if this classifier represents a datatype. + */ +bool UMLClassifier::isDatatype() const +{ + return (m_BaseType == ot_Datatype); +} + +/** + * Checks whether an operation is valid based on its signature - + * An operation is "valid" if the operation's name and parameter list + * are unique in the classifier. + * + * @param name Name of the operation to check. + * @param opParams The operation's argument list. + * @param exemptOp Pointer to the exempt method (optional.) + * @return NULL if the signature is valid (ok), else return a pointer + * to the existing UMLOperation that causes the conflict. + */ +UMLOperation * UMLClassifier::checkOperationSignature( + const QString& name, + UMLAttributeList opParams, + UMLOperation *exemptOp) +{ + UMLOperationList list = findOperations(name); + if (list.count() == 0) { + return NULL; + } + const int inputParmCount = opParams.count(); + + // there is at least one operation with the same name... compare the parameter list + foreach (UMLOperation* test, list) { + if (test == exemptOp) { + continue; + } + UMLAttributeList testParams = test->getParmList(); + const int pCount = testParams.count(); + if (pCount != inputParmCount) { + continue; + } + int i = 0; + while (i < pCount) { + // The only criterion for equivalence is the parameter types. + // (Default values are not considered.) + if(testParams.at(i)->getTypeName() != opParams.at(i)->getTypeName()) + break; + i++; + } + if (i == pCount) { // all parameters matched->the signature is not unique + return test; + } + } + // we did not find an exact match, so the signature is unique (acceptable) + return NULL; +} + +/** + * Find an operation of the given name and parameter signature. + * + * @param name The name of the operation to find. + * @param params The parameter descriptors of the operation to find. + * + * @return The operation found. Will return 0 if none found. + */ +UMLOperation* UMLClassifier::findOperation(const QString& name, + Model_Utils::NameAndType_List params) +{ + UMLOperationList list = findOperations(name); + if (list.count() == 0) { + return NULL; + } + // if there are operation(s) with the same name then compare the parameter list + const int inputParmCount = params.count(); + + foreach (UMLOperation* test, list) { + UMLAttributeList testParams = test->getParmList(); + const int pCount = testParams.count(); + if (inputParmCount == 0 && pCount == 0) + return test; + if (inputParmCount != pCount) + continue; + int i = 0; + for (; i < pCount; ++i) { + Model_Utils::NameAndType_ListIt nt(params.begin() + i); + UMLClassifier *type = dynamic_cast((*nt).m_type); + UMLClassifier *testType = testParams.at(i)->getType(); + if (type == NULL && testType == NULL) { //no parameter type + continue; + } else if (type == NULL) { //template parameter + if (testType->name() != QLatin1String("class")) + break; + } else if (type != testType) + break; + } + if (i == pCount) + return test; // all parameters matched + } + return 0; +} + +/** + * Creates an operation in the current document. + * The new operation is initialized with name, id, etc. + * If a method with the given profile already exists in the classifier, + * no new method is created and the existing operation is returned. + * If no name is provided, or if the params are NULL, an Operation + * Dialog is shown to ask the user for a name and parameters. + * The operation's signature is checked for validity within the parent + * classifier. + * + * @param name The operation name (will be chosen internally if + * none given.) + * @param isExistingOp Optional pointer to bool. If supplied, the bool is + * set to true if an existing operation is returned. + * @param params Optional list of parameter names and types. + * If supplied, new operation parameters are + * constructed using this list. + * @return The new operation, or NULL if the operation could not be + * created because for example, the user canceled the dialog + * or no appropriate name can be found. + */ +UMLOperation* UMLClassifier::createOperation( + const QString &name /*=QString()*/, + bool *isExistingOp /*=NULL*/, + Model_Utils::NameAndType_List *params /*=NULL*/) +{ + bool nameNotSet = (name.isNull() || name.isEmpty()); + if (! nameNotSet) { + Model_Utils::NameAndType_List parList; + if (params) + parList = *params; + UMLOperation* existingOp = findOperation(name, parList); + if (existingOp != NULL) { + if (isExistingOp != NULL) + *isExistingOp = true; + return existingOp; + } + } + // we did not find an exact match, so the signature is unique + UMLOperation *op = new UMLOperation(this, name); + if (params) { + for (Model_Utils::NameAndType_ListIt it = params->begin(); it != params->end(); ++it) { + const Model_Utils::NameAndType &nt = *it; + UMLAttribute *par = new UMLAttribute(op, nt.m_name, Uml::ID::None, Uml::Visibility::Private, + nt.m_type, nt.m_initialValue); + par->setParmKind(nt.m_direction); + op->addParm(par); + } + } + + // Only show the operation dialog if no name was provided (allows quick-create + // from listview) + if (nameNotSet) { + op->setName(uniqChildName(UMLObject::ot_Operation)); + + while (true) { + QPointer operationDialog = new UMLOperationDialog(0, op); + if(operationDialog->exec() != QDialog::Accepted) { + delete op; + delete operationDialog; + return NULL; + } else if (checkOperationSignature(op->name(), op->getParmList())) { + KMessageBox::information(0, + i18n("An operation with the same name and signature already exists. You cannot add it again.")); + } else { + break; + } + delete operationDialog; + } + } + + // operation name is ok, formally add it to the classifier + if (! addOperation(op)) { + delete op; + return NULL; + } + + UMLDoc *umldoc = UMLApp::app()->document(); + umldoc->signalUMLObjectCreated(op); + return op; +} + +/** + * Appends an operation to the classifier. + * This function is mainly intended for the clipboard. + * + * @param op Pointer to the UMLOperation to add. + * @param position Inserted at the given position. + * @return True if the operation was added successfully. + */ +bool UMLClassifier::addOperation(UMLOperation* op, int position) +{ + Q_ASSERT(op); + if (m_List.indexOf(op) != -1) { + uDebug() << "findRef(" << op->name() << ") finds op (bad)"; + return false; + } + if (checkOperationSignature(op->name(), op->getParmList())) { + uDebug() << "checkOperationSignature(" << op->name() << ") op is non-unique"; + return false; + } + + if (position >= 0 && position <= m_List.count()) { + uDebug() << op->name() << ": inserting at position " << position; + m_List.insert(position, op); + UMLClassifierListItemList itemList = getFilteredList(UMLObject::ot_Operation); + QString buf; + foreach (UMLClassifierListItem* currentAtt, itemList) { + buf.append(QLatin1Char(' ') + currentAtt->name()); + } + uDebug() << " list after change: " << buf; + } + else { + m_List.append(op); + } + emit operationAdded(op); + UMLObject::emitModified(); + connect(op, SIGNAL(modified()), this, SIGNAL(modified())); + return true; +} + +/** + * Appends an operation to the classifier. + * @see bool addOperation(UMLOperation* Op, int position = -1) + * This function is mainly intended for the clipboard. + * + * @param op Pointer to the UMLOperation to add. + * @param log Pointer to the IDChangeLog. + * @return True if the operation was added successfully. + */ +bool UMLClassifier::addOperation(UMLOperation* op, IDChangeLog* log) +{ + if (addOperation(op, -1)) { + return true; + } + else if (log) { + log->removeChangeByNewID(op->id()); + } + return false; +} + +/** + * Remove an operation from the Classifier. + * The operation is not deleted so the caller is responsible for what + * happens to it after this. + * + * @param op The operation to remove. + * @return Count of the remaining operations after removal, or + * -1 if the given operation was not found. + */ +int UMLClassifier::removeOperation(UMLOperation *op) +{ + if (op == NULL) { + uDebug() << "called on NULL op"; + return -1; + } + if (!m_List.removeAll(op)) { + uDebug() << "cannot find op " << op->name() << " in list"; + return -1; + } + // disconnection needed. + // note that we don't delete the operation, just remove it from the Classifier + disconnect(op, SIGNAL(modified()), this, SIGNAL(modified())); + emit operationRemoved(op); + UMLObject::emitModified(); + return m_List.count(); +} + +/** + * Create and add a just created template. + * @param currentName the name of the template + * @return the template or NULL + */ +UMLObject* UMLClassifier::createTemplate(const QString& currentName /*= QString()*/) +{ + QString name = currentName; + bool goodName = !name.isEmpty(); + if (!goodName) { + name = uniqChildName(UMLObject::ot_Template); + } + UMLTemplate* newTemplate = new UMLTemplate(this, name); + + int button = QDialog::Accepted; + + while (button == QDialog::Accepted && !goodName) { + QPointer templateDialog = new UMLTemplateDialog(0, newTemplate); + button = templateDialog->exec(); + name = newTemplate->name(); + + if (name.length() == 0) { + KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); + } + else if (findChildObject(name) != NULL) { + KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name")); + } + else { + goodName = true; + } + delete templateDialog; + } + + if (button != QDialog::Accepted) { + return NULL; + } + + addTemplate(newTemplate); + + UMLDoc *umldoc = UMLApp::app()->document(); + umldoc->signalUMLObjectCreated(newTemplate); + return newTemplate; +} + +/** + * Returns the number of attributes for the class. + * + * @return The number of attributes for the class. + */ +int UMLClassifier::attributes() +{ + UMLClassifierListItemList atts = getFilteredList(UMLObject::ot_Attribute); + return atts.count(); +} + +/** + * Returns the attributes for the specified scope. + * @return List of true attributes for the class. + */ +UMLAttributeList UMLClassifier::getAttributeList() const +{ + UMLAttributeList attributeList; + foreach (UMLObject* listItem, m_List) { + uIgnoreZeroPointer(listItem); + if (listItem->baseType() == UMLObject::ot_Attribute) { + attributeList.append(static_cast(listItem)); + } + } + return attributeList; +} + +/** + * Returns the attributes for the specified scope. + * @param scope The scope of the attribute. + * @return List of true attributes for the class. + */ +UMLAttributeList UMLClassifier::getAttributeList(Visibility::Enum scope) const +{ + UMLAttributeList list; + if (!isInterface()) + { + UMLAttributeList atl = getAttributeList(); + foreach(UMLAttribute* at, atl) + { + uIgnoreZeroPointer(at); + if (! at->isStatic()) + { + if (scope == Uml::Visibility::Private) + { + if ((at->visibility() == Uml::Visibility::Private) || + (at->visibility() == Uml::Visibility::Implementation)) + { + list.append(at); + } + } + else if (scope == at->visibility()) + { + list.append(at); + } + } + } + } + return list; +} + +/** + * Returns the static attributes for the specified scope. + * + * @param scope The scope of the attribute. + * @return List of true attributes for the class. + */ +UMLAttributeList UMLClassifier::getAttributeListStatic(Visibility::Enum scope) const +{ + UMLAttributeList list; + if (!isInterface()) + { + UMLAttributeList atl = getAttributeList(); + foreach(UMLAttribute* at, atl) + { + uIgnoreZeroPointer(at); + if (at->isStatic()) + { + if (scope == Uml::Visibility::Private) + { + if ((at->visibility() == Uml::Visibility::Private) || + (at->visibility() == Uml::Visibility::Implementation)) + { + list.append(at); + } + } + else if (scope == at->visibility()) + { + list.append(at); + } + } + } + } + return list; +} + +/** + * Find a list of operations with the given name. + * + * @param n The name of the operation to find. + * @return The list of objects found; will be empty if none found. + */ +UMLOperationList UMLClassifier::findOperations(const QString &n) +{ + const bool caseSensitive = UMLApp::app()->activeLanguageIsCaseSensitive(); + UMLOperationList list; + foreach (UMLObject* obj, m_List) { + uIgnoreZeroPointer(obj); + if (obj->baseType() != UMLObject::ot_Operation) + continue; + UMLOperation *op = static_cast(obj); + if (caseSensitive) { + if (obj->name() == n) + list.append(op); + } else if (obj->name().toLower() == n.toLower()) { + list.append(op); + } + } + return list; +} + +/** + * Find the child object by the given id. + * @param id the id of the child object + * @param considerAncestors flag whether the ancestors should be considered during search + * @return the found child object or NULL + */ +UMLObject* UMLClassifier::findChildObjectById(Uml::ID::Type id, bool considerAncestors /* =false */) +{ + UMLObject *o = UMLCanvasObject::findChildObjectById(id); + if (o) { + return o; + } + if (considerAncestors) { + UMLClassifierList ancestors = findSuperClassConcepts(); + foreach (UMLClassifier *anc, ancestors) { + UMLObject *o = anc->findChildObjectById(id); + if (o) { + return o; + } + } + } + return NULL; +} + +/** + * Returns a list of concepts which inherit from this concept. + * + * @param type The ClassifierType to seek. + * @return List of UMLClassifiers that inherit from us. + */ +UMLClassifierList UMLClassifier::findSubClassConcepts (ClassifierType type) +{ + UMLClassifierList list = getSubClasses(); + UMLAssociationList rlist = getRealizations(); + + UMLClassifierList inheritingConcepts; + Uml::ID::Type myID = id(); + foreach(UMLClassifier *c, list) { + uIgnoreZeroPointer(c); + if (type == ALL || (!c->isInterface() && type == CLASS) + || (c->isInterface() && type == INTERFACE)) { + inheritingConcepts.append(c); + } + } + + foreach (UMLAssociation *a, rlist) { + uIgnoreZeroPointer(a); + if (a->getObjectId(RoleType::A) != myID) + { + UMLObject* obj = a->getObject(RoleType::A); + UMLClassifier *concept = dynamic_cast(obj); + if (concept && (type == ALL || (!concept->isInterface() && type == CLASS) + || (concept->isInterface() && type == INTERFACE)) + && (inheritingConcepts.indexOf(concept) == -1)) + { + inheritingConcepts.append(concept); + } + } + } + + return inheritingConcepts; +} + +/** + * Returns a list of concepts which this concept inherits from. + * + * @param type The ClassifierType to seek. + * @return List of UMLClassifiers we inherit from. + */ +UMLClassifierList UMLClassifier::findSuperClassConcepts (ClassifierType type) +{ + UMLClassifierList list = getSuperClasses(); + UMLAssociationList rlist = getRealizations(); + + UMLClassifierList parentConcepts; + Uml::ID::Type myID = id(); + foreach (UMLClassifier *concept, list) { + uIgnoreZeroPointer(concept); + if (type == ALL || (!concept->isInterface() && type == CLASS) + || (concept->isInterface() && type == INTERFACE)) + parentConcepts.append(concept); + } + + foreach (UMLAssociation *a, rlist) { + if (a->getObjectId(RoleType::A) == myID) + { + UMLObject* obj = a->getObject(RoleType::B); + UMLClassifier *concept = dynamic_cast(obj); + if (concept && (type == ALL || (!concept->isInterface() && type == CLASS) + || (concept->isInterface() && type == INTERFACE)) + && (parentConcepts.indexOf(concept) == -1)) + parentConcepts.append(concept); + } + } + + return parentConcepts; +} + +/** + * Overloaded '==' operator. + */ +bool UMLClassifier::operator==(const UMLClassifier & rhs) const +{ + return UMLCanvasObject::operator==(rhs); +} + +/** + * Copy the internal presentation of this object into the new + * object. + */ +void UMLClassifier::copyInto(UMLObject *lhs) const +{ + UMLClassifier *target = static_cast(lhs); + UMLCanvasObject::copyInto(target); + target->setBaseType(m_BaseType); + // CHECK: association property m_pClassAssoc is not copied + m_List.copyInto(&(target->m_List)); +} + +/** + * Make a clone of this object. + */ +UMLObject* UMLClassifier::clone() const +{ + UMLClassifier *clone = new UMLClassifier(); + copyInto(clone); + return clone; +} + +/** + * Needs to be called after all UML objects are loaded from file. + * Calls the parent resolveRef(), and calls resolveRef() on all + * UMLClassifierListItems. + * Overrides the method from UMLObject. + * + * @return true for success. + */ +bool UMLClassifier::resolveRef() +{ + bool success = UMLPackage::resolveRef(); + // Using reentrant iteration is a bare necessity here: + foreach (UMLObject* obj, m_List) { + uIgnoreZeroPointer(obj); + /**** For reference, here is the non-reentrant iteration scheme - + DO NOT USE THIS ! + for (UMLObject *obj = m_List.first(); obj; obj = m_List.next()) + { .... } + ****/ + if (obj->resolveRef()) { + UMLClassifierListItem *cli = static_cast(obj); + switch (cli->baseType()) { + case UMLObject::ot_Attribute: + emit attributeAdded(cli); + break; + case UMLObject::ot_Operation: + emit operationAdded(cli); + break; + case UMLObject::ot_Template: + emit templateAdded(cli); + break; + default: + break; + } + } + } + return success; +} + +/** + * Reimplemented from UMLObject. + */ +bool UMLClassifier::acceptAssociationType(AssociationType::Enum type) +{ + switch(type) + { + case AssociationType::Generalization: + case AssociationType::Aggregation: + case AssociationType::Relationship: + case AssociationType::Dependency: + case AssociationType::Association: + case AssociationType::Association_Self: + case AssociationType::Containment: + case AssociationType::Composition: + case AssociationType::Realization: + case AssociationType::UniAssociation: + return true; + default: + return false; + } + return false; //shutup compiler warning +} + +/** + * Creates an attribute for the class. + * + * @param name An optional name, used by when creating through UMLListView + * @param type An optional type, used by when creating through UMLListView + * @param vis An optional visibility, used by when creating through UMLListView + * @param init An optional initial value, used by when creating through UMLListView + * @return The UMLAttribute created + */ +UMLAttribute* UMLClassifier::createAttribute(const QString &name, + UMLObject *type, + Visibility::Enum vis, + const QString &init) +{ + Uml::ID::Type id = UniqueID::gen(); + QString currentName; + if (name.isNull()) { + currentName = uniqChildName(UMLObject::ot_Attribute); + } else { + currentName = name; + } + UMLAttribute* newAttribute = new UMLAttribute(this, currentName, id, vis, type, init); + + int button = QDialog::Accepted; + bool goodName = false; + + //check for name.isNull() stops dialog being shown + //when creating attribute via list view + while (button == QDialog::Accepted && !goodName && name.isNull()) { + QPointer attributeDialog = new UMLAttributeDialog(0, newAttribute); + button = attributeDialog->exec(); + QString name = newAttribute->name(); + + if(name.length() == 0) { + KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); + } else if (findChildObject(name) != NULL) { + KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name")); + } else { + goodName = true; + } + delete attributeDialog; + } + + if (button != QDialog::Accepted) { + delete newAttribute; + return NULL; + } + + addAttribute(newAttribute); + + UMLDoc *umldoc = UMLApp::app()->document(); + umldoc->signalUMLObjectCreated(newAttribute); + return newAttribute; +} + +/** + * Creates and adds an attribute for the class. + * + * @param name an optional name, used by when creating through UMLListView + * @param id an optional id + * @return the UMLAttribute created and added + */ + +UMLAttribute* UMLClassifier::addAttribute(const QString &name, Uml::ID::Type id /* = Uml::id_None */) +{ + foreach (UMLObject* obj, m_List) { + uIgnoreZeroPointer(obj); + if (obj->baseType() == UMLObject::ot_Attribute && obj->name() == name) + return static_cast(obj); + } + Uml::Visibility::Enum scope = Settings::optionState().classState.defaultAttributeScope; + UMLAttribute *a = new UMLAttribute(this, name, id, scope); + m_List.append(a); + emit attributeAdded(a); + UMLObject::emitModified(); + connect(a, SIGNAL(modified()), this, SIGNAL(modified())); + return a; +} + +/** + * Adds an already created attribute. + * The attribute object must not belong to any other concept. + * + * @param name the name of the attribute + * @param type the type of the attribute + * @param scope the visibility of the attribute + * @return the just created and added attribute + */ +UMLAttribute* UMLClassifier::addAttribute(const QString &name, UMLObject *type, Visibility::Enum scope) +{ + UMLAttribute *a = new UMLAttribute(this); + a->setName(name); + a->setVisibility(scope); + a->setID(UniqueID::gen()); + if (type) { + a->setType(type); + } + m_List.append(a); + emit attributeAdded(a); + UMLObject::emitModified(); + connect(a, SIGNAL(modified()), this, SIGNAL(modified())); + return a; +} + +/** + * Adds an already created attribute. + * The attribute object must not belong to any other concept. + * + * @param att Pointer to the UMLAttribute. + * @param log Pointer to the IDChangeLog (optional.) + * @param position Position index for the insertion (optional.) + * If the position is omitted, or if it is + * negative or too large, the attribute is added + * to the end of the list. + * @return True if the attribute was successfully added. + */ +bool UMLClassifier::addAttribute(UMLAttribute* att, IDChangeLog* log /* = 0 */, + int position /* = -1 */) +{ + Q_ASSERT(att); + if (findChildObject(att->name()) == NULL) { + att->setParent(this); + if (position >= 0 && position < (int)m_List.count()) { + m_List.insert(position, att); + } + else { + m_List.append(att); + } + emit attributeAdded(att); + UMLObject::emitModified(); + connect(att, SIGNAL(modified()), this, SIGNAL(modified())); + return true; + } else if (log) { + log->removeChangeByNewID(att->id()); + delete att; + } + return false; +} + +/** + * Removes an attribute from the class. + * + * @param att The attribute to remove. + * @return Count of the remaining attributes after removal. + * Returns -1 if the given attribute was not found. + */ +int UMLClassifier::removeAttribute(UMLAttribute* att) +{ + if (!m_List.removeAll(att)) { + uDebug() << "cannot find att given in list"; + return -1; + } + emit attributeRemoved(att); + UMLObject::emitModified(); + // If we are deleting the object, then we don't need to disconnect..this is done auto-magically + // for us by QObject. -b.t. + // disconnect(att, SIGNAL(modified()), this, SIGNAL(modified())); + delete att; + return m_List.count(); +} + +/** + * Sets the UMLAssociation for which this class shall act as an + * association class. + */ +void UMLClassifier::setClassAssoc(UMLAssociation *assoc) +{ + m_pClassAssoc = assoc; +} + +/** + * Returns the UMLAssociation for which this class acts as an + * association class. Returns NULL if this class does not act + * as an association class. + */ +UMLAssociation *UMLClassifier::getClassAssoc() const +{ + return m_pClassAssoc; +} + +/** + * Return true if this classifier has abstract operations. + */ +bool UMLClassifier::hasAbstractOps () +{ + UMLOperationList opl(getOpList()); + foreach(UMLOperation *op, opl) { + uIgnoreZeroPointer(op); + if (op->isAbstract()) { + return true; + } + } + return false; +} + +/** + * Counts the number of operations in the Classifier. + * + * @return The number of operations for the Classifier. + */ +int UMLClassifier::operations() +{ + return getOpList().count(); +} + + +/** + * Return a list of operations for the Classifier. + * + * @param includeInherited Includes operations from superclasses. + * @param alreadyTraversed internal used object to avoid recursive loops + * @return The list of operations for the Classifier. + */ +UMLOperationList UMLClassifier::getOpList(bool includeInherited, UMLClassifierSet *alreadyTraversed) +{ + UMLOperationList ops; + foreach (UMLObject* li, m_List) { + uIgnoreZeroPointer(li); + if (li->baseType() == ot_Operation) { + ops.append(static_cast(li)); + } + } + if (includeInherited) { + if (!alreadyTraversed) { + alreadyTraversed = new UMLClassifierSet; + } + else + alreadyTraversed->level++; + + if (!alreadyTraversed->contains(this)) + *alreadyTraversed << this; + + // get a list of parents of this class + UMLClassifierList parents = findSuperClassConcepts(); + foreach(UMLClassifier *c, parents) { + if (alreadyTraversed->contains(c)) { + uError() << "class " << c->name() << " is starting a dependency loop!"; + continue; + } + // get operations for each parent by recursive call + UMLOperationList pops = c->getOpList(true, alreadyTraversed); + // add these operations to operation list, but only if unique. + foreach (UMLOperation *po, pops) { + QString po_as_string(po->toString(Uml::SignatureType::SigNoVis)); + bool breakFlag = false; + foreach (UMLOperation* o, ops) { + if (o->toString(Uml::SignatureType::SigNoVis) == po_as_string) { + breakFlag = true; + break; + } + } + if (breakFlag == false) + ops.append(po); + } + // remember this node + *alreadyTraversed << c; + } + if (alreadyTraversed->level-- == 0) { + delete alreadyTraversed; + alreadyTraversed = 0; + } + } + return ops; +} + +/** + * Returns the entries in m_List that are of the requested type. + * If the requested type is UMLObject::ot_UMLObject then all entries + * are returned. + * @param ot the requested object type + * @return The list of true operations for the Concept. + */ +UMLClassifierListItemList UMLClassifier::getFilteredList(UMLObject::ObjectType ot) const +{ + UMLClassifierListItemList resultList; + foreach (UMLObject* o, m_List) { + uIgnoreZeroPointer(o); + if (!o || o->baseType() == UMLObject::ot_Association) { + continue; + } + UMLClassifierListItem *listItem = static_cast(o); + if (ot == UMLObject::ot_UMLObject || listItem->baseType() == ot) { + resultList.append(listItem); + } + } + return resultList; +} + +/** + * Adds an already created template. + * The template object must not belong to any other concept. + * + * @param name the name of the template + * @param id the id of the template + * @return the added template + */ +UMLTemplate* UMLClassifier::addTemplate(const QString &name, Uml::ID::Type id) +{ + UMLTemplate *templt = findTemplate(name); + if (templt) { + return templt; + } + templt = new UMLTemplate(this, name, id); + m_List.append(templt); + emit templateAdded(templt); + UMLObject::emitModified(); + connect(templt, SIGNAL(modified()), this, SIGNAL(modified())); + return templt; +} + +/** + * Adds an already created template. + * The template object must not belong to any other concept. + * + * @param newTemplate Pointer to the UMLTemplate object to add. + * @param log Pointer to the IDChangeLog. + * @return True if the template was successfully added. + */ +bool UMLClassifier::addTemplate(UMLTemplate* newTemplate, IDChangeLog* log /* = 0*/) +{ + QString name = newTemplate->name(); + if (findChildObject(name) == NULL) { + newTemplate->setParent(this); + m_List.append(newTemplate); + emit templateAdded(newTemplate); + UMLObject::emitModified(); + connect(newTemplate, SIGNAL(modified()), this, SIGNAL(modified())); + return true; + } + else if (log) { + log->removeChangeByNewID(newTemplate->id()); + delete newTemplate; + } + return false; +} + +/** + * Adds an template to the class. + * The template object must not belong to any other class. + * TODO: If the param IDChangeLog from the method above is not being used, + * give position a default value of -1 and the method can replace the above one. + * @param templt Pointer to the UMLTemplate to add. + * @param position The position of the template in the list. + * A value of -1 will add the template at the end. + * @return True if the template was successfully added. + */ +bool UMLClassifier::addTemplate(UMLTemplate* templt, int position) +{ + Q_ASSERT(templt); + QString name = templt->name(); + if (findChildObject(name) == NULL) { + templt->setParent(this); + if (position >= 0 && position <= (int)m_List.count()) { + m_List.insert(position, templt); + } + else { + m_List.append(templt); + } + emit templateAdded(templt); + UMLObject::emitModified(); + connect(templt, SIGNAL(modified()), this, SIGNAL(modified())); + return true; + } + //else + return false; +} + +/** + * Removes a template from the class. + * + * @param umltemplate The template to remove. + * @return Count of the remaining templates after removal. + * Returns -1 if the given template was not found. + */ +int UMLClassifier::removeTemplate(UMLTemplate* umltemplate) +{ + if (!m_List.removeAll(umltemplate)) { + uWarning() << "cannot find att given in list"; + return -1; + } + emit templateRemoved(umltemplate); + UMLObject::emitModified(); + disconnect(umltemplate, SIGNAL(modified()), this, SIGNAL(modified())); + return m_List.count(); +} + +/** + * Seeks the template parameter of the given name. + * @param name the template name + * @return the found template or 0 + */ +UMLTemplate *UMLClassifier::findTemplate(const QString& name) +{ + UMLTemplateList templParams = getTemplateList(); + foreach (UMLTemplate *templt, templParams) { + if (templt->name() == name) { + return templt; + } + } + return 0; +} + +/** + * Returns the number of templates for the class. + * + * @return The number of templates for the class. + */ +int UMLClassifier::templates() +{ + UMLClassifierListItemList tempList = getFilteredList(UMLObject::ot_Template); + return tempList.count(); +} + +/** + * Returns the templates. + * Same as UMLClassifier::getFilteredList(ot_Template) but + * return type is a true UMLTemplateList. + * + * @return Pointer to the list of true templates for the class. + */ +UMLTemplateList UMLClassifier::getTemplateList() const +{ + UMLTemplateList templateList; + foreach (UMLObject* listItem, m_List) { + uIgnoreZeroPointer(listItem); + if (listItem->baseType() == UMLObject::ot_Template) { + templateList.append(static_cast(listItem)); + } + } + return templateList; +} + +/** + * Take and return a subordinate item from this classifier. + * Ownership of the item is passed to the caller. + * + * @param item Subordinate item to take. + * @return Index in m_List of the item taken. + * Return -1 if the item is not found in m_List. + */ +int UMLClassifier::takeItem(UMLClassifierListItem *item) +{ + QString buf; + foreach (UMLObject* currentAtt, m_List) { + uIgnoreZeroPointer(currentAtt); + QString txt = currentAtt->name(); + if (txt.isEmpty()) { + txt = QLatin1String("Type-") + QString::number((int) currentAtt->baseType()); + } + buf.append(QLatin1Char(' ') + currentAtt->name()); + } + uDebug() << " UMLClassifier::takeItem (before): m_List is " << buf; + + int index = m_List.indexOf(item); + if (index == -1) { + return -1; + } + switch (item->baseType()) { + case UMLObject::ot_Operation: { + if (removeOperation(dynamic_cast(item)) < 0) { + index = -1; + } + break; + } + case UMLObject::ot_Attribute: { + UMLAttribute *retval = dynamic_cast(m_List.takeAt(index).data()); + if (retval) { + emit attributeRemoved(retval); + UMLObject::emitModified(); + } else { + index = -1; + } + break; + } + case UMLObject::ot_Template: { + UMLTemplate *templt = dynamic_cast(m_List.takeAt(index).data()); + if (templt) { + emit templateRemoved(templt); + UMLObject::emitModified(); + } else { + index = -1; + } + break; + } + case UMLObject::ot_EnumLiteral: { + UMLEnumLiteral *el = dynamic_cast(m_List.takeAt(index).data()); + if (el) { + UMLEnum *e = static_cast(this); + e->signalEnumLiteralRemoved(el); + UMLObject::emitModified(); + } else { + index = -1; + } + break; + } + case UMLObject::ot_EntityAttribute: { + UMLEntityAttribute* el = dynamic_cast(m_List.takeAt(index).data()); + if (el) { + UMLEntity *e = static_cast(this); + e->signalEntityAttributeRemoved(el); + UMLObject::emitModified(); + } else { + index = -1; + } + break; + } + default: + index = -1; + break; + } + return index; +} + +/** + * Set the origin type (in case of e.g. typedef) + * @param origType the origin type to set + */ +void UMLClassifier::setOriginType(UMLClassifier *origType) +{ + m_pSecondary = origType; +} + +/** + * Get the origin type (in case of e.g. typedef) + * @return the origin type + */ +UMLClassifier * UMLClassifier::originType() const +{ + return dynamic_cast(m_pSecondary.data()); +} + +/** + * Set the m_isRef flag (true when dealing with a pointer type) + * @param isRef the flag to set + */ +void UMLClassifier::setIsReference(bool isRef) +{ + m_isRef = isRef; +} + +/** + * Get the m_isRef flag. + * @return true if is reference, otherwise false + */ +bool UMLClassifier::isReference() const +{ + return m_isRef; +} + +/** + * Return true if this classifier has associations. + * @return true if classifier has associations + */ +bool UMLClassifier::hasAssociations() +{ + return getSpecificAssocs(AssociationType::Association).count() > 0 + || getAggregations().count() > 0 + || getCompositions().count() > 0 + || getUniAssociationToBeImplemented().count() > 0; +} + +/** + * Return true if this classifier has attributes. + */ +bool UMLClassifier::hasAttributes() +{ + return getAttributeList(Uml::Visibility::Public).count() > 0 + || getAttributeList(Uml::Visibility::Protected).count() > 0 + || getAttributeList(Uml::Visibility::Private).count() > 0 + || getAttributeListStatic(Uml::Visibility::Public).count() > 0 + || getAttributeListStatic(Uml::Visibility::Protected).count() > 0 + || getAttributeListStatic(Uml::Visibility::Private).count() > 0; +} + +/** + * Return true if this classifier has static attributes. + */ +bool UMLClassifier::hasStaticAttributes() +{ + return getAttributeListStatic(Uml::Visibility::Public).count() > 0 + || getAttributeListStatic(Uml::Visibility::Protected).count() > 0 + || getAttributeListStatic(Uml::Visibility::Private).count() > 0; +} + +/** + * Return true if this classifier has accessor methods. + */ +bool UMLClassifier::hasAccessorMethods() +{ + return hasAttributes() || hasAssociations(); +} + +/** + * Return true if this classifier has operation methods. + */ +bool UMLClassifier::hasOperationMethods() +{ + return getOpList().last() ? true : false; +} + +/** + * Return true if this classifier has methods. + */ +bool UMLClassifier::hasMethods() +{ + return hasOperationMethods() || hasAccessorMethods(); +} + +// this is a bit too simplistic..some associations are for +// SINGLE objects, and WONT be declared as Vectors, so this +// is a bit overly inclusive (I guess that's better than the other way around) + +/** + * Return true if this classifier has vector fields. + */ +bool UMLClassifier::hasVectorFields() +{ + return hasAssociations(); +} + +/** + * Return the list of unidirectional association that should show up in the code + */ +UMLAssociationList UMLClassifier::getUniAssociationToBeImplemented() +{ + UMLAssociationList associations = getSpecificAssocs(AssociationType::UniAssociation); + UMLAssociationList uniAssocListToBeImplemented; + + foreach (UMLAssociation *a, associations) { + uIgnoreZeroPointer(a); + if (a->getObjectId(RoleType::B) == id()) { + continue; // we need to be at the A side + } + QString roleNameB = a->getRoleName(RoleType::B); + if (!roleNameB.isEmpty()) { + UMLAttributeList atl = getAttributeList(); + bool found = false; + //make sure that an attribute with the same name doesn't already exist + foreach (UMLAttribute *at, atl) { + uIgnoreZeroPointer(a); + if (at->name() == roleNameB) { + found = true; + break; + } + } + if (!found) { + uniAssocListToBeImplemented.append(a); + } + } + } + return uniAssocListToBeImplemented; +} + +/** + * Creates XML tag , , or + * depending on m_BaseType. + * Saves possible template parameters, generalizations, attributes, + * operations, and contained objects to the given QDomElement. + */ +void UMLClassifier::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +{ + QString tag; + switch (m_BaseType) { + case UMLObject::ot_Class: + tag = QLatin1String("UML:Class"); + break; + case UMLObject::ot_Interface: + tag = QLatin1String("UML:Interface"); + break; + case UMLObject::ot_Datatype: + tag = QLatin1String("UML:DataType"); + break; + case UMLObject::ot_Package: + UMLPackage::saveToXMI(qDoc, qElement); + return; + break; + default: + uError() << "internal error: basetype is " << m_BaseType; + return; + } + QDomElement classifierElement = UMLObject::save(tag, qDoc); + if (m_BaseType == UMLObject::ot_Datatype && m_pSecondary != NULL) + classifierElement.setAttribute(QLatin1String("elementReference"), + Uml::ID::toString(m_pSecondary->id())); + + //save templates + UMLClassifierListItemList list = getFilteredList(UMLObject::ot_Template); + if (list.count()) { + QDomElement tmplElement = qDoc.createElement(QLatin1String("UML:ModelElement.templateParameter")); + foreach (UMLClassifierListItem *tmpl, list) { + tmpl->saveToXMI(qDoc, tmplElement); + } + classifierElement.appendChild(tmplElement); + } + + //save generalizations (we are the subclass, the other end is the superclass) + UMLAssociationList generalizations = getSpecificAssocs(AssociationType::Generalization); + if (generalizations.count()) { + QDomElement genElement = qDoc.createElement(QLatin1String("UML:GeneralizableElement.generalization")); + foreach (UMLAssociation *a, generalizations) { + // We are the subclass if we are at the role A end. + if (m_nId != a->getObjectId(RoleType::A)) { + continue; + } + QDomElement gElem = qDoc.createElement(QLatin1String("UML:Generalization")); + gElem.setAttribute(QLatin1String("xmi.idref"), Uml::ID::toString(a->id())); + genElement.appendChild(gElem); + } + if (genElement.hasChildNodes()) { + classifierElement.appendChild(genElement); + } + } + + // save attributes + QDomElement featureElement = qDoc.createElement(QLatin1String("UML:Classifier.feature")); + UMLClassifierListItemList attList = getFilteredList(UMLObject::ot_Attribute); + foreach (UMLClassifierListItem *pAtt, attList) { + pAtt->saveToXMI(qDoc, featureElement); + } + + // save operations + UMLOperationList opList = getOpList(); + foreach (UMLOperation *pOp, opList) { + pOp->saveToXMI(qDoc, featureElement); + } + if (featureElement.hasChildNodes()) { + classifierElement.appendChild(featureElement); + } + + // save contained objects + if (m_objects.count()) { + QDomElement ownedElement = qDoc.createElement(QLatin1String("UML:Namespace.ownedElement")); + foreach (UMLObject* obj, m_objects) { + uIgnoreZeroPointer(obj); + obj->saveToXMI (qDoc, ownedElement); + } + classifierElement.appendChild(ownedElement); + } + qElement.appendChild(classifierElement); +} + +/** + * Create a new ClassifierListObject (attribute, operation, template) + * according to the given XMI tag. + * Returns NULL if the string given does not contain one of the tags + * , , or . + * Used by the clipboard for paste operation. + */ +UMLClassifierListItem* UMLClassifier::makeChildObject(const QString& xmiTag) +{ + UMLClassifierListItem* pObject = NULL; + if (UMLDoc::tagEq(xmiTag, QLatin1String("Operation")) || + UMLDoc::tagEq(xmiTag, QLatin1String("ownedOperation"))) { + pObject = new UMLOperation(this); + } else if (UMLDoc::tagEq(xmiTag, QLatin1String("Attribute")) || + UMLDoc::tagEq(xmiTag, QLatin1String("ownedAttribute"))) { + if (baseType() != UMLObject::ot_Class) + return NULL; + pObject = new UMLAttribute(this); + } else if (UMLDoc::tagEq(xmiTag, QLatin1String("TemplateParameter"))) { + pObject = new UMLTemplate(this); + } + return pObject; +} + +/** + * Auxiliary to loadFromXMI: + * The loading of operations is implemented here. + * Calls loadSpecialized() for any other tag. + * Child classes can override the loadSpecialized method + * to load its additional tags. + */ +bool UMLClassifier::load(QDomElement& element) +{ + UMLClassifierListItem *child = NULL; + m_SecondaryId = element.attribute(QLatin1String("elementReference")); + if (!m_SecondaryId.isEmpty()) { + // @todo We do not currently support composition. + m_isRef = true; + } + bool totalSuccess = true; + for (QDomNode node = element.firstChild(); !node.isNull(); + node = node.nextSibling()) { + if (node.isComment()) + continue; + element = node.toElement(); + QString tag = element.tagName(); + QString stereotype = element.attribute(QLatin1String("stereotype")); + if (UMLDoc::tagEq(tag, QLatin1String("ModelElement.templateParameter")) || + UMLDoc::tagEq(tag, QLatin1String("Classifier.feature")) || + UMLDoc::tagEq(tag, QLatin1String("Namespace.ownedElement")) || + UMLDoc::tagEq(tag, QLatin1String("Element.ownedElement")) || // Embarcadero's Describe + UMLDoc::tagEq(tag, QLatin1String("Namespace.contents"))) { + load(element); + // Not evaluating the return value from load() + // because we want a best effort. + + } else if ((child = makeChildObject(tag)) != NULL) { + if (child->loadFromXMI(element)) { + switch (child->baseType()) { + case UMLObject::ot_Template: + addTemplate(static_cast(child)); + break; + case UMLObject::ot_Operation: + if (! addOperation(static_cast(child))) { + uError() << "error from addOperation(op)"; + delete child; + totalSuccess = false; + } + break; + case UMLObject::ot_Attribute: + addAttribute(static_cast(child)); + break; + default: + break; + } + } else { + uWarning() << "failed to load " << tag; + delete child; + totalSuccess = false; + } + } else if (!Model_Utils::isCommonXMIAttribute(tag)) { + UMLObject *pObject = Object_Factory::makeObjectFromXMI(tag, stereotype); + if (pObject == NULL) { + // Not setting totalSuccess to false + // because we want a best effort. + continue; + } + pObject->setUMLPackage(this); + if (! pObject->loadFromXMI(element)) { + removeObject(pObject); + delete pObject; + totalSuccess = false; + } + } + } + return totalSuccess; +} + +/* +UMLClassifierList UMLClassifier::getPlainAssocChildClassifierList() +{ + UMLAssociationList plainAssociations = getSpecificAssocs(Uml::AssociationType::Association); + return findAssocClassifierObjsInRoles(&plainAssociations); +} + +UMLClassifierList UMLClassifier::getAggregateChildClassifierList() +{ + UMLAssociationList aggregations = getAggregations(); + return findAssocClassifierObjsInRoles(&aggregations); +} + +UMLClassifierList UMLClassifier::getCompositionChildClassifierList() +{ + UMLAssociationList compositions = getCompositions(); + return findAssocClassifierObjsInRoles(&compositions); +} + +UMLClassifierList UMLClassifier::findAssocClassifierObjsInRoles (UMLAssociationList * list) +{ + UMLClassifierList classifiers; + + for (UMLAssociationListIt alit(*list); alit.hasNext(); ) { + UMLAssociation* a = alit.next(); + // DON'T accept a classifier IF the association role is empty, by + // convention, that means to ignore the classifier on that end of + // the association. + // We also ignore classifiers which are the same as the current one + // (e.g. id matches), we only want the "other" classifiers + if (a->getObjectId(RoleType::A) == id() && !a->getRoleName(RoleType::B).isEmpty()) { + UMLClassifier *c = dynamic_cast(a->getObject(RoleType::B)); + if(c) + classifiers.append(c); + } else if (a->getObjectId(RoleType::B) == id() && !a->getRoleName(RoleType::A).isEmpty()) { + UMLClassifier *c = dynamic_cast(a->getObject(RoleType::A)); + if(c) + classifiers.append(c); + } + } + + return classifiers; +} +*/ + + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/classifier.h umbrello-kf6-15.08.1/umbrello/umlmodel/classifier.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/classifier.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/classifier.h 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,199 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ +#ifndef CLASSIFIER_H +#define CLASSIFIER_H + +#include "package.h" +#include "umlattributelist.h" +#include "umloperationlist.h" +#include "umlclassifierlistitemlist.h" +#include "classifierlistitem.h" +#include "umltemplatelist.h" +#include "model_utils.h" + +// forward declarations +class UMLAssociation; +class IDChangeLog; +class UMLClassifierSet; + +/** + * This class defines the non-graphical information required for a + * UML Classifier (ie a class or interface). + * This class inherits from @ref UMLPackage which allows classifiers + * to also act as namespaces, i.e. it allows classifiers to nest. + * + * NOTE: There is a unit test available for this class. + * Please, use and adapt it when necessary. + * + * @short Information for a non-graphical Concept/Class. + * @author Paul Hensgen + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class UMLClassifier : public UMLPackage +{ + Q_OBJECT +public: + + /** + * Enumeration identifying the type of classifier. + */ + enum ClassifierType { ALL = 0, CLASS, INTERFACE, DATATYPE }; + + explicit UMLClassifier(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); + virtual ~UMLClassifier(); + + bool operator==(const UMLClassifier & rhs) const; + + virtual void copyInto(UMLObject *lhs) const; + + UMLObject* clone() const; + + virtual UMLAttribute* createAttribute(const QString &name = QString(), + UMLObject *type = 0, + Uml::Visibility::Enum vis = Uml::Visibility::Private, + const QString &init = QString()); + + UMLAttribute* addAttribute(const QString &name, Uml::ID::Type id = Uml::ID::None); + UMLAttribute* addAttribute(const QString &name, UMLObject *type, Uml::Visibility::Enum scope); + + bool addAttribute(UMLAttribute* att, IDChangeLog* log = 0, + int position = -1); + + int removeAttribute(UMLAttribute *att); + + int attributes() ; + + UMLAttributeList getAttributeList() const; + UMLAttributeList getAttributeList(Uml::Visibility::Enum scope) const; + UMLAttributeList getAttributeListStatic(Uml::Visibility::Enum scope) const; + + UMLOperation* createOperation(const QString &name = QString(), + bool *isExistingOp = NULL, + Model_Utils::NameAndType_List *params = NULL); + + bool addOperation(UMLOperation* op, int position = -1); + bool addOperation(UMLOperation* op, IDChangeLog* log); + + UMLOperation * checkOperationSignature(const QString& name, + UMLAttributeList opParams, + UMLOperation *exemptOp = NULL); + + int removeOperation(UMLOperation *op); + + int operations(); + + UMLOperationList getOpList(bool includeInherited = false, UMLClassifierSet *alreadyTraversed = 0); + + UMLObject* createTemplate(const QString& name = QString()); + + UMLTemplate* addTemplate(const QString &name, Uml::ID::Type id = Uml::ID::None); + + bool addTemplate(UMLTemplate* newTemplate, IDChangeLog* log = 0); + bool addTemplate(UMLTemplate* templt, int position); + + int removeTemplate(UMLTemplate* umltemplate); + + UMLTemplate *findTemplate(const QString& name); + + int templates(); + + UMLTemplateList getTemplateList() const; + + int takeItem(UMLClassifierListItem* item); + + virtual UMLClassifierListItemList getFilteredList(UMLObject::ObjectType ot) const; + + virtual bool resolveRef(); + + UMLOperationList findOperations(const QString &n); + + virtual UMLObject* findChildObjectById(Uml::ID::Type id, bool considerAncestors = false); + + UMLOperation* findOperation(const QString& name, + Model_Utils::NameAndType_List params); + + UMLClassifierList findSuperClassConcepts(ClassifierType type = ALL); + + UMLClassifierList findSubClassConcepts(ClassifierType type = ALL); + + virtual bool acceptAssociationType(Uml::AssociationType::Enum type); + + void setClassAssoc(UMLAssociation *assoc); + UMLAssociation *getClassAssoc() const; + + void setBaseType(UMLObject::ObjectType ot); + + bool isInterface() const; + + bool isDatatype() const; + + void setOriginType(UMLClassifier *origType); + UMLClassifier * originType() const; + + void setIsReference(bool isRef = true); + bool isReference() const; + + bool hasAbstractOps(); + bool hasAssociations(); + bool hasAttributes(); + bool hasStaticAttributes(); + bool hasMethods(); + bool hasAccessorMethods(); + bool hasOperationMethods(); + bool hasVectorFields(); + + /** + * utility functions to allow easy determination of what classifiers + * are "owned" by the current one via named association type (e.g. + * plain, aggregate or compositions). + */ +// UMLClassifierList getPlainAssocChildClassifierList(); +// UMLClassifierList getAggregateChildClassifierList(); +// UMLClassifierList getCompositionChildClassifierList(); + + virtual UMLClassifierListItem* makeChildObject(const QString& xmiTag); + + virtual UMLAssociationList getUniAssociationToBeImplemented(); + +signals: + + void operationAdded(UMLClassifierListItem *); + void operationRemoved(UMLClassifierListItem *); + + void templateAdded(UMLClassifierListItem*); + void templateRemoved(UMLClassifierListItem*); + + // only applies when (m_Type == ot_Class) + void attributeAdded(UMLClassifierListItem*); + void attributeRemoved(UMLClassifierListItem*); + +private: + + UMLAssociation *m_pClassAssoc; + + bool m_isRef; + + /** + * Utility method called by "get*ChildClassfierList()" methods. It basically + * finds all the classifiers named in each association in the given association list + * which aren't the current one. Useful for finding which classifiers are "owned" by the + * current one via declared associations such as in aggregations/compositions. + */ +// UMLClassifierList findAssocClassifierObjsInRoles (UMLAssociationList * list); + +protected: + + void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); + + virtual bool load(QDomElement& element); + +}; + +#endif // CLASSIFIER_H diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/classifierlistitem.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/classifierlistitem.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/classifierlistitem.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/classifierlistitem.cpp 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,159 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "classifierlistitem.h" + +// local includes +#include "debug_utils.h" +#include "classifier.h" +#include "model_utils.h" +#include "object_factory.h" +#include "uml.h" +#include "umldoc.h" + +// kde includes +#include + +/** + * Constructor. + * + * @param parent The parent to this operation. + * At first sight it would appear that the type of the + * parent should be UMLClassifier. However, the class + * UMLAttribute is also used for the parameters of + * operations, and in this case the UMLOperation is the + * parent. + * @param name The name of the operation. + * @param id The id of the operation. + */ +UMLClassifierListItem::UMLClassifierListItem(UMLObject *parent, + const QString& name, Uml::ID::Type id) + : UMLObject(parent, name, id) +{ + UMLObject *parentObj = const_cast(parent); + UMLClassifier *pc = dynamic_cast(parentObj); + if (pc) + UMLObject::setUMLPackage(pc); +} + +/** + * Constructor. + * + * @param parent The parent to this operation. + * At first sight it would appear that the type of the + * parent should be UMLClassifier. However, the class + * UMLAttribute is also used for the parameters of + * operations, and in this case the UMLOperation is the + * parent. + */ +UMLClassifierListItem::UMLClassifierListItem(UMLObject *parent) + : UMLObject(parent) +{ + UMLObject *parentObj = const_cast(parent); + UMLClassifier *pc = dynamic_cast(parentObj); + if (pc) + UMLObject::setUMLPackage(pc); +} + +/** + * Destructor. Empty. + */ +UMLClassifierListItem::~UMLClassifierListItem() +{ +} + +/** + * Copy the internal presentation of this object into the new + * object. + */ +void UMLClassifierListItem::copyInto(UMLObject *lhs) const +{ + // Call the parent. + UMLObject::copyInto(lhs); +} + +/** + * Returns a string representation of the list item. + * + * @param sig What type of operation string to show. + * @return The string representation of the operation. + */ +QString UMLClassifierListItem::toString(Uml::SignatureType::Enum sig) +{ + Q_UNUSED(sig); + return name(); +} + +/** + * Returns the type of the UMLClassifierListItem. + * + * @return The type of the UMLClassifierListItem. + */ +UMLClassifier * UMLClassifierListItem::getType() const +{ + return dynamic_cast(m_pSecondary.data()); +} + +/** + * Returns the type name of the UMLClassifierListItem. + * + * @return The type name of the UMLClassifierListItem. + */ +QString UMLClassifierListItem::getTypeName() const +{ + if (m_pSecondary == NULL) + return m_SecondaryId; + const UMLPackage *typePkg = m_pSecondary->umlPackage(); + if (typePkg != NULL && typePkg != m_pUMLPackage) + return m_pSecondary->fullyQualifiedName(); + return m_pSecondary->name(); +} + +/** + * Sets the type of the UMLAttribute. + * + * @param type Pointer to the UMLObject of the type. + */ +void UMLClassifierListItem::setType(UMLObject *type) +{ + if (m_pSecondary != type) { + m_pSecondary = type; + UMLObject::emitModified(); + } +} + +/** + * Sets the type name of the UMLClassifierListItem. + * DEPRECATED - use setType() instead. + * + * @param type The type name of the UMLClassifierListItem. + */ +void UMLClassifierListItem::setTypeName(const QString &type) +{ + if (type.isEmpty() || type == QLatin1String("void")) { + m_pSecondary = NULL; + m_SecondaryId.clear(); + return; + } + UMLDoc *pDoc = UMLApp::app()->document(); + m_pSecondary = pDoc->findUMLObject(type); + if (m_pSecondary == NULL) { + // Make data type for easily identified cases + if (Model_Utils::isCommonDataType(type) || type.contains(QLatin1Char('*'))) { + m_pSecondary = Object_Factory::createUMLObject(UMLObject::ot_Datatype, type); + uDebug() << "created datatype for " << type; + } else { + m_SecondaryId = type; + } + } + UMLObject::emitModified(); +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/classifierlistitem.h umbrello-kf6-15.08.1/umbrello/umlmodel/classifierlistitem.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/classifierlistitem.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/classifierlistitem.h 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,58 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef CLASSIFIERLISTITEM_H +#define CLASSIFIERLISTITEM_H + +#include "umlobject.h" + +// forward declaration +class UMLClassifier; + +/** + * Classifiers (classes, interfaces) have lists of operations, + * attributes, templates and others. This is a base class for + * the items in this list. This abstraction should remove + * duplication of dialogs and allow for stereotypes in lists. + * + * @short A base class for classifier list items (e.g. attributes) + * @author Jonathan Riddell + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class UMLClassifierListItem : public UMLObject +{ + Q_OBJECT +public: + + UMLClassifierListItem(UMLObject *parent, + const QString& name, + Uml::ID::Type id = Uml::ID::None); + explicit UMLClassifierListItem(UMLObject *parent); + virtual ~UMLClassifierListItem(); + + virtual void setType(UMLObject *type); + UMLClassifier * getType() const; + + void setTypeName(const QString &type); + virtual QString getTypeName() const; + + virtual QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); + + virtual void copyInto(UMLObject *lhs) const; + + /** + * The abstract method UMLObject::clone() must be implemented + * by the classes inheriting from UMLClassifierListItem. + */ + virtual UMLObject* clone() const = 0; + +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/component.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/component.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/component.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/component.cpp 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,127 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "component.h" +// app includes +#include "association.h" +#include "debug_utils.h" +#include "object_factory.h" +#include "model_utils.h" +#include "clipboard/idchangelog.h" +#include "umldoc.h" +// kde includes +#include + +/** + * Sets up a Component. + * @param name The name of the Concept. + * @param id The unique id of the Concept. + */ +UMLComponent::UMLComponent(const QString & name, Uml::ID::Type id) + : UMLPackage(name, id), + m_executable(false) +{ + m_BaseType = UMLObject::ot_Component; +} + +/** + * Destructor. + */ +UMLComponent::~UMLComponent() +{ +} + +/** + * Make a clone of this object. + */ +UMLObject* UMLComponent::clone() const +{ + UMLComponent *clone = new UMLComponent(); + UMLObject::copyInto(clone); + return clone; +} + +/** + * Creates the UML:Component element including its operations, + * attributes and templates + */ +void UMLComponent::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +{ + QDomElement componentElement = UMLObject::save(QLatin1String("UML:Component"), qDoc); + componentElement.setAttribute(QLatin1String("executable"), m_executable); + // Save contained components if any. + if (m_objects.count()) { + QDomElement ownedElement = qDoc.createElement(QLatin1String("UML:Namespace.ownedElement")); + for (UMLObjectListIt objectsIt(m_objects); objectsIt.hasNext();) { + UMLObject* obj = objectsIt.next(); + uIgnoreZeroPointer(obj); + obj->saveToXMI (qDoc, ownedElement); + } + componentElement.appendChild(ownedElement); + } + qElement.appendChild(componentElement); +} + +/** + * Loads the UML:Component element including its ports et al. + */ +bool UMLComponent::load(QDomElement& element) +{ + QString executable = element.attribute(QLatin1String("executable"), QLatin1String("0")); + m_executable = (bool)executable.toInt(); + for (QDomNode node = element.firstChild(); !node.isNull(); + node = node.nextSibling()) { + if (node.isComment()) + continue; + QDomElement tempElement = node.toElement(); + QString type = tempElement.tagName(); + if (Model_Utils::isCommonXMIAttribute(type)) + continue; + if (UMLDoc::tagEq(type, QLatin1String("Namespace.ownedElement")) || + UMLDoc::tagEq(type, QLatin1String("Namespace.contents"))) { + //CHECK: umbrello-kf6 currently assumes that nested elements + // are ownedElements anyway. + // Therefore these tags are not further interpreted. + if (! load(tempElement)) + return false; + continue; + } + UMLObject *pObject = Object_Factory::makeObjectFromXMI(type); + if (!pObject) { + uWarning() << "Unknown type of umlobject to create: " << type; + continue; + } + pObject->setUMLPackage(this); + if (pObject->loadFromXMI(tempElement)) { + addObject(pObject); + } else { + delete pObject; + } + } + return true; +} + +/** + * Sets m_executable. + */ +void UMLComponent::setExecutable(bool executable) +{ + m_executable = executable; +} + +/** + * Returns the value of m_executable. + */ +bool UMLComponent::getExecutable() +{ + return m_executable; +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/component.h umbrello-kf6-15.08.1/umbrello/umlmodel/component.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/component.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/component.h 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,48 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef COMPONENT_H +#define COMPONENT_H + +#include "package.h" + +/** + * This class contains the non-graphical information required for a + * UML Component. + * This class inherits from @ref UMLPackage which contains most + * of the information. + * + * @short Non-graphical information for a Component. + * @author Jonathan Riddell + * @see UMLCanvasObject + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class UMLComponent : public UMLPackage +{ + Q_OBJECT +public: + explicit UMLComponent(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); + virtual ~UMLComponent(); + + virtual UMLObject* clone() const; + + void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); + + void setExecutable(bool executable); + bool getExecutable(); + +protected: + bool load(QDomElement & element); + +private: + bool m_executable; ///< holds whether this is an executable component or not +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/entityattribute.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/entityattribute.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/entityattribute.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/entityattribute.cpp 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,280 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "entityattribute.h" + +// app includes +#include "debug_utils.h" +//#include "umlcanvasobject.h" +#include "umldoc.h" +#include "uml.h" +#include "umlentityattributedialog.h" +#include "object_factory.h" + +// qt includes +#include + +/** + * Sets up an entityattribute. + * @param parent The parent of this UMLEntityAttribute. + * @param name The name of this UMLEntityAttribute. + * @param id The unique id given to this UMLEntityAttribute. + * @param s The visibility of the UMLEntityAttribute. + * @param type The type of this UMLEntityAttribute. + * @param iv The initial value of the entityattribute. + */ +UMLEntityAttribute::UMLEntityAttribute(UMLObject *parent, const QString& name, + Uml::ID::Type id, Uml::Visibility::Enum s, + UMLObject *type, const QString& iv) + : UMLAttribute(parent, name, id, s, type, iv) +{ + init(); + if (m_pSecondary) { + m_pSecondary->setBaseType(UMLObject::ot_Entity); + } +} + +/** + * Sets up an entityattribute. + * @param parent The parent of this UMLEntityAttribute. + */ +UMLEntityAttribute::UMLEntityAttribute(UMLObject *parent) + : UMLAttribute(parent) +{ + init(); +} + +/** + * Destructor. + */ +UMLEntityAttribute::~UMLEntityAttribute() +{ +} + +/** + * Initialize members of this class. + * Auxiliary method used by constructors. + */ +void UMLEntityAttribute::init() +{ + m_BaseType = UMLObject::ot_EntityAttribute; + m_indexType = UMLEntityAttribute::None; + m_autoIncrement = false; + m_null = false; +} + +/** + * Returns the value of the UMLEntityAttribute's attributes property. + * @return The value of the UMLEntityAttribute's attributes property. + */ +QString UMLEntityAttribute::getAttributes() const +{ + return m_attributes; +} + +/** + * Sets the UMLEntityAttribute's attributes property. + * @param attributes The new value for the attributes property. + */ +void UMLEntityAttribute::setAttributes(const QString& attributes) +{ + m_attributes = attributes; +} + +/** + * Returns the UMLEntityAttribute's length/values property. + * @return The new value of the length/values property. + */ +QString UMLEntityAttribute::getValues() const +{ + return m_values; +} + +/** + * Sets the UMLEntityAttribute's length/values property. + * @param values The new value of the length/values property. + */ +void UMLEntityAttribute::setValues(const QString& values) +{ + m_values = values; +} + +/** + * Returns the UMLEntityAttribute's auto_increment boolean + * @return The UMLEntityAttribute's auto_increment boolean + */ +bool UMLEntityAttribute::getAutoIncrement() const +{ + return m_autoIncrement; +} + +/** + * Sets the UMLEntityAttribute's auto_increment boolean + * @param autoIncrement The UMLEntityAttribute's auto_increment boolean + */ +void UMLEntityAttribute::setAutoIncrement(const bool autoIncrement) +{ + m_autoIncrement = autoIncrement; +} + +/** + * Returns the UMLEntityAttribute's index type property. + * @return The value of the UMLEntityAttribute's index type property. + */ +UMLEntityAttribute::DBIndex_Type UMLEntityAttribute::indexType() const +{ + return m_indexType; +} + +/** + * Sets the initial value of the UMLEntityAttribute's index type property. + * @param indexType The initial value of the UMLEntityAttribute's index type property. + */ +void UMLEntityAttribute::setIndexType(const UMLEntityAttribute::DBIndex_Type indexType) +{ + m_indexType = indexType; +} + +/** + * Returns the UMLEntityAttribute's allow null value. + * @return The UMLEntityAttribute's allow null value. + */ +bool UMLEntityAttribute::getNull() const +{ + return m_null; +} + +/** + * Sets the initial value of the UMLEntityAttribute's allow null value. + * @param nullIn The initial value of the UMLEntityAttribute's allow null value. + */ +void UMLEntityAttribute::setNull(const bool nullIn) +{ + m_null = nullIn; +} + +/** + * Returns a string representation of the UMLEntityAttribute. + * @param sig If true will show the entityattribute type and initial value. + * @return Returns a string representation of the UMLEntityAttribute. + */ +QString UMLEntityAttribute::toString(Uml::SignatureType::Enum sig) +{ + QString s; + //FIXME + + if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::NoSig) { + s = Uml::Visibility::toString(m_visibility, true) + QLatin1Char(' '); + } + + if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::SigNoVis) { + QString string = s + name() + QLatin1String(" : ") + getTypeName(); + if(m_InitialValue.length() > 0) + string += QLatin1String(" = ") + m_InitialValue; + return string; + } else + return s + name(); +} + +/** + * Overloaded '==' operator + */ +bool UMLEntityAttribute::operator==(const UMLEntityAttribute &rhs) const +{ + if(this == &rhs) + return true; + + if(!UMLObject::operator==(rhs)) + return false; + + // The type name is the only distinguishing criterion. + // (Some programming languages might support more, but others don't.) + if (m_pSecondary != rhs.m_pSecondary) + return false; + + return true; +} + +/** + * Copy the internal presentation of this object into the UMLEntityAttribute + * object. + */ +void UMLEntityAttribute::copyInto(UMLObject *lhs) const +{ + UMLEntityAttribute *target = static_cast(lhs); + + // call the parent first. + UMLClassifierListItem::copyInto(target); + + // Copy all datamembers + target->m_pSecondary = m_pSecondary; + target->m_SecondaryId = m_SecondaryId; + target->m_InitialValue = m_InitialValue; + target->m_ParmKind = m_ParmKind; +} + +/** + * Make a clone of the UMLEntityAttribute. + */ +UMLObject* UMLEntityAttribute::clone() const +{ + UMLEntityAttribute* clone = new UMLEntityAttribute((UMLEntityAttribute*)parent()); + copyInto(clone); + + return clone; +} + +/** + * Creates the XMI element. + */ +void UMLEntityAttribute::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +{ + QDomElement entityattributeElement = UMLObject::save(QLatin1String("UML:EntityAttribute"), qDoc); + if (m_pSecondary == NULL) { + uDebug() << name() << ": m_pSecondary is NULL, using local name " << m_SecondaryId; + entityattributeElement.setAttribute(QLatin1String("type"), m_SecondaryId); + } else { + entityattributeElement.setAttribute(QLatin1String("type"), Uml::ID::toString(m_pSecondary->id())); + } + entityattributeElement.setAttribute(QLatin1String("initialValue"), m_InitialValue); + entityattributeElement.setAttribute(QLatin1String("dbindex_type"), m_indexType); + entityattributeElement.setAttribute(QLatin1String("values"), m_values); + entityattributeElement.setAttribute(QLatin1String("attributes"), m_attributes); + entityattributeElement.setAttribute(QLatin1String("auto_increment"), m_autoIncrement); + entityattributeElement.setAttribute(QLatin1String("allow_null"), m_null); + qElement.appendChild(entityattributeElement); +} + +/** + * Loads the XMI element. + */ +bool UMLEntityAttribute::load(QDomElement & element) +{ + if (! UMLAttribute::load(element)) + return false; + int indexType = element.attribute(QLatin1String("dbindex_type"), QLatin1String("1100")).toInt(); + m_indexType = (UMLEntityAttribute::DBIndex_Type)indexType; + m_values = element.attribute(QLatin1String("values")); + m_attributes = element.attribute(QLatin1String("attributes")); + m_autoIncrement = (bool)element.attribute(QLatin1String("auto_increment")).toInt(); + m_null = (bool)element.attribute(QLatin1String("allow_null")).toInt(); + return true; +} + +/** + * Display the properties configuration dialog for the entityattribute. + */ +bool UMLEntityAttribute::showPropertiesDialog(QWidget* parent) +{ + UMLEntityAttributeDialog dialog(parent, this); + return dialog.exec(); +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/entityattribute.h umbrello-kf6-15.08.1/umbrello/umlmodel/entityattribute.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/entityattribute.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/entityattribute.h 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,85 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef ENTITYATTRIBUTE_H +#define ENTITYATTRIBUTE_H + +#include "attribute.h" +#include "basictypes.h" + +/** + * This class is used to set up information for an entityattribute. This is a database field + * It has a type, name, index type and default value. + * + * @short Sets up entityattribute information. + * @author Jonathan Riddell + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class UMLEntityAttribute : public UMLAttribute +{ + Q_OBJECT + Q_ENUMS(DBIndex_Type) +public: + enum DBIndex_Type + { + None = 1100, + Primary, + Index, + Unique + }; + + UMLEntityAttribute(UMLObject* parent, const QString& name, + Uml::ID::Type id = Uml::ID::None, + Uml::Visibility::Enum s = Uml::Visibility::Private, + UMLObject *type = 0, const QString& iv = QString()); + explicit UMLEntityAttribute(UMLObject* parent); + virtual ~UMLEntityAttribute(); + + bool operator==(const UMLEntityAttribute& rhs) const; + + virtual void copyInto(UMLObject *lhs) const; + + virtual UMLObject* clone() const; + + void setAttributes(const QString& attributes); + QString getAttributes() const; + + void setIndexType(const DBIndex_Type indexType); + DBIndex_Type indexType() const; + + void setValues(const QString& values); + QString getValues() const; + + void setAutoIncrement(const bool autoIncrement); + bool getAutoIncrement() const; + + void setNull(const bool null); + bool getNull() const; + + QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); + + virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); + + virtual bool showPropertiesDialog(QWidget* parent = 0); + +protected: + void init(); + + bool load(QDomElement& element); + +private: + DBIndex_Type m_indexType; + QString m_values; + QString m_attributes; + bool m_autoIncrement; + bool m_null; +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/entityconstraint.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/entityconstraint.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/entityconstraint.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/entityconstraint.cpp 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,76 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +//own header +#include "entityconstraint.h" + +// app includes +#include "umlobject.h" +#include "umldoc.h" +#include "uml.h" + +// qt includes +#include + +/** + * Sets up a constraint. + * @param parent The parent of this UMLEntityConstraint. + * @param name The name of this UMLEntityConstraint. + * @param id The unique id given to this UMLEntityConstraint. + */ +UMLEntityConstraint::UMLEntityConstraint(UMLObject *parent, + const QString& name, Uml::ID::Type id) + : UMLClassifierListItem(parent, name, id) +{ + m_BaseType = UMLObject::ot_EntityConstraint; +} + +/** + * Sets up a constraint. + * @param parent The parent of this UMLEntityConstraint. + */ +UMLEntityConstraint::UMLEntityConstraint(UMLObject *parent) + : UMLClassifierListItem(parent) +{ + m_BaseType = UMLObject::ot_EntityConstraint; +} + +/** + * Overloaded '==' operator + */ +bool UMLEntityConstraint::operator==(const UMLEntityConstraint &rhs) const +{ + if(this == &rhs) + return true; + + if(!UMLObject::operator==(rhs)) + return false; + + return true; +} + +/** + * destructor. + */ +UMLEntityConstraint::~UMLEntityConstraint() +{ +} + +/** + * Copy the internal presentation of this object into the UMLEntityConstraint + * object. + */ +void UMLEntityConstraint::copyInto(UMLObject *lhs) const +{ + // call the parent first. + UMLClassifierListItem::copyInto(lhs); +} + + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/entityconstraint.h umbrello-kf6-15.08.1/umbrello/umlmodel/entityconstraint.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/entityconstraint.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/entityconstraint.h 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,49 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef ENTITYCONSTRAINT_H +#define ENTITYCONSTRAINT_H + +#include "basictypes.h" +#include "classifierlistitem.h" +#include "umlclassifierlist.h" + +/** + * This class is used to set up information for a entity constraint. + * + * @short Sets up entity constraint information. + * @author Sharan Rao + * @see UMLObject UMLClassifierListItem + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class UMLEntityConstraint : public UMLClassifierListItem +{ + Q_OBJECT + +public: + UMLEntityConstraint(UMLObject *parent, const QString& name, + Uml::ID::Type id = Uml::ID::None); + + explicit UMLEntityConstraint(UMLObject *parent); + + bool operator==(const UMLEntityConstraint &rhs) const; + + virtual ~UMLEntityConstraint(); + + virtual void copyInto(UMLObject *lhs) const; + + /** + * Make a clone of the UMLEntityConstraint. + */ + virtual UMLObject* clone() const = 0; + +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/entity.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/entity.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/entity.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/entity.cpp 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,719 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "entity.h" + +// app includes +#include "debug_utils.h" +#include "entityattribute.h" +#include "uniqueconstraint.h" +#include "foreignkeyconstraint.h" +#include "checkconstraint.h" +#include "umldoc.h" +#include "uml.h" +#include "uniqueid.h" +#include "umlentityattributelist.h" +#include "umlentityconstraintlist.h" +#include "idchangelog.h" +#include "umlentityattributedialog.h" +#include "umluniqueconstraintdialog.h" +#include "umlforeignkeyconstraintdialog.h" +#include "umlcheckconstraintdialog.h" + +// kde includes +#include +#include + +// qt includes +#include + +/** + * Constructor. + */ +UMLEntity::UMLEntity(const QString& name, Uml::ID::Type id) + : UMLClassifier(name, id), + m_PrimaryKey(0) +{ + m_BaseType = UMLObject::ot_Entity; + connect(this, SIGNAL(entityAttributeRemoved(UMLClassifierListItem*)), + this, SLOT(slotEntityAttributeRemoved(UMLClassifierListItem*))); +} + +/** + * Standard destructor. + */ +UMLEntity::~UMLEntity() +{ + m_List.clear(); +} + +/** + * Overloaded '==' operator. + */ +bool UMLEntity::operator==(const UMLEntity& rhs) const +{ + return UMLClassifier::operator==(rhs); +} + +/** + * Copy the internal presentation of this object into the new + * object. + */ +void UMLEntity::copyInto(UMLObject *lhs) const +{ + UMLEntity *target = static_cast(lhs); + + // call base class copy function + UMLClassifier::copyInto(target); + + // copy local data items + target->m_PrimaryKey = m_PrimaryKey; +} + +/** + * Make a clone of this object. + */ +UMLObject* UMLEntity::clone() const +{ + UMLEntity* clone = new UMLEntity(); + copyInto(clone); + + return clone; +} + +/** + * Create an UMLAttribute. + * @param name an optional name for the attribute + * @param type an optional type object for the attribute + * @param vis the visibility of the attribute + * @param iv the initial value for the attribute + * @return the just created attribute or null + */ +UMLAttribute* UMLEntity::createAttribute(const QString &name /*= QString()*/, UMLObject *type /*= 0*/, + Uml::Visibility::Enum vis /* = Uml::Visibility::Private*/, + const QString& iv /* = QString()*/) +{ + Uml::ID::Type id = UniqueID::gen(); + QString currentName; + if (name.isNull()) { + currentName = uniqChildName(UMLObject::ot_EntityAttribute); + } else { + currentName = name; + } + + UMLEntityAttribute* newAttribute = new UMLEntityAttribute(this, currentName, id, vis, type, iv); + + int button = QDialog::Accepted; + bool goodName = false; + + //check for name.isNull() stops dialog being shown + //when creating attribute via list view + while (button == QDialog::Accepted && !goodName && name.isNull()) { + QPointer dialog = new UMLEntityAttributeDialog(0, newAttribute); + button = dialog->exec(); + QString name = newAttribute->name(); + + if (name.length() == 0) { + KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); + } else if (findChildObject(name) != NULL) { + KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name")); + } else { + goodName = true; + } + delete dialog; + } + + if (button != QDialog::Accepted) { + delete newAttribute; + return 0; + } + + addEntityAttribute(newAttribute); + + UMLDoc *umldoc = UMLApp::app()->document(); + umldoc->signalUMLObjectCreated(newAttribute); + return newAttribute; +} + +/** + * Creates a Unique Constraint for this Entity. + * @param name an optional name + * @return the UniqueConstraint created + */ +UMLUniqueConstraint* UMLEntity::createUniqueConstraint(const QString &name) +{ + Uml::ID::Type id = UniqueID::gen(); + QString currentName; + if (name.isNull()) { + + /** + * @todo check parameter + */ + currentName = uniqChildName(UMLObject::ot_UniqueConstraint); + } else { + currentName = name; + } + + UMLUniqueConstraint* newUniqueConstraint = new UMLUniqueConstraint(this, currentName, id); + + int button = QDialog::Accepted; + bool goodName = false; + + //check for name.isNull() stops dialog being shown + //when creating attribute via list view + while (button == QDialog::Accepted && !goodName && name.isNull()) { + QPointer dialog = new UMLUniqueConstraintDialog(0, newUniqueConstraint); + button = dialog->exec(); + QString name = newUniqueConstraint->name(); + + if (name.length() == 0) { + KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); + } else if (findChildObject(name) != NULL) { + KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name")); + } else { + goodName = true; + } + delete dialog; + } + + if (button != QDialog::Accepted) { + delete newUniqueConstraint; + return NULL; + } + + addConstraint(newUniqueConstraint); + + UMLDoc *umldoc = UMLApp::app()->document(); + umldoc->signalUMLObjectCreated(newUniqueConstraint); + emitModified(); + return newUniqueConstraint; +} + +/** + * Creates a Foreign Key Constraint for this Entity. + * @param name an optional name + * @return the ForeignKeyConstraint created + */ +UMLForeignKeyConstraint* UMLEntity::createForeignKeyConstraint(const QString &name) +{ + Uml::ID::Type id = UniqueID::gen(); + QString currentName; + if (name.isNull()) { + currentName = uniqChildName(UMLObject::ot_ForeignKeyConstraint); + } else { + currentName = name; + } + + UMLForeignKeyConstraint* newForeignKeyConstraint = new UMLForeignKeyConstraint(this, currentName, id); + + int button = QDialog::Accepted; + bool goodName = false; + + //check for name.isNull() stops dialog being shown + //when creating attribute via list view + while (button == QDialog::Accepted && !goodName && name.isNull()) { + QPointer dialog = new UMLForeignKeyConstraintDialog(0, newForeignKeyConstraint); + button = dialog->exec(); + QString name = newForeignKeyConstraint->name(); + + if (name.length() == 0) { + KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); + } else if (findChildObject(name) != NULL) { + KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name")); + } else { + goodName = true; + } + delete dialog; + } + + if (button != QDialog::Accepted) { + return NULL; + } + + addConstraint(newForeignKeyConstraint); + + UMLDoc *umldoc = UMLApp::app()->document(); + umldoc->signalUMLObjectCreated(newForeignKeyConstraint); + emitModified(); + return newForeignKeyConstraint; +} + +/** + * Creates a Check Constraint for this Entity. + * @param name an optional name + * @return the CheckConstraint created + */ +UMLCheckConstraint* UMLEntity::createCheckConstraint(const QString &name) +{ + Uml::ID::Type id = UniqueID::gen(); + QString currentName; + if (name.isNull()) { + currentName = uniqChildName(UMLObject::ot_CheckConstraint); + } else { + currentName = name; + } + + UMLCheckConstraint* newCheckConstraint = new UMLCheckConstraint(this, currentName, id); + + int button = QDialog::Accepted; + bool goodName = false; + + //check for name.isNull() stops dialog being shown + //when creating attribute via list view + while (button == QDialog::Accepted && !goodName && name.isNull()) { + QPointer dialog = new UMLCheckConstraintDialog(0, newCheckConstraint); + button = dialog->exec(); + QString name = newCheckConstraint->name(); + + if (name.length() == 0) { + KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); + } else if (findChildObject(name) != NULL) { + KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name")); + } else { + goodName = true; + } + delete dialog; + } + + if (button != QDialog::Accepted) { + return NULL; + } + + addConstraint(newCheckConstraint); + + UMLDoc *umldoc = UMLApp::app()->document(); + umldoc->signalUMLObjectCreated(newCheckConstraint); + emitModified(); + return newCheckConstraint; +} + +/** + * Adds an entityAttribute. + * The entityAttribute object must not belong to any other concept. + * @param name name of the UMLEntityAttribute + * @param id id of the UMLEntityAttribute + * @return True if the entityAttribute was successfully added. + */ +UMLObject* UMLEntity::addEntityAttribute(const QString& name, Uml::ID::Type id) +{ + UMLEntityAttribute* literal = new UMLEntityAttribute(this, name, id); + m_List.append(literal); + emit entityAttributeAdded(literal); + UMLObject::emitModified(); + connect(literal, SIGNAL(modified()), this, SIGNAL(modified())); + return literal; +} + +/** + * Adds an already created entityAttribute. + * The entityAttribute object must not belong to any other concept. + * @param att Pointer to the UMLEntityAttribute. + * @param log Pointer to the IDChangeLog. + * @return True if the entityAttribute was successfully added. + */ +bool UMLEntity::addEntityAttribute(UMLEntityAttribute* att, IDChangeLog* log /* = 0*/) +{ + QString name = (QString)att->name(); + if (findChildObject(name) == NULL) { + att->setParent(this); + m_List.append(att); + emit entityAttributeAdded(att); + UMLObject::emitModified(); + connect(att, SIGNAL(modified()), this, SIGNAL(modified())); + return true; + } else if (log) { + log->removeChangeByNewID(att->id()); + delete att; + } + return false; +} + +/** + * Adds an entityAttribute to the entity, at the given position. + * If position is negative or too large, the entityAttribute is added + * to the end of the list. + * TODO: give default value -1 to position (append) - now it conflicts with the method above.. + * @param att Pointer to the UMLEntityAttribute. + * @param position Position index for the insertion. + * @return True if the entityAttribute was successfully added. + */ +bool UMLEntity::addEntityAttribute(UMLEntityAttribute* att, int position) +{ + Q_ASSERT(att); + QString name = (QString)att->name(); + if (findChildObject(name) == NULL) { + att->setParent(this); + if (position >= 0 && position <= (int)m_List.count()) { + m_List.insert(position, att); + } else { + m_List.append(att); + } + emit entityAttributeAdded(att); + UMLObject::emitModified(); + connect(att, SIGNAL(modified()), this, SIGNAL(modified())); + return true; + } + return false; +} + +/** + * Removes an entityAttribute from the class. + * @param att The entityAttribute to remove. + * @return Count of the remaining entityAttributes after removal. + * Returns -1 if the given entityAttribute was not found. + */ +int UMLEntity::removeEntityAttribute(UMLClassifierListItem* att) +{ + if (!m_List.removeAll((UMLEntityAttribute*)att)) { + uDebug() << "cannot find att given in list"; + return -1; + } + emit entityAttributeRemoved(att); + UMLObject::emitModified(); + // If we are deleting the object, then we don't need to disconnect..this is done auto-magically + // for us by QObject. -b.t. + // disconnect(att, SIGNAL(modified()), this, SIGNAL(modified())); + delete att; + return m_List.count(); +} + +/** + * Returns the number of entityAttributes for the class. + * @return The number of entityAttributes for the class. + */ +int UMLEntity::entityAttributes() +{ + UMLClassifierListItemList entityAttributes = getFilteredList(UMLObject::ot_EntityAttribute); + return entityAttributes.count(); +} + +/** + * Emit the entityAttributeRemoved signal. + */ +void UMLEntity::signalEntityAttributeRemoved(UMLClassifierListItem *eattr) +{ + emit entityAttributeRemoved(eattr); +} + +/** + * Resolve the types referenced by our UMLEntityAttributes. + * Reimplements the method from UMLClassifier. + */ +bool UMLEntity::resolveRef() +{ + bool success = UMLClassifier::resolveRef(); + for (UMLObjectListIt oit(m_List); oit.hasNext();) { + UMLObject* obj = oit.next(); + if (obj->resolveRef()) { + UMLClassifierListItem *cli = static_cast(obj); + switch (cli->baseType()) { + case UMLObject::ot_EntityAttribute: + emit entityAttributeAdded(cli); + break; + case UMLObject::ot_UniqueConstraint: + case UMLObject::ot_ForeignKeyConstraint: + emit entityConstraintAdded(cli); + break; + default: + break; + } + } + } + return success; +} + +/** + * Creates the element including its entityliterals. + */ +void UMLEntity::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +{ + QDomElement entityElement = UMLObject::save(QLatin1String("UML:Entity"), qDoc); + //save operations + UMLClassifierListItemList entityAttributes = getFilteredList(UMLObject::ot_EntityAttribute); + UMLClassifierListItem* pEntityAttribute = 0; + foreach (pEntityAttribute, entityAttributes) { + pEntityAttribute->saveToXMI(qDoc, entityElement); + } + + UMLClassifierListItemList entityConstraints = getFilteredList(UMLObject::ot_EntityConstraint); + foreach(UMLClassifierListItem* cli, entityConstraints) { + cli->saveToXMI(qDoc, entityElement); + } + + qElement.appendChild(entityElement); +} + +/** + * Loads the element including its entityAttributes. + */ +bool UMLEntity::load(QDomElement& element) +{ + QDomNode node = element.firstChild(); + while(!node.isNull()) { + if (node.isComment()) { + node = node.nextSibling(); + continue; + } + QDomElement tempElement = node.toElement(); + QString tag = tempElement.tagName(); + if (UMLDoc::tagEq(tag, QLatin1String("EntityAttribute"))) { // for backward compatibility + UMLEntityAttribute* pEntityAttribute = new UMLEntityAttribute(this); + if(!pEntityAttribute->loadFromXMI(tempElement)) { + return false; + } + m_List.append(pEntityAttribute); + } else if (UMLDoc::tagEq(tag, QLatin1String("UniqueConstraint"))) { + UMLUniqueConstraint* pUniqueConstraint = new UMLUniqueConstraint(this); + if (!pUniqueConstraint->loadFromXMI(tempElement)) { + return false; + } + addConstraint(pUniqueConstraint); + } else if (UMLDoc::tagEq(tag, QLatin1String("ForeignKeyConstraint"))) { + UMLForeignKeyConstraint* pForeignKeyConstraint = new UMLForeignKeyConstraint(this); + if (!pForeignKeyConstraint->loadFromXMI(tempElement)) { + return false; + } + + addConstraint(pForeignKeyConstraint); + } else if (UMLDoc::tagEq(tag, QLatin1String("CheckConstraint"))) { + + UMLCheckConstraint* pCheckConstraint = new UMLCheckConstraint(this); + if (!pCheckConstraint->loadFromXMI(tempElement)) { + return false; + } + + addConstraint(pCheckConstraint); + } else if (tag == QLatin1String("stereotype")) { + uDebug() << name() << ": losing old-format stereotype."; + } else { + uWarning() << "unknown child type in UMLEntity::load"; + } + node = node.nextSibling(); + }//end while + return true; +} + +/** + * Sets the UniqueConstraint passed as the Primary Key of this Entity + * If the UniqueConstraint exists, then it is made a primary key + * Else the UniqueConstraint is added and set as PrimaryKey + * @param uconstr The Unique Constraint that is to be set as Primary Key + * @return true if Primary key could be set successfully + */ +bool UMLEntity::setAsPrimaryKey(UMLUniqueConstraint* uconstr) +{ + if (uconstr == NULL) { + uDebug() << "NULL value passed. To unset a Primary Key use " + << "unsetPrimaryKey()"; + return false; + } + + if (static_cast(uconstr->parent()) != this) { + + uDebug() << "Parent of " << uconstr->name() + << " does not match with current entity"; + return false; + } + + // check if this constraint already exists as a unique constraint for this entity + UMLUniqueConstraint* uuc = static_cast(findChildObjectById(uconstr->id())); + if (uuc == NULL) { + addConstraint(uconstr); + uuc = uconstr; + } + + UMLUniqueConstraint* oldPrimaryKey = m_PrimaryKey; + + m_PrimaryKey = uuc; + + if (oldPrimaryKey != NULL) + oldPrimaryKey->emitModified(); + + uuc->emitModified(); + emitModified(); + return true; +} + +/** + * Unset a Primary Key Constraint if it exists, else does nothing + * This function will make the primary key into just another UniqueConstraint + * if it exists + */ +void UMLEntity::unsetPrimaryKey() +{ + m_PrimaryKey = 0; +} + +/** + * Checks if This UMLEntity has a primary key set. + * @return true if a Primary Key Exists for this UMLEntity + */ +bool UMLEntity::hasPrimaryKey() const +{ + if (m_PrimaryKey) { + return true; + } + + return false; +} + +/** + * Adds a Constraint to this UMLEntity. + * To set a UMLUniqueConstraint as Primary Key use setAsPrimaryKey. + * @param constr The UMLEntityConstraint that is to be added + * @return true if the constraint could be added successfully + */ +bool UMLEntity::addConstraint(UMLEntityConstraint* constr) +{ + if (findChildObjectById(constr->id()) != NULL) { + uDebug() << "Constraint with id " << Uml::ID::toString(constr->id()) + << " already exists "; + return false; + } + + m_List.append(constr); + + emit entityConstraintAdded(constr); + UMLObject::emitModified(); + connect(constr, SIGNAL(modified()), this, SIGNAL(modified())); + + return true; +} + +/** + * Removes an existing constraint from this UMLEntity. + * If the Contraint is a Primary Key, this Entity will no longer have a PrimaryKey. + * @param constr the constraint to be removed + * @return true if the constraint could be removed successfully + */ +bool UMLEntity::removeConstraint(UMLEntityConstraint* constr) +{ + if (findChildObjectById(constr->id()) == NULL) { + uDebug() << "Constraint with id " << Uml::ID::toString(constr->id()) + << " does not exist "; + return false; + } + + if (m_PrimaryKey == constr) { + unsetPrimaryKey(); + } + + m_List.removeAll(constr); + + emit entityConstraintRemoved(constr); + UMLObject::emitModified(); + + delete constr; + return true; +} + +/** + * Slot for entity attribute removed. + */ +void UMLEntity::slotEntityAttributeRemoved(UMLClassifierListItem* cli) +{ + // this function does some cleanjobs related to this entity when the attribute is + // removed, like, removing the attribute from all constraints + + UMLEntityAttribute* entAtt = static_cast(cli); + if (cli) { + UMLClassifierListItemList ual = this->getFilteredList(UMLObject::ot_UniqueConstraint); + + foreach(UMLClassifierListItem* ucli, ual) { + UMLUniqueConstraint* uuc = static_cast(ucli); + if (uuc->hasEntityAttribute(entAtt)) { + uuc->removeEntityAttribute(entAtt); + } + } + } + +} + +/** + * Reimplementation of getFilteredList to support ot=UMLObject::ot_EntityConstraint. + */ +UMLClassifierListItemList UMLEntity::getFilteredList(UMLObject::ObjectType ot) const +{ + if (ot == UMLObject::ot_EntityConstraint) { + UMLClassifierListItemList ucList, fcList, ccList, rcList; + ucList = UMLClassifier::getFilteredList(UMLObject::ot_UniqueConstraint); + fcList = UMLClassifier::getFilteredList(UMLObject::ot_ForeignKeyConstraint); + ccList = UMLClassifier::getFilteredList(UMLObject::ot_CheckConstraint); + + // append the lists to rcList + // first the Unique Constraints + foreach(UMLClassifierListItem* ucli, ucList) { + rcList.append(ucli); + } + + // then the Foreign Key Constraints + foreach(UMLClassifierListItem* ucli, fcList) { + rcList.append(ucli); + } + + foreach(UMLClassifierListItem* ucli, ccList) { + rcList.append(ucli); + } + + return rcList; + } else { + return UMLClassifier::getFilteredList(ot); + } +} + +/** + * Checks if a given Unique Constraint is primary key of this entity + * @param uConstr a Unique Constraint + * @return bool true if passed parameter is a primary key of this entity + */ +bool UMLEntity::isPrimaryKey(UMLUniqueConstraint* uConstr) const +{ + if (uConstr == m_PrimaryKey) { + return true; + } + + return false; +} + +/** + * Returns the Entity Attributes. + * Same as getFilteredList(UMLObject::ot_EntityAttribute). + */ +UMLEntityAttributeList UMLEntity::getEntityAttributes() const +{ + UMLEntityAttributeList entityAttributeList; + for (UMLObjectListIt lit(m_List); lit.hasNext();) { + UMLObject *listItem = lit.next(); + if (listItem->baseType() == UMLObject::ot_EntityAttribute) { + entityAttributeList.append(static_cast(listItem)); + } + } + return entityAttributeList; +} + + +/** + * Create a new ClassifierListObject (entityattribute) + * according to the given XMI tag. + * Returns NULL if the string given does not contain one of the tags + * + * Used by the clipboard for paste operation. + * Reimplemented from UMLClassifier for UMLEntity + */ +UMLClassifierListItem* UMLEntity::makeChildObject(const QString& xmiTag) +{ + UMLClassifierListItem* pObject = NULL; + if (UMLDoc::tagEq(xmiTag, QLatin1String("EntityAttribute"))) { + pObject = new UMLEntityAttribute(this); + } + return pObject; +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/entity.h umbrello-kf6-15.08.1/umbrello/umlmodel/entity.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/entity.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/entity.h 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,108 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef ENTITY_H +#define ENTITY_H + +#include "classifier.h" + +// forward declarations +class UMLEntityAttribute; +class UMLEntityConstraint; +class UMLUniqueConstraint; +class UMLForeignKeyConstraint; +class UMLCheckConstraint; +class UMLEntityAttributeList; + +/** + * This class contains the non-graphical information required for a UML + * Entity. + * This class inherits from @ref UMLClassifier which contains most of the + * information. + * + * @short Non-graphical Information for an Entity. + * @author Jonathan Riddell + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class UMLEntity : public UMLClassifier +{ + Q_OBJECT +public: + explicit UMLEntity(const QString& name = QString(), Uml::ID::Type id = Uml::ID::None); + virtual ~UMLEntity(); + + bool operator==(const UMLEntity& rhs) const; + + virtual void copyInto(UMLObject *lhs) const; + + virtual UMLObject* clone() const; + + virtual UMLAttribute* createAttribute(const QString &name = QString(), + UMLObject *type = 0, Uml::Visibility::Enum vis = Uml::Visibility::Private, + const QString &init = QString()); + + UMLUniqueConstraint* createUniqueConstraint(const QString &name = QString()); + UMLForeignKeyConstraint* createForeignKeyConstraint(const QString &name = QString()); + UMLCheckConstraint* createCheckConstraint(const QString &name = QString()); + + UMLObject* addEntityAttribute(const QString &name, Uml::ID::Type id = Uml::ID::None); + bool addEntityAttribute(UMLEntityAttribute* att, IDChangeLog* log = 0); + bool addEntityAttribute(UMLEntityAttribute* att, int position); + + int removeEntityAttribute(UMLClassifierListItem* att); + + void signalEntityAttributeRemoved(UMLClassifierListItem *eattr); + + int entityAttributes() ; + + bool setAsPrimaryKey(UMLUniqueConstraint* uconstr); + void unsetPrimaryKey(); + bool hasPrimaryKey() const; + bool isPrimaryKey(UMLUniqueConstraint* uConstr) const; + + bool addConstraint(UMLEntityConstraint* constr); + bool removeConstraint(UMLEntityConstraint* constr); + + virtual bool resolveRef(); + + virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); + + UMLClassifierListItemList getFilteredList(UMLObject::ObjectType ot) const; + + UMLEntityAttributeList getEntityAttributes() const; + + virtual UMLClassifierListItem* makeChildObject(const QString& xmiTag); + +private slots: + void slotEntityAttributeRemoved(UMLClassifierListItem*); + +signals: + void entityAttributeAdded(UMLClassifierListItem*); + void entityAttributeRemoved(UMLClassifierListItem*); + void entityConstraintAdded(UMLClassifierListItem*); + void entityConstraintRemoved(UMLClassifierListItem*); + +protected: + bool load(QDomElement& element); + +private: + + /** + * Primary Key of this Entity + * This is a pointer kept for easy access to the primary key, and to distinguish it + * from all other UniqueConstraints. It is also there in m_List (inherited from + * UMLCanvasObject) + */ + UMLUniqueConstraint* m_PrimaryKey; + +}; + +#endif // ENTITY_H + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/enum.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/enum.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/enum.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/enum.cpp 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,302 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "enum.h" + +// app includes +#include "debug_utils.h" +#include "enumliteral.h" +#include "umldoc.h" +#include "uml.h" +#include "uniqueid.h" +#include "idchangelog.h" + +// kde includes +#include +#include + +/** + * Sets up an enum. + * @param name The name of the Enum. + * @param id The unique id of the Enum. + */ +UMLEnum::UMLEnum(const QString& name, Uml::ID::Type id) : UMLClassifier(name, id) +{ + init(); +} + +/** + * Standard destructor. + */ +UMLEnum::~UMLEnum() +{ + m_List.clear(); +} + +/** + * Overloaded '==' operator. + */ +bool UMLEnum::operator==(const UMLEnum & rhs) const +{ + return UMLClassifier::operator==(rhs); +} + +/** + * Copy the internal presentation of this object into the new + * object. + */ +void UMLEnum::copyInto(UMLObject *lhs) const +{ + UMLClassifier::copyInto(lhs); +} + +/** + * Make a clone of this object. + */ +UMLObject* UMLEnum::clone() const +{ + UMLEnum *clone = new UMLEnum(); + copyInto(clone); + + return clone; +} + +/** + * Initializes key variables of the class. + */ +void UMLEnum::init() +{ + m_BaseType = UMLObject::ot_Enum; + setStereotypeCmd(QLatin1String("enum")); +} + +/** + * Creates a literal for the enum. + * @return The UMLEnum created + */ +UMLObject* UMLEnum::createEnumLiteral(const QString& name) +{ + Uml::ID::Type id = UniqueID::gen(); + QString currentName; + if (name.isNull()) { + currentName = uniqChildName(UMLObject::ot_EnumLiteral); + } else { + currentName = name; + } + + UMLEnumLiteral* newEnumLiteral = new UMLEnumLiteral(this, currentName); + + bool ok = true; + bool goodName = false; + + //check for name.isNull() stops dialog being shown + //when creating enum literal via list view + while (ok && !goodName && name.isNull()) { + ok = newEnumLiteral->showPropertiesDialog(UMLApp::app()); + QString name = newEnumLiteral->name(); + + if(name.length() == 0) { + KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); + } else { + goodName = true; + } + } + + if (!ok) { + delete newEnumLiteral; + return NULL; + } + + addEnumLiteral(newEnumLiteral); + + UMLDoc *umldoc = UMLApp::app()->document(); + umldoc->signalUMLObjectCreated(newEnumLiteral); + return newEnumLiteral; +} + +/** + * Adds an enumliteral to the enum. + * @param name The name of the enumliteral. + * @param id The id of the enumliteral (optional.) + * If omitted a new ID is assigned internally. + * @return Pointer to the UMLEnumliteral created. + */ +UMLObject* UMLEnum::addEnumLiteral(const QString &name, Uml::ID::Type id) +{ + UMLObject *el = UMLCanvasObject::findChildObject(name); + if (el != NULL) { + uDebug() << name << " is already present"; + return el; + } + UMLEnumLiteral* literal = new UMLEnumLiteral(this, name, id); + m_List.append(literal); + UMLObject::emitModified(); + emit enumLiteralAdded(literal); + connect(literal, SIGNAL(modified()), this, SIGNAL(modified())); + return literal; +} + +/** + * Adds an already created enumliteral. + * The enumliteral object must not belong to any other concept. + * @param literal Pointer to the UMLEnumLiteral. + * @param Log Pointer to the IDChangeLog. + * @return True if the enumliteral was successfully added. + */ +bool UMLEnum::addEnumLiteral(UMLEnumLiteral* literal, IDChangeLog* Log /* = 0*/) +{ + QString name = (QString)literal->name(); + if (findChildObject(name) == NULL) { + literal->setParent(this); + m_List.append(literal); + UMLObject::emitModified(); + emit enumLiteralAdded(literal); + connect(literal, SIGNAL(modified()), this, SIGNAL(modified())); + return true; + } else if (Log) { + Log->removeChangeByNewID(literal->id()); + delete literal; + } + return false; +} + +/** + * Adds an enumliteral to the enum, at the given position. + * If position is negative or too large, the enumliteral is added + * to the end of the list. + * TODO: give default value -1 to position (append) - now it conflicts with the method above.. + * @param literal Pointer to the UMLEnumLiteral. + * @param position Position index for the insertion. + * @return True if the enumliteral was successfully added. + */ +bool UMLEnum::addEnumLiteral(UMLEnumLiteral* literal, int position) +{ + Q_ASSERT(literal); + QString name = (QString)literal->name(); + if (findChildObject(name) == NULL) { + literal->setParent(this); + if (position >= 0 && position <= (int)m_List.count()) { + m_List.insert(position, literal); + } else { + m_List.append(literal); + } + UMLObject::emitModified(); + emit enumLiteralAdded(literal); + connect(literal, SIGNAL(modified()), this, SIGNAL(modified())); + return true; + } + return false; +} + +/** + * Removes an enumliteral from the class. + * @param literal The enumliteral to remove. + * @return Count of the remaining enumliterals after removal. + * Returns -1 if the given enumliteral was not found. + */ +int UMLEnum::removeEnumLiteral(UMLEnumLiteral* literal) +{ + if (!m_List.removeAll(literal)) { + uDebug() << "cannot find att given in list"; + return -1; + } + emit enumLiteralRemoved(literal); + UMLObject::emitModified(); + // If we are deleting the object, then we don't need to disconnect..this is done auto-magically + // for us by QObject. -b.t. + // disconnect(a, SIGNAL(modified()), this, SIGNAL(modified())); + delete literal; + return m_List.count(); +} + +/** + * Returns the number of enumliterals for the class. + * @return The number of enumliterals for the class. + */ +int UMLEnum::enumLiterals() +{ + return m_List.count(); +} + +/** + * Emit the enumLiteralRemoved signal. + */ +void UMLEnum::signalEnumLiteralRemoved(UMLClassifierListItem *elit) +{ + emit enumLiteralRemoved(elit); +} + +/** + * Creates the element including its enumliterals. + */ +void UMLEnum::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +{ + QDomElement enumElement = UMLObject::save(QLatin1String("UML:Enumeration"), qDoc); + // save enum literals + UMLClassifierListItemList enumLiterals = getFilteredList(UMLObject::ot_EnumLiteral); + foreach (UMLClassifierListItem* pEnumLiteral, enumLiterals) { + pEnumLiteral->saveToXMI(qDoc, enumElement); + } + qElement.appendChild(enumElement); +} + +/** + * Loads the element including its enumliterals. + */ +bool UMLEnum::load(QDomElement& element) +{ + QDomNode node = element.firstChild(); + while(!node.isNull()) { + if (node.isComment()) { + node = node.nextSibling(); + continue; + } + QDomElement tempElement = node.toElement(); + QString tag = tempElement.tagName(); + if (UMLDoc::tagEq(tag, QLatin1String("EnumerationLiteral")) || + UMLDoc::tagEq(tag, QLatin1String("ownedLiteral")) || + UMLDoc::tagEq(tag, QLatin1String("EnumLiteral"))) { // for backward compatibility + UMLEnumLiteral* pEnumLiteral = new UMLEnumLiteral(this); + if(!pEnumLiteral->loadFromXMI(tempElement)) { + return false; + } + m_List.append(pEnumLiteral); + } else if (UMLDoc::tagEq(tag, QLatin1String("Enumeration.literal"))) { // Embarcadero's Describe + if (! load(tempElement)) + return false; + } else if (tag == QLatin1String("stereotype")) { + uDebug() << name() << ": losing old-format stereotype."; + } else { + uWarning() << "unknown child type: " << tag; + } + node = node.nextSibling(); + }//end while + return true; +} + +/** + * Create a new ClassifierListObject (enumLiteral) + * according to the given XMI tag. + * Returns NULL if the string given does not contain one of the tags + * + * Used by the clipboard for paste operation. + * Reimplemented from UMLClassifier for UMLEnum + */ +UMLClassifierListItem* UMLEnum::makeChildObject(const QString& xmiTag) +{ + UMLClassifierListItem* pObject = NULL; + if (UMLDoc::tagEq(xmiTag, QLatin1String("EnumerationLiteral")) || + UMLDoc::tagEq(xmiTag, QLatin1String("EnumLiteral"))) { + pObject = new UMLEnumLiteral(this); + } + return pObject; +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/enum.h umbrello-kf6-15.08.1/umbrello/umlmodel/enum.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/enum.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/enum.h 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,72 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef ENUM_H +#define ENUM_H + +#include "classifier.h" + +class UMLEnumLiteral; + +/** + * This class contains the non-graphical information required for a UML + * Enum. + * This class inherits from @ref UMLClassifier which contains most of the + * information. + * + * @short Non-graphical Information for an Enum. + * @author Jonathan Riddell + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class UMLEnum : public UMLClassifier +{ + Q_OBJECT +public: + explicit UMLEnum(const QString& name = QString(), Uml::ID::Type id = Uml::ID::None); + + virtual ~UMLEnum(); + + bool operator==(const UMLEnum& rhs) const; + + virtual void copyInto(UMLObject *lhs) const; + + virtual UMLObject* clone() const; + + UMLObject* createEnumLiteral(const QString& name = QString()); + + UMLObject* addEnumLiteral(const QString &name, Uml::ID::Type id = Uml::ID::None); + + bool addEnumLiteral(UMLEnumLiteral* literal, IDChangeLog* Log = 0); + bool addEnumLiteral(UMLEnumLiteral* literal, int position); + + int removeEnumLiteral(UMLEnumLiteral* literal); + + int enumLiterals(); + + void signalEnumLiteralRemoved(UMLClassifierListItem *elit); + + virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); + + virtual UMLClassifierListItem* makeChildObject(const QString& xmiTag); + +signals: + void enumLiteralAdded(UMLClassifierListItem*); + void enumLiteralRemoved(UMLClassifierListItem*); + +protected: + bool load(QDomElement & element); + +private: + void init(); + +}; + +#endif // ENUM_H + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/enumliteral.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/enumliteral.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/enumliteral.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/enumliteral.cpp 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,126 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#include "enumliteral.h" + +// kde includes +#if QT_VERSION < 0x050000 +#include +#endif +#include + +// qt includes +#if QT_VERSION >= 0x050000 +#include +#endif + +/** + * Sets up an enum literal. + * @param parent The parent of this UMLEnumLiteral. + * @param name The name of this UMLEnumLiteral. + * @param id The unique id given to this UMLEnumLiteral. + */ +UMLEnumLiteral::UMLEnumLiteral(UMLObject *parent, + const QString& name, Uml::ID::Type id) + : UMLClassifierListItem(parent, name, id) +{ + m_BaseType = UMLObject::ot_EnumLiteral; +} + +/** + * Sets up an enum literal. + * @param parent The parent of this UMLEnumLiteral. + */ +UMLEnumLiteral::UMLEnumLiteral(UMLObject *parent) + : UMLClassifierListItem(parent) +{ + m_BaseType = UMLObject::ot_EnumLiteral; +} + +/** + * Destructor. + */ +UMLEnumLiteral::~UMLEnumLiteral() +{ +} + +/** + * Overloaded '==' operator + */ +bool UMLEnumLiteral::operator==(const UMLEnumLiteral& rhs) const +{ + if (this == &rhs) { + return true; + } + if (!UMLObject::operator==(rhs)) { + return false; + } + return true; +} + +/** + * Copy the internal presentation of this object into the new + * object. + */ +void UMLEnumLiteral::copyInto(UMLObject *lhs) const +{ + UMLClassifierListItem::copyInto(lhs); +} + +/** + * Make a clone of this object. + */ +UMLObject* UMLEnumLiteral::clone() const +{ + UMLEnumLiteral *clone = new UMLEnumLiteral((UMLObject *) parent()); + copyInto(clone); + + return clone; +} + +/** + * Creates the XMI element. + */ +void UMLEnumLiteral::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +{ + QDomElement attributeElement = UMLObject::save(QLatin1String("UML:EnumerationLiteral"), qDoc); + qElement.appendChild(attributeElement); +} + +/** + * Loads the XMI element (empty.) + */ +bool UMLEnumLiteral::load(QDomElement& element) +{ + Q_UNUSED(element); + return true; +} + +/** + * Display the properties configuration dialog for the enum literal. + */ +bool UMLEnumLiteral::showPropertiesDialog(QWidget* parent) +{ + bool ok; +#if QT_VERSION >= 0x050000 + QString enumName = QInputDialog::getText(parent, + i18nc("enum name", "Name"), i18n("Enter name:"), + QLineEdit::Normal, + name(), &ok); +#else + QString enumName = KInputDialog::getText(i18nc("enum name", "Name"), i18n("Enter name:"), name(), &ok, parent); +#endif + if (ok && !enumName.isEmpty()) { + setName(enumName); + return true; + } else { + return false; + } +} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/enumliteral.h umbrello-kf6-15.08.1/umbrello/umlmodel/enumliteral.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/enumliteral.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/enumliteral.h 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,49 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef ENUMLITERAL_H +#define ENUMLITERAL_H + +#include "classifierlistitem.h" + +/** + * This class is used to set up information for an enum literal. Enum + * literals are the values that enums can be set to. + * + * @short Sets up attribute information. + * @author Paul Hensgen + * @see UMLObject + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class UMLEnumLiteral : public UMLClassifierListItem +{ +public: + UMLEnumLiteral(UMLObject* parent, + const QString& name, Uml::ID::Type id = Uml::ID::None); + explicit UMLEnumLiteral(UMLObject* parent); + + bool operator==(const UMLEnumLiteral &rhs) const; + + virtual void copyInto(UMLObject *lhs) const; + + virtual UMLObject* clone() const; + + virtual ~UMLEnumLiteral(); + + virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); + + virtual bool showPropertiesDialog(QWidget* parent = 0); + +protected: + bool load(QDomElement& element); + +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/folder.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/folder.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/folder.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/folder.cpp 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,558 @@ +/*************************************************************************** + * 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) 2006-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "folder.h" + +// app includes +#include "debug_utils.h" +#include "model_utils.h" +#include "object_factory.h" +#include "optionstate.h" +#include "uml.h" +#include "umldoc.h" +#include "umlscene.h" +#include "umlview.h" + +// kde includes +#include +#include + +// qt includes +#include + +/** + * Sets up a Folder. + * @param name The name of the Folder. + * @param id The unique id of the Folder. A new ID will be generated + * if this argument is left away. + */ +UMLFolder::UMLFolder(const QString & name, Uml::ID::Type id) + : UMLPackage(name, id) +{ + m_BaseType = UMLObject::ot_Folder; + UMLObject::setStereotypeCmd(QLatin1String("folder")); +} + +/** + * Empty destructor. + */ +UMLFolder::~UMLFolder() +{ + qDeleteAll(m_diagrams); + m_diagrams.clear(); +} + +/** + * Make a clone of this object. + */ +UMLObject* UMLFolder::clone() const +{ + UMLFolder *clone = new UMLFolder(); + UMLObject::copyInto(clone); + return clone; +} + +/** + * Set the localized name of this folder. + * This is set for the predefined root views (Logical, + * UseCase, Component, Deployment, EntityRelationship, + * and the Datatypes folder inside the Logical View.) + */ +void UMLFolder::setLocalName(const QString& localName) +{ + m_localName = localName; +} + +/** + * Return the localized name of this folder. + * Only useful for the predefined root folders. + */ +QString UMLFolder::localName() const +{ + return m_localName; +} + +/** + * Add a view to the diagram list. + */ +void UMLFolder::addView(UMLView *view) +{ + m_diagrams.append(view); +} + +/** + * Remove a view from the diagram list. + */ +void UMLFolder::removeView(UMLView *view) +{ + m_diagrams.removeAll(view); + delete view; +} + +/** + * Append the views in this folder to the given diagram list. + * @param viewList The UMLViewList to which to append the diagrams. + * @param includeNested Whether to include diagrams from nested folders + * (default: true.) + */ +void UMLFolder::appendViews(UMLViewList& viewList, bool includeNested) +{ + if (includeNested) { + foreach (UMLObject* o, m_objects) { + uIgnoreZeroPointer(o); + if (o->baseType() == UMLObject::ot_Folder) { + UMLFolder *f = static_cast(o); + f->appendViews(viewList); + } + } + } + foreach (UMLView* v, m_diagrams) { + viewList.append(v); + } +} + +/** + * Acivate the views in this folder. + * "Activation": Some widgets require adjustments after loading from file, + * those are done here. + */ +void UMLFolder::activateViews() +{ + foreach (UMLObject* o, m_objects) { + uIgnoreZeroPointer(o); + if (o->baseType() == UMLObject::ot_Folder) { + UMLFolder *f = static_cast(o); + f->activateViews(); + } + } + + foreach (UMLView* v, m_diagrams) { + v->umlScene()->activateAfterLoad(); + } + // Make sure we have a treeview item for each diagram. + // It may happen that we are missing them after switching off tabbed widgets. + Settings::OptionState optionState = Settings::optionState(); + if (optionState.generalState.tabdiagrams) { + return; + } + Model_Utils::treeViewAddViews(m_diagrams); +} + +/** + * Seek a view of the given ID in this folder. + * @param id ID of the view to find. + * @return Pointer to the view if found, NULL if no view found. + */ +UMLView *UMLFolder::findView(Uml::ID::Type id) +{ + foreach (UMLView* v, m_diagrams) { + if (v->umlScene()->ID() == id) { + return v; + } + } + + UMLView* v = 0; + UMLPackageList packages; + appendPackages(packages); + foreach (UMLPackage *o, packages) { + if (o->baseType() != UMLObject::ot_Folder) { + continue; + } + UMLFolder *f = static_cast(o); + v = f->findView(id); + if (v) { + break; + } + } + return v; +} + +/** + * Seek a view by the type and name given. + * @param type The type of view to find. + * @param name The name of the view to find. + * @param searchAllScopes Search in all subfolders (default: true.) + * @return Pointer to the view found, or NULL if not found. + */ +UMLView *UMLFolder::findView(Uml::DiagramType::Enum type, const QString &name, bool searchAllScopes) +{ + foreach (UMLView* v, m_diagrams) { + if (v->umlScene()->type() == type && v->umlScene()->name() == name) { + return v; + } + } + + UMLView* v = 0; + if (searchAllScopes) { + foreach (UMLObject* o, m_objects) { + uIgnoreZeroPointer(o); + if (o->baseType() != UMLObject::ot_Folder) { + continue; + } + UMLFolder *f = static_cast(o); + v = f->findView(type, name, searchAllScopes); + if (v) { + break; + } + } + } + return v; +} + +/** + * Set the options for the views in this folder. + */ +void UMLFolder::setViewOptions(const Settings::OptionState& optionState) +{ + // for each view update settings + foreach (UMLView* v, m_diagrams) { + v->umlScene()->setOptionState(optionState); + } +} + +/** + * Remove all views in this folder. + */ +void UMLFolder::removeAllViews() +{ + foreach (UMLObject* o, m_objects) { + uIgnoreZeroPointer(o); + if (o->baseType() != UMLObject::ot_Folder) + continue; + UMLFolder *f = static_cast(o); + f->removeAllViews(); + } + + foreach (UMLView* v, m_diagrams) { + // TODO ------------------ check this code - bad: calling back to UMLDoc::removeView() + v->umlScene()->removeAllAssociations(); // note : It may not be apparent, but when we remove all associations + // from a view, it also causes any UMLAssociations that lack parent + // association widgets (but once had them) to remove themselves from + // this document. + uDebug() << "removing " << v->umlScene()->name(); + UMLApp::app()->document()->removeView(v, false); + } + + qDeleteAll(m_diagrams); + m_diagrams.clear(); +} + +/** + * Set the folder file name for a separate submodel. + */ +void UMLFolder::setFolderFile(const QString& fileName) +{ + m_folderFile = fileName; +} + +/** + * Get the folder file name for a separate submodel. + */ +QString UMLFolder::folderFile() const +{ + return m_folderFile; +} + +/** + * Auxiliary to saveToXMI(): Save the contained objects and diagrams. + * Can be used regardless of whether saving to the main model file + * or to an external folder file (see m_folderFile.) + */ +void UMLFolder::saveContents(QDomDocument& qDoc, QDomElement& qElement) +{ + QDomElement ownedElement = qDoc.createElement(QLatin1String("UML:Namespace.ownedElement")); + UMLObject *obj = 0; + // Save contained objects if any. + for (UMLObjectListIt oit(m_objects); oit.hasNext();) { + obj = oit.next(); + uIgnoreZeroPointer(obj); + obj->saveToXMI (qDoc, ownedElement); + } + // Save asscociations if any. + for (UMLObjectListIt ait(m_List); ait.hasNext();) { + obj = ait.next(); + obj->saveToXMI (qDoc, ownedElement); + } + qElement.appendChild(ownedElement); + // Save diagrams to `extension'. + if (m_diagrams.count()) { + QDomElement diagramsElement = qDoc.createElement(QLatin1String("diagrams")); + + foreach (UMLView* pView, m_diagrams) { + pView->umlScene()->saveToXMI(qDoc, diagramsElement); + } + QDomElement extension = qDoc.createElement(QLatin1String("XMI.extension")); + extension.setAttribute(QLatin1String("xmi.extender"), QLatin1String("umbrello-kf6")); + extension.appendChild(diagramsElement); + qElement.appendChild(extension); + } +} + +/** + * Auxiliary to saveToXMI(): Creates a element when saving + * a predefined modelview, or a element when saving a + * user created folder. Invokes saveContents() with the newly created + * element. + */ +void UMLFolder::save(QDomDocument& qDoc, QDomElement& qElement) +{ + UMLDoc *umldoc = UMLApp::app()->document(); + QString elementName(QLatin1String("UML:Package")); + const Uml::ModelType::Enum mt = umldoc->rootFolderType(this); + if (mt != Uml::ModelType::N_MODELTYPES) { + elementName = QLatin1String("UML:Model"); + } + QDomElement folderElement = UMLObject::save(elementName, qDoc); + saveContents(qDoc, folderElement); + qElement.appendChild(folderElement); +} + +/** + * Creates a UML:Model or UML:Package element: + * UML:Model is created for the predefined fixed folders, + * UML:Package with stereotype "folder" is created for all else. + */ +void UMLFolder::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +{ + if (m_folderFile.isEmpty()) { + save(qDoc, qElement); + return; + } + // See if we can create the external file. + // If not then internalize the folder. + UMLDoc *umldoc = UMLApp::app()->document(); +#if QT_VERSION >= 0x050000 + QString fileName = umldoc->url().adjusted(QUrl::RemoveFilename).path() + m_folderFile; +#else + QString fileName = umldoc->url().directory() + QLatin1Char('/') + m_folderFile; +#endif + QFile file(fileName); + if (!file.open(QIODevice::WriteOnly)) { + uError() << m_folderFile << QLatin1String(": ") + << "cannot create file, contents will be saved in main model file"; + m_folderFile.clear(); + save(qDoc, qElement); + return; + } + // Okay, external file is writable. Wrap up main file. + QDomElement folderElement = UMLObject::save(QLatin1String("UML:Package"), qDoc); + QDomElement extension = qDoc.createElement(QLatin1String("XMI.extension")); + extension.setAttribute(QLatin1String("xmi.extender"), QLatin1String("umbrello-kf6")); + QDomElement fileElement = qDoc.createElement(QLatin1String("external_file")); + fileElement.setAttribute(QLatin1String("name"), m_folderFile); + extension.appendChild(fileElement); + folderElement.appendChild(extension); + qElement.appendChild(folderElement); + + // Save folder to external file. + QDomDocument folderDoc; + QDomElement folderRoot; + QDomProcessingInstruction xmlHeading = + folderDoc.createProcessingInstruction(QLatin1String("xml"), + QString::fromLatin1("version=\"1.0\" encoding=\"UTF-8\"")); + folderDoc.appendChild(xmlHeading); + folderRoot = folderDoc.createElement(QLatin1String("external_file")); + folderRoot.setAttribute(QLatin1String("name"), name()); + folderRoot.setAttribute(QLatin1String("filename"), m_folderFile); + folderRoot.setAttribute(QLatin1String("mainModel"), umldoc->url().fileName()); + folderRoot.setAttribute(QLatin1String("parentId"), Uml::ID::toString(m_pUMLPackage->id())); + folderRoot.setAttribute(QLatin1String("parent"), m_pUMLPackage->fullyQualifiedName(QLatin1String("::"), true)); + saveContents(folderDoc, folderRoot); + folderDoc.appendChild(folderRoot); + QTextStream stream(&file); + stream.setCodec("UTF-8"); + stream << folderDoc.toString(); + file.close(); +} + +/** + * Auxiliary to load(): + * Load the diagrams from the "diagrams" in the + */ +bool UMLFolder::loadDiagramsFromXMI(QDomNode& diagrams) +{ + const Settings::OptionState optionState = Settings::optionState(); + UMLDoc *umldoc = UMLApp::app()->document(); + bool totalSuccess = true; + for (QDomElement diagram = diagrams.toElement(); !diagram.isNull(); + diagrams = diagrams.nextSibling(), diagram = diagrams.toElement()) { + QString tag = diagram.tagName(); + if (tag != QLatin1String("diagram")) { + uDebug() << "ignoring " << tag << " in "; + continue; + } + UMLView * pView = new UMLView(this); + pView->umlScene()->setOptionState(optionState); + if (pView->umlScene()->loadFromXMI(diagram)) { + pView->hide(); + umldoc->addView(pView); + } else { + delete pView; + totalSuccess = false; + } + } + return totalSuccess; +} + +/** + * Folders in the listview can be marked such that their contents + * are saved to a separate file. + * This method loads the separate folder file. + * CAVEAT: This is not XMI standard compliant. + * If standard compliance is an issue then avoid folder files. + * @param path Fully qualified file name, i.e. absolute directory + * plus file name. + * @return True for success. + */ +bool UMLFolder::loadFolderFile(const QString& path) +{ + QFile file(path); + if (!file.exists()) { + KMessageBox::error(0, i18n("The folderfile %1 does not exist.", path), i18n("Load Error")); + return false; + } + if (!file.open(QIODevice::ReadOnly)) { + KMessageBox::error(0, i18n("The folderfile %1 cannot be opened.", path), i18n("Load Error")); + return false; + } + QTextStream stream(&file); + QString data = stream.readAll(); + file.close(); + QDomDocument doc; + QString error; + int line; + if (!doc.setContent(data, false, &error, &line)) { + uError() << "Cannot set content:" << error << " line:" << line; + return false; + } + QDomNode rootNode = doc.firstChild(); + while (rootNode.isComment() || rootNode.isProcessingInstruction()) { + rootNode = rootNode.nextSibling(); + } + if (rootNode.isNull()) { + uError() << "Root node is Null"; + return false; + } + QDomElement element = rootNode.toElement(); + QString type = element.tagName(); + if (type != QLatin1String("external_file")) { + uError() << "Root node has unknown type " << type; + return false; + } + return load(element); +} + +/** + * Loads the owned elements of the . + */ +bool UMLFolder::load(QDomElement& element) +{ + UMLDoc *umldoc = UMLApp::app()->document(); + bool totalSuccess = true; + for (QDomNode node = element.firstChild(); !node.isNull(); + node = node.nextSibling()) { + if (node.isComment()) + continue; + QDomElement tempElement = node.toElement(); + QString type = tempElement.tagName(); + if (Model_Utils::isCommonXMIAttribute(type)) + continue; + if (UMLDoc::tagEq(type, QLatin1String("Namespace.ownedElement")) || + UMLDoc::tagEq(type, QLatin1String("Namespace.contents"))) { + //CHECK: umbrello-kf6 currently assumes that nested elements + // are ownedElements anyway. + // Therefore these tags are not further interpreted. + if (! load(tempElement)) { + uDebug() << "An error happened while loading the " << type + << " of the " << name(); + totalSuccess = false; + } + continue; + } else if (UMLDoc::tagEq(type, QLatin1String("packagedElement")) || + UMLDoc::tagEq(type, QLatin1String("ownedElement"))) { + type = tempElement.attribute(QLatin1String("xmi:type")); + } else if (type == QLatin1String("XMI.extension")) { + for (QDomNode xtnode = node.firstChild(); !xtnode.isNull(); + xtnode = xtnode.nextSibling()) { + QDomElement el = xtnode.toElement(); + const QString xtag = el.tagName(); + if (xtag == QLatin1String("diagrams")) { + QDomNode diagramNode = xtnode.firstChild(); + if (!loadDiagramsFromXMI(diagramNode)) + totalSuccess = false; + } else if (xtag == QLatin1String("external_file")) { +#if QT_VERSION >= 0x050000 + const QString rootDir(umldoc->url().adjusted(QUrl::RemoveFilename).path()); +#else + const QString rootDir(umldoc->url().directory()); +#endif + QString fileName = el.attribute(QLatin1String("name")); + const QString path(rootDir + QLatin1Char('/') + fileName); + if (loadFolderFile(path)) + m_folderFile = fileName; + } else { + uDebug() << name() << ": ignoring XMI.extension " << xtag; + continue; + } + } + continue; + } + // Do not re-create the predefined Datatypes folder in the Logical View, + // it already exists. + UMLFolder *logicalView = umldoc->rootFolder(Uml::ModelType::Logical); + if (this == logicalView && UMLDoc::tagEq(type, QLatin1String("Package"))) { + QString thisName = tempElement.attribute(QLatin1String("name")); + if (thisName == QLatin1String("Datatypes")) { + UMLFolder *datatypeFolder = umldoc->datatypeFolder(); + if (!datatypeFolder->loadFromXMI(tempElement)) + totalSuccess = false; + continue; + } + } + UMLObject *pObject = 0; + // Avoid duplicate creation of forward declared object + QString idStr = Model_Utils::getXmiId(tempElement); + if (!idStr.isEmpty()) { + Uml::ID::Type id = Uml::ID::fromString(idStr); + pObject = umldoc->findObjectById(id); + if (pObject) { + uDebug() << "object " << idStr << "already exists"; + } + } + if (pObject == 0) { + QString stereoID = tempElement.attribute(QLatin1String("stereotype")); + pObject = Object_Factory::makeObjectFromXMI(type, stereoID); + if (!pObject) { + uWarning() << "Unknown type of umlobject to create: " << type; + continue; + } + } + pObject->setUMLPackage(this); + if (!pObject->loadFromXMI(tempElement)) { + removeObject(pObject); + delete pObject; + totalSuccess = false; + } + } + return totalSuccess; +} + +/** + * Overloading operator for debugging output. + */ +QDebug operator<<(QDebug out, const UMLFolder& item) +{ + out.nospace() << "UMLFolder: localName=" << item.m_localName + << ", folderFile=" << item.m_folderFile + << ", diagrams=" << item.m_diagrams.count(); + return out.space(); +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/folder.h umbrello-kf6-15.08.1/umbrello/umlmodel/folder.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/folder.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/folder.h 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,92 @@ +/*************************************************************************** + * 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) 2006-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef UMLFOLDER_H +#define UMLFOLDER_H + +#include "package.h" +#include "umlviewlist.h" +#include "optionstate.h" + +/** + * This class manages the UMLObjects and UMLViews of a Folder. + * This class inherits from UMLPackage which contains most + * of the information. + * + * The UMLDoc class allocates a fixed instance of this class for + * each of the predefined Logical, UseCase, Component, Deployment, and + * Entity-Relationship folders. Further instances are created on demand + * for user folders. + * + * @short Non-graphical management of objects and diagrams of a Folder + * @author Oliver Kellogg + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + * + * TODO: This whole class needs a relook regarding view/scene. + */ +class UMLFolder : public UMLPackage +{ + Q_OBJECT +public: + explicit UMLFolder(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); + virtual ~UMLFolder(); + + virtual UMLObject* clone() const; + + void setLocalName(const QString& localName); + QString localName() const; + + void addView(UMLView *view); + + void removeView(UMLView *view); + + void appendViews(UMLViewList& viewList, bool includeNested = true); + + void activateViews(); + + UMLView* findView(Uml::ID::Type id); + UMLView* findView(Uml::DiagramType::Enum type, const QString &name, bool searchAllScopes = true); + + void setViewOptions(const Settings::OptionState& optionState); + + void removeAllViews(); + + void setFolderFile(const QString& fileName); + QString folderFile() const; + + void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); + + friend QDebug operator<<(QDebug out, const UMLFolder& item); + +protected: + void saveContents(QDomDocument& qDoc, QDomElement& qElement); + + void save(QDomDocument& qDoc, QDomElement& qElement); + + bool loadDiagramsFromXMI(QDomNode& diagrams); + + bool loadFolderFile(const QString& path); + + bool load(QDomElement & element); + +private: + QString m_localName; ///< i18n name, only used for predefined root folders + /** + * If m_folderFile is not empty then it contains a file name to which + * this folder is saved. + * In this case the folder file acts as a physically separate submodel. + * What is saved in the main model is not the folder contents but a + * reference to the folder file. + */ + QString m_folderFile; + UMLViewList m_diagrams; +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/foreignkeyconstraint.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/foreignkeyconstraint.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/foreignkeyconstraint.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/foreignkeyconstraint.cpp 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,444 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +//own header +#include "foreignkeyconstraint.h" + +// app includes +#include "debug_utils.h" +#include "entity.h" +#include "entityattribute.h" +#include "umlobject.h" +#include "umldoc.h" +#include "uml.h" +#include "umlforeignkeyconstraintdialog.h" +#include "object_factory.h" + +/** + * Sets up a constraint. + * @param parent The parent of this UMLForeignKeyConstraint. + * @param name The name of this UMLForeignKeyConstraint. + * @param id The unique id given to this UMLForeignKeyConstraint. + */ +UMLForeignKeyConstraint::UMLForeignKeyConstraint(UMLObject *parent, + const QString& name, Uml::ID::Type id) + : UMLEntityConstraint(parent, name, id) +{ + init(); +} + +/** + * Sets up a constraint. + * @param parent The parent of this UMLForeignKeyConstraint. + */ +UMLForeignKeyConstraint::UMLForeignKeyConstraint(UMLObject *parent) + : UMLEntityConstraint(parent) +{ + init(); +} + +/** + * Initialisation of common variables + */ +void UMLForeignKeyConstraint::init() +{ + // initialise attributes + m_BaseType = UMLObject::ot_ForeignKeyConstraint; + + // should be NULL actually + // self referencing assigned to protect default behaviour + m_ReferencedEntity = static_cast(parent()); + + m_UpdateAction = uda_NoAction; + m_DeleteAction = uda_NoAction; + + // connecte signals and slots + connect(this, SIGNAL(sigReferencedEntityChanged()), this, SLOT(slotReferencedEntityChanged())); +} + +/** + * Overloaded '==' operator + */ +bool UMLForeignKeyConstraint::operator==(const UMLForeignKeyConstraint &rhs) const +{ + if(this == &rhs) + return true; + + if(!UMLObject::operator==(rhs)) + return false; + + return true; +} + +/** + * Destructor. + */ +UMLForeignKeyConstraint::~UMLForeignKeyConstraint() +{ +} + +/** + * Copy the internal presentation of this object into the UMLForeignKeyConstraint + * object. + */ +void UMLForeignKeyConstraint::copyInto(UMLObject *lhs) const +{ + UMLForeignKeyConstraint *target = static_cast(lhs); + + // call the parent first. + UMLEntityConstraint::copyInto(target); + + // Copy all datamembers + target->m_ReferencedEntity = m_ReferencedEntity; + target->m_AttributeMap = m_AttributeMap; + target->m_DeleteAction = m_DeleteAction; + target->m_UpdateAction = m_UpdateAction; +} + +/** + * Make a clone of the UMLForeignKeyConstraint. + */ +UMLObject* UMLForeignKeyConstraint::clone() const +{ + //FIXME: The new attribute should be slaved to the NEW parent not the old. + UMLForeignKeyConstraint *clone = new UMLForeignKeyConstraint(static_cast(parent())); + copyInto(clone); + return clone; +} + +/** + * Returns a string representation of the UMLForeignKeyConstraint. + * @param sig If true will show the attribute type and initial value. + * @return Returns a string representation of the UMLAttribute. + */ +QString UMLForeignKeyConstraint::toString(Uml::SignatureType::Enum sig) +{ + QString s; + + if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::SigNoVis) { + s = name() + QLatin1Char(':'); + s += QLatin1String(" Foreign Key ("); + QList keys = m_AttributeMap.keys(); + bool first = true; + foreach(UMLEntityAttribute* key, keys) { + if (first) { + first = false; + } else + s += QLatin1Char(','); + s += key->name(); + } + s += QLatin1Char(')'); + } + + return s; +} + +/** + * Creates the XMI element. + */ +void UMLForeignKeyConstraint::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +{ + QDomElement foreignKeyConstraintElement = UMLObject::save(QLatin1String("UML:ForeignKeyConstraint"), qDoc); + + foreignKeyConstraintElement.setAttribute(QLatin1String("referencedEntity"), Uml::ID::toString(m_ReferencedEntity->id())); + + int updateAction = (int)m_UpdateAction; + int deleteAction = (int)m_DeleteAction; + + foreignKeyConstraintElement.setAttribute(QLatin1String("updateAction"), updateAction); + foreignKeyConstraintElement.setAttribute(QLatin1String("deleteAction"), deleteAction); + + QMap::iterator i; + for (i = m_AttributeMap.begin(); i!= m_AttributeMap.end() ; ++i) { + QDomElement mapElement = qDoc.createElement(QLatin1String("AttributeMap")); + mapElement.setAttribute(QLatin1String("key"), Uml::ID::toString((i.key())->id())); + mapElement.setAttribute(QLatin1String("value"), Uml::ID::toString((i.value())->id())); + foreignKeyConstraintElement.appendChild(mapElement); + } + + qElement.appendChild(foreignKeyConstraintElement); +} + +/** + * Display the properties configuration dialog for the attribute. + */ +bool UMLForeignKeyConstraint::showPropertiesDialog(QWidget* parent) +{ + UMLForeignKeyConstraintDialog dialog(parent, this); + return dialog.exec(); +} + +/** + * Adds the attribute pair to the attributeMap + * @param pAttr The Attribute of the Parent Entity + * @param rAttr The Attribute of the Referenced Entity + * @return true if the attribute pair could be added successfully + */ +bool UMLForeignKeyConstraint::addEntityAttributePair(UMLEntityAttribute* pAttr, UMLEntityAttribute* rAttr) +{ + UMLEntity *owningParent = dynamic_cast(parent()); + + if (pAttr == NULL || rAttr == NULL) { + uError() << "null values passed to function"; + return false; + } + // check for sanity of pAttr (parent entity attribute) + if (owningParent == NULL) { + uError() << name() << ": parent is not a UMLEntity"; + return false; + } + + if (owningParent->findChildObjectById(pAttr->id()) == NULL) { + uError() << " parent " << owningParent->name() + << " does not contain attribute " << pAttr->name(); + return false; + } + + //check for sanity of rAttr (referenced entity attribute) + if (m_ReferencedEntity != NULL) { + if (m_ReferencedEntity->findChildObjectById(rAttr->id()) == NULL) { + uError() << " parent " << m_ReferencedEntity->name() + << " does not contain attribute " << rAttr->name(); + return false; + } + } else { + uError() << "Referenced Table Not set. Not Adding Pair "; + return false; + } + + // check if key takes part in some mapping + if (m_AttributeMap.contains(pAttr) == true) + return false; + + // check if value takes part in some mapping (no direct function) + foreach(UMLEntityAttribute* attr, m_AttributeMap.values()) { + if (rAttr == attr) + return false; + } + + // passed all checks, insert now + m_AttributeMap.insert(pAttr, rAttr); + + QMap::iterator i; + for (i = m_AttributeMap.begin(); i != m_AttributeMap.end(); ++i) + uDebug() << i.key()->name() << QLatin1String(" ") << i.key()->baseType() + << QLatin1String(" ") << i.value()->name() << QLatin1String(" ") << i.value()->baseType(); + + return true; +} + +/** + * Removes an Attribute pair + * @param pAttr The Attribute of the Parent Entity in the map. This attribute is the + key of the map. + * @return true of the attribute pair could be removed successfully + */ +bool UMLForeignKeyConstraint::removeEntityAttributePair(UMLEntityAttribute* /*key*/ pAttr) +{ + bool state = m_AttributeMap.remove(pAttr); + + return state; +} + +/** + * Check if a attribute pair already exists + * @param pAttr The Attribute of the Parent Entity + * @param rAttr The Attribute of the Referenced Entity + * @return true if the attribute pair could be found. + */ +bool UMLForeignKeyConstraint::hasEntityAttributePair(UMLEntityAttribute* pAttr, UMLEntityAttribute* rAttr) const +{ + if (m_AttributeMap.contains(pAttr)) { + if (m_AttributeMap.value(pAttr) == rAttr) { + return true; + } + } + + return false; +} + +/** + * Loads the XMI element. + */ +bool UMLForeignKeyConstraint::load(QDomElement & element) +{ + UMLDoc* doc = UMLApp::app()->document(); + + Uml::ID::Type referencedEntityId = Uml::ID::fromString(element.attribute(QLatin1String("referencedEntity"))); + + UMLObject* obj = doc->findObjectById(referencedEntityId); + m_ReferencedEntity = static_cast(obj); + + if (m_ReferencedEntity == NULL) { + // save for resolving later + m_pReferencedEntityID = referencedEntityId; + } + + m_UpdateAction = (UpdateDeleteAction)element.attribute(QLatin1String("updateAction")).toInt(); + m_DeleteAction = (UpdateDeleteAction)element.attribute(QLatin1String("deleteAction")).toInt(); + + QDomNode node = element.firstChild(); + while (!node.isNull()) { + if (node.isComment()) { + node = node.nextSibling(); + continue; + } + QDomElement tempElement = node.toElement(); + QString tag = tempElement.tagName(); + if (UMLDoc::tagEq(tag, QLatin1String("AttributeMap"))) { + + QString xmiKey = tempElement.attribute(QLatin1String("key")); + QString xmiValue = tempElement.attribute(QLatin1String("value")); + Uml::ID::Type keyId = Uml::ID::fromString(xmiKey); + Uml::ID::Type valueId = Uml::ID::fromString(xmiValue); + + UMLEntity* parentEntity = static_cast(parent()); + UMLObject* keyObj = parentEntity->findChildObjectById(keyId); + UMLEntityAttribute* key = static_cast(keyObj); + + if (keyObj == NULL) { + uWarning() << "unable to resolve foreign key referencing attribute " << xmiKey; + } else if (m_ReferencedEntity == NULL) { + // if referenced entity is null, then we won't find its attributes even + // save for resolving later + m_pEntityAttributeIDMap.insert(key, valueId); + } else { + UMLObject* valueObj = m_ReferencedEntity->findChildObjectById(valueId); + if (valueObj == NULL) { + uWarning() << "unable to resolve foreign key referenced attribute" << xmiValue; + } else { + m_AttributeMap[key] = static_cast(valueObj); + } + } + + } else { + uWarning() << "unknown child type in UMLForeignKeyConstraint::load"; + } + + node = node.nextSibling(); + } + + return true; +} + +/** + * Set the Referenced Entity. + * @param ent The Entity to Reference + */ +void UMLForeignKeyConstraint::setReferencedEntity(UMLEntity* ent) +{ + if (ent == m_ReferencedEntity) + return; + + m_ReferencedEntity = ent; + + emit sigReferencedEntityChanged(); +} + +/** + * Get the Referenced Entity. + * @return the UML entity object + */ +UMLEntity* UMLForeignKeyConstraint::getReferencedEntity() const +{ + return m_ReferencedEntity; +} + +/** + * Slot for referenced entity changed. + */ +void UMLForeignKeyConstraint::slotReferencedEntityChanged() +{ + // clear all mappings + m_AttributeMap.clear(); +} + +/** + * Clears all mappings between local and referenced attributes + */ +void UMLForeignKeyConstraint::clearMappings() +{ + m_AttributeMap.clear(); +} + +/** + * Remimplementation from base classes + * Used to resolve forward references to referenced entities in xmi + */ +bool UMLForeignKeyConstraint::resolveRef() +{ + // resolve referenced entity first + UMLDoc* doc = UMLApp::app()->document(); + + bool success = true; + + //resolve the referenced entity + if (!Uml::ID::toString(m_pReferencedEntityID).isEmpty()) { + UMLObject* obj = doc->findObjectById(m_pReferencedEntityID); + m_ReferencedEntity = static_cast(obj); + if (m_ReferencedEntity == NULL) { + success = false; + } + } + + QMap::iterator i; + for (i = m_pEntityAttributeIDMap.begin(); i!= m_pEntityAttributeIDMap.end() ; ++i) { + if (!Uml::ID::toString(i.value()).isEmpty()) { + UMLObject* obj = doc->findObjectById(i.value()); + m_AttributeMap[i.key()] = static_cast(obj); + if (m_AttributeMap[i.key()] == NULL) { + success = false; + } + } + } + + return success; +} + +/** + * Retrieve all Pairs of Attributes. + */ +QMap UMLForeignKeyConstraint::getEntityAttributePairs() +{ + return m_AttributeMap; +} + +/** + * Get the Delete Action. + */ +UMLForeignKeyConstraint::UpdateDeleteAction UMLForeignKeyConstraint::getDeleteAction() const +{ + return m_DeleteAction; +} + +/** + * Get the Update Action. + */ +UMLForeignKeyConstraint::UpdateDeleteAction UMLForeignKeyConstraint::getUpdateAction() const +{ + return m_UpdateAction; +} + +/** + * Set the Delete Action to the specified UpdateDeleteAction. + */ +void UMLForeignKeyConstraint::setDeleteAction(UpdateDeleteAction uda) +{ + m_DeleteAction = uda; +} + +/** + * Set the Update Action to the specified UpdateDeleteAction + */ +void UMLForeignKeyConstraint::setUpdateAction(UpdateDeleteAction uda) +{ + m_UpdateAction = uda; +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/foreignkeyconstraint.h umbrello-kf6-15.08.1/umbrello/umlmodel/foreignkeyconstraint.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/foreignkeyconstraint.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/foreignkeyconstraint.h 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,120 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef FOREIGNKEYCONSTRAINT_H +#define FOREIGNKEYCONSTRAINT_H + +// appl includes +#include "basictypes.h" +#include "entityconstraint.h" + +// qt includes +#include + +//forward declarations +class UMLEntityAttribute; +class UMLEntity; + +/** + * This class is used to set up information for a foreign key entity constraint. + * @short Sets up Foreign Key entity constraint information. + * @author Sharan Rao + * @see UMLObject UMLClassifierListItem UMLEntityConstraint + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class UMLForeignKeyConstraint : public UMLEntityConstraint +{ + Q_OBJECT + +public: + + /** + * Update/Delete Action: Action to be taken on Update or Delete of a referenced attribute + * is either, No Action, Restrict, Cascade, Set NULL, Set Default. + */ + enum UpdateDeleteAction { uda_NoAction = 0, + uda_Restrict, + uda_Cascade, + uda_SetNull, + uda_SetDefault }; + + UMLForeignKeyConstraint(UMLObject *parent, const QString& name, + Uml::ID::Type id = Uml::ID::None); + explicit UMLForeignKeyConstraint(UMLObject *parent); + + bool operator==(const UMLForeignKeyConstraint &rhs) const; + + virtual ~UMLForeignKeyConstraint(); + + virtual void copyInto(UMLObject *lhs) const; + + virtual UMLObject* clone() const; + + QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); + + void setReferencedEntity(UMLEntity* ent); + UMLEntity* getReferencedEntity() const; + + void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); + + virtual bool showPropertiesDialog(QWidget* parent = 0); + + bool addEntityAttributePair(UMLEntityAttribute* pAttr, UMLEntityAttribute* rAttr); + + bool removeEntityAttributePair(UMLEntityAttribute* /*key*/ pAttr); + + bool hasEntityAttributePair(UMLEntityAttribute* pAttr, UMLEntityAttribute* rAttr) const; + + QMap getEntityAttributePairs(); + + void setDeleteAction(UpdateDeleteAction uda); + UpdateDeleteAction getDeleteAction() const; + + void setUpdateAction(UpdateDeleteAction uda); + UpdateDeleteAction getUpdateAction() const; + + void clearMappings(); + + bool resolveRef(); + +signals: + void sigReferencedEntityChanged(); + +private slots: + void slotReferencedEntityChanged(); + +protected: + bool load(QDomElement & element); + +private: + + Uml::ID::Type m_pReferencedEntityID; ///< Used to resolve forward references to UMLEntity. + + /** + * Used to resolve forward references to UMLEntityAttributes + * Key -> The local attribute + * Value -> Id of the attribute it is mapping to + */ + QMap m_pEntityAttributeIDMap; + + void init(); + + UMLEntity* m_ReferencedEntity; ///< The UMLEntity that this foreign key references. + + /** + * Stores the Mapping of attributes between parent table and referenced table + */ + QMap m_AttributeMap; + + UpdateDeleteAction m_UpdateAction; ///< What to do on Update of referenced attributes. + UpdateDeleteAction m_DeleteAction; ///< What to do on Deletion of referenced attributes. +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/node.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/node.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/node.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/node.cpp 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,68 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#include "node.h" + +#include + +/** + * Sets up a Node. + * + * @param name The name of the Concept. + * @param id The unique id of the Concept. + */ +UMLNode::UMLNode(const QString & name, Uml::ID::Type id) + : UMLCanvasObject(name, id) +{ + init(); +} + +/** + * Destructor. + */ +UMLNode::~UMLNode() +{ +} + +/** + * Initializes key variables of the class. + */ +void UMLNode::init() +{ + m_BaseType = UMLObject::ot_Node; +} + +/** + * Make a clone of this object. + */ +UMLObject* UMLNode::clone() const +{ + UMLNode *clone = new UMLNode(); + UMLObject::copyInto(clone); + return clone; +} + +/** + * Creates the XMI element. + */ +void UMLNode::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +{ + QDomElement nodeElement = UMLObject::save(QLatin1String("UML:Node"), qDoc); + qElement.appendChild(nodeElement); +} + +/** + * Loads the XMI element (empty.) + */ +bool UMLNode::load(QDomElement&) +{ + return true; +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/node.h umbrello-kf6-15.08.1/umbrello/umlmodel/node.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/node.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/node.h 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,46 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef NODE_H +#define NODE_H + +#include "umlcanvasobject.h" + +/** + * This class contains the non-graphical information required for a UML Node. + * This class inherits from @ref UMLCanvasObject which contains most of the + * information. + * + * @short Non-graphical information for a Node. + * @author Jonathan Riddell + * @see UMLCanvasObject + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class UMLNode : public UMLCanvasObject +{ + Q_OBJECT +public: + + explicit UMLNode(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); + virtual ~UMLNode(); + + virtual void init(); + + virtual UMLObject* clone() const; + + void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); + +protected: + + bool load(QDomElement & element); + +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/operation.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/operation.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/operation.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/operation.cpp 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,611 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "operation.h" + +// app includes +#include "attribute.h" +#include "classifier.h" +#include "model_utils.h" +#include "debug_utils.h" +#include "uml.h" +#include "umldoc.h" +#include "uniqueid.h" +#include "umloperationdialog.h" +#include "codegenerator.h" +#include "codedocument.h" +#include "codeblock.h" + +// kde includes +#include + +// qt includes +#include + +/** + * Constructs an UMLOperation. + * Not intended for general use: The operation is not tied in with + * umbrello-kf6's Qt signalling for object creation. + * If you want to create an Operation use the method in UMLDoc instead. + * + * @param parent the parent to this operation + * @param name the name of the operation + * @param id the id of the operation + * @param s the visibility of the operation + * @param rt the return type of the operation + */ +UMLOperation::UMLOperation(UMLClassifier *parent, const QString& name, + Uml::ID::Type id, Uml::Visibility::Enum s, UMLObject *rt) + : UMLClassifierListItem(parent, name, id) +{ + if (rt) + m_returnId = UniqueID::gen(); + else + m_returnId = Uml::ID::None; + m_pSecondary = rt; + m_visibility = s; + m_BaseType = UMLObject::ot_Operation; + m_bConst = false; + m_Code.clear(); +} + +/** + * Constructs an UMLOperation. + * Not intended for general use: The operation is not tied in with + * umbrello-kf6's Qt signalling for object creation. + * If you want to create an Operation use the method in UMLDoc instead. + * + * @param parent the parent to this operation + */ +UMLOperation::UMLOperation(UMLClassifier * parent) + : UMLClassifierListItem (parent) +{ + m_BaseType = UMLObject::ot_Operation; + m_bConst = false; + m_Code.clear(); +} + +/** + * Destructor. + */ +UMLOperation::~UMLOperation() +{ +} + +/** + * Reimplement method from UMLClassifierListItem. + * + * @param type pointer to the type object + */ +void UMLOperation::setType(UMLObject* type) +{ + UMLClassifierListItem::setType(type); + if (m_returnId == Uml::ID::None) + m_returnId = UniqueID::gen(); +} + +/** + * Move a parameter one position to the left. + * + * @param a the parameter to move + */ +void UMLOperation::moveParmLeft(UMLAttribute * a) +{ + if (a == NULL) { + uDebug() << "called on NULL attribute"; + return; + } + uDebug() << "called for " << a->name(); + disconnect(a, SIGNAL(modified()), this, SIGNAL(modified())); + int idx; + if ((idx=m_List.indexOf(a)) == -1) { + uDebug() << "Error move parm left " << a->name(); + return; + } + if (idx == 0) + return; + m_List.removeAll(a); + m_List.insert(idx-1, a); +} + +/** + * Move a parameter one position to the right. + * + * @param a the parameter to move + */ +void UMLOperation::moveParmRight(UMLAttribute * a) +{ + if (a == NULL) { + uDebug() << "called on NULL attribute"; + return; + } + uDebug() << "called for " << a->name(); + disconnect(a, SIGNAL(modified()), this, SIGNAL(modified())); + int idx; + if ((idx=m_List.indexOf(a)) == -1) { + uDebug() << "Error move parm right " << a->name(); + return; + } + int count = m_List.count(); + if (idx == count-1) + return; + m_List.removeAll(a); + m_List.insert(idx+1, a); +} + +/** + * Remove a parameter from the operation. + * + * @param a the parameter to remove + * @param emitModifiedSignal whether to emit the "modified" signal + * which creates an entry in the Undo stack for the + * removal, default: true + */ +void UMLOperation::removeParm(UMLAttribute * a, bool emitModifiedSignal /* =true */) +{ + if (a == NULL) { + uDebug() << "called on NULL attribute"; + return; + } + uDebug() << "called for " << a->name(); + disconnect(a, SIGNAL(modified()), this, SIGNAL(modified())); + if(!m_List.removeAll(a)) + uDebug() << "Error removing parm " << a->name(); + + if (emitModifiedSignal) + emit modified(); +} + +/** + * Returns a list of parameters. + * + * @return a list of the parameters in the operation + */ +UMLAttributeList UMLOperation::getParmList() const +{ + return m_List; +} + +/** + * Finds a parameter of the operation. + * + * @param name the parameter name to search for + * @return the found parameter, 0 if not found + */ +UMLAttribute* UMLOperation::findParm(const QString &name) +{ + UMLAttribute * obj=0; + foreach (obj, m_List) { + if (obj->name() == name) + return obj; + } + return 0; +} + +/** + * Returns a string representation of the operation. + * + * @param sig what type of operation string to show + * @return the string representation of the operation + */ +QString UMLOperation::toString(Uml::SignatureType::Enum sig) +{ + QString s; + + if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::NoSig) + s = Uml::Visibility::toString(m_visibility, true) + QLatin1Char(' '); + + s += name(); + Uml::ProgrammingLanguage::Enum pl = UMLApp::app()->activeLanguage(); + bool parameterlessOpNeedsParentheses = + (pl != Uml::ProgrammingLanguage::Pascal && pl != Uml::ProgrammingLanguage::Ada); + + if (sig == Uml::SignatureType::NoSig || sig == Uml::SignatureType::NoSigNoVis) { + if (parameterlessOpNeedsParentheses) + s.append(QLatin1String("()")); + return s; + } + int last = m_List.count(); + if (last) { + s.append(QLatin1String("(")); + int i = 0; + foreach (UMLAttribute *param, m_List) { + i++; + s.append(param->toString(Uml::SignatureType::SigNoVis)); + if (i < last) + s.append(QLatin1String(", ")); + } + s.append(QLatin1String(")")); + } else if (parameterlessOpNeedsParentheses) { + s.append(QLatin1String("()")); + } + UMLClassifier *ownParent = static_cast(parent()); + QString returnType; + UMLClassifier *retType = UMLClassifierListItem::getType(); + if (retType) { + UMLPackage *retVisibility = retType->umlPackage(); + if (retVisibility != ownParent && retVisibility != ownParent->umlPackage()) + returnType = retType->fullyQualifiedName(); + else + returnType = retType->name(); + } + if (returnType.length() > 0 && returnType != QLatin1String("void")) { + s.append(QLatin1String(" : ")); + + if (returnType.startsWith(QLatin1String(QLatin1String("virtual ")))) { + s += returnType.mid(8); + } else { + s += returnType; + } + } + return s; +} + +/** + * Add a parameter to the operation. + * + * @param parameter the parameter to add + * @param position the position in the parameter list. + * If position = -1 the parameter will be + * appended to the list. + */ +void UMLOperation::addParm(UMLAttribute *parameter, int position) +{ + if(position >= 0 && position <= (int)m_List.count()) + m_List.insert(position, parameter); + else + m_List.append(parameter); + UMLObject::emitModified(); + connect(parameter, SIGNAL(modified()), this, SIGNAL(modified())); +} + +/** + * Returns an unused parameter name for a new parameter. + */ +QString UMLOperation::getUniqueParameterName() +{ + QString currentName = i18n("new_parameter"); + QString name = currentName; + for (int number = 1; findParm(name); ++number) { + name = currentName + QLatin1Char('_') + QString::number(number); + } + return name; +} + +/** + * Overloaded '==' operator. + */ +bool UMLOperation::operator==(const UMLOperation & rhs) const +{ + if (this == &rhs) + return true; + + if (!UMLObject::operator==(rhs)) + return false; + + if (getTypeName() != rhs.getTypeName()) + return false; + + if (m_List.count() != rhs.m_List.count()) + return false; + + if (!(m_List == rhs.m_List)) + return false; + + return true; +} + +/** + * Copy the internal presentation of this object into the new + * object. + */ +void UMLOperation::copyInto(UMLObject *lhs) const +{ + UMLOperation *target = static_cast(lhs); + + UMLClassifierListItem::copyInto(target); + + m_List.copyInto(&(target->m_List)); +} + +/** + * Make a clone of this object. + */ +UMLObject* UMLOperation::clone() const +{ + //FIXME: The new operation should be slaved to the NEW parent not the old. + UMLOperation *clone = new UMLOperation(static_cast(parent())); + copyInto(clone); + + return clone; +} + +/** + * Calls resolveRef() on all parameters. + * Needs to be called after all UML objects are loaded from file. + * + * @return true for success + */ +bool UMLOperation::resolveRef() +{ + bool overallSuccess = UMLObject::resolveRef(); + // See remark on iteration style in UMLClassifier::resolveRef() + foreach (UMLAttribute* pAtt, m_List) { + if (! pAtt->resolveRef()) + overallSuccess = false; + } + return overallSuccess; +} + +/** + * Returns whether this operation is a constructor. + * + * @return true if this operation is a constructor + */ +bool UMLOperation::isConstructorOperation() +{ + // if an operation has the stereotype constructor + // return true + if (stereotype() == QLatin1String("constructor")) + return true; + + UMLClassifier * c = static_cast(this->parent()); + QString cName = c->name(); + QString opName = name(); + // It's a constructor operation if the operation name + // matches that of the parent classifier. + return (cName == opName); +} + +/** + * Returns whether this operation is a destructor. + * + * @return true if this operation is a destructor + */ +bool UMLOperation::isDestructorOperation() +{ + if (stereotype() == QLatin1String("destructor")) + return true; + UMLClassifier * c = static_cast(this->parent()); + + QString cName = c->name(); + QString opName = name(); + // Special support for C++ syntax: + // It's a destructor operation if the operation name begins + // with "~" followed by the name of the parent classifier. + if (! opName.startsWith(QLatin1Char('~'))) + return false; + opName.remove(QRegExp(QLatin1String("^~\\s*"))); + return (cName == opName); +} + +/** + * Shortcut for (isConstructorOperation() || isDestructorOperation()). + * + * @return true if this operation is a constructor or destructor + */ +bool UMLOperation::isLifeOperation() +{ + return (isConstructorOperation() || isDestructorOperation()); +} + +/** + * Sets whether this operation is a query (C++ "const"). + */ +void UMLOperation::setConst(bool b) +{ + m_bConst = b; +} + +/** + * Returns whether this operation is a query (C++ "const"). + */ +bool UMLOperation::getConst() const +{ + return m_bConst; +} + +/** + * Display the properties configuration dialog for the template. + * + * @param parent the parent for the dialog + */ +bool UMLOperation::showPropertiesDialog(QWidget* parent) +{ + UMLOperationDialog dialog(parent, this); + return dialog.exec(); +} + +/** + * Sets the source code for this operation. + * + * @param code the body of this operation + */ +void UMLOperation::setSourceCode(const QString& code) +{ + m_Code = code; +} + +/** + * Returns the source code for this operation. + */ +QString UMLOperation::getSourceCode() const +{ + return m_Code; +} + +/** + * Saves to the XMI element. + */ +void UMLOperation::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +{ + QDomElement operationElement = UMLObject::save(QLatin1String("UML:Operation"), qDoc); + operationElement.setAttribute(QLatin1String("isQuery"), m_bConst ? QLatin1String("true") : QLatin1String("false")); + QDomElement featureElement = qDoc.createElement(QLatin1String("UML:BehavioralFeature.parameter")); + if (m_pSecondary) { + QDomElement retElement = qDoc.createElement(QLatin1String("UML:Parameter")); + if (m_returnId == Uml::ID::None) { + uDebug() << name() << ": m_returnId is not set, setting it now."; + m_returnId = UniqueID::gen(); + } + retElement.setAttribute(QLatin1String("xmi.id"), Uml::ID::toString(m_returnId)); + retElement.setAttribute(QLatin1String("type"), Uml::ID::toString(m_pSecondary->id())); + retElement.setAttribute(QLatin1String("kind"), QLatin1String("return")); + featureElement.appendChild(retElement); + } else { + uDebug() << "m_SecondaryId is " << m_SecondaryId; + } + + //save each attribute here, type different + foreach(UMLAttribute* pAtt, m_List) { + QDomElement attElement = pAtt->UMLObject::save(QLatin1String("UML:Parameter"), qDoc); + UMLClassifier *attrType = pAtt->getType(); + if (attrType) { + attElement.setAttribute(QLatin1String("type"), Uml::ID::toString(attrType->id())); + } else { + attElement.setAttribute(QLatin1String("type"), pAtt->getTypeName()); + } + attElement.setAttribute(QLatin1String("value"), pAtt->getInitialValue()); + + Uml::ParameterDirection::Enum kind = pAtt->getParmKind(); + if (kind == Uml::ParameterDirection::Out) + attElement.setAttribute(QLatin1String("kind"), QLatin1String("out")); + else if (kind == Uml::ParameterDirection::InOut) + attElement.setAttribute(QLatin1String("kind"), QLatin1String("inout")); + // The default for the parameter kind is "in". + + featureElement.appendChild(attElement); + } + if (featureElement.hasChildNodes()) { + operationElement.appendChild(featureElement); + } + qElement.appendChild(operationElement); +} + +/** + * Loads a XMI element. + */ +bool UMLOperation::load(QDomElement & element) +{ + m_SecondaryId = element.attribute(QLatin1String("type")); + QString isQuery = element.attribute(QLatin1String("isQuery")); + if (!isQuery.isEmpty()) { + // We need this extra test for isEmpty() because load() might have been + // called again by the processing for BehavioralFeature.parameter (see below) + m_bConst = (isQuery == QLatin1String("true")); + } + QDomNode node = element.firstChild(); + if (node.isComment()) + node = node.nextSibling(); + QDomElement attElement = node.toElement(); + while (!attElement.isNull()) { + QString tag = attElement.tagName(); + if (UMLDoc::tagEq(tag, QLatin1String("BehavioralFeature.parameter")) || + UMLDoc::tagEq(tag, QLatin1String("Element.ownedElement"))) { // Embarcadero's Describe + if (! load(attElement)) + return false; + } else if (UMLDoc::tagEq(tag, QLatin1String("Parameter"))) { + QString kind = attElement.attribute(QLatin1String("kind")); + if (kind.isEmpty()) { + kind = attElement.attribute(QLatin1String("direction")); // Embarcadero's Describe + if (kind.isEmpty()) { + // Perhaps the kind is stored in a child node: + for (QDomNode n = attElement.firstChild(); !n.isNull(); n = n.nextSibling()) { + if (n.isComment()) + continue; + QDomElement tempElement = n.toElement(); + QString tag = tempElement.tagName(); + if (!UMLDoc::tagEq(tag, QLatin1String("kind"))) + continue; + kind = tempElement.attribute(QLatin1String("xmi.value")); + break; + } + } + if (kind.isEmpty()) { + kind = QLatin1String("in"); + } + } + if (kind == QLatin1String("return") || + kind == QLatin1String("result")) { // Embarcadero's Describe + QString returnId = Model_Utils::getXmiId(attElement); + if (!returnId.isEmpty()) + m_returnId = Uml::ID::fromString(returnId); + m_SecondaryId = attElement.attribute(QLatin1String("type")); + if (m_SecondaryId.isEmpty()) { + // Perhaps the type is stored in a child node: + QDomNode node = attElement.firstChild(); + while (!node.isNull()) { + if (node.isComment()) { + node = node.nextSibling(); + continue; + } + QDomElement tempElement = node.toElement(); + QString tag = tempElement.tagName(); + if (!UMLDoc::tagEq(tag, QLatin1String("type"))) { + node = node.nextSibling(); + continue; + } + m_SecondaryId = Model_Utils::getXmiId(tempElement); + if (m_SecondaryId.isEmpty()) + m_SecondaryId = tempElement.attribute(QLatin1String("xmi.idref")); + if (m_SecondaryId.isEmpty()) { + QDomNode inner = node.firstChild(); + QDomElement tmpElem = inner.toElement(); + m_SecondaryId = Model_Utils::getXmiId(tmpElem); + if (m_SecondaryId.isEmpty()) + m_SecondaryId = tmpElem.attribute(QLatin1String("xmi.idref")); + } + break; + } + if (m_SecondaryId.isEmpty()) { + uError() << name() << ": cannot find return type."; + } + } + // Use deferred xmi.id resolution. + m_pSecondary = NULL; + } else { + UMLAttribute * pAtt = new UMLAttribute(this); + if(!pAtt->loadFromXMI(attElement)) { + delete pAtt; + return false; + } + if (kind == QLatin1String("out")) + pAtt->setParmKind(Uml::ParameterDirection::Out); + else if (kind == QLatin1String("inout")) + pAtt->setParmKind(Uml::ParameterDirection::InOut); + else + pAtt->setParmKind(Uml::ParameterDirection::In); + m_List.append(pAtt); + } + } + node = node.nextSibling(); + if (node.isComment()) + node = node.nextSibling(); + attElement = node.toElement(); + + // loading the source code which was entered in the 'classpropdlg' dialog is not done + // with the following code, because there is no CodeDocument. + /* + CodeGenerator* codegen = UMLApp::app()->getGenerator(); + if (codegen) { + uDebug() << "CodeDocument searching with id=" << Uml::ID::toString(UMLObject::ID()); + CodeDocument* codeDoc = codegen->findCodeDocumentByID(Uml::ID::toString(UMLObject::ID())); + if (codeDoc) { + uDebug() << "CodeDocument found:\n" << codeDoc; + } + } + */ + // it is done in the code generators by calling CodeGenerator::loadFromXMI(...). + + }//end while + return true; +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/operation.h umbrello-kf6-15.08.1/umbrello/umlmodel/operation.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/operation.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/operation.h 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,84 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef OPERATION_H +#define OPERATION_H + +#include "umlattributelist.h" +#include "classifierlistitem.h" + +class UMLClassifier; + +/** + * This class represents an operation in the UML model. + * + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class UMLOperation : public UMLClassifierListItem +{ + Q_OBJECT +public: + UMLOperation(UMLClassifier * parent, const QString& name, + Uml::ID::Type id = Uml::ID::None, + Uml::Visibility::Enum s = Uml::Visibility::Public, + UMLObject *rt = 0); + explicit UMLOperation(UMLClassifier * parent); + virtual ~UMLOperation(); + + bool operator==(const UMLOperation & rhs) const; + + virtual void copyInto(UMLObject *lhs) const; + + virtual UMLObject* clone() const; + + void setType(UMLObject* type); + + void moveParmLeft(UMLAttribute *a); + void moveParmRight(UMLAttribute *a); + + void removeParm(UMLAttribute *a, bool emitModifiedSignal = true); + + UMLAttributeList getParmList() const; + + UMLAttribute * findParm(const QString &name); + + QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); + + void addParm(UMLAttribute *parameter, int position = -1); + + bool resolveRef(); + + QString getUniqueParameterName(); + + virtual bool showPropertiesDialog(QWidget* parent = 0); + + bool isConstructorOperation(); + bool isDestructorOperation(); + bool isLifeOperation(); + + void setConst(bool b); + bool getConst() const; + + void setSourceCode(const QString& code); + QString getSourceCode() const; + + void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); + +protected: + bool load(QDomElement & element); + +private: + Uml::ID::Type m_returnId; ///< Holds the xmi.id of the + UMLAttributeList m_List; ///< Parameter list + bool m_bConst; ///< Holds the isQuery attribute of the + QString m_Code; ///< Holds the entered source code +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/package.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/package.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/package.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/package.cpp 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,461 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header file +#include "package.h" + +// local includes +#include "debug_utils.h" +#include "dialog_utils.h" +#include "uml.h" +#include "umldoc.h" +#include "classifier.h" +#include "association.h" +#include "entity.h" +#include "object_factory.h" +#include "model_utils.h" + +// kde includes +#if QT_VERSION < 0x050000 +#include +#endif +#include +#include + +// qt includes +#if QT_VERSION >= 0x050000 +#include +#endif + +using namespace Uml; + +/** + * Sets up a Package. + * @param name The name of the Concept. + * @param id The unique id of the Concept. + */ +UMLPackage::UMLPackage(const QString & name, Uml::ID::Type id) + : UMLCanvasObject(name, id) +{ + m_BaseType = ot_Package; +} + +/** + * Destructor. + */ +UMLPackage::~UMLPackage() +{ +} + +/** + * Copy the internal presentation of this object into the new object. + */ +void UMLPackage::copyInto(UMLObject *lhs) const +{ + UMLPackage *target = static_cast(lhs); + + UMLCanvasObject::copyInto(target); + + m_objects.copyInto(&(target->m_objects)); +} + +/** + * Make a clone of this object. + */ +UMLObject* UMLPackage::clone() const +{ + UMLPackage *clone = new UMLPackage(); + copyInto(clone); + + return clone; +} + +/** + * Adds an existing association to the matching concept in the list of concepts. + * The selection of the matching concept depends on the association type: + * For generalizations, the assoc is added to the concept that matches role A. + * For aggregations and compositions, the assoc is added to the concept + * that matches role B. + * @param assoc the association to add + */ +void UMLPackage::addAssocToConcepts(UMLAssociation* assoc) +{ + if (! AssociationType::hasUMLRepresentation(assoc->getAssocType())) + return; + Uml::ID::Type AId = assoc->getObjectId(Uml::RoleType::A); + Uml::ID::Type BId = assoc->getObjectId(Uml::RoleType::B); + UMLObject *o = NULL; + for (UMLObjectListIt oit(m_objects); oit.hasNext();) { + o = oit.next(); + UMLCanvasObject *c = dynamic_cast(o); + if (c == NULL) + continue; + if (AId == c->id() || (BId == c->id())) { + if (c->hasAssociation(assoc)) + uDebug() << c->name() << " already has association id=" << Uml::ID::toString(assoc->id()); + else + c->addAssociationEnd(assoc); + } + UMLPackage *pkg = dynamic_cast(c); + if (pkg) + pkg->addAssocToConcepts(assoc); + } +} + +/** + * Remove the association from the participating concepts. + * @param assoc the association to remove + */ +void UMLPackage::removeAssocFromConcepts(UMLAssociation *assoc) +{ + UMLObject *o = 0; + for (UMLObjectListIt oit(m_objects); oit.hasNext();) { + o = oit.next(); + UMLCanvasObject *c = dynamic_cast(o); + if (c) { + if (c->hasAssociation(assoc)) + c->removeAssociationEnd(assoc); + UMLPackage *pkg = dynamic_cast(c); + if (pkg) + pkg->removeAssocFromConcepts(assoc); + } + } +} + +/** + * Adds an object in this package. + * + * @param pObject Pointer to the UMLObject to add. + * @return True if the object was actually added. + */ +bool UMLPackage::addObject(UMLObject *pObject) +{ + if (pObject == NULL) { + uError() << "is called with a NULL object"; + return false; + } + if (pObject == this) { + uError() << "adding myself as child is not allowed"; + return false; + } + + if (m_objects.indexOf(pObject) != -1) { + uDebug() << pObject->name() << " is already there"; + return false; + } + if (pObject->baseType() == UMLObject::ot_Association) { + UMLAssociation *assoc = static_cast(pObject); + // Adding the UMLAssociation at the participating concepts is done + // again later (in UMLAssociation::resolveRef()) if they are not yet + // known right here. + if (assoc->getObject(Uml::RoleType::A) && assoc->getObject(Uml::RoleType::B)) { + UMLPackage *pkg = pObject->umlPackage(); + if (pkg != this) { + uError() << "UMLPackage " << name() << " addObject: " + << "assoc's UMLPackage is " << pkg->name(); + } + addAssocToConcepts(assoc); + } + } + else { + QString name = pObject->name(); + QString oldName = name; + while (findObject(name) != NULL) { + QString prevName = name; + name = Model_Utils::uniqObjectName(pObject->baseType(), this); + bool ok = Dialog_Utils::askName(i18nc("object name", "Name"), + i18n("An object with the name %1\nalready exists in the package %2.\nPlease enter a new name:", prevName, this->name()), + name); + if (!ok) { + name = oldName; + continue; + } + if (name.length() == 0) { + KMessageBox::error(0, i18n("That is an invalid name."), + i18n("Invalid Name")); + continue; + } + } + if (oldName != name) { + pObject->setName(name); + } + } + m_objects.append(pObject); + return true; +} + +/** + * Removes an object from this package. + * Does not physically delete the object. + * + * @param pObject Pointer to the UMLObject to be removed. + */ +void UMLPackage::removeObject(UMLObject *pObject) +{ + if (pObject->baseType() == UMLObject::ot_Association) { + UMLObject *o = const_cast(pObject); + UMLAssociation *assoc = static_cast(o); + removeAssocFromConcepts(assoc); + } + if (m_objects.indexOf(pObject) == -1) + uDebug() << name() << " removeObject: object with id=" + << Uml::ID::toString(pObject->id()) << "not found."; + else + m_objects.removeAll(pObject); +} + +/** + * Removes all objects from this package. + * Inner containers (e.g. nested packages) are removed recursively. + */ +void UMLPackage::removeAllObjects() +{ + UMLCanvasObject::removeAllChildObjects(); + UMLObject *o = NULL; + + while (!m_objects.isEmpty() && (o = m_objects.first()) != NULL) { + UMLPackage *pkg = dynamic_cast(o); + if (pkg) + pkg->removeAllObjects(); + removeObject(o); + delete o; + } +} + +/** + * Returns the list of objects contained in this package. + */ +UMLObjectList UMLPackage::containedObjects() +{ + return m_objects; +} + +/** + * Find the object of the given name in the list of contained objects. + * + * @param name The name to seek. + * @return Pointer to the UMLObject found or NULL if not found. + */ +UMLObject * UMLPackage::findObject(const QString &name) +{ + const bool caseSensitive = UMLApp::app()->activeLanguageIsCaseSensitive(); + for (UMLObjectListIt oit(m_objects); oit.hasNext();) { + UMLObject *obj = oit.next(); + if (!obj) + continue; + if (caseSensitive) { + if (obj->name() == name) + return obj; + } else if (obj->name().toLower() == name.toLower()) { + return obj; + } + } + return NULL; +} + +/** + * Find the object of the given ID in the list of contained objects. + * + * @param id The ID to seek. + * @return Pointer to the UMLObject found or NULL if not found. + */ +UMLObject * UMLPackage::findObjectById(Uml::ID::Type id) +{ + return Model_Utils::findObjectInList(id, m_objects); +} + +/** + * Append all packages from this package (and those from nested packages) + * to the given UMLPackageList. + * + * @param packages The list to append to + * @param includeNested Whether to include the packages from nested packages + * (default:true) + */ +void UMLPackage::appendPackages(UMLPackageList& packages, bool includeNested) +{ + for (UMLObjectListIt oit(m_objects); oit.hasNext();) { + UMLObject *o = oit.next(); + uIgnoreZeroPointer(o); + ObjectType ot = o->baseType(); + if (ot == ot_Package || ot == ot_Folder) { + packages.append(static_cast(o)); + if (includeNested) { + UMLPackage *inner = static_cast(o); + inner->appendPackages(packages); + } + } + } +} + +/** + * Append all classifiers from this package (and those from + * nested packages) to the given UMLClassifierList. + * + * @param classifiers The list to append to. + * @param includeNested Whether to include the classifiers from + * nested packages (default: true.) + */ +void UMLPackage::appendClassifiers(UMLClassifierList& classifiers, + bool includeNested /* = true */) +{ + for (UMLObjectListIt oit(m_objects); oit.hasNext();) { + UMLObject *o = oit.next(); + uIgnoreZeroPointer(o); + ObjectType ot = o->baseType(); + if (ot == ot_Class || ot == ot_Interface || + ot == ot_Datatype || ot == ot_Enum || ot == ot_Entity) { + classifiers.append((UMLClassifier *)o); + } else if (includeNested && (ot == ot_Package || ot == ot_Folder)) { + UMLPackage *inner = static_cast(o); + inner->appendClassifiers(classifiers); + } + } +} + +/** + * Append all entities from this package (and those + * from nested packages) to the given UMLEntityList. + * + * @param entities The list to append to. + * @param includeNested Whether to include the entities from + * nested packages (default: true.) + */ +void UMLPackage::appendEntities(UMLEntityList& entities, + bool includeNested /* = true */) +{ + for (UMLObjectListIt oit(m_objects); oit.hasNext();) { + UMLObject *o = oit.next(); + uIgnoreZeroPointer(o); + ObjectType ot = o->baseType(); + if (ot == ot_Entity) { + UMLEntity *c = static_cast(o); + entities.append(c); + } else if (includeNested && (ot == ot_Package || ot == ot_Folder)) { + UMLPackage *inner = static_cast(o); + inner->appendEntities(entities); + } + } +} + +/** + * Append all classes and interfaces from this package (and those + * from nested packages) to the given UMLClassifierList. + * + * @param classifiers The list to append to. + * @param includeNested Whether to include the classifiers from + * nested packages (default: true.) + */ +void UMLPackage::appendClassesAndInterfaces(UMLClassifierList& classifiers, + bool includeNested /* = true */) +{ + for (UMLObjectListIt oit(m_objects); oit.hasNext();) { + UMLObject *o = oit.next(); + uIgnoreZeroPointer(o); + ObjectType ot = o->baseType(); + if (ot == ot_Class || ot == ot_Interface) { + UMLClassifier *c = static_cast(o); + classifiers.append(c); + } else if (includeNested && (ot == ot_Package || ot == ot_Folder)) { + UMLPackage *inner = static_cast(o); + inner->appendClassesAndInterfaces(classifiers); + } + } +} + +/** + * Resolve types. Required when dealing with foreign XMI files. + * Needs to be called after all UML objects are loaded from file. + * Overrides the method from UMLObject. + * Calls resolveRef() on each contained object. + * + * @return True for overall success. + */ +bool UMLPackage::resolveRef() +{ + bool overallSuccess = UMLCanvasObject::resolveRef(); + for (UMLObjectListIt oit(m_objects); oit.hasNext();) { + UMLObject *obj = oit.next(); + uIgnoreZeroPointer(obj); + if (! obj->resolveRef()) { + UMLObject::ObjectType ot = obj->baseType(); + if (ot != UMLObject::ot_Package && ot != UMLObject::ot_Folder) + m_objects.removeAll(obj); + overallSuccess = false; + } + } + return overallSuccess; +} + +/** + * Creates the XMI element. + */ +void UMLPackage::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +{ + QDomElement packageElement = UMLObject::save(QLatin1String("UML:Package"), qDoc); + QDomElement ownedElement = qDoc.createElement(QLatin1String("UML:Namespace.ownedElement")); + UMLObject *obj = NULL; + // save classifiers etc. + for (UMLObjectListIt oit(m_objects); oit.hasNext();) { + obj = oit.next(); + uIgnoreZeroPointer(obj); + obj->saveToXMI (qDoc, ownedElement); + } + // save associations + for (UMLObjectListIt ait(m_List); ait.hasNext();) { + obj = ait.next(); + obj->saveToXMI (qDoc, ownedElement); + } + + packageElement.appendChild(ownedElement); + qElement.appendChild(packageElement); +} + +/** + * Loads the XMI element. + * Auxiliary to UMLObject::loadFromXMI. + */ +bool UMLPackage::load(QDomElement& element) +{ + for (QDomNode node = element.firstChild(); !node.isNull(); + node = node.nextSibling()) { + if (node.isComment()) + continue; + QDomElement tempElement = node.toElement(); + QString type = tempElement.tagName(); + if (Model_Utils::isCommonXMIAttribute(type)) + continue; + if (UMLDoc::tagEq(type, QLatin1String("Namespace.ownedElement")) || + UMLDoc::tagEq(type, QLatin1String("Element.ownedElement")) || // Embarcadero's Describe + UMLDoc::tagEq(type, QLatin1String("Namespace.contents"))) { + //CHECK: umbrello-kf6 currently assumes that nested elements + // are ownedElements anyway. + // Therefore these tags are not further interpreted. + if (! load(tempElement)) + return false; + continue; + } else if (UMLDoc::tagEq(type, QLatin1String("packagedElement")) || + UMLDoc::tagEq(type, QLatin1String("ownedElement"))) { + type = tempElement.attribute(QLatin1String("xmi:type")); + } + UMLObject *pObject = Object_Factory::makeObjectFromXMI(type); + if(!pObject) { + uWarning() << "Unknown type of umlobject to create: " << type; + continue; + } + pObject->setUMLPackage(this); + if (!pObject->loadFromXMI(tempElement)) { + removeObject(pObject); + delete pObject; + } + } + return true; +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/package.h umbrello-kf6-15.08.1/umbrello/umlmodel/package.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/package.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/package.h 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,79 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef PACKAGE_H +#define PACKAGE_H + +#include "umlcanvasobject.h" +#include "umlclassifierlist.h" +#include "umlentitylist.h" + +// forward declarations +class UMLAssociation; + +/** + * This class contains the non-graphical information required for a UML + * Package. + * This class inherits from @ref UMLCanvasObject which contains most of the + * information. + * + * @short Non-graphical information for a Package. + * @author Jonathan Riddell + * @see UMLCanvasObject + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class UMLPackage : public UMLCanvasObject +{ + Q_OBJECT +public: + explicit UMLPackage(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); + virtual ~UMLPackage(); + + virtual void copyInto(UMLObject *lhs) const; + + virtual UMLObject* clone() const; + + bool addObject(UMLObject *pObject); + void removeObject(UMLObject *pObject); + + virtual void removeAllObjects(); + + UMLObjectList containedObjects(); + + void addAssocToConcepts(UMLAssociation* assoc); + void removeAssocFromConcepts(UMLAssociation *assoc); + + UMLObject * findObject(const QString &name); + UMLObject * findObjectById(Uml::ID::Type id); + + void appendPackages(UMLPackageList& packages, bool includeNested = true); + void appendClassifiers(UMLClassifierList& classifiers, + bool includeNested = true); + void appendClassesAndInterfaces(UMLClassifierList& classifiers, + bool includeNested = true); + void appendEntities(UMLEntityList& entities, + bool includeNested = true); + + virtual bool resolveRef(); + + virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); + +protected: + virtual bool load(QDomElement& element); + + /** + * References to the objects contained in this package. + * The UMLPackage is the owner of the objects. + */ + UMLObjectList m_objects; + +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/port.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/port.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/port.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/port.cpp 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,68 @@ +/*************************************************************************** + * 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) 2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#include "port.h" + +#include + +/** + * Sets up a Port. + * + * @param name The name of the Concept. + * @param id The unique id of the Concept. + */ +UMLPort::UMLPort(const QString & name, Uml::ID::Type id) + : UMLCanvasObject(name, id) +{ + init(); +} + +/** + * Destructor. + */ +UMLPort::~UMLPort() +{ +} + +/** + * Initializes key variables of the class. + */ +void UMLPort::init() +{ + m_BaseType = UMLObject::ot_Port; +} + +/** + * Make a clone of this object. + */ +UMLObject* UMLPort::clone() const +{ + UMLPort *clone = new UMLPort(); + UMLObject::copyInto(clone); + return clone; +} + +/** + * Creates the XMI element. + */ +void UMLPort::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +{ + QDomElement portElement = UMLObject::save(QLatin1String("UML:Port"), qDoc); + qElement.appendChild(portElement); +} + +/** + * Loads the XMI element (empty.) + */ +bool UMLPort::load(QDomElement&) +{ + return true; +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/port.h umbrello-kf6-15.08.1/umbrello/umlmodel/port.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/port.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/port.h 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,46 @@ +/*************************************************************************** + * 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) 2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef PORT_H +#define PORT_H + +#include "umlcanvasobject.h" + +/** + * This class contains the non-graphical information required for a UML Port. + * This class inherits from @ref UMLCanvasObject which contains most of the + * information. + * + * @short Non-graphical information for a Port. + * @author Oliver Kellogg + * @see UMLCanvasObject + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class UMLPort : public UMLCanvasObject +{ + Q_OBJECT +public: + + explicit UMLPort(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); + virtual ~UMLPort(); + + virtual void init(); + + virtual UMLObject* clone() const; + + void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); + +protected: + + bool load(QDomElement & element); + +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/stereotype.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/stereotype.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/stereotype.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/stereotype.cpp 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,165 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "stereotype.h" + +// local includes +#include "debug_utils.h" +#include "umldoc.h" +#include "uml.h" + +// kde includes +#if QT_VERSION < 0x050000 +#include +#endif +#include + +// qt includes +#if QT_VERSION >= 0x050000 +#include +#endif + +/** + * Sets up a stereotype. + * + * @param name The name of this UMLStereotype. + * @param id The unique id given to this UMLStereotype. + */ +UMLStereotype::UMLStereotype(const QString &name, Uml::ID::Type id /* = Uml::id_None */) + : UMLObject(name, id) +{ + m_BaseType = UMLObject::ot_Stereotype; + UMLStereotype * existing = UMLApp::app()->document()->findStereotype(name); + if (existing) { + uError() << "UMLStereotype constructor: " << name << " already exists"; + } + m_refCount = 0; +} + +/** + * Sets up a stereotype. + */ +UMLStereotype::UMLStereotype() + : UMLObject() +{ + m_BaseType = UMLObject::ot_Stereotype; + m_refCount = 0; +} + +/** + * Destructor. + */ +UMLStereotype::~UMLStereotype() +{ + //Q_ASSERT(m_refCount == 0); +} + +/** + * Overloaded '==' operator. + */ +bool UMLStereotype::operator==(const UMLStereotype &rhs) const +{ + if (this == &rhs) { + return true; + } + + if (!UMLObject::operator==(rhs)) { + return false; + } + + return true; +} + +/** + * Copy the internal presentation of this object into the new + * object. + */ +void UMLStereotype::copyInto(UMLObject *lhs) const +{ + UMLObject::copyInto(lhs); +} + +/** + * Make a clone of this object. + */ +UMLObject* UMLStereotype::clone() const +{ + UMLStereotype *clone = new UMLStereotype(); + copyInto(clone); + + return clone; +} + +/** + * Saves to the XMI element. + */ +void UMLStereotype::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +{ + //FIXME: uml13.dtd compliance + QDomElement stereotypeElement = UMLObject::save(QLatin1String("UML:Stereotype"), qDoc); + qElement.appendChild(stereotypeElement); +} + +/** + * Display the properties configuration dialog for the stereotype + * (just a line edit). + */ +bool UMLStereotype::showPropertiesDialog(QWidget* parent) +{ + bool ok; +#if QT_VERSION >= 0x050000 + QString stereoTypeName = QInputDialog::getText(parent, + i18n("Stereotype"), i18n("Enter name:"), + QLineEdit::Normal, + name(), &ok); +#else + QString stereoTypeName = KInputDialog::getText(i18n("Stereotype"), i18n("Enter name:"), name(), &ok, parent); +#endif + if (ok) { + setName(stereoTypeName); + } + return ok; +} + +/** + * Increments the reference count for this stereotype. + */ +void UMLStereotype::incrRefCount() +{ + m_refCount++; +} + +/** + * Decrements the reference count for this stereotype. + */ +void UMLStereotype::decrRefCount() +{ + m_refCount--; +} + +/** + * Returns the reference count for this stereotype. + */ +int UMLStereotype::refCount() const +{ + return m_refCount; +} + +/** + * Returns the name as string + */ +QString UMLStereotype::name(bool includeAdornments) const +{ + if (includeAdornments) + return QString::fromUtf8("«") + UMLObject::name() + QString::fromUtf8("»"); + else + return UMLObject::name(); +} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/stereotype.h umbrello-kf6-15.08.1/umbrello/umlmodel/stereotype.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/stereotype.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/stereotype.h 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,71 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef STEREOTYPE_H +#define STEREOTYPE_H + +#include "umlobject.h" + +/** + * This class is used to set up information for a stereotype. + * Stereotypes are used essentially as properties of + * attributes and operations etc. + * + * Each stereotype object is reference counted, i.e. client code + * manages it such that it comes into existence as soon as there is + * at least one user, and ceases existing when the number of users + * drops to 0. + * m_refCount reflects the number of users. It is externally managed, + * i.e. client code must take care to call incrRefCount() and + * decrRefCount() as appropriate. + * + * The one and only owner of all stereotypes is the UMLDoc, and the + * ownership is specially managed (umlPackage() returns NULL for a + * UMLStereotype.) The reason for this special treatment is that + * class UMLDoc does not inherit from class UMLPackage, and therefore + * setUMLPackage() cannot be used for stereotypes. + * + * @short Sets up stereotype information. + * @author Jonathan Riddell + * @author Oliver Kellogg + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class UMLStereotype : public UMLObject +{ + Q_OBJECT +public: + explicit UMLStereotype(const QString &name, Uml::ID::Type id = Uml::ID::None); + UMLStereotype(); + + virtual ~UMLStereotype(); + + bool operator==(const UMLStereotype &rhs) const; + + virtual void copyInto(UMLObject *lhs) const; + + virtual UMLObject* clone() const; + + void incrRefCount(); + void decrRefCount(); + + int refCount() const; + + QString name(bool includeAdornments=false) const; + + void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); + + virtual bool showPropertiesDialog(QWidget* parent); + +protected: + int m_refCount; + +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/template.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/template.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/template.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/template.cpp 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,146 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "template.h" + +// app includes +#include "debug_utils.h" +#include "uml.h" +#include "umldoc.h" +#include "umltemplatedialog.h" + +/** + * Sets up a template. + * + * @param parent The parent of this UMLTemplate (i.e. its concept). + * @param name The name of this UMLTemplate. + * @param id The unique id given to this UMLTemplate. + * @param type The type of this UMLTemplate. + */ +UMLTemplate::UMLTemplate(UMLObject *parent, const QString& name, + Uml::ID::Type id, const QString& type) + : UMLClassifierListItem(parent, name, id) +{ + setTypeName(type); + m_BaseType = UMLObject::ot_Template; +} + +/** + * Sets up a template. + * + * @param parent The parent of this UMLTemplate (i.e. its concept). + */ +UMLTemplate::UMLTemplate(UMLObject *parent) + : UMLClassifierListItem(parent) +{ + m_BaseType = UMLObject::ot_Template; +} + +/** + * Destructor. + */ +UMLTemplate::~UMLTemplate() +{ +} + +QString UMLTemplate::toString(Uml::SignatureType::Enum sig) +{ + Q_UNUSED(sig); + if (m_pSecondary == NULL || m_pSecondary->name() == QLatin1String("class")) { + return name(); + } else { + return name() + QLatin1String(" : ") + m_pSecondary->name(); + } +} + +/** + * Overrides method from UMLClassifierListItem. + * Returns the type name of the UMLTemplate. + * If the template parameter is a class, there is no separate + * type object. In this case, getTypeName() returns "class". + * + * @return The type name of the UMLClassifierListItem. + */ +QString UMLTemplate::getTypeName() const +{ + if (m_pSecondary == NULL) + return QLatin1String("class"); + return m_pSecondary->name(); +} + +/** + * Overloaded '==' operator. + */ +bool UMLTemplate::operator==(const UMLTemplate &rhs) const +{ + if (this == &rhs) { + return true; + } + if (!UMLObject::operator==(rhs)) { + return false; + } + if (m_pSecondary != rhs.m_pSecondary) { + return false; + } + return true; +} + +/** + * Copy the internal presentation of this object into the new + * object. + */ +void UMLTemplate::copyInto(UMLObject *lhs) const +{ + UMLClassifierListItem::copyInto(lhs); +} + +/** + * Make a clone of this object. + */ +UMLObject* UMLTemplate::clone() const +{ + UMLTemplate *clone = new UMLTemplate((UMLTemplate*) parent()); + copyInto(clone); + + return clone; +} + +/** + * Writes the XMI element. + */ +void UMLTemplate::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +{ + //FIXME: uml13.dtd compliance + QDomElement attributeElement = UMLObject::save(QLatin1String("UML:TemplateParameter"), qDoc); + if (m_pSecondary) + attributeElement.setAttribute(QLatin1String("type"), Uml::ID::toString(m_pSecondary->id())); + qElement.appendChild(attributeElement); +} + +/** + * Loads the XMI element. + */ +bool UMLTemplate::load(QDomElement& element) +{ + m_SecondaryId = element.attribute(QLatin1String("type")); + return true; +} + +/** + * Display the properties configuration dialog for the template. + * + * @return Success status. + */ +bool UMLTemplate::showPropertiesDialog(QWidget* parent) +{ + UMLTemplateDialog dialog(parent, this); + return dialog.exec(); +} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/template.h umbrello-kf6-15.08.1/umbrello/umlmodel/template.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/template.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/template.h 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,57 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef TEMPLATE_H +#define TEMPLATE_H + +#include "classifierlistitem.h" + +/** + * This class holds information used by template classes, called + * paramaterised class in UML and a generic in Java. It has a + * type (usually just "class") and name. + * + * @short Sets up template information. + * @author Jonathan Riddell + * @see UMLObject + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class UMLTemplate : public UMLClassifierListItem +{ +public: + + UMLTemplate(UMLObject *parent, const QString& name, + Uml::ID::Type id = Uml::ID::None, const QString& type = QLatin1String("class")); + + explicit UMLTemplate(UMLObject *parent); + + bool operator==(const UMLTemplate &rhs) const; + + virtual void copyInto(UMLObject *lhs) const; + + virtual UMLObject* clone() const; + + virtual ~UMLTemplate(); + + QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); + + virtual QString getTypeName() const; + + virtual bool showPropertiesDialog(QWidget* parent); + + void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); + +protected: + + bool load(QDomElement & element); + +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlassociationlist.h umbrello-kf6-15.08.1/umbrello/umlmodel/umlassociationlist.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlassociationlist.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlassociationlist.h 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,23 @@ +/*************************************************************************** + * * + * 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) 2004-2007 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef UMLASSOCIATIONLIST_H +#define UMLASSOCIATIONLIST_H + +#include + +// forward declaration +class UMLAssociation; + +typedef QList UMLAssociationList; +typedef QListIterator UMLAssociationListIt; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlattributelist.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/umlattributelist.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlattributelist.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlattributelist.cpp 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,61 @@ +/*************************************************************************** + * 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) 2004-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#include "umlattributelist.h" + +#include "attribute.h" + +#include + +UMLAttributeList::UMLAttributeList() +{ +} + +UMLAttributeList::UMLAttributeList(const UMLAttributeList& other) + : QList(other) +{ +} + +UMLAttributeList::~UMLAttributeList() +{ +} + +/** + * Copy the internal presentation of this object into the new + * object. + */ +void UMLAttributeList::copyInto(UMLAttributeList *rhs) const +{ + // Don't copy yourself. + if (rhs == this) return; + + rhs->clear(); + + // Suffering from const; we shall not modify our object. + UMLAttributeList *tmp = new UMLAttributeList(*this); + + UMLAttribute *item; + for (UMLAttributeListIt ait(*tmp); ait.hasNext() ;) + { + item = ait.next(); + rhs->append((UMLAttribute*)item->clone()); + } + delete tmp; +} + +/** + * Make a clone of this object. + */ +UMLAttributeList* UMLAttributeList::clone() const +{ + UMLAttributeList *clone = new UMLAttributeList(); + copyInto(clone); + return clone; +} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlattributelist.h umbrello-kf6-15.08.1/umbrello/umlmodel/umlattributelist.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlattributelist.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlattributelist.h 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,42 @@ +/*************************************************************************** + * * + * 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) 2004-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef UMLATTRIBUTELIST_H +#define UMLATTRIBUTELIST_H + +#include + +#include "attribute.h" + +//typedef QPtrList UMLAttributeList; +typedef QListIterator UMLAttributeListIt; + +/** + * This sub-class adds copyInto and clone to the QPtrList + * base class. + */ +class UMLAttributeList : public QList +{ +public: + + UMLAttributeList(); + + UMLAttributeList(const UMLAttributeList&); + + virtual ~UMLAttributeList(); + + virtual void copyInto(UMLAttributeList *rhs) const; + + virtual UMLAttributeList* clone() const; +}; + + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlcanvasobject.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/umlcanvasobject.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlcanvasobject.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlcanvasobject.cpp 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,464 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "umlcanvasobject.h" + +// local includes +#include "debug_utils.h" +#include "uml.h" +#include "umldoc.h" +#include "classifier.h" +#include "association.h" +#include "attribute.h" +#include "operation.h" +#include "template.h" +#include "stereotype.h" +#include "idchangelog.h" + +// kde includes +#include + +DEBUG_REGISTER_DISABLED(UMLCanvasObject) + +/** + * Sets up a UMLCanvasObject. + * + * @param name The name of the Concept. + * @param id The unique id of the Concept. + */ +UMLCanvasObject::UMLCanvasObject(const QString & name, Uml::ID::Type id) + : UMLObject(name, id) +{ +} + +/** + * Standard deconstructor. + */ +UMLCanvasObject::~UMLCanvasObject() +{ + //removeAllAssociations(); + // No! This is way too late to do that. + // It should have been called explicitly before destructing the + // UMLCanvasObject. + if (associations()) + DEBUG(DBG_SRC) << "UMLCanvasObject destructor: FIXME: there are still associations()"; +} + +/** + * Return the subset of m_List that matches the given type. + * + * @param assocType The AssociationType::Enum to match. + * @return The list of associations that match assocType. + */ +UMLAssociationList UMLCanvasObject::getSpecificAssocs(Uml::AssociationType::Enum assocType) +{ + UMLAssociationList list; + UMLObject *o = NULL; + for (UMLObjectListIt oit(m_List); oit.hasNext();) { + o = oit.next(); + uIgnoreZeroPointer(o); + if (o->baseType() != UMLObject::ot_Association) + continue; + UMLAssociation *a = static_cast(o); + if (a->getAssocType() == assocType) + list.append(a); + } + return list; +} + +/** + * Adds an association end to m_List. + * + * @param assoc The association to add. + * @todo change param type to UMLRole + */ +bool UMLCanvasObject::addAssociationEnd(UMLAssociation* assoc) +{ + Q_ASSERT(assoc); + // add association only if not already present in list + if (!hasAssociation(assoc)) + { + m_List.append(assoc); + + // Don't emit signals during load from XMI + UMLObject::emitModified(); + emit sigAssociationEndAdded(assoc); + return true; + } + return false; +} + +/** + * Determine if this canvasobject has the given association. + * + * @param assoc The association to check. + */ +bool UMLCanvasObject::hasAssociation(UMLAssociation* assoc) +{ + uint cnt = m_List.count(assoc); + DEBUG(DBG_SRC) << "count is " << cnt; + return (cnt > 0); +} + +/** + * Remove an association end from the CanvasObject. + * + * @param assoc The association to remove. + * @todo change param type to UMLRole + */ +int UMLCanvasObject::removeAssociationEnd(UMLAssociation * assoc) +{ + if (!hasAssociation(assoc) || !m_List.removeAll(assoc)) { + DEBUG(DBG_SRC) << "cannot find given assoc " << assoc << " in list"; + return -1; + } + UMLApp::app()->document()->removeAssociation(assoc, false); + UMLObject::emitModified(); + emit sigAssociationEndRemoved(assoc); + return m_List.count(); +} + +/** + * Remove all association ends from the CanvasObject. + */ +void UMLCanvasObject::removeAllAssociationEnds() +{ + for (int i = 0; i < m_List.count(); i++) { + UMLObject *o = m_List.at(i); + uIgnoreZeroPointer(o); + if (o->baseType() != UMLObject::ot_Association) { + continue; + } + UMLAssociation *assoc = static_cast(o); + //umldoc->slotRemoveUMLObject(assoc); + UMLObject* objA = assoc->getObject(Uml::RoleType::A); + UMLObject* objB = assoc->getObject(Uml::RoleType::B); + UMLCanvasObject *roleAObj = dynamic_cast(objA); + if (roleAObj) { + roleAObj->removeAssociationEnd(assoc); + } else if (objA) { + DEBUG(DBG_SRC) << name() << ": objA " << objA->name() << " is not a UMLCanvasObject"; + } else + DEBUG(DBG_SRC) << name() << "): objA is NULL"; + UMLCanvasObject *roleBObj = dynamic_cast(objB); + if (roleBObj) { + roleBObj->removeAssociationEnd(assoc); + } else if (objB) { + DEBUG(DBG_SRC) << name() << "): objB " << objB->name() << " is not a UMLCanvasObject"; + } else + DEBUG(DBG_SRC) << name() << "): objB is NULL"; + } +} + +/** + * Remove all child objects. + * Just clear list, objects must be deleted where they were created + * (or we have bad crashes). + */ +void UMLCanvasObject::removeAllChildObjects() +{ + if (!m_List.isEmpty()) { + removeAllAssociationEnds(); + m_List.clear(); + } +} + +/** + * Returns a name for the new association, operation, template + * or attribute appended with a number if the default name is + * taken e.g. new_association, new_association_1 etc. + * + * @param type The object type for which to make a name. + * @param prefix Optional prefix to use for the name. + * If not given then uniqChildName() will choose the prefix + * internally based on the object type. + * @return Unique name string for the ObjectType given. + */ +QString UMLCanvasObject::uniqChildName(const UMLObject::ObjectType type, + const QString &prefix /* = QString() */) +{ + QString currentName; + currentName = prefix; + if (currentName.isEmpty()) { + switch (type) { + case UMLObject::ot_Association: + currentName = i18n("new_association"); + break; + case UMLObject::ot_Attribute: + currentName = i18n("new_attribute"); + break; + case UMLObject::ot_Template: + currentName = i18n("new_template"); + break; + case UMLObject::ot_Operation: + currentName = i18n("new_operation"); + break; + case UMLObject::ot_EnumLiteral: + currentName = i18n("new_literal"); + break; + case UMLObject::ot_EntityAttribute: + currentName = i18n("new_field"); + break; + case UMLObject::ot_UniqueConstraint: + currentName = i18n("new_unique_constraint"); + break; + case UMLObject::ot_ForeignKeyConstraint: + currentName = i18n("new_fkey_constraint"); + break; + case UMLObject::ot_CheckConstraint: + currentName = i18n("new_check_constraint"); + break; + default: + uWarning() << "uniqChildName() called for unknown child type " << UMLObject::toString(type); + return QLatin1String("ERROR_in_UMLCanvasObject_uniqChildName"); + } + } + + QString name = currentName; + for (int number = 1; findChildObject(name); ++number) { + name = currentName + QLatin1Char('_') + QString::number(number); + } + return name; +} + +/** + * Find a child object with the given name. + * + * @param n The name of the object to find. + * @param t The type to find (optional.) If not given then + * any object type will match. + * @return Pointer to the object found; NULL if none found. + */ +UMLObject * UMLCanvasObject::findChildObject(const QString &n, UMLObject::ObjectType t) +{ + const bool caseSensitive = UMLApp::app()->activeLanguageIsCaseSensitive(); + UMLObject *obj = NULL; + for (UMLObjectListIt oit(m_List); oit.hasNext();) { + obj = oit.next(); + uIgnoreZeroPointer(obj); + if (t != UMLObject::ot_UMLObject && obj->baseType() != t) + continue; + if (caseSensitive) { + if (obj->name() == n) + return obj; + } else if (obj->name().toLower() == n.toLower()) { + return obj; + } + } + return NULL; +} + +/** + * Find an association. + * + * @param id The id of the object to find. + * @param considerAncestors boolean switch to consider ancestors while searching + * @return Pointer to the object found (NULL if not found.) + */ +UMLObject* UMLCanvasObject::findChildObjectById(Uml::ID::Type id, bool considerAncestors) +{ + Q_UNUSED(considerAncestors); + UMLObject *o = NULL; + for (UMLObjectListIt oit(m_List); oit.hasNext();) { + o = oit.next(); + uIgnoreZeroPointer(o); + if (o->id() == id) + return o; + } + return 0; +} + +/** + * Overloaded '==' operator + */ +bool UMLCanvasObject::operator==(const UMLCanvasObject& rhs) const +{ + if (this == &rhs) { + return true; + } + if (!UMLObject::operator==(rhs)) { + return false; + } + if (m_List.count() != rhs.m_List.count()) { + return false; + } + if (&m_List != &(rhs.m_List)) { + return false; + } + return true; +} + +/** + * Copy the internal presentation of this object into the new + * object. + */ +void UMLCanvasObject::copyInto(UMLObject *lhs) const +{ + UMLObject::copyInto(lhs); + + // TODO Associations are not copied at the moment. This because + // the duplicate function (on umlwidgets) do not copy the associations. + // + //target->m_List = m_List; +} + +/** + * Returns the number of associations for the CanvasObject. + * This is the sum of the aggregations and compositions. + * + * @return The number of associations for the Concept. + */ +int UMLCanvasObject::associations() +{ + int count = 0; + UMLObject *obj = NULL; + for (UMLObjectListIt oit(m_List); oit.hasNext();) { + obj = oit.next(); + uIgnoreZeroPointer(obj); + if (obj->baseType() == UMLObject::ot_Association) + count++; + } + return count; +} + +/** + * Return the list of associations for the CanvasObject. + * + * @return The list of associations for the CanvasObject. + */ +UMLAssociationList UMLCanvasObject::getAssociations() +{ + UMLAssociationList assocs; + UMLObject *o = NULL; + for (UMLObjectListIt oit(m_List); oit.hasNext() ;) { + o = oit.next(); + uIgnoreZeroPointer(o); + if (o->baseType() != UMLObject::ot_Association) + continue; + UMLAssociation *assoc = static_cast(o); + assocs.append(assoc); + } + return assocs; +} + +/** + * Return a list of the superclasses of this concept. + * TODO: This overlaps with UMLClassifier::findSuperClassConcepts(), + * see if we can merge the two. + * + * @param withRealizations include realizations in the returned list (default=yes) + * @return The list of superclasses for the concept. + */ +UMLClassifierList UMLCanvasObject::getSuperClasses(bool withRealizations) +{ + UMLClassifierList list; + UMLAssociationList assocs = getAssociations(); + foreach (UMLAssociation* a, assocs) { + uIgnoreZeroPointer(a); + if ((a->getAssocType() != Uml::AssociationType::Generalization && + a->getAssocType() != Uml::AssociationType::Realization) || + (!withRealizations && a->getAssocType() == Uml::AssociationType::Realization) || + a->getObjectId(Uml::RoleType::A) != id()) + continue; + UMLClassifier *c = dynamic_cast(a->getObject(Uml::RoleType::B)); + if (c) + list.append(c); + else + DEBUG(DBG_SRC) << name() << ": generalization's other end is not a " + << "UMLClassifier (id= " << Uml::ID::toString(a->getObjectId(Uml::RoleType::B)) << ")"; + } + return list; +} + +/** + * Return a list of the classes that inherit from this concept. + * TODO: This overlaps with UMLClassifier::findSubClassConcepts(), + * see if we can merge the two. + * + * @return The list of classes inheriting from the concept. + */ +UMLClassifierList UMLCanvasObject::getSubClasses() +{ + UMLClassifierList list; + UMLAssociationList assocs = getAssociations(); + foreach (UMLAssociation* a, assocs) { + uIgnoreZeroPointer(a); + if ((a->getAssocType() != Uml::AssociationType::Generalization && + a->getAssocType() != Uml::AssociationType::Realization) || + a->getObjectId(Uml::RoleType::B) != id()) + continue; + UMLClassifier *c = dynamic_cast(a->getObject(Uml::RoleType::A)); + if (c) + list.append(c); + else + DEBUG(DBG_SRC) << "specialization's other end is not a UMLClassifier" + << " (id=" << Uml::ID::toString(a->getObjectId(Uml::RoleType::A)) << ")"; + } + return list; +} + +/** + * Shorthand for getSpecificAssocs(Uml::at_Realization) + * + * @return The list of realizations for the Concept. + */ +UMLAssociationList UMLCanvasObject::getRealizations() +{ + return getSpecificAssocs(Uml::AssociationType::Realization); +} + +/** + * Shorthand for getSpecificAssocs(Uml::at_Aggregation) + * + * @return The list of aggregations for the Concept. + */ +UMLAssociationList UMLCanvasObject::getAggregations() +{ + return getSpecificAssocs(Uml::AssociationType::Aggregation); +} + +/** + * Shorthand for getSpecificAssocs(Uml::at_Composition) + * + * @return The list of compositions for the Concept. + */ +UMLAssociationList UMLCanvasObject::getCompositions() +{ + return getSpecificAssocs(Uml::AssociationType::Composition); +} + +/** + * Shorthand for getSpecificAssocs(Uml::at_Relationship) + * + * @return The list of relationships for the entity. + */ +UMLAssociationList UMLCanvasObject::getRelationships() +{ + return getSpecificAssocs(Uml::AssociationType::Relationship); +} + +/** + * Reimplementation of UMLObject method. + */ +bool UMLCanvasObject::resolveRef() +{ + bool overallSuccess = UMLObject::resolveRef(); + for (UMLObjectListIt ait(m_List); ait.hasNext();) { + UMLObject *obj = ait.next(); + uIgnoreZeroPointer(obj); + if (! obj->resolveRef()) { + m_List.removeAll(obj); + overallSuccess = false; + } + } + return overallSuccess; +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlcanvasobject.h umbrello-kf6-15.08.1/umbrello/umlmodel/umlcanvasobject.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlcanvasobject.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlcanvasobject.h 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,108 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef CANVASOBJECT_H +#define CANVASOBJECT_H + +#include "umlobject.h" +#include "umlobjectlist.h" +#include "umlclassifierlist.h" +#include "umlassociationlist.h" + +/** + * This class contains the non-graphical information required for UMLObjects + * which appear as moveable widgets on the scene. + * + * This class inherits from @ref UMLObject which contains most of the + * information. + * It is not instantiated itself, it's just used as a super class for + * actual model objects. + * + * @short Non-graphical information for a UMLCanvasObject. + * @author Jonathan Riddell + * @see UMLObject + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class UMLCanvasObject : public UMLObject +{ + Q_OBJECT + +public: + explicit UMLCanvasObject(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); + virtual ~UMLCanvasObject(); + + bool operator==(const UMLCanvasObject& rhs) const; + + virtual void copyInto(UMLObject *lhs) const; + + // The abstract method UMLObject::clone() is implemented + // in the classes inheriting from UMLCanvasObject. + + bool addAssociationEnd(UMLAssociation* assoc); + + bool hasAssociation(UMLAssociation* assoc); + + int removeAssociationEnd(UMLAssociation *assoc); + + void removeAllAssociationEnds(); + + int associations(); + + UMLAssociationList getAssociations(); + + UMLAssociationList getSpecificAssocs(Uml::AssociationType::Enum assocType); + + UMLClassifierList getSuperClasses(bool withRealizations = true); + UMLClassifierList getSubClasses(); + + virtual UMLAssociationList getRealizations(); + + UMLAssociationList getAggregations(); + UMLAssociationList getCompositions(); + UMLAssociationList getRelationships(); + + virtual UMLObject *findChildObject(const QString &n, + UMLObject::ObjectType t = UMLObject::ot_UMLObject); + virtual UMLObject *findChildObjectById(Uml::ID::Type id, bool considerAncestors = false); + + virtual QString uniqChildName(const UMLObject::ObjectType type, + const QString &prefix = QString()); + + virtual void removeAllChildObjects(); + + UMLObjectList subordinates() const { + return m_List; + } + + virtual bool resolveRef(); + + // The abstract method UMLObject::saveToXMI() is implemented + // in the classes inheriting from UMLCanvasObject. + +protected: + + /** + * List of all the associations in this object. + * Inheriting classes add more types of objects that are possible in this list; + * for example, UMLClassifier adds operations, attributes, and templates. + * + * @todo Only a pointer to the appropriate assocation end object + * (UMLRole) should be saved here, not the entire UMLAssociation. + */ + UMLObjectList m_List; + +signals: + + void sigAssociationEndAdded(UMLAssociation * assoc); + void sigAssociationEndRemoved(UMLAssociation * assoc); + +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlclassifierlist.h umbrello-kf6-15.08.1/umbrello/umlmodel/umlclassifierlist.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlclassifierlist.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlclassifierlist.h 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,22 @@ +/*************************************************************************** + * 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-2010 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef UMLCLASSIFIERLIST_H +#define UMLCLASSIFIERLIST_H + +#include + +// forward declaration +class UMLClassifier; + +typedef QList UMLClassifierList; +typedef QListIterator UMLClassifierListIt; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlclassifierlistitemlist.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/umlclassifierlistitemlist.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlclassifierlistitemlist.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlclassifierlistitemlist.cpp 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,60 @@ +/*************************************************************************** + * 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) 2004-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#include "umlclassifierlistitemlist.h" + +#include "classifierlistitem.h" + +#include + +UMLClassifierListItemList::UMLClassifierListItemList() +{ +} + +UMLClassifierListItemList::UMLClassifierListItemList(const UMLClassifierListItemList& other) + : QList(other) +{ +} + +UMLClassifierListItemList::~UMLClassifierListItemList() +{ +} + +/** + * Copy the internal presentation of this object into the new + * object. + */ +void UMLClassifierListItemList::copyInto(UMLClassifierListItemList *rhs) const +{ + // Prevent copying to yourself. (Can cause serious injuries) + if (rhs == this) return; + + rhs->clear(); + + // Suffering from const; we shall not modify our object. + UMLClassifierListItemList *tmp = new UMLClassifierListItemList(*this); + + UMLClassifierListItem *item; + for (UMLClassifierListItemListIt clit(*tmp); clit.hasNext() ;) { + item = clit.next(); + rhs->append((UMLClassifierListItem*)item->clone()); + } + delete tmp; +} + +/** + * Make a clone of this object. + */ +UMLClassifierListItemList* UMLClassifierListItemList::clone() const +{ + UMLClassifierListItemList *clone = new UMLClassifierListItemList(); + copyInto(clone); + return clone; +} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlclassifierlistitemlist.h umbrello-kf6-15.08.1/umbrello/umlmodel/umlclassifierlistitemlist.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlclassifierlistitemlist.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlclassifierlistitemlist.h 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,41 @@ +/*************************************************************************** + * 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) 2004-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef UMLCLASSIFIERLISTITEMLIST_H +#define UMLCLASSIFIERLISTITEMLIST_H + +#include + +// forward declaration +class UMLClassifierListItem; + +//typedef QPtrList UMLClassifierListItemList; +typedef QListIterator UMLClassifierListItemListIt; + +/** + * This sub-class adds copyInto and clone to the QPtrList + * base class. + */ +class UMLClassifierListItemList : public QList +{ +public: + + UMLClassifierListItemList(); + UMLClassifierListItemList(const UMLClassifierListItemList& other); + + virtual ~UMLClassifierListItemList(); + + virtual void copyInto (UMLClassifierListItemList *rhs) const; + + virtual UMLClassifierListItemList* clone() const; + +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlentityattributelist.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/umlentityattributelist.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlentityattributelist.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlentityattributelist.cpp 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,60 @@ +/*************************************************************************** + * 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) 2004-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#include "umlentityattributelist.h" + +#include "entityattribute.h" + +#include + +UMLEntityAttributeList::UMLEntityAttributeList() +{ +} + +UMLEntityAttributeList::UMLEntityAttributeList(const UMLEntityAttributeList& other) + : QList(other) +{ +} + +UMLEntityAttributeList::~UMLEntityAttributeList() +{ +} + +/** + * Copy the internal presentation of this object into the new + * object. + */ +void UMLEntityAttributeList::copyInto(UMLEntityAttributeList* rhs) const +{ + // Don't copy yourself. + if (rhs == this) return; + + rhs->clear(); + + // Suffering from const; we shall not modify our object. + UMLEntityAttributeList* tmp = new UMLEntityAttributeList(*this); + + UMLEntityAttribute* item; + for (UMLEntityAttributeListIt eait(*tmp); eait.hasNext() ;) { + item = eait.next(); + rhs->append((UMLEntityAttribute*)item->clone()); + } + delete tmp; +} + +/** + * Make a clone of this object. + */ +UMLEntityAttributeList* UMLEntityAttributeList::clone() const +{ + UMLEntityAttributeList *clone = new UMLEntityAttributeList(); + copyInto(clone); + return clone; +} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlentityattributelist.h umbrello-kf6-15.08.1/umbrello/umlmodel/umlentityattributelist.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlentityattributelist.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlentityattributelist.h 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,41 @@ +/*************************************************************************** + * * + * 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) 2004-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef UMLENTITYATTRIBUTELIST_H +#define UMLENTITYATTRIBUTELIST_H + +#include +#include "entityattribute.h" + +//typedef QPtrList UMLEntityAttributeList; +typedef QListIterator UMLEntityAttributeListIt; + +/** + * This sub-class adds copyInto and clone to the QPtrList + * base class. + */ +class UMLEntityAttributeList : public QList +{ +public: + + UMLEntityAttributeList(); + + UMLEntityAttributeList(const UMLEntityAttributeList&); + + virtual ~UMLEntityAttributeList(); + + virtual void copyInto (UMLEntityAttributeList* rhs) const; + + virtual UMLEntityAttributeList* clone() const; +}; + + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlentityconstraintlist.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/umlentityconstraintlist.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlentityconstraintlist.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlentityconstraintlist.cpp 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,60 @@ +/*************************************************************************** + * 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) 2004-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#include "umlentityconstraintlist.h" + +#include "entityconstraint.h" + +#include + +UMLEntityConstraintList::UMLEntityConstraintList() +{ +} + +UMLEntityConstraintList::UMLEntityConstraintList(const UMLEntityConstraintList& other) + : QList(other) +{ +} + +UMLEntityConstraintList::~UMLEntityConstraintList() +{ +} + +/** + * Copy the internal presentation of this object into the new + * object. + */ +void UMLEntityConstraintList::copyInto(UMLEntityConstraintList* rhs) const +{ + // Don't copy yourself. + if (rhs == this) return; + + rhs->clear(); + + // Suffering from const; we shall not modify our object. + UMLEntityConstraintList* tmp = new UMLEntityConstraintList(*this); + + UMLEntityConstraint* item; + for (UMLEntityConstraintListIt ecit(*tmp); ecit.hasNext() ;) { + item = ecit.next(); + rhs->append((UMLEntityConstraint*)item->clone()); + } + delete tmp; +} + +/** + * Make a clone of this object. + */ +UMLEntityConstraintList* UMLEntityConstraintList::clone() const +{ + UMLEntityConstraintList *clone = new UMLEntityConstraintList(); + copyInto(clone); + return clone; +} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlentityconstraintlist.h umbrello-kf6-15.08.1/umbrello/umlmodel/umlentityconstraintlist.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlentityconstraintlist.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlentityconstraintlist.h 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,43 @@ +/*************************************************************************** + * * + * 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) 2004-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef UMLENTITYCONSTRAINTLIST_H +#define UMLENTITYCONSTRAINTLIST_H + +#include + +// forward declaration +class UMLEntityConstraint; + + +typedef QListIterator UMLEntityConstraintListIt; + +/** + * This sub-class adds copyInto and clone to the QPtrList + * base class. + */ +class UMLEntityConstraintList : public QList +{ +public: + + UMLEntityConstraintList(); + + UMLEntityConstraintList(const UMLEntityConstraintList&); + + virtual ~UMLEntityConstraintList(); + + virtual void copyInto (UMLEntityConstraintList* rhs) const; + + virtual UMLEntityConstraintList* clone() const; +}; + + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlentitylist.h umbrello-kf6-15.08.1/umbrello/umlmodel/umlentitylist.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlentitylist.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlentitylist.h 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,22 @@ +/*************************************************************************** + * 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-2010 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef UMLENTITYLIST_H +#define UMLENTITYLIST_H + +#include + +// forward declaration +class UMLEntity; + +typedef QList UMLEntityList; +typedef QListIterator UMLEntityListIt; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlenumliterallist.h umbrello-kf6-15.08.1/umbrello/umlmodel/umlenumliterallist.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlenumliterallist.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlenumliterallist.h 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,23 @@ +/*************************************************************************** + * * + * 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) 2004-2007 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef UMLENUMLITERALLIST_H +#define UMLENUMLITERALLIST_H + +#include + +// forward declaration +class UMLEnumLiteral; + +typedef QList UMLEnumLiteralList; +typedef QListIterator UMLEnumLiteralListIt; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlobject.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/umlobject.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlobject.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlobject.cpp 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,1157 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "umlobject.h" + +// app includes +#include "classpropertiesdialog.h" +#include "debug_utils.h" +#include "enumliteral.h" +#include "uniqueid.h" +#include "uml.h" +#include "umldoc.h" +#include "umllistview.h" +#include "package.h" +#include "folder.h" +#include "stereotype.h" +#include "object_factory.h" +#include "model_utils.h" +#include "import_utils.h" +#include "docwindow.h" +#include "cmds.h" + +// kde includes +#include + +// qt includes +#include +#include + +using namespace Uml; + +DEBUG_REGISTER_DISABLED(UMLObject) + +/** + * Creates a UMLObject. + * @param other object to created from + */ +UMLObject::UMLObject(const UMLObject &other) + : QObject(other.parent()) +{ + other.copyInto(this); +} + +/** + * Creates a UMLObject. + * @param parent The parent of the object. + * @param name The name of the object. + * @param id The ID of the object (optional.) If omitted + * then a new ID will be assigned internally. + */ +UMLObject::UMLObject(UMLObject* parent, const QString& name, ID::Type id) + : QObject(parent), + m_nId(id), + m_name(name) +{ + init(); + if (id == Uml::ID::None) + m_nId = UniqueID::gen(); +} + +/** + * Creates a UMLObject. + * @param name The name of the object. + * @param id The ID of the object (optional.) If omitted + * then a new ID will be assigned internally. + */ +UMLObject::UMLObject(const QString& name, ID::Type id) + : QObject(UMLApp::app()->document()), + m_nId(id), + m_name(name) +{ + init(); + if (id == Uml::ID::None) + m_nId = UniqueID::gen(); +} + +/** + * Creates a UMLObject. + * @param parent The parent of the object. + */ +UMLObject::UMLObject(UMLObject * parent) + : QObject(parent), + m_nId(Uml::ID::None), + m_name(QString()) +{ + init(); +} + +/** + * Standard destructor. + */ +UMLObject::~UMLObject() +{ + // unref stereotype + setUMLStereotype(0); + if (m_pSecondary && m_pSecondary->baseType() == ot_Stereotype) { + UMLStereotype* stereotype = dynamic_cast(m_pSecondary.data()); + if (stereotype) + stereotype->decrRefCount(); + } +} + +/** + * Initializes key variables of the class. + */ +void UMLObject::init() +{ + setObjectName(QLatin1String("UMLObject")); + m_BaseType = ot_UMLObject; + m_pUMLPackage = 0; + m_visibility = Uml::Visibility::Public; + m_pStereotype = 0; + m_Doc.clear(); + m_bAbstract = false; + m_bStatic = false; + m_bCreationWasSignalled = false; + m_pSecondary = 0; +} + +/** + * Display the properties configuration dialog for the object. + * + * @param parent The parent widget. + * @return True for success of this operation. + */ +bool UMLObject::showPropertiesDialog(QWidget *parent) +{ + DocWindow *docwindow = UMLApp::app()->docWindow(); + docwindow->updateDocumentation(false); + QPointer dlg = new ClassPropertiesDialog(parent, this, false); + bool modified = false; + if (dlg->exec()) { + docwindow->showDocumentation(this, true); + UMLApp::app()->document()->setModified(true); + modified = true; + } + dlg->close(); + delete dlg; + return modified; +} + +/** + * This should be reimplemented by subclasses if they wish to + * accept certain types of associations. Note that this only + * tells if this UMLObject can accept the association + * type. When creating an association another check is made to + * see if the association is valid. For example a UMLClass + * (UMLClassifier) can accept generalizations and should + * return true. If while creating a generalization the + * superclass is already subclassed from this, the association + * is not valid and will not be created. The default accepts + * nothing (returns false) + */ +bool UMLObject::acceptAssociationType(Uml::AssociationType::Enum type) +{ + Q_UNUSED(type); + // A UMLObject accepts nothing. This should be reimplemented by the subclasses + return false; +} + +/** + * Assigns a new Id to the object + */ +void UMLObject::setID(ID::Type NewID) +{ + m_nId = NewID; + emitModified(); +} + +/** + * Set the UMLObject's name + */ +void UMLObject::setName(const QString &strName) +{ + if (name() != strName) { + UMLApp::app()->executeCommand(new Uml::CmdRenameUMLObject(this, strName)); + } +} + +/** + * Method used by setName: it is called by cmdSetName, Don't use it! + */ +void UMLObject::setNameCmd(const QString &strName) +{ + m_name = strName; + emitModified(); +} + +/** + * Returns a copy of m_name + */ +QString UMLObject::name() const +{ + return m_name; +} + +/** + * Returns the fully qualified name, i.e. all package prefixes and then m_name. + * + * @param separator The separator string to use (optional.) + * If not given then the separator is chosen according + * to the currently selected active programming language + * of import and code generation. + * @param includeRoot Whether to prefix the root folder name to the FQN. + * See UMLDoc::getRootFolder(). Default: false. + * @return The fully qualified name of this UMLObject. + */ +QString UMLObject::fullyQualifiedName(const QString& separator, + bool includeRoot /* = false */) const +{ + QString fqn; + if (m_pUMLPackage && m_pUMLPackage != this) { + bool skipPackage = false; + if (!includeRoot) { + UMLDoc *umldoc = UMLApp::app()->document(); + if (umldoc->rootFolderType(m_pUMLPackage) != Uml::ModelType::N_MODELTYPES || + m_pUMLPackage == umldoc->datatypeFolder()) + skipPackage = true; + } + if (!skipPackage) { + QString tempSeparator = separator; + if (tempSeparator.isEmpty()) + tempSeparator = UMLApp::app()->activeLanguageScopeSeparator(); + fqn = m_pUMLPackage->fullyQualifiedName(tempSeparator, includeRoot); + fqn.append(tempSeparator); + } + } + fqn.append(m_name); + return fqn; +} + +/** + * Overloaded '==' operator + */ +bool UMLObject::operator==(const UMLObject & rhs) const +{ + 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-kf6 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 visibility should not be part of the equality test. + // What does it mean if two objects are the same but differ in their + // visibility? - I'm not aware of any programming language that would + // support that. + //if(m_visibility != rhs.m_visibility) + // 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; +} + +/** + * Copy the internal presentation of this object into the new + * object. + */ +void UMLObject::copyInto(UMLObject *lhs) const +{ + // Data members with copy constructor + lhs->m_Doc = m_Doc; + lhs->m_pStereotype = m_pStereotype; + if (lhs->m_pStereotype) + lhs->m_pStereotype->incrRefCount(); + lhs->m_bAbstract = m_bAbstract; + lhs->m_bStatic = m_bStatic; + lhs->m_BaseType = m_BaseType; + lhs->m_visibility = m_visibility; + lhs->m_pUMLPackage = m_pUMLPackage; + + // We don't want the same name existing twice. + lhs->m_name = Model_Utils::uniqObjectName(m_BaseType, m_pUMLPackage, m_name); + + // Create a new ID. + lhs->m_nId = UniqueID::gen(); + + // Hope that the parent from QObject is okay. + if (lhs->parent() != parent()) + uDebug() << "copyInto has a wrong parent"; +} + +UMLObject *UMLObject::clone() const +{ + UMLObject *clone = new UMLObject; + UMLObject::copyInto(clone); + return clone; +} + +/** + * Returns the abstract state of the object. + */ +bool UMLObject::isAbstract() const +{ + return m_bAbstract; +} + +/** + * Sets the paste state of the object. + */ +void UMLObject::setAbstract(bool bAbstract) +{ + m_bAbstract = bAbstract; + emitModified(); +} + +/** + * Returns true if this UMLObject has classifier scope, + * otherwise false (the default). + */ +bool UMLObject::isStatic() const +{ + return m_bStatic; +} + +/** + * Sets the value for m_bStatic. + */ +void UMLObject::setStatic(bool bStatic) +{ + m_bStatic = bStatic; + emitModified(); +} + +/** + * Forces the emission of the modified signal. Useful when + * updating several attributes at a time: you can block the + * signals, update all atts, and then force the signal. + */ +void UMLObject::emitModified() +{ + UMLDoc *umldoc = UMLApp::app()->document(); + if (!umldoc->loading() && !umldoc->closing()) + emit modified(); +} + +/** + * Returns the type of the object. + * + * @return Returns the type of the object. + */ +UMLObject::ObjectType UMLObject::baseType() const +{ + return m_BaseType; +} + +/** + * @return The type used for rtti as string. + */ +QLatin1String UMLObject::baseTypeStr() const +{ + return QLatin1String(ENUM_NAME(UMLObject, ObjectType, m_BaseType)); +} + +/** + * Set the type of the object. + * + * @param ot The ObjectType to set. + */ +void UMLObject::setBaseType(ObjectType ot) +{ + m_BaseType = ot; +} + +/** + * Returns the ID of the object. + * + * @return Returns the ID of the object. + */ +ID::Type UMLObject::id() const +{ + return m_nId; +} + +/** + * Returns the documentation for the object. + * + * @return Returns the documentation for the object. + */ +QString UMLObject::doc() const +{ + return m_Doc; +} + +/** + * Returns state of documentation for the object. + * + * @return false if documentation is empty + */ +bool UMLObject::hasDoc() const +{ + return !m_Doc.isEmpty(); +} + +/** + * Sets the documentation for the object. + * + * @param d The documentation for the object. + */ +void UMLObject::setDoc(const QString &d) +{ + m_Doc = d; + //emit modified(); No, this is done centrally at DocWindow::updateDocumentation() +} + +/** + * Returns the visibility of the object. + * + * @return Returns the visibility of the object. + */ +Visibility::Enum UMLObject::visibility() const +{ + return m_visibility; +} + +/** + * Sets the visibility of the object. + * + * @param visibility The visibility of the object. + */ +void UMLObject::setVisibility(Visibility::Enum visibility) +{ + if (m_visibility != visibility) { + UMLApp::app()->executeCommand(new CmdSetVisibility(this, visibility)); + } +} + +/** + * Method used by setVisibility: it is called by cmdSetVisibility, Don't use it! + */ +void UMLObject::setVisibilityCmd(Visibility::Enum visibility) +{ + m_visibility = visibility; + emitModified(); +} + +/** + * Sets the class' UMLStereotype. Adjusts the reference counts + * at the previously set stereotype and at the new stereotype. + * If the previously set UMLStereotype's reference count drops + * to zero then the UMLStereotype is removed at the UMLDoc and + * it is then physically deleted. + * + * @param stereo Sets the classes UMLStereotype. + */ +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()->document(); + pDoc->removeStereotype(m_pStereotype); + delete m_pStereotype; + } + } + m_pStereotype = stereo; + // TODO: don't emit modified() if predefined folder + emitModified(); +} + +/** + * Sets the classes stereotype name. + * Internally uses setUMLStereotype(). + * + * @param name Sets the classes stereotype name. + */ +void UMLObject::setStereotype(const QString &name) +{ + if (name != stereotype()) { + UMLApp::app()->executeCommand(new CmdSetStereotype(this, name)); + } +} + +void UMLObject::setStereotypeCmd(const QString& name) +{ + if (name.isEmpty()) { + setUMLStereotype(NULL); + return; + } + UMLDoc *pDoc = UMLApp::app()->document(); + UMLStereotype *s = pDoc->findOrCreateStereotype(name); + setUMLStereotype(s); +} + +/** + * Sets the UMLPackage in which this class is located. + * + * @param pPkg Pointer to the class' UMLPackage. + */ +bool UMLObject::setUMLPackage(UMLPackage* pPkg) +{ + if (pPkg == this) { + uDebug() << "setting parent to myself is not allowed"; + return false; + } + + if (pPkg == NULL) { + // Allow setting to NULL for stereotypes + m_pUMLPackage = pPkg; + return true; + } + + if (pPkg->umlPackage() == this) { + uDebug() << "setting parent to an object of which I'm already the parent is not allowed"; + return false; + } + + m_pUMLPackage = pPkg; + emitModified(); + return true; +} + +/** + * Returns the classes UMLStereotype object. + * + * @return Returns the classes UMLStereotype object. + */ +UMLStereotype * UMLObject::umlStereotype() +{ + return m_pStereotype; +} + +/** + * Returns the stereotype. + */ +QString UMLObject::stereotype(bool includeAdornments /* = false */) const +{ + if (m_pStereotype == NULL) + return QString(); + return m_pStereotype->name(includeAdornments); +} + +/** + * Return the package(s) in which this UMLObject is contained + * as a text. + * + * @param separator Separator string for joining together the + * individual package prefixes (optional.) + * If no separator is given then the separator + * of the currently selected language is used. + * @param includeRoot Whether to prefix the root folder name. + * Default: false. + * @return The UMLObject's enclosing package(s) as a text. + */ +QString UMLObject::package(const QString& separator, bool includeRoot) +{ + QString tempSeparator = separator; + if (tempSeparator.isEmpty()) + tempSeparator = UMLApp::app()->activeLanguageScopeSeparator(); + QString fqn = fullyQualifiedName(tempSeparator, includeRoot); + if (!fqn.contains(tempSeparator)) + return QString(); + QString scope = fqn.left(fqn.length() - tempSeparator.length() - m_name.length()); + return scope; +} + +/** + * Return a list of the packages in which this class is embedded. + * The outermost package is first in the list. + * + * @param includeRoot Whether to prefix the root folder name. + * Default: false. + * @return UMLPackageList of the containing packages. + */ +UMLPackageList UMLObject::packages(bool includeRoot) const +{ + UMLPackageList pkgList; + UMLPackage* pkg = m_pUMLPackage; + while (pkg != NULL) { + pkgList.prepend(pkg); + pkg = pkg->umlPackage(); + } + if (!includeRoot) + pkgList.removeFirst(); + return pkgList; +} + +/** + * Returns the UMLPackage that this class is located in. + * + * @return Pointer to the UMLPackage of this class. + */ +UMLPackage* UMLObject::umlPackage() +{ + return m_pUMLPackage; +} + +/** + * Return secondary ID. Required by resolveRef(). + */ +QString UMLObject::secondaryId() const +{ + return m_SecondaryId; +} + +/** + * Set the secondary ID. + * Currently only required by petalTree2Uml(); all other setting of the + * m_SecondaryID is internal to the UMLObject class hierarchy. + */ +void UMLObject::setSecondaryId(const QString& id) +{ + m_SecondaryId = id; +} + +/** + * Return secondary ID fallback. + * Required by resolveRef() for imported model files. + */ +QString UMLObject::secondaryFallback() const +{ + return m_SecondaryFallback; +} + +/** + * Set the secondary ID fallback. + * Currently only used by petalTree2Uml(). + */ +void UMLObject::setSecondaryFallback(const QString& id) +{ + m_SecondaryFallback = id; +} + +/** + * Calls UMLDoc::signalUMLObjectCreated() if m_BaseType affords + * doing so. + */ +void UMLObject::maybeSignalObjectCreated() +{ + if (!m_bCreationWasSignalled && + m_BaseType != ot_Stereotype && + m_BaseType != ot_Association && + m_BaseType != ot_Role) { + m_bCreationWasSignalled = true; + UMLDoc* umldoc = UMLApp::app()->document(); + umldoc->signalUMLObjectCreated(this); + } +} + +/** + * Resolve referenced objects (if any.) + * Needs to be called after all UML objects are loaded from file. + * This needs to be done after all model objects are loaded because + * some of the xmi.id's might be forward references, i.e. they may + * identify model objects which were not yet loaded at the point of + * reference. + * The default implementation attempts resolution of the m_SecondaryId. + * + * @return True for success. + */ +bool UMLObject::resolveRef() +{ + if (m_pSecondary || (m_SecondaryId.isEmpty() && m_SecondaryFallback.isEmpty())) { + maybeSignalObjectCreated(); + return true; + } +#ifdef VERBOSE_DEBUGGING + uDebug() << m_name << ": m_SecondaryId is " << m_SecondaryId; +#endif + UMLDoc *pDoc = UMLApp::app()->document(); + // 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(Uml::ID::fromString(m_SecondaryId)); + if (m_pSecondary != NULL) { + if (m_pSecondary->baseType() == ot_Stereotype) { + if (m_pStereotype) + m_pStereotype->decrRefCount(); + m_pStereotype = dynamic_cast(m_pSecondary.data()); + m_pStereotype->incrRefCount(); + m_pSecondary = NULL; + } + m_SecondaryId = QString(); + maybeSignalObjectCreated(); + return true; + } + if (m_SecondaryFallback.isEmpty()) { + uDebug() << "object with xmi.id=" << m_SecondaryId << " not found, setting to undef"; + UMLFolder *datatypes = pDoc->datatypeFolder(); + m_pSecondary = Object_Factory::createUMLObject(ot_Datatype, QLatin1String("undef"), datatypes, false); + return true; + } + } + if (m_SecondaryFallback.isEmpty()) { + uError() << m_name << ": cannot find type with id " << m_SecondaryId; + return false; + } +#ifdef VERBOSE_DEBUGGING + uDebug() << m_name << ": could not resolve secondary ID " << m_SecondaryId + << ", using secondary fallback " << m_SecondaryFallback; +#endif + m_SecondaryId = m_SecondaryFallback; + // Assume we're dealing with the older umbrello-kf6 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, ot_UMLObject, this); + if (m_pSecondary) { + m_SecondaryId = QString(); + maybeSignalObjectCreated(); + return true; + } + // Work around Object_Factory::createUMLObject()'s incapability + // of on-the-fly scope creation: + if (m_SecondaryId.contains(QLatin1String("::"))) { + // TODO: Merge Import_Utils::createUMLObject() into Object_Factory::createUMLObject() + m_pSecondary = Import_Utils::createUMLObject(ot_UMLObject, m_SecondaryId, m_pUMLPackage); + if (m_pSecondary) { + if (Import_Utils::newUMLObjectWasCreated()) { + maybeSignalObjectCreated(); + qApp->processEvents(); + uDebug() << "Import_Utils::createUMLObject() created a new type for " + << m_SecondaryId; + } else { + uDebug() << "Import_Utils::createUMLObject() returned an existing type for " + << m_SecondaryId; + } + m_SecondaryId = QString(); + return true; + } + uError() << "Import_Utils::createUMLObject() failed to create a new type for " + << m_SecondaryId; + return false; + } + uDebug() << "Creating new type for " << m_SecondaryId; + // 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(QLatin1Char('*')) || + m_SecondaryId.contains(QLatin1Char('&'))); + ObjectType ot = ot_Class; + if (isReferenceType) { + ot = ot_Datatype; + } else { + if (Model_Utils::isCommonDataType(m_SecondaryId)) + ot = ot_Datatype; + } + m_pSecondary = Object_Factory::createUMLObject(ot, m_SecondaryId, NULL); + if (m_pSecondary == NULL) + return false; + m_SecondaryId = QString(); + maybeSignalObjectCreated(); + //qApp->processEvents(); + return true; +} + +void UMLObject::saveToXMI(QDomDocument &qDoc, QDomElement &qElement) +{ + Q_UNUSED(qDoc); Q_UNUSED(qElement); +} + +/** + * Auxiliary to saveToXMI. + * Create a QDomElement with the given tag, and save the XMI attributes + * that are common to all child classes to the newly created element. + * This method does not need to be overridden by child classes. + */ +QDomElement UMLObject::save(const QString &tag, QDomDocument & qDoc) +{ + /* + Call as the first action of saveToXMI() in child class: + This creates the QDomElement with which to work. + */ + QDomElement qElement = qDoc.createElement(tag); + qElement.setAttribute(QLatin1String("isSpecification"), QLatin1String("false")); + if (m_BaseType != ot_Association && + m_BaseType != ot_Role && + m_BaseType != ot_Attribute) { + qElement.setAttribute(QLatin1String("isLeaf"), QLatin1String("false")); + qElement.setAttribute(QLatin1String("isRoot"), QLatin1String("false")); + if (m_bAbstract) + qElement.setAttribute(QLatin1String("isAbstract"), QLatin1String("true")); + else + qElement.setAttribute(QLatin1String("isAbstract"), QLatin1String("false")); + } + qElement.setAttribute(QLatin1String("xmi.id"), Uml::ID::toString(m_nId)); + qElement.setAttribute(QLatin1String("name"), m_name); + if (m_BaseType != ot_Operation && + m_BaseType != ot_Role && + m_BaseType != ot_Attribute) { + Uml::ID::Type nmSpc; + if (m_pUMLPackage) + nmSpc = m_pUMLPackage->id(); + else + nmSpc = UMLApp::app()->document()->modelID(); + qElement.setAttribute(QLatin1String("namespace"), Uml::ID::toString(nmSpc)); + } + if (! m_Doc.isEmpty()) + qElement.setAttribute(QLatin1String("comment"), m_Doc); //CHECK: uml13.dtd compliance +#ifdef XMI_FLAT_PACKAGES + if (m_pUMLPackage) //FIXME: uml13.dtd compliance + qElement.setAttribute(QLatin1String("package"), m_pUMLPackage->ID()); +#endif + QString visibility = Uml::Visibility::toString(m_visibility, false); + qElement.setAttribute(QLatin1String("visibility"), visibility); + if (m_pStereotype != NULL) + qElement.setAttribute(QLatin1String("stereotype"), Uml::ID::toString(m_pStereotype->id())); + if (m_bStatic) + qElement.setAttribute(QLatin1String("ownerScope"), QLatin1String("classifier")); + /* else + qElement.setAttribute("ownerScope", "instance"); + *** ownerScope defaults to instance if not set **********/ + return qElement; +} + +/** + * Auxiliary to loadFromXMI. + * This method is usually overridden by child classes. + * It is responsible for loading the specific XMI structure + * of the child class. + */ +bool UMLObject::load(QDomElement&) +{ + // This body is not usually executed because child classes + // overwrite the load method. + return true; +} + +/** + * Analyzes the given QDomElement for a reference to a stereotype. + * + * @param element QDomElement to analyze. + * @return True if a stereotype reference was found, else false. + */ +bool UMLObject::loadStereotype(QDomElement & element) +{ + QString tag = element.tagName(); + if (!UMLDoc::tagEq(tag, QLatin1String("stereotype"))) + return false; + QString stereo = element.attribute(QLatin1String("xmi.value")); + if (stereo.isEmpty() && element.hasChildNodes()) { + /* like so: + + + + */ + QDomNode stereoNode = element.firstChild(); + QDomElement stereoElem = stereoNode.toElement(); + tag = stereoElem.tagName(); + if (UMLDoc::tagEq(tag, QLatin1String("Stereotype"))) { + stereo = stereoElem.attribute(QLatin1String("xmi.idref")); + } + } + if (stereo.isEmpty()) + return false; + Uml::ID::Type stereoID = Uml::ID::fromString(stereo); + UMLDoc *pDoc = UMLApp::app()->document(); + if (m_pStereotype) + m_pStereotype->decrRefCount(); + m_pStereotype = pDoc->findStereotypeById(stereoID); + if (m_pStereotype) + m_pStereotype->incrRefCount(); + else + m_SecondaryId = stereo; // leave it to resolveRef() + return true; +} + +/** + * This method loads the generic parts of the XMI common to most model + * classes. It is not usually reimplemented by child classes. + * Instead, it invokes the load() method which implements the loading + * of the specifics of each child class. + * + * @param element The QDomElement from which to load. + */ +bool UMLObject::loadFromXMI(QDomElement & element) +{ + UMLDoc* umldoc = UMLApp::app()->document(); + if (umldoc == 0) { + uError() << "umldoc is NULL"; + return false; + } + // Read the name first so that if we encounter a problem, the error + // message can say the name. + m_name = element.attribute(QLatin1String("name")); + QString id = Model_Utils::getXmiId(element); + if (id.isEmpty() || id == QLatin1String("-1")) { + // Before version 1.4, umbrello-kf6 did not save the xmi.id of UMLRole objects. + // Some tools (such as Embarcadero's) do not have an xmi.id on all attributes. + m_nId = UniqueID::gen(); + uWarning() << m_name << ": xmi.id not present, generating a new one"; + } else { + Uml::ID::Type nId = Uml::ID::fromString(id); + if (m_BaseType == ot_Role) { + // Some older umbrello-kf6 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(nId); + if (o) { + uError() << "loadFromXMI(UMLRole): id " << id + << " is already in use!!! Please fix your XMI file."; + } + } + m_nId = nId; + } + + if (element.hasAttribute(QLatin1String("documentation"))) // for bkwd compat. + m_Doc = element.attribute(QLatin1String("documentation")); + else + m_Doc = element.attribute(QLatin1String("comment")); //CHECK: need a UML:Comment? + + m_visibility = Uml::Visibility::Public; + if (element.hasAttribute(QLatin1String("scope"))) { // for bkwd compat. + QString scope = element.attribute(QLatin1String("scope")); + if (scope == QLatin1String("instance_level")) // nsuml compat. + m_bStatic = false; + else if (scope == QLatin1String("classifier_level")) // nsuml compat. + m_bStatic = true; + else { + int nScope = scope.toInt(); + switch (nScope) { + case 200: + m_visibility = Uml::Visibility::Public; + break; + case 201: + m_visibility = Uml::Visibility::Private; + break; + case 202: + m_visibility = Uml::Visibility::Protected; + break; + default: + uError() << m_name << ": illegal scope " << nScope; + } + } + } else { + QString visibility = element.attribute(QLatin1String("visibility"), QLatin1String("public")); + if (visibility == QLatin1String("private") + || visibility == QLatin1String("private_vis")) // for compatibility with other programs + m_visibility = Uml::Visibility::Private; + else if (visibility == QLatin1String("protected") + || visibility == QLatin1String("protected_vis")) // for compatibility with other programs + m_visibility = Uml::Visibility::Protected; + else if (visibility == QLatin1String("implementation")) + m_visibility = Uml::Visibility::Implementation; + } + + QString stereo = element.attribute(QLatin1String("stereotype")); + if (!stereo.isEmpty()) { + Uml::ID::Type stereoID = Uml::ID::fromString(stereo); + if (m_pStereotype) + m_pStereotype->decrRefCount(); + m_pStereotype = umldoc->findStereotypeById(stereoID); + if (m_pStereotype) { + m_pStereotype->incrRefCount(); + } else { + uDebug() << m_name << ": UMLStereotype " << Uml::ID::toString(stereoID) + << " not found, creating now."; + setStereotypeCmd(stereo); + } + } + + if (element.hasAttribute(QLatin1String("abstract"))) { // for bkwd compat. + QString abstract = element.attribute(QLatin1String("abstract"), QLatin1String("0")); + m_bAbstract = (bool)abstract.toInt(); + } else { + QString isAbstract = element.attribute(QLatin1String("isAbstract"), QLatin1String("false")); + m_bAbstract = (isAbstract == QLatin1String("true")); + } + + if (element.hasAttribute(QLatin1String("static"))) { // for bkwd compat. + QString staticScope = element.attribute(QLatin1String("static"), QLatin1String("0")); + m_bStatic = (bool)staticScope.toInt(); + } else { + QString ownerScope = element.attribute(QLatin1String("ownerScope"), QLatin1String("instance")); + m_bStatic = (ownerScope == QLatin1String("classifier")); + } + + // If the node has child nodes, check whether attributes can be + // extracted from them. + if (element.hasChildNodes()) { + QDomNode node = element.firstChild(); + if (node.isComment()) + node = node.nextSibling(); + QDomElement elem = node.toElement(); + while (!elem.isNull()) { + QString tag = elem.tagName(); + if (UMLDoc::tagEq(tag, QLatin1String("name"))) { + m_name = elem.attribute(QLatin1String("xmi.value")); + if (m_name.isEmpty()) + m_name = elem.text(); + } else if (UMLDoc::tagEq(tag, QLatin1String("visibility"))) { + QString vis = elem.attribute(QLatin1String("xmi.value")); + if (vis.isEmpty()) + vis = elem.text(); + if (vis == QLatin1String("private") || vis == QLatin1String("private_vis")) + m_visibility = Uml::Visibility::Private; + else if (vis == QLatin1String("protected") || vis == QLatin1String("protected_vis")) + m_visibility = Uml::Visibility::Protected; + else if (vis == QLatin1String("implementation")) + m_visibility = Uml::Visibility::Implementation; + } else if (UMLDoc::tagEq(tag, QLatin1String("isAbstract"))) { + QString isAbstract = elem.attribute(QLatin1String("xmi.value")); + if (isAbstract.isEmpty()) + isAbstract = elem.text(); + m_bAbstract = (isAbstract == QLatin1String("true")); + } else if (UMLDoc::tagEq(tag, QLatin1String("ownerScope"))) { + QString ownerScope = elem.attribute(QLatin1String("xmi.value")); + if (ownerScope.isEmpty()) + ownerScope = elem.text(); + m_bStatic = (ownerScope == QLatin1String("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 != ot_Operation && m_BaseType != ot_Attribute && + m_BaseType != ot_EnumLiteral && m_BaseType != ot_EntityAttribute && + m_BaseType != ot_Template && m_BaseType != ot_Stereotype && + m_BaseType != ot_Role && m_BaseType != ot_UniqueConstraint && + m_BaseType != ot_ForeignKeyConstraint && m_BaseType != ot_CheckConstraint) { + if (m_pUMLPackage) { + m_pUMLPackage->addObject(this); + } else if (umldoc->rootFolderType(this) == Uml::ModelType::N_MODELTYPES) { + // m_pUMLPackage is not set on the root folders. + uDebug() << m_name << ": m_pUMLPackage is not set"; + } + } + return load(element); +} + +/** + * Helper function for debug output. + * Returns the given enum value as string. + * @param ot ObjectType of which a string representation is wanted + * @return the ObjectType as string + */ +QString UMLObject::toString(ObjectType ot) +{ + return QLatin1String(ENUM_NAME(UMLObject, ObjectType, ot)); +} + +/** + * Returns the given object type value as localized string. + * @param ot ObjectType of which a string representation is wanted + * @return the ObjectType as localized string + */ +QString UMLObject::toI18nString(ObjectType t) +{ + QString name; + + switch (t) { + case UMLObject::ot_Actor: + name = i18n("Actor &name:"); + break; + case UMLObject::ot_Artifact: + name = i18n("Artifact &name:"); + break; + case UMLObject::ot_Class: + name = i18n("Class &name:"); + break; + case UMLObject::ot_Component: + name = i18n("Component &name:"); + break; + case UMLObject::ot_Datatype: + name = i18n("Datatype &name:"); + break; + case UMLObject::ot_Entity: + name = i18n("Entity &name:"); + break; + case UMLObject::ot_Enum: + name = i18n("Enum &name:"); + break; + case UMLObject::ot_Folder: + name = i18n("Folder &name:"); + break; + case UMLObject::ot_Interface: + name = i18n("Interface &name:"); + break; + case UMLObject::ot_Node: + name = i18n("Node &name:"); + break; + case UMLObject::ot_Package: + name = i18n("Package &name:"); + break; + case UMLObject::ot_Port: + name = i18n("Port &name:"); + break; + case UMLObject::ot_Stereotype: + name = i18n("Stereotype &name:"); + break; + case UMLObject::ot_UseCase: + name = i18n("Use case &name:"); + break; + default: + name = QLatin1String(" &name:"); + uWarning() << "unknown object type"; + break; + } + return name; +} + +/** + * Print UML Object to debug output stream, so it can be used like + * uDebug() << "This object shouldn't be here: " << illegalObject; + */ +QDebug operator<<(QDebug out, const UMLObject& obj) +{ + out.nospace() << "UMLObject: name= " << obj.name() + << ", type= " << UMLObject::toString(obj.m_BaseType); + return out.space(); +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlobject.h umbrello-kf6-15.08.1/umbrello/umlmodel/umlobject.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlobject.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlobject.h 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,198 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef UMLOBJECT_H +#define UMLOBJECT_H + +#include "basictypes.h" +#include "umlpackagelist.h" + +//qt includes +#include +#include +#include +#include +#include + +class UMLStereotype; + +/** + * This class is the non-graphical version of @ref UMLWidget. These are + * created and maintained in the class @ref UMLDoc. This class holds all + * the generic information needed for all UML objects. + * + * @ref clone needs to be implemented by each child class. + * + * @ref saveToXMI saves the XMI attributes of each specific model class. + * It needs to be implemented by each child class. + * For creating the QDomElement and saving the common XMI parts, + * it can use the save() method. + * + * @short The base class for UML objects. + * @author Paul Hensgen + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class UMLObject : public QObject +{ + Q_OBJECT + Q_ENUMS(ObjectType) + +public: + enum ObjectType + { + ot_Unknown = -1, + ot_UMLObject = 100, + ot_Actor, + ot_UseCase, + ot_Package, + ot_Interface, + ot_Datatype, + ot_Enum, + ot_Class, + ot_Association, + ot_Attribute, + ot_Operation, + ot_EnumLiteral, + ot_Template, + ot_Component, + ot_Artifact, + ot_Node, + ot_Stereotype, + ot_Role, + ot_Entity, + ot_EntityAttribute, + ot_Folder, + ot_EntityConstraint, + ot_UniqueConstraint, + ot_ForeignKeyConstraint, + ot_CheckConstraint, + ot_Category, + ot_Port + }; + + static QString toString(ObjectType ot); + static QString toI18nString(ObjectType t); + + explicit UMLObject(const UMLObject& other); + explicit UMLObject(UMLObject* parent, const QString& name, Uml::ID::Type id = Uml::ID::None); + explicit UMLObject(UMLObject* parent); + explicit UMLObject(const QString& name = QString(), Uml::ID::Type id = Uml::ID::None); + virtual ~UMLObject(); + + bool operator==(const UMLObject & rhs) const; + + virtual void copyInto(UMLObject *lhs) const; + + virtual UMLObject* clone() const; + + virtual void setBaseType(ObjectType ot); + ObjectType baseType() const; + QLatin1String baseTypeStr() const; + + virtual void setID(Uml::ID::Type NewID); + virtual Uml::ID::Type id() const; + + QString doc() const; + bool hasDoc() const; + void setDoc(const QString &d); + + void setVisibility(Uml::Visibility::Enum visibility); + void setVisibilityCmd(Uml::Visibility::Enum visibility); + Uml::Visibility::Enum visibility() const; + + void setStereotype(const QString &_name); + void setStereotypeCmd(const QString &_name); + QString stereotype(bool includeAdornments = false) const; + + void setUMLStereotype(UMLStereotype *stereo); + UMLStereotype *umlStereotype(); + + QString package(const QString& separator = QString(), + bool includeRoot = false); + + bool setUMLPackage(UMLPackage* pPkg); + UMLPackage* umlPackage(); + + UMLPackageList packages(bool includeRoot = false) const; + + virtual void setName(const QString &strName); + void setNameCmd(const QString &strName) ; + QString name() const; + + virtual QString fullyQualifiedName(const QString& separator = QString(), + bool includeRoot = false) const; + + void setAbstract(bool bAbstract); + bool isAbstract() const; + + virtual bool showPropertiesDialog(QWidget* parent = 0); + + virtual bool resolveRef(); + + virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); + virtual bool loadFromXMI(QDomElement & element); + + bool loadStereotype(QDomElement & element); + + void setStatic(bool bStatic); + bool isStatic() const; + + virtual bool acceptAssociationType(Uml::AssociationType::Enum); //:TODO: check if this is really needed here + + void setSecondaryId(const QString& id); + QString secondaryId() const; + + void setSecondaryFallback(const QString& id); + QString secondaryFallback() const; + + QDomElement save(const QString &tag, QDomDocument & qDoc); + + friend QDebug operator<< (QDebug out, const UMLObject& obj); + +public slots: + void emitModified(); + +signals: + void modified(); + +protected: + void init(); + + void maybeSignalObjectCreated(); + + virtual bool load(QDomElement& element); + + Uml::ID::Type m_nId; ///< object's id + QString m_Doc; ///< object's documentation + UMLPackage* m_pUMLPackage; ///< package the object belongs to if applicable + QPointer m_pStereotype; ///< stereotype of the object if applicable + QString m_name; ///< objects name + ObjectType m_BaseType; ///< objects type + Uml::Visibility::Enum m_visibility; ///< objects visibility + bool m_bAbstract; ///< state of whether the object is abstract or not + bool m_bStatic; ///< flag for instance scope + bool m_bInPaste; ///< caller sets this true when in paste operation + bool m_bCreationWasSignalled; ///< auxiliary to maybeSignalObjectCreated() + QPointer m_pSecondary; ///< pointer to an associated object + ///< Only a few of the classes inheriting from UMLObject use this. + ///< However, it needs to be here because of inheritance graph + ///< disjunctness. + QString m_SecondaryId; ///< xmi.id of the secondary object for intermediate use during + ///< loading. The secondary ID is resolved to the m_pSecondary + ///< in the course of resolveRef() at the end of loading. + QString m_SecondaryFallback; ///< Last-chance backup for when m_SecondaryId is not found. + ///< Used by Rose import: MDL files specify both a "quidu" + ///< (which corresponds to m_SecondaryId) and the human readable + ///< fully qualified target name of a reference. + ///< In case the quidu is not found, the human readable name is + ///< used which we store in m_SecondaryFallback. +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlobjectlist.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/umlobjectlist.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlobjectlist.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlobjectlist.cpp 2015-10-08 11:48:59.507089026 +0300 @@ -0,0 +1,53 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#include "umlobjectlist.h" +#include "umlobject.h" + +UMLObjectList::UMLObjectList() +{ +} + +UMLObjectList::~UMLObjectList() +{ +} + +/** + * Copy the internal presentation of this object into the new + * object. + */ +void UMLObjectList::copyInto(UMLObjectList *rhs) const +{ + // Don't copy yourself. + if (rhs == this) return; + + rhs->clear(); + + // Suffering from const; we shall not modify our object. + UMLObjectList *tmp = new UMLObjectList(*this); + + UMLObject *item = NULL; + for (UMLObjectListIt oit(*tmp); oit.hasNext() ;) + { + item = oit.next(); + rhs->append(item->clone()); + } + delete tmp; +} + +/** + * Make a clone of this object. + */ +UMLObjectList* UMLObjectList::clone() const +{ + UMLObjectList *clone = new UMLObjectList(); + copyInto(clone); + return clone; +} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlobjectlist.h umbrello-kf6-15.08.1/umbrello/umlmodel/umlobjectlist.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlobjectlist.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlobjectlist.h 2015-10-08 11:48:59.508089026 +0300 @@ -0,0 +1,40 @@ +/*************************************************************************** + * 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) 2001 Gustavo Madrigal gmadrigal@nextphere.com * + * copyright (C) 2002-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef UMLOBJECTLIST_H +#define UMLOBJECTLIST_H + +#include +#include + +// forward declarations +class UMLObject; + +typedef QListIterator > +UMLObjectListIt; + +/** + * This sub-class adds copyInto and clone to the QList + * base class. + */ +class UMLObjectList : public QList > +{ +public: + + UMLObjectList(); + virtual ~UMLObjectList(); + + virtual void copyInto(UMLObjectList *rhs) const; + + virtual UMLObjectList* clone() const; +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umloperationlist.h umbrello-kf6-15.08.1/umbrello/umlmodel/umloperationlist.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umloperationlist.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/umloperationlist.h 2015-10-08 11:48:59.508089026 +0300 @@ -0,0 +1,23 @@ +/*************************************************************************** + * * + * 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-2007 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef UMLOPERATIONLIST_H +#define UMLOPERATIONLIST_H + +#include + +// forward declaration +class UMLOperation; + +typedef QList UMLOperationList; +typedef QListIterator UMLOperationListIt; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlpackagelist.h umbrello-kf6-15.08.1/umbrello/umlmodel/umlpackagelist.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlpackagelist.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlpackagelist.h 2015-10-08 11:48:59.508089026 +0300 @@ -0,0 +1,22 @@ +/*************************************************************************** + * * + * 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-2007 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef UMLPACKAGELIST_H +#define UMLPACKAGELIST_H + +#include + +class UMLPackage; + +typedef QList UMLPackageList; +typedef QListIterator UMLPackageListIt; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlrole.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/umlrole.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlrole.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlrole.cpp 2015-10-08 11:48:59.508089026 +0300 @@ -0,0 +1,415 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "umlrole.h" + +// local includes +#include "association.h" +#include "debug_utils.h" +#include "umldoc.h" +#include "umlroledialog.h" +#include "uml.h" + +// qt includes +#include +#include + +/** + * Sets up an association. + * + * @param parent The parent (association) of this UMLRole. + * @param parentObj The Parent UML Object of this UMLRole + * @param role The Uml::RoleType::Enum of this UMLRole + */ +UMLRole::UMLRole(UMLAssociation * parent, UMLObject * parentObj, Uml::RoleType::Enum role) + : UMLObject(const_cast(parent)), + m_pAssoc(parent), + m_role(role), + m_Multi(QString()), + m_Changeability(Uml::Changeability::Changeable) +{ + m_BaseType = UMLObject::ot_Role; + m_name.clear(); + m_pSecondary = parentObj; + + // connect this up to parent + connect(this, SIGNAL(modified()), parent, SIGNAL(modified())); +} + +/** + * Standard destructor. + */ +UMLRole::~UMLRole() +{ +} + +/** + * Overloaded '==' operator. + */ +bool UMLRole::operator==(const UMLRole &rhs) const +{ + if (this == &rhs) { + return true; + } + return (UMLObject::operator==(rhs) && + m_Changeability == rhs.m_Changeability && + m_Multi == rhs.m_Multi && + m_name == rhs.m_name + ); +} + +UMLAssociation * UMLRole::parentAssociation() const +{ + return m_pAssoc; +} + +/** + * Returns the UMLObject assigned to the role. + * @return Pointer to the UMLObject in role. + */ +UMLObject* UMLRole::object() const +{ + return m_pSecondary; +} + +/** + * Returns the Changeablity of the role. + * + * @return Changeability of role. + */ +Uml::Changeability::Enum UMLRole::changeability() const +{ + return m_Changeability; +} + +/** + * Returns the multiplicity assigned to the role. + * + * @return The multiplicity assigned to the role. + */ +QString UMLRole::multiplicity() const +{ + return m_Multi; +} + +/** + * Sets the UMLObject playing the role in the association. + * + * @param obj Pointer to the UMLObject of role. + */ +void UMLRole::setObject(UMLObject *obj) +{ + // because we will get the id of this role from the parent + // object, we CANT allow UMLRoles to take other UMLRoles as + // parent objects. In fact, there is probably good reason + // to only take UMLClassifiers here, but I'll leave it more open + // for the time being. -b.t. + if (obj && dynamic_cast(obj)) { + uError() << "UMLRole(" << Uml::ID::toString(m_nId) << ") cannot setObject() to another UMLRole(" + << Uml::ID::toString(obj->id()) << ")"; + return; + } + + m_pSecondary = obj; + UMLObject::emitModified(); +} + +/** + * Sets the changeability of the role. + * + * @param value Changeability::Enum of role. + */ +void UMLRole::setChangeability(Uml::Changeability::Enum value) +{ + m_Changeability = value; + UMLObject::emitModified(); +} + +/** + * Sets the multiplicity of the role. + * + * @param multi The multiplicity of role. + */ +void UMLRole::setMultiplicity(const QString &multi) +{ + m_Multi = multi; + UMLObject::emitModified(); +} + +/** + * Get the 'id' of the role (NOT the parent object). This could be + * either Uml::RoleType::A or Uml::RoleType::B. Yes, it would be better if we + * could get along without this, but we need it to distinguish saved + * umlrole objects in the XMI for 'self' associations where both roles + * will point to the same underlying UMLObject. + */ +Uml::RoleType::Enum UMLRole::role() const +{ + return m_role; +} + +/** + * Creates the XMI element. + */ +void UMLRole::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +{ + QDomElement roleElement = UMLObject::save(QLatin1String("UML:AssociationEnd"), qDoc); + if (m_pSecondary) + roleElement.setAttribute(QLatin1String("type"), Uml::ID::toString(m_pSecondary->id())); + else + uError() << "id " << Uml::ID::toString(m_nId) << ": m_pSecondary is NULL"; + if (!m_Multi.isEmpty()) + roleElement.setAttribute(QLatin1String("multiplicity"), m_Multi); + if (m_role == Uml::RoleType::A) { // role aggregation based on parent type + // role A + switch (m_pAssoc->getAssocType()) { + case Uml::AssociationType::Composition: + roleElement.setAttribute(QLatin1String("aggregation"), QLatin1String("composite")); + break; + case Uml::AssociationType::Aggregation: + roleElement.setAttribute(QLatin1String("aggregation"), QLatin1String("aggregate")); + break; + default: + roleElement.setAttribute(QLatin1String("aggregation"), QLatin1String("none")); + break; + } + if (m_pAssoc->getAssocType() == Uml::AssociationType::UniAssociation) { + // Normally the isNavigable attribute is "true". + // We set it to false on role A to indicate that + // role B gets an explicit arrowhead. + roleElement.setAttribute(QLatin1String("isNavigable"), QLatin1String("false")); + } else { + roleElement.setAttribute(QLatin1String("isNavigable"), QLatin1String("true")); + } + } else { + roleElement.setAttribute(QLatin1String("aggregation"), QLatin1String("none")); + roleElement.setAttribute(QLatin1String("isNavigable"), QLatin1String("true")); + //FIXME obviously this isn't standard XMI + if (m_pAssoc->getAssocType() == Uml::AssociationType::Relationship) { + roleElement.setAttribute(QLatin1String("relationship"), QLatin1String("true")); + } + } + + roleElement.setAttribute(QLatin1String("visibility"), Uml::Visibility::toString(visibility(), false)); + + switch (m_Changeability) { + case Uml::Changeability::Frozen: + roleElement.setAttribute(QLatin1String("changeability"), QLatin1String("frozen")); + break; + case Uml::Changeability::AddOnly: + roleElement.setAttribute(QLatin1String("changeability"), QLatin1String("addOnly")); + break; + case Uml::Changeability::Changeable: + roleElement.setAttribute(QLatin1String("changeability"), QLatin1String("changeable")); + break; + } + qElement.appendChild(roleElement); +} + +/** + * Display the properties configuration dialog for the object. + * + * @param parent The parent widget. + * @return True for success of this operation. + */ +bool UMLRole::showPropertiesDialog(QWidget *parent) +{ + QPointer dlg = new UMLRoleDialog(parent, this); + bool modified = false; + if (dlg->exec() == QDialog::Accepted) { + modified = true; + } + delete dlg; + return modified; +} + +/** + * Loads the XMI element. + * Auxiliary to UMLObject::loadFromXMI. + */ +bool UMLRole::load(QDomElement & element) +{ + UMLDoc * doc = UMLApp::app()->document(); + QString type = element.attribute(QLatin1String("type")); + if (!type.isEmpty()) { + if (!m_SecondaryId.isEmpty()) + uWarning() << "overwriting old m_SecondaryId \"" << m_SecondaryId + << " with new value \"" << type << "\""; + m_SecondaryId = type; + } + // Inspect child nodes - for multiplicity (and type if not set above.) + for (QDomNode node = element.firstChild(); !node.isNull(); node = node.nextSibling()) { + if (node.isComment()) + continue; + QDomElement tempElement = node.toElement(); + QString tag = tempElement.tagName(); + if (UMLDoc::tagEq(tag, QLatin1String("name"))) { + m_name = tempElement.text(); + } else if (UMLDoc::tagEq(tag, QLatin1String("AssociationEnd.multiplicity"))) { + /* + * There are different ways in which the multiplicity might be given: + * - direct value in the tag, + * - attributes "lower" and "upper" of a subordinate , + * - direct value in subordinate and + * tags + */ + QDomNode n = tempElement.firstChild(); + if (node.isNull() || tempElement.isNull() || n.isNull() || + n.toElement().isNull()) { + m_Multi = tempElement.text().trimmed(); + continue; + } + tempElement = n.toElement(); + tag = tempElement.tagName(); + if (!UMLDoc::tagEq(tag, QLatin1String("Multiplicity"))) { + m_Multi = tempElement.text().trimmed(); + continue; + } + n = tempElement.firstChild(); + tempElement = n.toElement(); + tag = tempElement.tagName(); + if (!UMLDoc::tagEq(tag, QLatin1String("Multiplicity.range"))) { + m_Multi = tempElement.text().trimmed(); + continue; + } + n = tempElement.firstChild(); + tempElement = n.toElement(); + tag = tempElement.tagName(); + if (!UMLDoc::tagEq(tag, QLatin1String("MultiplicityRange"))) { + m_Multi = tempElement.text().trimmed(); + continue; + } + QString multiUpper; + if (tempElement.hasAttribute(QLatin1String("lower"))) { + m_Multi = tempElement.attribute(QLatin1String("lower")); + multiUpper = tempElement.attribute(QLatin1String("upper")); + if (!multiUpper.isEmpty()) { + if (!m_Multi.isEmpty()) + m_Multi.append(QLatin1String("..")); + m_Multi.append(multiUpper); + } + continue; + } + n = tempElement.firstChild(); + while (!n.isNull()) { + tempElement = n.toElement(); + tag = tempElement.tagName(); + if (UMLDoc::tagEq(tag, QLatin1String("MultiplicityRange.lower"))) { + m_Multi = tempElement.text(); + } else if (UMLDoc::tagEq(tag, QLatin1String("MultiplicityRange.upper"))) { + multiUpper = tempElement.text(); + } + n = n.nextSibling(); + } + if (!multiUpper.isEmpty()) { + if (!m_Multi.isEmpty()) + m_Multi.append(QLatin1String("..")); + m_Multi.append(multiUpper); + } + } else if (m_SecondaryId.isEmpty() && + (UMLDoc::tagEq(tag, QLatin1String("type")) || + UMLDoc::tagEq(tag, QLatin1String("participant")))) { + m_SecondaryId = tempElement.attribute(QLatin1String("xmi.id")); + if (m_SecondaryId.isEmpty()) + m_SecondaryId = tempElement.attribute(QLatin1String("xmi.idref")); + if (m_SecondaryId.isEmpty()) { + QDomNode inner = tempElement.firstChild(); + QDomElement innerElem = inner.toElement(); + m_SecondaryId = innerElem.attribute(QLatin1String("xmi.id")); + if (m_SecondaryId.isEmpty()) + m_SecondaryId = innerElem.attribute(QLatin1String("xmi.idref")); + } + } + } + if (!m_Multi.isEmpty()) + uDebug() << name() << ": m_Multi is " << m_Multi; + if (m_SecondaryId.isEmpty()) { + uError() << name() << ": type not given or illegal"; + return false; + } + UMLObject * obj; + obj = doc->findObjectById(Uml::ID::fromString(m_SecondaryId)); + if (obj) { + m_pSecondary = obj; + m_SecondaryId = QString(); + } + + // block signals to prevent needless updating + blockSignals(true); + // Here comes the handling of the association type. + // This is open for discussion - I'm pretty sure there are better ways.. + + // Yeah, for one, setting the *parent* object parameters from here is sucky + // as hell. Why are we using roleA to store what is essentially a parent (association) + // parameter, eh? The UML13.dtd is pretty silly, but since that is what + // is driving us to that point, we have to go with it. Some analysis of + // the component roles/linked items needs to be done in order to get things + // right. *sigh* -b.t. + + // Setting association type from the role (A) + // Determination of the "aggregation" attribute used to be done only + // when (m_role == Uml::RoleType::A) but some XMI writers (e.g. StarUML) place + // the aggregation attribute at role B. + // The role end with the aggregation unequal to "none" wins. + QString aggregation = element.attribute(QLatin1String("aggregation"), QLatin1String("none")); + if (aggregation == QLatin1String("composite")) + m_pAssoc->setAssociationType(Uml::AssociationType::Composition); + else if (aggregation == QLatin1String("shared") // UML1.3 + || aggregation == QLatin1String("aggregate")) // UML1.4 + m_pAssoc->setAssociationType(Uml::AssociationType::Aggregation); + + if (!element.hasAttribute(QLatin1String("isNavigable"))) { + // Backward compatibility mode: In umbrello-kf6 version 1.3.x the + // logic for saving the isNavigable flag was wrong. + // May happen on loading role A. + m_pAssoc->setOldLoadMode(true); + } else if (m_pAssoc->getOldLoadMode() == true) { + // Here is the original logic: + // "Role B: + // If isNavigable is not given, we make no change to the + // association type. + // If isNavigable is given, and is "true", then we assume that + // the association's other end (role A) is not navigable, and + // therefore we change the association type to UniAssociation. + // The case that isNavigable is given as "false" is ignored. + // Combined with the association type logic for role A, this + // allows us to support at_Association and at_UniAssociation." + if (element.attribute(QLatin1String("isNavigable")) == QLatin1String("true")) + m_pAssoc->setAssociationType(Uml::AssociationType::UniAssociation); + } else if (element.attribute(QLatin1String("isNavigable")) == QLatin1String("false")) { + m_pAssoc->setAssociationType(Uml::AssociationType::UniAssociation); + } + + //FIXME not standard XMI + if (element.hasAttribute(QLatin1String("relationship"))) { + if (element.attribute(QLatin1String("relationship")) == QLatin1String("true")) { + m_pAssoc->setAssociationType(Uml::AssociationType::Relationship); + } + } + + if (m_Multi.isEmpty()) + m_Multi = element.attribute(QLatin1String("multiplicity")); + + // Changeability defaults to Changeable if it cant set it here.. + m_Changeability = Uml::Changeability::Changeable; + QString changeability = element.attribute(QLatin1String("changeability")); + if (changeability.isEmpty()) + element.attribute(QLatin1String("changeable")); // for backward compatibility + if (changeability == QLatin1String("frozen")) + m_Changeability = Uml::Changeability::Frozen; + else if (changeability == QLatin1String("addOnly")) + m_Changeability = Uml::Changeability::AddOnly; + + // finished config, now unblock + blockSignals(false); + return true; +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlrole.h umbrello-kf6-15.08.1/umbrello/umlmodel/umlrole.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlrole.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlrole.h 2015-10-08 11:48:59.508089026 +0300 @@ -0,0 +1,65 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef UMLROLE_H +#define UMLROLE_H + +#include "umlobject.h" + +class UMLAssociation; + +/** + * This class contains the non-graphic representation of an association role. + * + * @author Brian Thomas + * @see UMLObject + */ +class UMLRole : public UMLObject +{ + Q_OBJECT +public: + + UMLRole(UMLAssociation * parent, UMLObject * parentUMLObject, Uml::RoleType::Enum role); + virtual ~UMLRole(); + + bool operator==(const UMLRole & rhs) const; + + void setObject(UMLObject *obj); + UMLObject* object() const; + + void setChangeability(Uml::Changeability::Enum value); + Uml::Changeability::Enum changeability() const; + + void setMultiplicity(const QString &multi); + QString multiplicity() const; + + UMLAssociation * parentAssociation() const; + + Uml::RoleType::Enum role() const; + + UMLObject* clone() const { return NULL; } + + void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); + + virtual bool showPropertiesDialog(QWidget *parent = 0); + +protected: + + bool load(QDomElement& element); + +private: + + UMLAssociation * m_pAssoc; + Uml::RoleType::Enum m_role; + QString m_Multi; + Uml::Changeability::Enum m_Changeability; +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlstereotypelist.h umbrello-kf6-15.08.1/umbrello/umlmodel/umlstereotypelist.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umlstereotypelist.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/umlstereotypelist.h 2015-10-08 11:48:59.508089026 +0300 @@ -0,0 +1,22 @@ +/*************************************************************************** + * 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-2012 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef UMLSTEREOTYPELIST_H +#define UMLSTEREOTYPELIST_H + +#include + +// forward declaration +class UMLStereotype; + +typedef QList UMLStereotypeList; +typedef QListIterator UMLStereotypeListIt; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umltemplatelist.h umbrello-kf6-15.08.1/umbrello/umlmodel/umltemplatelist.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/umltemplatelist.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/umltemplatelist.h 2015-10-08 11:48:59.508089026 +0300 @@ -0,0 +1,23 @@ +/*************************************************************************** + * * + * 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) 2004-2007 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef UMLTEMPLATELIST_H +#define UMLTEMPLATELIST_H + +#include + +// forward declaration +class UMLTemplate; + +typedef QList UMLTemplateList; +typedef QListIterator UMLTemplateListIt; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/uniqueconstraint.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/uniqueconstraint.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/uniqueconstraint.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/uniqueconstraint.cpp 2015-10-08 11:48:59.508089026 +0300 @@ -0,0 +1,325 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +//own header +#include "uniqueconstraint.h" + +// app includes +#include "debug_utils.h" +#include "entity.h" +#include "entityattribute.h" +#include "umldoc.h" +#include "uml.h" +#include "umlattributedialog.h" +#include "umluniqueconstraintdialog.h" +#include "object_factory.h" + +/** + * Sets up a constraint. + * + * @param parent The parent of this UMLUniqueConstraint. + * @param name The name of this UMLUniqueConstraint. + * @param id The unique id given to this UMLUniqueConstraint. + */ +UMLUniqueConstraint::UMLUniqueConstraint(UMLObject *parent, const QString& name, Uml::ID::Type id) + : UMLEntityConstraint(parent, name, id) +{ + init(); +} + +/** + * Sets up a constraint. + * + * @param parent The parent of this UMLUniqueConstraint. + */ +UMLUniqueConstraint::UMLUniqueConstraint(UMLObject *parent) + : UMLEntityConstraint(parent) +{ + init(); +} + +/** + * Overloaded '==' operator + */ +bool UMLUniqueConstraint::operator==(const UMLUniqueConstraint &rhs) const +{ + if(this == &rhs) + return true; + + if(!UMLObject::operator==(rhs)) + return false; + + return true; +} + +/** + * Destructor. + */ +UMLUniqueConstraint::~UMLUniqueConstraint() +{ +} + +/** + * Copy the internal presentation of this object into the UMLUniqueConstraint + * object. + */ +void UMLUniqueConstraint::copyInto(UMLObject *lhs) const +{ + UMLUniqueConstraint *target = static_cast(lhs); + + // call the parent first. + UMLEntityConstraint::copyInto(target); + + // Copy all datamembers + target->m_EntityAttributeList.clear(); + bool valid = true; + foreach(UMLEntityAttribute* attr, m_EntityAttributeList) { + if (!valid) + break; + valid = target->addEntityAttribute(attr); + } + + if (!valid) { + target->m_EntityAttributeList.clear(); + uDebug() <<"Copying Attributes Failed : Target list cleared instead"; + } +} + +/** + * Make a clone of the UMLUniqueConstraint. + */ +UMLObject* UMLUniqueConstraint::clone() const +{ + //FIXME: The new attribute should be slaved to the NEW parent not the old. + UMLUniqueConstraint *clone = new UMLUniqueConstraint(static_cast(parent())); + copyInto(clone); + return clone; +} + +/** + * Returns a string representation of the UMLUniqueConstraint. + * + * @param sig If true will show the attribute type and initial value. + * @return Returns a string representation of the UMLAttribute. + */ +QString UMLUniqueConstraint::toString(Uml::SignatureType::Enum sig) +{ + QString s; + + if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::SigNoVis) { + s = name() + QLatin1Char(':'); + + if (static_cast(parent())->isPrimaryKey(this)) { + s += QLatin1String("Primary Key ("); + } else { + s += QLatin1String("Unique ("); + } + + bool first = true; + foreach(UMLEntityAttribute* att, m_EntityAttributeList) { + if (first) { + first = false; + } else + s += QLatin1Char(','); + s += att->name(); + } + s += QLatin1Char(')') ; + } + + return s; +} + +QString UMLUniqueConstraint::getFullyQualifiedName(const QString& separator, + bool includeRoot) const +{ + Q_UNUSED(separator); Q_UNUSED(includeRoot); + return this->name(); +} + +/** + * Creates the XMI element. + */ +void UMLUniqueConstraint::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +{ + QDomElement uniqueConstraintElement = UMLObject::save(QLatin1String("UML:UniqueConstraint"), qDoc); + + UMLEntity* parentEnt = static_cast(parent()); + if (parentEnt->isPrimaryKey(this)) { + uniqueConstraintElement.setAttribute(QLatin1String("isPrimary"), QLatin1String("1")); + } else { + uniqueConstraintElement.setAttribute(QLatin1String("isPrimary"), QLatin1String("0")); + } + + foreach(UMLEntityAttribute* att, m_EntityAttributeList) { + att->saveToXMI(qDoc, uniqueConstraintElement); + } + + qElement.appendChild(uniqueConstraintElement); +} + +/** + * Display the properties configuration dialog for the attribute. + */ +bool UMLUniqueConstraint::showPropertiesDialog(QWidget* parent) +{ + UMLUniqueConstraintDialog dialog(parent, this); + return dialog.exec(); +} + +/** + * Loads the XMI element. + */ +bool UMLUniqueConstraint::load(QDomElement & element) +{ + int isPrimary = element.attribute(QLatin1String("isPrimary"), QLatin1String("0")).toInt(); + UMLEntity* parentEnt = static_cast(parent()); + + if (isPrimary == 1) { + parentEnt->setAsPrimaryKey(this); + } + + QDomNode node = element.firstChild(); + while (!node.isNull()) { + if (node.isComment()) { + node = node.nextSibling(); + continue; + } + QDomElement tempElement = node.toElement(); + QString tag = tempElement.tagName(); + if (UMLDoc::tagEq(tag, QLatin1String("EntityAttribute"))) { + + QString attName = tempElement.attribute(QLatin1String("name")); + UMLObject* obj = parentEnt->findChildObject(attName); + + UMLEntityAttribute* entAtt = static_cast(obj); + if (entAtt == NULL) + continue; + + m_EntityAttributeList.append(entAtt); + + } else { + uWarning() << "unknown child type in UMLUniqueConstraint::load"; + } + + node = node.nextSibling(); + } + + return true; +} + + +/** + * Check if a entity attribute is present in m_entityAttributeList + * + * @param attr The Entity Attribute to check for existence in list + * @return true if it exists in the list, else false + */ +bool UMLUniqueConstraint::hasEntityAttribute(UMLEntityAttribute* attr) +{ + if (m_EntityAttributeList.indexOf(attr) == -1) { + //not present + return false; + } + + // else present + return true; +} + +/** + * Adds a UMLEntityAttribute to the list. + * The UMLEntityAttribute should already exist and should + * belong to the parent UMLEntity. + * + * @param attr The UMLEntityAttribute to add + * @return false if it failed to add, else true + */ +bool UMLUniqueConstraint::addEntityAttribute(UMLEntityAttribute* attr) +{ + UMLEntity *owningParent = dynamic_cast(parent()); + + if (hasEntityAttribute(attr)) { + uDebug() << "Unique Constraint already contains" << attr->name(); + return false; + + } + if (owningParent == NULL) { + uError() << name() << ": parent is not a UMLEntity"; + return false; + } + + if (owningParent->findChildObjectById(attr->id()) == NULL) { + uError() + << " parent " << owningParent->name() + << " does not contain attribute " << attr->name(); + return false; + } + + //else add the attribute to the Entity Attribute List + m_EntityAttributeList.append(attr); + + return true; +} + +/** + * Removes a UMLEntityAttribute from the list + * + * @param attr The UMLEntityAttribute to remove from list + * @return false if it failed to remove the attribute from the list + */ +bool UMLUniqueConstraint::removeEntityAttribute(UMLEntityAttribute* attr) +{ + UMLEntity *owningParent = dynamic_cast(parent()); + + if (owningParent == NULL) { + uError() << name() << ": parent is not a UMLEntity"; + return false; + } + + /* + * The attribute may already be removed from the Entity when this function + * is called. So checking this is not right + * + * if (owningParent->findChildObjectById(attr->ID()) == NULL) { + * uError() + * << " parent " << owningParent->getName() + * << " does not contain attribute " << attr->getName(); + * return false; + * } + */ + + //else remove the attribute from the Entity Attribute List + if (m_EntityAttributeList.removeAll(attr)) { + return true; + } + + return false; +} + +/** + * Get the Entity Attributes List. + */ +UMLEntityAttributeList UMLUniqueConstraint::getEntityAttributeList() const +{ + return m_EntityAttributeList; +} + +void UMLUniqueConstraint::init() +{ + m_BaseType = UMLObject::ot_UniqueConstraint; +} + +/** + * Clear the list of attributes contained in this UniqueConstraint + */ +void UMLUniqueConstraint::clearAttributeList() +{ + m_EntityAttributeList.clear(); +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/uniqueconstraint.h umbrello-kf6-15.08.1/umbrello/umlmodel/uniqueconstraint.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/uniqueconstraint.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/uniqueconstraint.h 2015-10-08 11:48:59.508089026 +0300 @@ -0,0 +1,77 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef UNIQUECONSTRAINT_H +#define UNIQUECONSTRAINT_H + +#include "basictypes.h" +#include "classifierlistitem.h" +#include "entityconstraint.h" +#include "umlclassifierlist.h" +#include "umlentityattributelist.h" + +/** + * This class is used to set up information for a unique entity constraint. + * + * @short Sets up Unique entity constraint information. + * @author Sharan Rao + * @see UMLObject UMLClassifierListItem UMLEntityConstraint + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class UMLUniqueConstraint : public UMLEntityConstraint +{ +public: + + UMLUniqueConstraint(UMLObject *parent, const QString& name, + Uml::ID::Type id = Uml::ID::None); + explicit UMLUniqueConstraint(UMLObject *parent); + virtual ~UMLUniqueConstraint(); + + bool operator==(const UMLUniqueConstraint &rhs) const; + + virtual void copyInto(UMLObject *lhs) const; + + virtual UMLObject* clone() const; + + QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); + + QString getFullyQualifiedName(const QString& separator = QString(), + bool includeRoot = false) const; + + void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); + + virtual bool showPropertiesDialog(QWidget* parent = 0); + + bool hasEntityAttribute(UMLEntityAttribute* attr); + + bool addEntityAttribute(UMLEntityAttribute* attr); + + bool removeEntityAttribute(UMLEntityAttribute* attr); + + UMLEntityAttributeList getEntityAttributeList() const; + + void clearAttributeList(); + +protected: + + bool load(QDomElement & element); + +private: + + void init(); + + /** + * The list of entity attributes that together make up the unique constraint. + */ + UMLEntityAttributeList m_EntityAttributeList; + +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/usecase.cpp umbrello-kf6-15.08.1/umbrello/umlmodel/usecase.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/usecase.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/usecase.cpp 2015-10-08 11:48:59.508089026 +0300 @@ -0,0 +1,67 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#include "usecase.h" + +/** + * Creates a UseCase object + * + * @param name The name of the object. + * @param id The id of the object. + */ +UMLUseCase::UMLUseCase(const QString & name, Uml::ID::Type id) + : UMLCanvasObject(name, id) +{ + init(); +} + +/** + * Standard decstructor. + */ +UMLUseCase::~UMLUseCase() +{ +} + +/** + * Initializes key variables of the class. + */ +void UMLUseCase::init() +{ + m_BaseType = UMLObject::ot_UseCase; +} + +/** + * Make a clone of this object. + */ +UMLObject* UMLUseCase::clone() const +{ + UMLUseCase *clone = new UMLUseCase(); + UMLObject::copyInto(clone); + return clone; +} + +/** + * Creates the element. + */ +void UMLUseCase::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +{ + QDomElement usecaseElement = UMLObject::save(QLatin1String("UML:UseCase"), qDoc); + qElement.appendChild(usecaseElement); +} + +/** + * Loads the element (TODO). + */ +bool UMLUseCase::load(QDomElement&) +{ + return true; +} + + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlmodel/usecase.h umbrello-kf6-15.08.1/umbrello/umlmodel/usecase.h --- umbrello-kf6-15.08.1.orig/umbrello/umlmodel/usecase.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlmodel/usecase.h 2015-10-08 11:48:59.508089026 +0300 @@ -0,0 +1,40 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef USECASE_H +#define USECASE_H + +#include "umlcanvasobject.h" + +/** + * This class contains the non-graphical information required for a UML UseCase. + * This class inherits from @ref UMLCanvasObject which contains most of the information. + * + * @short Information for a non-graphical UML UseCase. + * @author Paul Hensgen + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class UMLUseCase : public UMLCanvasObject +{ +public: + explicit UMLUseCase(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); + ~UMLUseCase(); + + virtual void init(); + + virtual UMLObject* clone() const; + + void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); + +protected: + bool load(QDomElement & element); +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlobject.cpp umbrello-kf6-15.08.1/umbrello/umlobject.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlobject.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/umlobject.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,1142 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "umlobject.h" - -// app includes -#include "classpropertiesdialog.h" -#include "debug_utils.h" -#include "enumliteral.h" -#include "uniqueid.h" -#include "uml.h" -#include "umldoc.h" -#include "umllistview.h" -#include "package.h" -#include "folder.h" -#include "stereotype.h" -#include "object_factory.h" -#include "model_utils.h" -#include "import_utils.h" -#include "docwindow.h" -#include "cmds.h" - -// kde includes -#include - -// qt includes -#include -#include - -using namespace Uml; - -DEBUG_REGISTER_DISABLED(UMLObject) - -/** - * Creates a UMLObject. - * @param other object to created from - */ -UMLObject::UMLObject(const UMLObject &other) - : QObject(other.parent()) -{ - other.copyInto(this); -} - -/** - * Creates a UMLObject. - * @param parent The parent of the object. - * @param name The name of the object. - * @param id The ID of the object (optional.) If omitted - * then a new ID will be assigned internally. - */ -UMLObject::UMLObject(UMLObject* parent, const QString& name, ID::Type id) - : QObject(parent), - m_nId(id), - m_name(name) -{ - init(); - if (id == Uml::ID::None) - m_nId = UniqueID::gen(); -} - -/** - * Creates a UMLObject. - * @param name The name of the object. - * @param id The ID of the object (optional.) If omitted - * then a new ID will be assigned internally. - */ -UMLObject::UMLObject(const QString& name, ID::Type id) - : QObject(UMLApp::app()->document()), - m_nId(id), - m_name(name) -{ - init(); - if (id == Uml::ID::None) - m_nId = UniqueID::gen(); -} - -/** - * Creates a UMLObject. - * @param parent The parent of the object. - */ -UMLObject::UMLObject(UMLObject * parent) - : QObject(parent), - m_nId(Uml::ID::None), - m_name(QString()) -{ - init(); -} - -/** - * Standard destructor. - */ -UMLObject::~UMLObject() -{ -} - -/** - * Initializes key variables of the class. - */ -void UMLObject::init() -{ - setObjectName(QLatin1String("UMLObject")); - m_BaseType = ot_UMLObject; - m_pUMLPackage = 0; - m_visibility = Uml::Visibility::Public; - m_pStereotype = 0; - m_Doc.clear(); - m_bAbstract = false; - m_bStatic = false; - m_bCreationWasSignalled = false; - m_pSecondary = 0; -} - -/** - * Display the properties configuration dialog for the object. - * - * @param parent The parent widget. - * @return True for success of this operation. - */ -bool UMLObject::showPropertiesDialog(QWidget *parent) -{ - DocWindow *docwindow = UMLApp::app()->docWindow(); - docwindow->updateDocumentation(false); - QPointer dlg = new ClassPropertiesDialog(parent, this, false); - bool modified = false; - if (dlg->exec()) { - docwindow->showDocumentation(this, true); - UMLApp::app()->document()->setModified(true); - modified = true; - } - dlg->close(); - delete dlg; - return modified; -} - -/** - * This should be reimplemented by subclasses if they wish to - * accept certain types of associations. Note that this only - * tells if this UMLObject can accept the association - * type. When creating an association another check is made to - * see if the association is valid. For example a UMLClass - * (UMLClassifier) can accept generalizations and should - * return true. If while creating a generalization the - * superclass is already subclassed from this, the association - * is not valid and will not be created. The default accepts - * nothing (returns false) - */ -bool UMLObject::acceptAssociationType(Uml::AssociationType::Enum type) -{ - Q_UNUSED(type); - // A UMLObject accepts nothing. This should be reimplemented by the subclasses - return false; -} - -/** - * Assigns a new Id to the object - */ -void UMLObject::setID(ID::Type NewID) -{ - m_nId = NewID; - emitModified(); -} - -/** - * Set the UMLObject's name - */ -void UMLObject::setName(const QString &strName) -{ - if (name() != strName) { - UMLApp::app()->executeCommand(new Uml::CmdRenameUMLObject(this, strName)); - } -} - -/** - * Method used by setName: it is called by cmdSetName, Don't use it! - */ -void UMLObject::setNameCmd(const QString &strName) -{ - m_name = strName; - emitModified(); -} - -/** - * Returns a copy of m_name - */ -QString UMLObject::name() const -{ - return m_name; -} - -/** - * Returns the fully qualified name, i.e. all package prefixes and then m_name. - * - * @param separator The separator string to use (optional.) - * If not given then the separator is chosen according - * to the currently selected active programming language - * of import and code generation. - * @param includeRoot Whether to prefix the root folder name to the FQN. - * See UMLDoc::getRootFolder(). Default: false. - * @return The fully qualified name of this UMLObject. - */ -QString UMLObject::fullyQualifiedName(const QString& separator, - bool includeRoot /* = false */) const -{ - QString fqn; - if (m_pUMLPackage && m_pUMLPackage != this) { - bool skipPackage = false; - if (!includeRoot) { - UMLDoc *umldoc = UMLApp::app()->document(); - if (umldoc->rootFolderType(m_pUMLPackage) != Uml::ModelType::N_MODELTYPES || - m_pUMLPackage == umldoc->datatypeFolder()) - skipPackage = true; - } - if (!skipPackage) { - QString tempSeparator = separator; - if (tempSeparator.isEmpty()) - tempSeparator = UMLApp::app()->activeLanguageScopeSeparator(); - fqn = m_pUMLPackage->fullyQualifiedName(tempSeparator, includeRoot); - fqn.append(tempSeparator); - } - } - fqn.append(m_name); - return fqn; -} - -/** - * Overloaded '==' operator - */ -bool UMLObject::operator==(const UMLObject & rhs) const -{ - 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-kf6 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 visibility should not be part of the equality test. - // What does it mean if two objects are the same but differ in their - // visibility? - I'm not aware of any programming language that would - // support that. - //if(m_visibility != rhs.m_visibility) - // 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; -} - -/** - * Copy the internal presentation of this object into the new - * object. - */ -void UMLObject::copyInto(UMLObject *lhs) const -{ - // Data members with copy constructor - lhs->m_Doc = m_Doc; - lhs->m_pStereotype = m_pStereotype; - lhs->m_bAbstract = m_bAbstract; - lhs->m_bStatic = m_bStatic; - lhs->m_BaseType = m_BaseType; - lhs->m_visibility = m_visibility; - lhs->m_pUMLPackage = m_pUMLPackage; - - // We don't want the same name existing twice. - lhs->m_name = Model_Utils::uniqObjectName(m_BaseType, m_pUMLPackage, m_name); - - // Create a new ID. - lhs->m_nId = UniqueID::gen(); - - // Hope that the parent from QObject is okay. - if (lhs->parent() != parent()) - uDebug() << "copyInto has a wrong parent"; -} - -UMLObject *UMLObject::clone() const -{ - UMLObject *clone = new UMLObject; - UMLObject::copyInto(clone); - return clone; -} - -/** - * Returns the abstract state of the object. - */ -bool UMLObject::isAbstract() const -{ - return m_bAbstract; -} - -/** - * Sets the paste state of the object. - */ -void UMLObject::setAbstract(bool bAbstract) -{ - m_bAbstract = bAbstract; - emitModified(); -} - -/** - * Returns true if this UMLObject has classifier scope, - * otherwise false (the default). - */ -bool UMLObject::isStatic() const -{ - return m_bStatic; -} - -/** - * Sets the value for m_bStatic. - */ -void UMLObject::setStatic(bool bStatic) -{ - m_bStatic = bStatic; - emitModified(); -} - -/** - * Forces the emission of the modified signal. Useful when - * updating several attributes at a time: you can block the - * signals, update all atts, and then force the signal. - */ -void UMLObject::emitModified() -{ - UMLDoc *umldoc = UMLApp::app()->document(); - if (!umldoc->loading() && !umldoc->closing()) - emit modified(); -} - -/** - * Returns the type of the object. - * - * @return Returns the type of the object. - */ -UMLObject::ObjectType UMLObject::baseType() const -{ - return m_BaseType; -} - -/** - * @return The type used for rtti as string. - */ -QLatin1String UMLObject::baseTypeStr() const -{ - return QLatin1String(ENUM_NAME(UMLObject, ObjectType, m_BaseType)); -} - -/** - * Set the type of the object. - * - * @param ot The ObjectType to set. - */ -void UMLObject::setBaseType(ObjectType ot) -{ - m_BaseType = ot; -} - -/** - * Returns the ID of the object. - * - * @return Returns the ID of the object. - */ -ID::Type UMLObject::id() const -{ - return m_nId; -} - -/** - * Returns the documentation for the object. - * - * @return Returns the documentation for the object. - */ -QString UMLObject::doc() const -{ - return m_Doc; -} - -/** - * Returns state of documentation for the object. - * - * @return false if documentation is empty - */ -bool UMLObject::hasDoc() const -{ - return !m_Doc.isEmpty(); -} - -/** - * Sets the documentation for the object. - * - * @param d The documentation for the object. - */ -void UMLObject::setDoc(const QString &d) -{ - m_Doc = d; - //emit modified(); No, this is done centrally at DocWindow::updateDocumentation() -} - -/** - * Returns the visibility of the object. - * - * @return Returns the visibility of the object. - */ -Visibility::Enum UMLObject::visibility() const -{ - return m_visibility; -} - -/** - * Sets the visibility of the object. - * - * @param visibility The visibility of the object. - */ -void UMLObject::setVisibility(Visibility::Enum visibility) -{ - if (m_visibility != visibility) { - UMLApp::app()->executeCommand(new CmdSetVisibility(this, visibility)); - } -} - -/** - * Method used by setVisibility: it is called by cmdSetVisibility, Don't use it! - */ -void UMLObject::setVisibilityCmd(Visibility::Enum visibility) -{ - m_visibility = visibility; - emitModified(); -} - -/** - * Sets the class' UMLStereotype. Adjusts the reference counts - * at the previously set stereotype and at the new stereotype. - * If the previously set UMLStereotype's reference count drops - * to zero then the UMLStereotype is removed at the UMLDoc and - * it is then physically deleted. - * - * @param stereo Sets the classes UMLStereotype. - */ -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()->document(); - pDoc->removeStereotype(m_pStereotype); - delete m_pStereotype; - } - } - m_pStereotype = stereo; - // TODO: don't emit modified() if predefined folder - emitModified(); -} - -/** - * Sets the classes stereotype name. - * Internally uses setUMLStereotype(). - * - * @param name Sets the classes stereotype name. - */ -void UMLObject::setStereotype(const QString &name) -{ - if (name != stereotype()) { - UMLApp::app()->executeCommand(new CmdSetStereotype(this, name)); - } -} - -void UMLObject::setStereotypeCmd(const QString& name) -{ - if (name.isEmpty()) { - setUMLStereotype(NULL); - return; - } - UMLDoc *pDoc = UMLApp::app()->document(); - UMLStereotype *s = pDoc->findOrCreateStereotype(name); - setUMLStereotype(s); -} - -/** - * Sets the UMLPackage in which this class is located. - * - * @param pPkg Pointer to the class' UMLPackage. - */ -bool UMLObject::setUMLPackage(UMLPackage* pPkg) -{ - if (pPkg == this) { - uDebug() << "setting parent to myself is not allowed"; - return false; - } - - if (pPkg == NULL) { - // Allow setting to NULL for stereotypes - m_pUMLPackage = pPkg; - return true; - } - - if (pPkg->umlPackage() == this) { - uDebug() << "setting parent to an object of which I'm already the parent is not allowed"; - return false; - } - - m_pUMLPackage = pPkg; - emitModified(); - return true; -} - -/** - * Returns the classes UMLStereotype object. - * - * @return Returns the classes UMLStereotype object. - */ -UMLStereotype * UMLObject::umlStereotype() -{ - return m_pStereotype; -} - -/** - * Returns the stereotype. - */ -QString UMLObject::stereotype(bool includeAdornments /* = false */) const -{ - if (m_pStereotype == NULL) - return QString(); - return m_pStereotype->name(includeAdornments); -} - -/** - * Return the package(s) in which this UMLObject is contained - * as a text. - * - * @param separator Separator string for joining together the - * individual package prefixes (optional.) - * If no separator is given then the separator - * of the currently selected language is used. - * @param includeRoot Whether to prefix the root folder name. - * Default: false. - * @return The UMLObject's enclosing package(s) as a text. - */ -QString UMLObject::package(const QString& separator, bool includeRoot) -{ - QString tempSeparator = separator; - if (tempSeparator.isEmpty()) - tempSeparator = UMLApp::app()->activeLanguageScopeSeparator(); - QString fqn = fullyQualifiedName(tempSeparator, includeRoot); - if (!fqn.contains(tempSeparator)) - return QString(); - QString scope = fqn.left(fqn.length() - tempSeparator.length() - m_name.length()); - return scope; -} - -/** - * Return a list of the packages in which this class is embedded. - * The outermost package is first in the list. - * - * @param includeRoot Whether to prefix the root folder name. - * Default: false. - * @return UMLPackageList of the containing packages. - */ -UMLPackageList UMLObject::packages(bool includeRoot) const -{ - UMLPackageList pkgList; - UMLPackage* pkg = m_pUMLPackage; - while (pkg != NULL) { - pkgList.prepend(pkg); - pkg = pkg->umlPackage(); - } - if (!includeRoot) - pkgList.removeFirst(); - return pkgList; -} - -/** - * Returns the UMLPackage that this class is located in. - * - * @return Pointer to the UMLPackage of this class. - */ -UMLPackage* UMLObject::umlPackage() -{ - return m_pUMLPackage; -} - -/** - * Return secondary ID. Required by resolveRef(). - */ -QString UMLObject::secondaryId() const -{ - return m_SecondaryId; -} - -/** - * Set the secondary ID. - * Currently only required by petalTree2Uml(); all other setting of the - * m_SecondaryID is internal to the UMLObject class hierarchy. - */ -void UMLObject::setSecondaryId(const QString& id) -{ - m_SecondaryId = id; -} - -/** - * Return secondary ID fallback. - * Required by resolveRef() for imported model files. - */ -QString UMLObject::secondaryFallback() const -{ - return m_SecondaryFallback; -} - -/** - * Set the secondary ID fallback. - * Currently only used by petalTree2Uml(). - */ -void UMLObject::setSecondaryFallback(const QString& id) -{ - m_SecondaryFallback = id; -} - -/** - * Calls UMLDoc::signalUMLObjectCreated() if m_BaseType affords - * doing so. - */ -void UMLObject::maybeSignalObjectCreated() -{ - if (!m_bCreationWasSignalled && - m_BaseType != ot_Stereotype && - m_BaseType != ot_Association && - m_BaseType != ot_Role) { - m_bCreationWasSignalled = true; - UMLDoc* umldoc = UMLApp::app()->document(); - umldoc->signalUMLObjectCreated(this); - } -} - -/** - * Resolve referenced objects (if any.) - * Needs to be called after all UML objects are loaded from file. - * This needs to be done after all model objects are loaded because - * some of the xmi.id's might be forward references, i.e. they may - * identify model objects which were not yet loaded at the point of - * reference. - * The default implementation attempts resolution of the m_SecondaryId. - * - * @return True for success. - */ -bool UMLObject::resolveRef() -{ - if (m_pSecondary || (m_SecondaryId.isEmpty() && m_SecondaryFallback.isEmpty())) { - maybeSignalObjectCreated(); - return true; - } -#ifdef VERBOSE_DEBUGGING - uDebug() << m_name << ": m_SecondaryId is " << m_SecondaryId; -#endif - UMLDoc *pDoc = UMLApp::app()->document(); - // 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(Uml::ID::fromString(m_SecondaryId)); - if (m_pSecondary != NULL) { - if (m_pSecondary->baseType() == ot_Stereotype) { - m_pStereotype = dynamic_cast(m_pSecondary.data()); - m_pStereotype->incrRefCount(); - m_pSecondary = NULL; - } - m_SecondaryId = QString(); - maybeSignalObjectCreated(); - return true; - } - if (m_SecondaryFallback.isEmpty()) { - uDebug() << "object with xmi.id=" << m_SecondaryId << " not found, setting to undef"; - UMLFolder *datatypes = pDoc->datatypeFolder(); - m_pSecondary = Object_Factory::createUMLObject(ot_Datatype, QLatin1String("undef"), datatypes, false); - return true; - } - } - if (m_SecondaryFallback.isEmpty()) { - uError() << m_name << ": cannot find type with id " << m_SecondaryId; - return false; - } -#ifdef VERBOSE_DEBUGGING - uDebug() << m_name << ": could not resolve secondary ID " << m_SecondaryId - << ", using secondary fallback " << m_SecondaryFallback; -#endif - m_SecondaryId = m_SecondaryFallback; - // Assume we're dealing with the older umbrello-kf6 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, ot_UMLObject, this); - if (m_pSecondary) { - m_SecondaryId = QString(); - maybeSignalObjectCreated(); - return true; - } - // Work around Object_Factory::createUMLObject()'s incapability - // of on-the-fly scope creation: - if (m_SecondaryId.contains(QLatin1String("::"))) { - // TODO: Merge Import_Utils::createUMLObject() into Object_Factory::createUMLObject() - m_pSecondary = Import_Utils::createUMLObject(ot_UMLObject, m_SecondaryId, m_pUMLPackage); - if (m_pSecondary) { - if (Import_Utils::newUMLObjectWasCreated()) { - maybeSignalObjectCreated(); - qApp->processEvents(); - uDebug() << "Import_Utils::createUMLObject() created a new type for " - << m_SecondaryId; - } else { - uDebug() << "Import_Utils::createUMLObject() returned an existing type for " - << m_SecondaryId; - } - m_SecondaryId = QString(); - return true; - } - uError() << "Import_Utils::createUMLObject() failed to create a new type for " - << m_SecondaryId; - return false; - } - uDebug() << "Creating new type for " << m_SecondaryId; - // 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(QLatin1Char('*')) || - m_SecondaryId.contains(QLatin1Char('&'))); - ObjectType ot = ot_Class; - if (isReferenceType) { - ot = ot_Datatype; - } else { - if (Model_Utils::isCommonDataType(m_SecondaryId)) - ot = ot_Datatype; - } - m_pSecondary = Object_Factory::createUMLObject(ot, m_SecondaryId, NULL); - if (m_pSecondary == NULL) - return false; - m_SecondaryId = QString(); - maybeSignalObjectCreated(); - //qApp->processEvents(); - return true; -} - -void UMLObject::saveToXMI(QDomDocument &qDoc, QDomElement &qElement) -{ - Q_UNUSED(qDoc); Q_UNUSED(qElement); -} - -/** - * Auxiliary to saveToXMI. - * Create a QDomElement with the given tag, and save the XMI attributes - * that are common to all child classes to the newly created element. - * This method does not need to be overridden by child classes. - */ -QDomElement UMLObject::save(const QString &tag, QDomDocument & qDoc) -{ - /* - Call as the first action of saveToXMI() in child class: - This creates the QDomElement with which to work. - */ - QDomElement qElement = qDoc.createElement(tag); - qElement.setAttribute(QLatin1String("isSpecification"), QLatin1String("false")); - if (m_BaseType != ot_Association && - m_BaseType != ot_Role && - m_BaseType != ot_Attribute) { - qElement.setAttribute(QLatin1String("isLeaf"), QLatin1String("false")); - qElement.setAttribute(QLatin1String("isRoot"), QLatin1String("false")); - if (m_bAbstract) - qElement.setAttribute(QLatin1String("isAbstract"), QLatin1String("true")); - else - qElement.setAttribute(QLatin1String("isAbstract"), QLatin1String("false")); - } - qElement.setAttribute(QLatin1String("xmi.id"), Uml::ID::toString(m_nId)); - qElement.setAttribute(QLatin1String("name"), m_name); - if (m_BaseType != ot_Operation && - m_BaseType != ot_Role && - m_BaseType != ot_Attribute) { - Uml::ID::Type nmSpc; - if (m_pUMLPackage) - nmSpc = m_pUMLPackage->id(); - else - nmSpc = UMLApp::app()->document()->modelID(); - qElement.setAttribute(QLatin1String("namespace"), Uml::ID::toString(nmSpc)); - } - if (! m_Doc.isEmpty()) - qElement.setAttribute(QLatin1String("comment"), m_Doc); //CHECK: uml13.dtd compliance -#ifdef XMI_FLAT_PACKAGES - if (m_pUMLPackage) //FIXME: uml13.dtd compliance - qElement.setAttribute(QLatin1String("package"), m_pUMLPackage->ID()); -#endif - QString visibility = Uml::Visibility::toString(m_visibility, false); - qElement.setAttribute(QLatin1String("visibility"), visibility); - if (m_pStereotype != NULL) - qElement.setAttribute(QLatin1String("stereotype"), Uml::ID::toString(m_pStereotype->id())); - if (m_bStatic) - qElement.setAttribute(QLatin1String("ownerScope"), QLatin1String("classifier")); - /* else - qElement.setAttribute("ownerScope", "instance"); - *** ownerScope defaults to instance if not set **********/ - return qElement; -} - -/** - * Auxiliary to loadFromXMI. - * This method is usually overridden by child classes. - * It is responsible for loading the specific XMI structure - * of the child class. - */ -bool UMLObject::load(QDomElement&) -{ - // This body is not usually executed because child classes - // overwrite the load method. - return true; -} - -/** - * Analyzes the given QDomElement for a reference to a stereotype. - * - * @param element QDomElement to analyze. - * @return True if a stereotype reference was found, else false. - */ -bool UMLObject::loadStereotype(QDomElement & element) -{ - QString tag = element.tagName(); - if (!UMLDoc::tagEq(tag, QLatin1String("stereotype"))) - return false; - QString stereo = element.attribute(QLatin1String("xmi.value")); - if (stereo.isEmpty() && element.hasChildNodes()) { - /* like so: - - - - */ - QDomNode stereoNode = element.firstChild(); - QDomElement stereoElem = stereoNode.toElement(); - tag = stereoElem.tagName(); - if (UMLDoc::tagEq(tag, QLatin1String("Stereotype"))) { - stereo = stereoElem.attribute(QLatin1String("xmi.idref")); - } - } - if (stereo.isEmpty()) - return false; - Uml::ID::Type stereoID = Uml::ID::fromString(stereo); - UMLDoc *pDoc = UMLApp::app()->document(); - m_pStereotype = pDoc->findStereotypeById(stereoID); - if (m_pStereotype) - m_pStereotype->incrRefCount(); - else - m_SecondaryId = stereo; // leave it to resolveRef() - return true; -} - -/** - * This method loads the generic parts of the XMI common to most model - * classes. It is not usually reimplemented by child classes. - * Instead, it invokes the load() method which implements the loading - * of the specifics of each child class. - * - * @param element The QDomElement from which to load. - */ -bool UMLObject::loadFromXMI(QDomElement & element) -{ - UMLDoc* umldoc = UMLApp::app()->document(); - if (umldoc == 0) { - uError() << "umldoc is NULL"; - return false; - } - // Read the name first so that if we encounter a problem, the error - // message can say the name. - m_name = element.attribute(QLatin1String("name")); - QString id = Model_Utils::getXmiId(element); - if (id.isEmpty() || id == QLatin1String("-1")) { - // Before version 1.4, umbrello-kf6 did not save the xmi.id of UMLRole objects. - // Some tools (such as Embarcadero's) do not have an xmi.id on all attributes. - m_nId = UniqueID::gen(); - uWarning() << m_name << ": xmi.id not present, generating a new one"; - } else { - Uml::ID::Type nId = Uml::ID::fromString(id); - if (m_BaseType == ot_Role) { - // Some older umbrello-kf6 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(nId); - if (o) { - uError() << "loadFromXMI(UMLRole): id " << id - << " is already in use!!! Please fix your XMI file."; - } - } - m_nId = nId; - } - - if (element.hasAttribute(QLatin1String("documentation"))) // for bkwd compat. - m_Doc = element.attribute(QLatin1String("documentation")); - else - m_Doc = element.attribute(QLatin1String("comment")); //CHECK: need a UML:Comment? - - m_visibility = Uml::Visibility::Public; - if (element.hasAttribute(QLatin1String("scope"))) { // for bkwd compat. - QString scope = element.attribute(QLatin1String("scope")); - if (scope == QLatin1String("instance_level")) // nsuml compat. - m_bStatic = false; - else if (scope == QLatin1String("classifier_level")) // nsuml compat. - m_bStatic = true; - else { - int nScope = scope.toInt(); - switch (nScope) { - case 200: - m_visibility = Uml::Visibility::Public; - break; - case 201: - m_visibility = Uml::Visibility::Private; - break; - case 202: - m_visibility = Uml::Visibility::Protected; - break; - default: - uError() << m_name << ": illegal scope " << nScope; - } - } - } else { - QString visibility = element.attribute(QLatin1String("visibility"), QLatin1String("public")); - if (visibility == QLatin1String("private") - || visibility == QLatin1String("private_vis")) // for compatibility with other programs - m_visibility = Uml::Visibility::Private; - else if (visibility == QLatin1String("protected") - || visibility == QLatin1String("protected_vis")) // for compatibility with other programs - m_visibility = Uml::Visibility::Protected; - else if (visibility == QLatin1String("implementation")) - m_visibility = Uml::Visibility::Implementation; - } - - QString stereo = element.attribute(QLatin1String("stereotype")); - if (!stereo.isEmpty()) { - Uml::ID::Type stereoID = Uml::ID::fromString(stereo); - m_pStereotype = umldoc->findStereotypeById(stereoID); - if (m_pStereotype) { - m_pStereotype->incrRefCount(); - } else { - uDebug() << m_name << ": UMLStereotype " << Uml::ID::toString(stereoID) - << " not found, creating now."; - setStereotypeCmd(stereo); - } - } - - if (element.hasAttribute(QLatin1String("abstract"))) { // for bkwd compat. - QString abstract = element.attribute(QLatin1String("abstract"), QLatin1String("0")); - m_bAbstract = (bool)abstract.toInt(); - } else { - QString isAbstract = element.attribute(QLatin1String("isAbstract"), QLatin1String("false")); - m_bAbstract = (isAbstract == QLatin1String("true")); - } - - if (element.hasAttribute(QLatin1String("static"))) { // for bkwd compat. - QString staticScope = element.attribute(QLatin1String("static"), QLatin1String("0")); - m_bStatic = (bool)staticScope.toInt(); - } else { - QString ownerScope = element.attribute(QLatin1String("ownerScope"), QLatin1String("instance")); - m_bStatic = (ownerScope == QLatin1String("classifier")); - } - - // If the node has child nodes, check whether attributes can be - // extracted from them. - if (element.hasChildNodes()) { - QDomNode node = element.firstChild(); - if (node.isComment()) - node = node.nextSibling(); - QDomElement elem = node.toElement(); - while (!elem.isNull()) { - QString tag = elem.tagName(); - if (UMLDoc::tagEq(tag, QLatin1String("name"))) { - m_name = elem.attribute(QLatin1String("xmi.value")); - if (m_name.isEmpty()) - m_name = elem.text(); - } else if (UMLDoc::tagEq(tag, QLatin1String("visibility"))) { - QString vis = elem.attribute(QLatin1String("xmi.value")); - if (vis.isEmpty()) - vis = elem.text(); - if (vis == QLatin1String("private") || vis == QLatin1String("private_vis")) - m_visibility = Uml::Visibility::Private; - else if (vis == QLatin1String("protected") || vis == QLatin1String("protected_vis")) - m_visibility = Uml::Visibility::Protected; - else if (vis == QLatin1String("implementation")) - m_visibility = Uml::Visibility::Implementation; - } else if (UMLDoc::tagEq(tag, QLatin1String("isAbstract"))) { - QString isAbstract = elem.attribute(QLatin1String("xmi.value")); - if (isAbstract.isEmpty()) - isAbstract = elem.text(); - m_bAbstract = (isAbstract == QLatin1String("true")); - } else if (UMLDoc::tagEq(tag, QLatin1String("ownerScope"))) { - QString ownerScope = elem.attribute(QLatin1String("xmi.value")); - if (ownerScope.isEmpty()) - ownerScope = elem.text(); - m_bStatic = (ownerScope == QLatin1String("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 != ot_Operation && m_BaseType != ot_Attribute && - m_BaseType != ot_EnumLiteral && m_BaseType != ot_EntityAttribute && - m_BaseType != ot_Template && m_BaseType != ot_Stereotype && - m_BaseType != ot_Role && m_BaseType != ot_UniqueConstraint && - m_BaseType != ot_ForeignKeyConstraint && m_BaseType != ot_CheckConstraint) { - if (m_pUMLPackage) { - m_pUMLPackage->addObject(this); - } else if (umldoc->rootFolderType(this) == Uml::ModelType::N_MODELTYPES) { - // m_pUMLPackage is not set on the root folders. - uDebug() << m_name << ": m_pUMLPackage is not set"; - } - } - return load(element); -} - -/** - * Helper function for debug output. - * Returns the given enum value as string. - * @param ot ObjectType of which a string representation is wanted - * @return the ObjectType as string - */ -QString UMLObject::toString(ObjectType ot) -{ - return QLatin1String(ENUM_NAME(UMLObject, ObjectType, ot)); -} - -/** - * Returns the given object type value as localized string. - * @param ot ObjectType of which a string representation is wanted - * @return the ObjectType as localized string - */ -QString UMLObject::toI18nString(ObjectType t) -{ - QString name; - - switch (t) { - case UMLObject::ot_Actor: - name = i18n("Actor &name:"); - break; - case UMLObject::ot_Artifact: - name = i18n("Artifact &name:"); - break; - case UMLObject::ot_Class: - name = i18n("Class &name:"); - break; - case UMLObject::ot_Component: - name = i18n("Component &name:"); - break; - case UMLObject::ot_Datatype: - name = i18n("Datatype &name:"); - break; - case UMLObject::ot_Entity: - name = i18n("Entity &name:"); - break; - case UMLObject::ot_Enum: - name = i18n("Enum &name:"); - break; - case UMLObject::ot_Folder: - name = i18n("Folder &name:"); - break; - case UMLObject::ot_Interface: - name = i18n("Interface &name:"); - break; - case UMLObject::ot_Node: - name = i18n("Node &name:"); - break; - case UMLObject::ot_Package: - name = i18n("Package &name:"); - break; - case UMLObject::ot_Port: - name = i18n("Port &name:"); - break; - case UMLObject::ot_Stereotype: - name = i18n("Stereotype &name:"); - break; - case UMLObject::ot_UseCase: - name = i18n("Use case &name:"); - break; - default: - name = QLatin1String(" &name:"); - uWarning() << "unknown object type"; - break; - } - return name; -} - -/** - * Print UML Object to debug output stream, so it can be used like - * uDebug() << "This object shouldn't be here: " << illegalObject; - */ -QDebug operator<<(QDebug out, const UMLObject& obj) -{ - out.nospace() << "UMLObject: name= " << obj.name() - << ", type= " << UMLObject::toString(obj.m_BaseType); - return out.space(); -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlobject.h umbrello-kf6-15.08.1/umbrello/umlobject.h --- umbrello-kf6-15.08.1.orig/umbrello/umlobject.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/umlobject.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,198 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef UMLOBJECT_H -#define UMLOBJECT_H - -#include "basictypes.h" -#include "umlpackagelist.h" - -//qt includes -#include -#include -#include -#include -#include - -class UMLStereotype; - -/** - * This class is the non-graphical version of @ref UMLWidget. These are - * created and maintained in the class @ref UMLDoc. This class holds all - * the generic information needed for all UML objects. - * - * @ref clone needs to be implemented by each child class. - * - * @ref saveToXMI saves the XMI attributes of each specific model class. - * It needs to be implemented by each child class. - * For creating the QDomElement and saving the common XMI parts, - * it can use the save() method. - * - * @short The base class for UML objects. - * @author Paul Hensgen - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class UMLObject : public QObject -{ - Q_OBJECT - Q_ENUMS(ObjectType) - -public: - enum ObjectType - { - ot_Unknown = -1, - ot_UMLObject = 100, - ot_Actor, - ot_UseCase, - ot_Package, - ot_Interface, - ot_Datatype, - ot_Enum, - ot_Class, - ot_Association, - ot_Attribute, - ot_Operation, - ot_EnumLiteral, - ot_Template, - ot_Component, - ot_Artifact, - ot_Node, - ot_Stereotype, - ot_Role, - ot_Entity, - ot_EntityAttribute, - ot_Folder, - ot_EntityConstraint, - ot_UniqueConstraint, - ot_ForeignKeyConstraint, - ot_CheckConstraint, - ot_Category, - ot_Port - }; - - static QString toString(ObjectType ot); - static QString toI18nString(ObjectType t); - - explicit UMLObject(const UMLObject& other); - explicit UMLObject(UMLObject* parent, const QString& name, Uml::ID::Type id = Uml::ID::None); - explicit UMLObject(UMLObject* parent); - explicit UMLObject(const QString& name = QString(), Uml::ID::Type id = Uml::ID::None); - virtual ~UMLObject(); - - bool operator==(const UMLObject & rhs) const; - - virtual void copyInto(UMLObject *lhs) const; - - virtual UMLObject* clone() const; - - virtual void setBaseType(ObjectType ot); - ObjectType baseType() const; - QLatin1String baseTypeStr() const; - - virtual void setID(Uml::ID::Type NewID); - virtual Uml::ID::Type id() const; - - QString doc() const; - bool hasDoc() const; - void setDoc(const QString &d); - - void setVisibility(Uml::Visibility::Enum visibility); - void setVisibilityCmd(Uml::Visibility::Enum visibility); - Uml::Visibility::Enum visibility() const; - - void setStereotype(const QString &_name); - void setStereotypeCmd(const QString &_name); - QString stereotype(bool includeAdornments = false) const; - - void setUMLStereotype(UMLStereotype *stereo); - UMLStereotype *umlStereotype(); - - QString package(const QString& separator = QString(), - bool includeRoot = false); - - bool setUMLPackage(UMLPackage* pPkg); - UMLPackage* umlPackage(); - - UMLPackageList packages(bool includeRoot = false) const; - - virtual void setName(const QString &strName); - void setNameCmd(const QString &strName) ; - QString name() const; - - virtual QString fullyQualifiedName(const QString& separator = QString(), - bool includeRoot = false) const; - - void setAbstract(bool bAbstract); - bool isAbstract() const; - - virtual bool showPropertiesDialog(QWidget* parent = 0); - - virtual bool resolveRef(); - - virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); - virtual bool loadFromXMI(QDomElement & element); - - bool loadStereotype(QDomElement & element); - - void setStatic(bool bStatic); - bool isStatic() const; - - virtual bool acceptAssociationType(Uml::AssociationType::Enum); //:TODO: check if this is really needed here - - void setSecondaryId(const QString& id); - QString secondaryId() const; - - void setSecondaryFallback(const QString& id); - QString secondaryFallback() const; - - QDomElement save(const QString &tag, QDomDocument & qDoc); - - friend QDebug operator<< (QDebug out, const UMLObject& obj); - -public slots: - void emitModified(); - -signals: - void modified(); - -protected: - void init(); - - void maybeSignalObjectCreated(); - - virtual bool load(QDomElement& element); - - Uml::ID::Type m_nId; ///< object's id - QString m_Doc; ///< object's documentation - UMLPackage* m_pUMLPackage; ///< package the object belongs to if applicable - UMLStereotype* m_pStereotype; ///< stereotype of the object if applicable - QString m_name; ///< objects name - ObjectType m_BaseType; ///< objects type - Uml::Visibility::Enum m_visibility; ///< objects visibility - bool m_bAbstract; ///< state of whether the object is abstract or not - bool m_bStatic; ///< flag for instance scope - bool m_bInPaste; ///< caller sets this true when in paste operation - bool m_bCreationWasSignalled; ///< auxiliary to maybeSignalObjectCreated() - QPointer m_pSecondary; ///< pointer to an associated object - ///< Only a few of the classes inheriting from UMLObject use this. - ///< However, it needs to be here because of inheritance graph - ///< disjunctness. - QString m_SecondaryId; ///< xmi.id of the secondary object for intermediate use during - ///< loading. The secondary ID is resolved to the m_pSecondary - ///< in the course of resolveRef() at the end of loading. - QString m_SecondaryFallback; ///< Last-chance backup for when m_SecondaryId is not found. - ///< Used by Rose import: MDL files specify both a "quidu" - ///< (which corresponds to m_SecondaryId) and the human readable - ///< fully qualified target name of a reference. - ///< In case the quidu is not found, the human readable name is - ///< used which we store in m_SecondaryFallback. -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlobjectlist.cpp umbrello-kf6-15.08.1/umbrello/umlobjectlist.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlobjectlist.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/umlobjectlist.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,53 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#include "umlobjectlist.h" -#include "umlobject.h" - -UMLObjectList::UMLObjectList() -{ -} - -UMLObjectList::~UMLObjectList() -{ -} - -/** - * Copy the internal presentation of this object into the new - * object. - */ -void UMLObjectList::copyInto(UMLObjectList *rhs) const -{ - // Don't copy yourself. - if (rhs == this) return; - - rhs->clear(); - - // Suffering from const; we shall not modify our object. - UMLObjectList *tmp = new UMLObjectList(*this); - - UMLObject *item = NULL; - for (UMLObjectListIt oit(*tmp); oit.hasNext() ;) - { - item = oit.next(); - rhs->append(item->clone()); - } - delete tmp; -} - -/** - * Make a clone of this object. - */ -UMLObjectList* UMLObjectList::clone() const -{ - UMLObjectList *clone = new UMLObjectList(); - copyInto(clone); - return clone; -} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlobjectlist.h umbrello-kf6-15.08.1/umbrello/umlobjectlist.h --- umbrello-kf6-15.08.1.orig/umbrello/umlobjectlist.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/umlobjectlist.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,40 +0,0 @@ -/*************************************************************************** - * 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) 2001 Gustavo Madrigal gmadrigal@nextphere.com * - * copyright (C) 2002-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef UMLOBJECTLIST_H -#define UMLOBJECTLIST_H - -#include -#include - -// forward declarations -class UMLObject; - -typedef QListIterator > -UMLObjectListIt; - -/** - * This sub-class adds copyInto and clone to the QList - * base class. - */ -class UMLObjectList : public QList > -{ -public: - - UMLObjectList(); - virtual ~UMLObjectList(); - - virtual void copyInto(UMLObjectList *rhs) const; - - virtual UMLObjectList* clone() const; -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umloperationlist.h umbrello-kf6-15.08.1/umbrello/umloperationlist.h --- umbrello-kf6-15.08.1.orig/umbrello/umloperationlist.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/umloperationlist.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,23 +0,0 @@ -/*************************************************************************** - * * - * 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-2007 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef UMLOPERATIONLIST_H -#define UMLOPERATIONLIST_H - -#include - -// forward declaration -class UMLOperation; - -typedef QList UMLOperationList; -typedef QListIterator UMLOperationListIt; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlpackagelist.h umbrello-kf6-15.08.1/umbrello/umlpackagelist.h --- umbrello-kf6-15.08.1.orig/umbrello/umlpackagelist.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/umlpackagelist.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,22 +0,0 @@ -/*************************************************************************** - * * - * 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-2007 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef UMLPACKAGELIST_H -#define UMLPACKAGELIST_H - -#include - -class UMLPackage; - -typedef QList UMLPackageList; -typedef QListIterator UMLPackageListIt; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlrole.cpp umbrello-kf6-15.08.1/umbrello/umlrole.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlrole.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/umlrole.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,415 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "umlrole.h" - -// local includes -#include "association.h" -#include "debug_utils.h" -#include "umldoc.h" -#include "umlroledialog.h" -#include "uml.h" - -// qt includes -#include -#include - -/** - * Sets up an association. - * - * @param parent The parent (association) of this UMLRole. - * @param parentObj The Parent UML Object of this UMLRole - * @param role The Uml::RoleType::Enum of this UMLRole - */ -UMLRole::UMLRole(UMLAssociation * parent, UMLObject * parentObj, Uml::RoleType::Enum role) - : UMLObject(const_cast(parent)), - m_pAssoc(parent), - m_role(role), - m_Multi(QString()), - m_Changeability(Uml::Changeability::Changeable) -{ - m_BaseType = UMLObject::ot_Role; - m_name.clear(); - m_pSecondary = parentObj; - - // connect this up to parent - connect(this, SIGNAL(modified()), parent, SIGNAL(modified())); -} - -/** - * Standard destructor. - */ -UMLRole::~UMLRole() -{ -} - -/** - * Overloaded '==' operator. - */ -bool UMLRole::operator==(const UMLRole &rhs) const -{ - if (this == &rhs) { - return true; - } - return (UMLObject::operator==(rhs) && - m_Changeability == rhs.m_Changeability && - m_Multi == rhs.m_Multi && - m_name == rhs.m_name - ); -} - -UMLAssociation * UMLRole::parentAssociation() const -{ - return m_pAssoc; -} - -/** - * Returns the UMLObject assigned to the role. - * @return Pointer to the UMLObject in role. - */ -UMLObject* UMLRole::object() const -{ - return m_pSecondary; -} - -/** - * Returns the Changeablity of the role. - * - * @return Changeability of role. - */ -Uml::Changeability::Enum UMLRole::changeability() const -{ - return m_Changeability; -} - -/** - * Returns the multiplicity assigned to the role. - * - * @return The multiplicity assigned to the role. - */ -QString UMLRole::multiplicity() const -{ - return m_Multi; -} - -/** - * Sets the UMLObject playing the role in the association. - * - * @param obj Pointer to the UMLObject of role. - */ -void UMLRole::setObject(UMLObject *obj) -{ - // because we will get the id of this role from the parent - // object, we CANT allow UMLRoles to take other UMLRoles as - // parent objects. In fact, there is probably good reason - // to only take UMLClassifiers here, but I'll leave it more open - // for the time being. -b.t. - if (obj && dynamic_cast(obj)) { - uError() << "UMLRole(" << Uml::ID::toString(m_nId) << ") cannot setObject() to another UMLRole(" - << Uml::ID::toString(obj->id()) << ")"; - return; - } - - m_pSecondary = obj; - UMLObject::emitModified(); -} - -/** - * Sets the changeability of the role. - * - * @param value Changeability::Enum of role. - */ -void UMLRole::setChangeability(Uml::Changeability::Enum value) -{ - m_Changeability = value; - UMLObject::emitModified(); -} - -/** - * Sets the multiplicity of the role. - * - * @param multi The multiplicity of role. - */ -void UMLRole::setMultiplicity(const QString &multi) -{ - m_Multi = multi; - UMLObject::emitModified(); -} - -/** - * Get the 'id' of the role (NOT the parent object). This could be - * either Uml::RoleType::A or Uml::RoleType::B. Yes, it would be better if we - * could get along without this, but we need it to distinguish saved - * umlrole objects in the XMI for 'self' associations where both roles - * will point to the same underlying UMLObject. - */ -Uml::RoleType::Enum UMLRole::role() const -{ - return m_role; -} - -/** - * Creates the XMI element. - */ -void UMLRole::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) -{ - QDomElement roleElement = UMLObject::save(QLatin1String("UML:AssociationEnd"), qDoc); - if (m_pSecondary) - roleElement.setAttribute(QLatin1String("type"), Uml::ID::toString(m_pSecondary->id())); - else - uError() << "id " << Uml::ID::toString(m_nId) << ": m_pSecondary is NULL"; - if (!m_Multi.isEmpty()) - roleElement.setAttribute(QLatin1String("multiplicity"), m_Multi); - if (m_role == Uml::RoleType::A) { // role aggregation based on parent type - // role A - switch (m_pAssoc->getAssocType()) { - case Uml::AssociationType::Composition: - roleElement.setAttribute(QLatin1String("aggregation"), QLatin1String("composite")); - break; - case Uml::AssociationType::Aggregation: - roleElement.setAttribute(QLatin1String("aggregation"), QLatin1String("aggregate")); - break; - default: - roleElement.setAttribute(QLatin1String("aggregation"), QLatin1String("none")); - break; - } - if (m_pAssoc->getAssocType() == Uml::AssociationType::UniAssociation) { - // Normally the isNavigable attribute is "true". - // We set it to false on role A to indicate that - // role B gets an explicit arrowhead. - roleElement.setAttribute(QLatin1String("isNavigable"), QLatin1String("false")); - } else { - roleElement.setAttribute(QLatin1String("isNavigable"), QLatin1String("true")); - } - } else { - roleElement.setAttribute(QLatin1String("aggregation"), QLatin1String("none")); - roleElement.setAttribute(QLatin1String("isNavigable"), QLatin1String("true")); - //FIXME obviously this isn't standard XMI - if (m_pAssoc->getAssocType() == Uml::AssociationType::Relationship) { - roleElement.setAttribute(QLatin1String("relationship"), QLatin1String("true")); - } - } - - roleElement.setAttribute(QLatin1String("visibility"), Uml::Visibility::toString(visibility(), false)); - - switch (m_Changeability) { - case Uml::Changeability::Frozen: - roleElement.setAttribute(QLatin1String("changeability"), QLatin1String("frozen")); - break; - case Uml::Changeability::AddOnly: - roleElement.setAttribute(QLatin1String("changeability"), QLatin1String("addOnly")); - break; - case Uml::Changeability::Changeable: - roleElement.setAttribute(QLatin1String("changeability"), QLatin1String("changeable")); - break; - } - qElement.appendChild(roleElement); -} - -/** - * Display the properties configuration dialog for the object. - * - * @param parent The parent widget. - * @return True for success of this operation. - */ -bool UMLRole::showPropertiesDialog(QWidget *parent) -{ - QPointer dlg = new UMLRoleDialog(parent, this); - bool modified = false; - if (dlg->exec() == QDialog::Accepted) { - modified = true; - } - delete dlg; - return modified; -} - -/** - * Loads the XMI element. - * Auxiliary to UMLObject::loadFromXMI. - */ -bool UMLRole::load(QDomElement & element) -{ - UMLDoc * doc = UMLApp::app()->document(); - QString type = element.attribute(QLatin1String("type")); - if (!type.isEmpty()) { - if (!m_SecondaryId.isEmpty()) - uWarning() << "overwriting old m_SecondaryId \"" << m_SecondaryId - << " with new value \"" << type << "\""; - m_SecondaryId = type; - } - // Inspect child nodes - for multiplicity (and type if not set above.) - for (QDomNode node = element.firstChild(); !node.isNull(); node = node.nextSibling()) { - if (node.isComment()) - continue; - QDomElement tempElement = node.toElement(); - QString tag = tempElement.tagName(); - if (UMLDoc::tagEq(tag, QLatin1String("name"))) { - m_name = tempElement.text(); - } else if (UMLDoc::tagEq(tag, QLatin1String("AssociationEnd.multiplicity"))) { - /* - * There are different ways in which the multiplicity might be given: - * - direct value in the tag, - * - attributes "lower" and "upper" of a subordinate , - * - direct value in subordinate and - * tags - */ - QDomNode n = tempElement.firstChild(); - if (node.isNull() || tempElement.isNull() || n.isNull() || - n.toElement().isNull()) { - m_Multi = tempElement.text().trimmed(); - continue; - } - tempElement = n.toElement(); - tag = tempElement.tagName(); - if (!UMLDoc::tagEq(tag, QLatin1String("Multiplicity"))) { - m_Multi = tempElement.text().trimmed(); - continue; - } - n = tempElement.firstChild(); - tempElement = n.toElement(); - tag = tempElement.tagName(); - if (!UMLDoc::tagEq(tag, QLatin1String("Multiplicity.range"))) { - m_Multi = tempElement.text().trimmed(); - continue; - } - n = tempElement.firstChild(); - tempElement = n.toElement(); - tag = tempElement.tagName(); - if (!UMLDoc::tagEq(tag, QLatin1String("MultiplicityRange"))) { - m_Multi = tempElement.text().trimmed(); - continue; - } - QString multiUpper; - if (tempElement.hasAttribute(QLatin1String("lower"))) { - m_Multi = tempElement.attribute(QLatin1String("lower")); - multiUpper = tempElement.attribute(QLatin1String("upper")); - if (!multiUpper.isEmpty()) { - if (!m_Multi.isEmpty()) - m_Multi.append(QLatin1String("..")); - m_Multi.append(multiUpper); - } - continue; - } - n = tempElement.firstChild(); - while (!n.isNull()) { - tempElement = n.toElement(); - tag = tempElement.tagName(); - if (UMLDoc::tagEq(tag, QLatin1String("MultiplicityRange.lower"))) { - m_Multi = tempElement.text(); - } else if (UMLDoc::tagEq(tag, QLatin1String("MultiplicityRange.upper"))) { - multiUpper = tempElement.text(); - } - n = n.nextSibling(); - } - if (!multiUpper.isEmpty()) { - if (!m_Multi.isEmpty()) - m_Multi.append(QLatin1String("..")); - m_Multi.append(multiUpper); - } - } else if (m_SecondaryId.isEmpty() && - (UMLDoc::tagEq(tag, QLatin1String("type")) || - UMLDoc::tagEq(tag, QLatin1String("participant")))) { - m_SecondaryId = tempElement.attribute(QLatin1String("xmi.id")); - if (m_SecondaryId.isEmpty()) - m_SecondaryId = tempElement.attribute(QLatin1String("xmi.idref")); - if (m_SecondaryId.isEmpty()) { - QDomNode inner = tempElement.firstChild(); - QDomElement innerElem = inner.toElement(); - m_SecondaryId = innerElem.attribute(QLatin1String("xmi.id")); - if (m_SecondaryId.isEmpty()) - m_SecondaryId = innerElem.attribute(QLatin1String("xmi.idref")); - } - } - } - if (!m_Multi.isEmpty()) - uDebug() << name() << ": m_Multi is " << m_Multi; - if (m_SecondaryId.isEmpty()) { - uError() << name() << ": type not given or illegal"; - return false; - } - UMLObject * obj; - obj = doc->findObjectById(Uml::ID::fromString(m_SecondaryId)); - if (obj) { - m_pSecondary = obj; - m_SecondaryId = QString(); - } - - // block signals to prevent needless updating - blockSignals(true); - // Here comes the handling of the association type. - // This is open for discussion - I'm pretty sure there are better ways.. - - // Yeah, for one, setting the *parent* object parameters from here is sucky - // as hell. Why are we using roleA to store what is essentially a parent (association) - // parameter, eh? The UML13.dtd is pretty silly, but since that is what - // is driving us to that point, we have to go with it. Some analysis of - // the component roles/linked items needs to be done in order to get things - // right. *sigh* -b.t. - - // Setting association type from the role (A) - // Determination of the "aggregation" attribute used to be done only - // when (m_role == Uml::RoleType::A) but some XMI writers (e.g. StarUML) place - // the aggregation attribute at role B. - // The role end with the aggregation unequal to "none" wins. - QString aggregation = element.attribute(QLatin1String("aggregation"), QLatin1String("none")); - if (aggregation == QLatin1String("composite")) - m_pAssoc->setAssociationType(Uml::AssociationType::Composition); - else if (aggregation == QLatin1String("shared") // UML1.3 - || aggregation == QLatin1String("aggregate")) // UML1.4 - m_pAssoc->setAssociationType(Uml::AssociationType::Aggregation); - - if (!element.hasAttribute(QLatin1String("isNavigable"))) { - // Backward compatibility mode: In umbrello-kf6 version 1.3.x the - // logic for saving the isNavigable flag was wrong. - // May happen on loading role A. - m_pAssoc->setOldLoadMode(true); - } else if (m_pAssoc->getOldLoadMode() == true) { - // Here is the original logic: - // "Role B: - // If isNavigable is not given, we make no change to the - // association type. - // If isNavigable is given, and is "true", then we assume that - // the association's other end (role A) is not navigable, and - // therefore we change the association type to UniAssociation. - // The case that isNavigable is given as "false" is ignored. - // Combined with the association type logic for role A, this - // allows us to support at_Association and at_UniAssociation." - if (element.attribute(QLatin1String("isNavigable")) == QLatin1String("true")) - m_pAssoc->setAssociationType(Uml::AssociationType::UniAssociation); - } else if (element.attribute(QLatin1String("isNavigable")) == QLatin1String("false")) { - m_pAssoc->setAssociationType(Uml::AssociationType::UniAssociation); - } - - //FIXME not standard XMI - if (element.hasAttribute(QLatin1String("relationship"))) { - if (element.attribute(QLatin1String("relationship")) == QLatin1String("true")) { - m_pAssoc->setAssociationType(Uml::AssociationType::Relationship); - } - } - - if (m_Multi.isEmpty()) - m_Multi = element.attribute(QLatin1String("multiplicity")); - - // Changeability defaults to Changeable if it cant set it here.. - m_Changeability = Uml::Changeability::Changeable; - QString changeability = element.attribute(QLatin1String("changeability")); - if (changeability.isEmpty()) - element.attribute(QLatin1String("changeable")); // for backward compatibility - if (changeability == QLatin1String("frozen")) - m_Changeability = Uml::Changeability::Frozen; - else if (changeability == QLatin1String("addOnly")) - m_Changeability = Uml::Changeability::AddOnly; - - // finished config, now unblock - blockSignals(false); - return true; -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlrole.h umbrello-kf6-15.08.1/umbrello/umlrole.h --- umbrello-kf6-15.08.1.orig/umbrello/umlrole.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/umlrole.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,65 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef UMLROLE_H -#define UMLROLE_H - -#include "umlobject.h" - -class UMLAssociation; - -/** - * This class contains the non-graphic representation of an association role. - * - * @author Brian Thomas - * @see UMLObject - */ -class UMLRole : public UMLObject -{ - Q_OBJECT -public: - - UMLRole(UMLAssociation * parent, UMLObject * parentUMLObject, Uml::RoleType::Enum role); - virtual ~UMLRole(); - - bool operator==(const UMLRole & rhs) const; - - void setObject(UMLObject *obj); - UMLObject* object() const; - - void setChangeability(Uml::Changeability::Enum value); - Uml::Changeability::Enum changeability() const; - - void setMultiplicity(const QString &multi); - QString multiplicity() const; - - UMLAssociation * parentAssociation() const; - - Uml::RoleType::Enum role() const; - - UMLObject* clone() const { return NULL; } - - void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); - - virtual bool showPropertiesDialog(QWidget *parent = 0); - -protected: - - bool load(QDomElement& element); - -private: - - UMLAssociation * m_pAssoc; - Uml::RoleType::Enum m_role; - QString m_Multi; - Uml::Changeability::Enum m_Changeability; -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlstereotypelist.h umbrello-kf6-15.08.1/umbrello/umlstereotypelist.h --- umbrello-kf6-15.08.1.orig/umbrello/umlstereotypelist.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/umlstereotypelist.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,22 +0,0 @@ -/*************************************************************************** - * 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-2012 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef UMLSTEREOTYPELIST_H -#define UMLSTEREOTYPELIST_H - -#include - -// forward declaration -class UMLStereotype; - -typedef QList UMLStereotypeList; -typedef QListIterator UMLStereotypeListIt; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umltemplatelist.h umbrello-kf6-15.08.1/umbrello/umltemplatelist.h --- umbrello-kf6-15.08.1.orig/umbrello/umltemplatelist.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/umltemplatelist.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,23 +0,0 @@ -/*************************************************************************** - * * - * 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) 2004-2007 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef UMLTEMPLATELIST_H -#define UMLTEMPLATELIST_H - -#include - -// forward declaration -class UMLTemplate; - -typedef QList UMLTemplateList; -typedef QListIterator UMLTemplateListIt; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/activitywidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/activitywidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/activitywidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/activitywidget.cpp 2015-10-08 11:48:59.508089026 +0300 @@ -0,0 +1,457 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "activitywidget.h" + +// app includes +#include "activitydialog.h" +#include "debug_utils.h" +#include "docwindow.h" +#include "listpopupmenu.h" +#include "uml.h" +#include "umldoc.h" +#include "umlscene.h" +#include "umlview.h" + +// kde includes +#include +#if QT_VERSION < 0x050000 +#include +#endif + +// qt includes +#if QT_VERSION >= 0x050000 +#include +#endif +#include +/** + * Creates a Activity widget. + * + * @param scene The parent of the widget. + * @param activityType The type of activity. + * @param id The ID to assign (-1 will prompt a new ID.) + */ +ActivityWidget::ActivityWidget(UMLScene * scene, ActivityType activityType, Uml::ID::Type id) + : UMLWidget(scene, WidgetBase::wt_Activity, id), + m_activityType(activityType) +{ + // set non zero size to avoid crash on painting + setSize(1, 1); +} + +/** + * Destructor. + */ +ActivityWidget::~ActivityWidget() +{ +} + +/** + * Returns the type of activity. + */ +ActivityWidget::ActivityType ActivityWidget::activityType() const +{ + return m_activityType; +} + +/** + * Returns the type string of activity. + */ +QString ActivityWidget::activityTypeStr() const +{ + return QLatin1String(ENUM_NAME(ActivityWidget, ActivityType, m_activityType)); +} + +/** + * Sets the type of activity. + */ +void ActivityWidget::setActivityType(ActivityType activityType) +{ + m_activityType = activityType; + updateGeometry(); + UMLWidget::m_resizable = true; +} + +/** + * Determines whether a toolbar button represents an Activity. + * CHECK: currently unused - can this be removed? + * + * @param tbb The toolbar button enum input value. + * @param resultType The ActivityType corresponding to tbb. + * This is only set if tbb is an Activity. + * @return True if tbb represents an Activity. + */ +bool ActivityWidget::isActivity(WorkToolBar::ToolBar_Buttons tbb, + ActivityType& resultType) +{ + bool status = true; + switch (tbb) { + case WorkToolBar::tbb_Initial_Activity: + resultType = Initial; + break; + case WorkToolBar::tbb_Activity: + resultType = Normal; + break; + case WorkToolBar::tbb_End_Activity: + resultType = End; + break; + case WorkToolBar::tbb_Final_Activity: + resultType = Final; + break; + case WorkToolBar::tbb_Branch: + resultType = Branch; + break; + default: + status = false; + break; + } + return status; +} + +/** + * This method get the name of the preText attribute. + */ +QString ActivityWidget::preconditionText() const +{ + return m_preconditionText; +} + +/** + * This method set the name of the preText attribute + */ +void ActivityWidget::setPreconditionText(const QString& aPreText) +{ + m_preconditionText = aPreText; + updateGeometry(); + adjustAssocs(x(), y()); +} + +/** + * This method get the name of the postText attribute. + */ +QString ActivityWidget::postconditionText() const +{ + return m_postconditionText; +} + +/** + * This method set the name of the postText attribute + */ +void ActivityWidget::setPostconditionText(const QString& aPostText) +{ + m_postconditionText = aPostText; + updateGeometry(); + adjustAssocs(x(), y()); +} + +/** + * Reimplemented from UMLWidget::showPropertiesDialog to show a + * properties dialog for an ActivityWidget. + */ +void ActivityWidget::showPropertiesDialog() +{ + UMLApp::app()->docWindow()->updateDocumentation(false); + + QPointer dialog = new ActivityDialog(umlScene()->activeView(), this); + if (dialog->exec() && dialog->getChangesMade()) { + UMLApp::app()->docWindow()->showDocumentation(this, true); + UMLApp::app()->document()->setModified(true); + } + delete dialog; +} + +/** + * Overrides the standard paint event. + */ +void ActivityWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + int w = width(); + int h = height(); + + // Only for the final activity + float x; + float y; + QPen pen = painter->pen(); + + switch (m_activityType) + { + case Normal: + UMLWidget::setPenFromSettings(painter); + if (UMLWidget::useFillColor()) { + painter->setBrush(UMLWidget::fillColor()); + } + { + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + int textStartY = (h / 2) - (fontHeight / 2); + painter->drawRoundRect(0, 0, w, h, (h * 60) / w, 60); + painter->setPen(textColor()); + painter->setFont(UMLWidget::font()); + painter->drawText(ACTIVITY_MARGIN, textStartY, + w - ACTIVITY_MARGIN * 2, fontHeight, Qt::AlignCenter, name()); + } + break; + + case Initial: + painter->setPen(QPen(WidgetBase::lineColor(), 1)); + painter->setBrush(WidgetBase::lineColor()); + painter->drawEllipse(0, 0, w, h); + break; + + case Final: + UMLWidget::setPenFromSettings(painter); + painter->setBrush(Qt::white); + pen.setWidth(2); + pen.setColor (Qt::red); + painter->setPen(pen); + painter->drawEllipse(0, 0, w, h); + x = w/2 ; + y = h/2 ; + { + const float w2 = 0.7071 * (float)w / 2.0; + painter->drawLine((int)(x - w2 + 1), (int)(y - w2 + 1), (int)(x + w2), (int)(y + w2)); + painter->drawLine((int)(x + w2 - 1), (int)(y - w2 + 1), (int)(x - w2), (int)(y + w2)); + } + break; + + case End: + painter->setPen(QPen(WidgetBase::lineColor(), 1)); + painter->setBrush(WidgetBase::lineColor()); + painter->drawEllipse(0, 0, w, h); + painter->setBrush(Qt::white); + painter->drawEllipse(1, 1, w - 2, h - 2); + painter->setBrush(WidgetBase::lineColor()); + painter->drawEllipse(3, 3, w - 6, h - 6); + break; + + case Branch: + UMLWidget::setPenFromSettings(painter); + if (UMLWidget::useFillColor()) { + painter->setBrush(UMLWidget::fillColor()); + } + { + QPolygon array(4); + array[ 0 ] = QPoint(w / 2, 0); + array[ 1 ] = QPoint(w, h / 2); + array[ 2 ] = QPoint(w / 2, h); + array[ 3 ] = QPoint(0, h / 2); + painter->drawPolygon(array); + painter->drawPolyline(array); + } + break; + + case Invok: + UMLWidget::setPenFromSettings(painter); + if (UMLWidget::useFillColor()) { + painter->setBrush(UMLWidget::fillColor()); + } + { + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + int textStartY = (h / 2) - (fontHeight / 2); + painter->drawRoundRect(0, 0, w, h, (h * 60) / w, 60); + painter->setPen(textColor()); + painter->setFont(UMLWidget::font()); + painter->drawText(ACTIVITY_MARGIN, textStartY, + w - ACTIVITY_MARGIN * 2, fontHeight, Qt::AlignCenter, name()); + + } + x = w - (w/5); + y = h - (h/3); + + painter->drawLine((int)x, (int) y, (int)x, (int)(y + 20)); + painter->drawLine((int)(x - 10), (int)(y + 10), (int)(x + 10), (int)(y + 10)); + painter->drawLine((int)(x - 10), (int)(y + 10), (int)(x - 10), (int)(y + 20)); + painter->drawLine((int)(x + 10), (int)(y + 10), (int)(x + 10), (int)(y + 20)); + break; + + case Param: + UMLWidget::setPenFromSettings(painter); + if (UMLWidget::useFillColor()) { + painter->setBrush(UMLWidget::fillColor()); + } + { + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + QString preCond= QLatin1String("<> ") + preconditionText(); + QString postCond= QLatin1String("<> ") + postconditionText(); + //int textStartY = (h / 2) - (fontHeight / 2); + painter->drawRoundRect(0, 0, w, h, (h * 60) / w, 60); + painter->setPen(textColor()); + painter->setFont(UMLWidget::font()); + painter->drawText(ACTIVITY_MARGIN, fontHeight + 10, + w - ACTIVITY_MARGIN * 2, fontHeight, Qt::AlignCenter, preCond); + painter->drawText(ACTIVITY_MARGIN, fontHeight * 2 + 10, + w - ACTIVITY_MARGIN * 2, fontHeight, Qt::AlignCenter, postCond); + painter->drawText(ACTIVITY_MARGIN, (fontHeight / 2), + w - ACTIVITY_MARGIN * 2, fontHeight, Qt::AlignCenter, name()); + } + + break; + } + UMLWidget::paint(painter, option, widget); +} + +/** + * Overridden from UMLWidget due to emission of signal sigActMoved() + */ +void ActivityWidget::moveWidgetBy(qreal diffX, qreal diffY) +{ + UMLWidget::moveWidgetBy(diffX, diffY); + emit sigActMoved(diffX, diffY); +} + +/** + * Loads the widget from the "activitywidget" XMI element. + */ +bool ActivityWidget::loadFromXMI(QDomElement& qElement) +{ + if(!UMLWidget::loadFromXMI(qElement)) + return false; + setName(qElement.attribute(QLatin1String("activityname"))); + setDocumentation(qElement.attribute(QLatin1String("documentation"))); + setPreconditionText(qElement.attribute(QLatin1String("precondition"))); + setPostconditionText(qElement.attribute(QLatin1String("postcondition"))); + + QString type = qElement.attribute(QLatin1String("activitytype"), QLatin1String("1")); + setActivityType((ActivityType)type.toInt()); + + return true; +} + +/** + * Saves the widget to the "activitywidget" XMI element. + */ +void ActivityWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +{ + QDomElement activityElement = qDoc.createElement(QLatin1String("activitywidget")); + UMLWidget::saveToXMI(qDoc, activityElement); + activityElement.setAttribute(QLatin1String("activityname"), name()); + activityElement.setAttribute(QLatin1String("documentation"), documentation()); + activityElement.setAttribute(QLatin1String("precondition"), preconditionText()); + activityElement.setAttribute(QLatin1String("postcondition"), postconditionText()); + activityElement.setAttribute(QLatin1String("activitytype"), m_activityType); + qElement.appendChild(activityElement); +} + +/** + * Overrides Method from UMLWidget. + */ +void ActivityWidget::constrain(qreal& width, qreal& height) +{ + if (m_activityType == Normal || m_activityType == Invok || m_activityType == Param) { + UMLWidget::constrain(width, height); + return; + } + + if (width > height) + width = height; + else if (height > width) + height = width; + + UMLWidget::constrain(width, height); +} + +/** + * Captures any popup menu signals for menus it created. + */ +void ActivityWidget::slotMenuSelection(QAction* action) +{ + ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); + + switch(sel) { + case ListPopupMenu::mt_Rename: + { + bool ok = false; + QString n = name(); +#if QT_VERSION >= 0x050000 + n = QInputDialog::getText(Q_NULLPTR, + i18n("Enter Activity Name"), + i18n("Enter the name of the new activity:"), + QLineEdit::Normal, + n, &ok); +#else + n = KInputDialog::getText(i18n("Enter Activity Name"), + i18n("Enter the name of the new activity:"), + n, &ok); +#endif + if (ok && !n.isEmpty()) { + setName(n); + } + } + break; + + case ListPopupMenu::mt_Properties: + showPropertiesDialog(); + break; + + default: + UMLWidget::slotMenuSelection(action); + } +} + +/** + * Overrides method from UMLWidget + */ +QSizeF ActivityWidget::minimumSize() const +{ + if (m_activityType == Normal || m_activityType == Invok || m_activityType == Param) { + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + + int textWidth = fm.width(name()); + int height = fontHeight; + height = height > ACTIVITY_HEIGHT ? height : ACTIVITY_HEIGHT; + height += ACTIVITY_MARGIN * 2; + + textWidth = textWidth > ACTIVITY_WIDTH ? textWidth : ACTIVITY_WIDTH; + + if (m_activityType == Invok) { + height += 40; + } else if (m_activityType == Param) { + QString maxSize; + + maxSize = name().length() > postconditionText().length() ? name() : postconditionText(); + maxSize = maxSize.length() > preconditionText().length() ? maxSize : preconditionText(); + + textWidth = fm.width(maxSize); + textWidth = textWidth + 50; + height += 100; + } + + int width = textWidth > ACTIVITY_WIDTH ? textWidth : ACTIVITY_WIDTH; + + width += ACTIVITY_MARGIN * 4; + return QSizeF(width, height); + } + else if (m_activityType == Branch) { + return QSizeF(20, 20); + } + return QSizeF(15, 15); +} + +/** + * Overrides method from UMLWidget + */ +QSizeF ActivityWidget::maximumSize() +{ + if (m_activityType == Normal || m_activityType == Invok || m_activityType == Param) { + return UMLWidget::maximumSize(); + } + if (m_activityType == Branch) { + return QSizeF(50, 50); + } + return QSizeF(30, 30); +} + + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/activitywidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/activitywidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/activitywidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/activitywidget.h 2015-10-08 11:48:59.508089026 +0300 @@ -0,0 +1,98 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef ACTIVITYWIDGET_H +#define ACTIVITYWIDGET_H + +#include "umlwidget.h" +#include "worktoolbar.h" + +#define ACTIVITY_MARGIN 5 +#define ACTIVITY_WIDTH 30 +#define ACTIVITY_HEIGHT 10 + +/** + * This class is the graphical version of a UML Activity. A ActivityWidget is created + * by a @ref UMLView. An ActivityWidget belongs to only one @ref UMLView instance. + * When the @ref UMLView instance that this class belongs to, it will be automatically deleted. + * + * The ActivityWidget class inherits from the @ref UMLWidget class which adds most of the functionality + * to this class. + * + * @short A graphical version of a UML Activity. + * @author Paul Hensgen + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class ActivityWidget : public UMLWidget +{ + Q_OBJECT + Q_ENUMS(ActivityType) +public: + enum ActivityType + { + Initial = 0, + Normal, + End, + Final, + Branch, + Invok, + Param + }; + + explicit ActivityWidget(UMLScene * scene, ActivityType activityType = Normal, Uml::ID::Type id = Uml::ID::None); + virtual ~ActivityWidget(); + + ActivityType activityType() const; + QString activityTypeStr() const; + void setActivityType(ActivityType activityType); + + static bool isActivity(WorkToolBar::ToolBar_Buttons tbb, + ActivityType& resultType); + + QString preconditionText() const; + void setPreconditionText(const QString&); + + QString postconditionText() const; + void setPostconditionText(const QString&); + + virtual void showPropertiesDialog(); + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + virtual void moveWidgetBy(qreal diffX, qreal diffY); + + virtual bool loadFromXMI(QDomElement & qElement); + virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); + + void constrain(qreal& width, qreal& height); + +signals: + /** + * Emitted when the activity widget is moved. + * Provides the delta X and delta Y amount by which the widget was moved + * relative to the previous position. + * Slots into PinWidget::slotActMoved() + * @param diffX The difference between previous and new X value. + * @param diffY The difference between previous and new Y value. + */ + void sigActMoved(qreal diffX, qreal diffY); + +public Q_SLOTS: + virtual void slotMenuSelection(QAction* action); + +protected: + virtual QSizeF minimumSize() const; + virtual QSizeF maximumSize(); + + ActivityType m_activityType; ///< Type of activity. + + QString m_preconditionText; + QString m_postconditionText; +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/actorwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/actorwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/actorwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/actorwidget.cpp 2015-10-08 11:48:59.508089026 +0300 @@ -0,0 +1,104 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header file +#include "actorwidget.h" + +// local includes +#include "actor.h" +#include "umlview.h" + +/** + * Constructs an ActorWidget. + * + * @param scene The parent of this ActorWidget. + * @param a The Actor class this ActorWidget will display. + */ +ActorWidget::ActorWidget(UMLScene * scene, UMLActor *a) + : UMLWidget(scene, WidgetBase::wt_Actor, a) +{ + setFixedAspectRatio(true); +} + +/** + * Destructor. + */ +ActorWidget::~ActorWidget() +{ +} + +/** + * Overrides the standard paint event. + */ +void ActorWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + UMLWidget::setPenFromSettings(painter); + if(UMLWidget::useFillColor()) + painter->setBrush(UMLWidget::fillColor()); + const int w = width(); + const int h = height(); + painter->setFont(UMLWidget::font()); + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + bool drawStereotype = umlObject() && !umlObject()->stereotype().isEmpty(); + const int a_height = h - (drawStereotype ? 2 * fontHeight : fontHeight) - A_MARGIN; + const int h2 = a_height / 2; + const int a_width = (h2); + const int middleX = w / 2; + const int thirdY = a_height / 3; + + //draw actor + painter->drawEllipse(middleX - a_width / 2, 0, a_width, thirdY); //head + painter->drawLine(middleX, thirdY, + middleX, thirdY * 2); //body + painter->drawLine(middleX, 2 * thirdY, + middleX - a_width / 2, a_height); //left leg + painter->drawLine(middleX, 2 * thirdY, + middleX + a_width / 2, a_height); //right leg + painter->drawLine(middleX - a_width / 2, thirdY + thirdY / 2, + middleX + a_width / 2, thirdY + thirdY / 2); //arms + //draw text + painter->setPen(textColor()); + if (drawStereotype) + painter->drawText(A_MARGIN, h - 2 * fontHeight, w - A_MARGIN * 2, fontHeight, Qt::AlignCenter, umlObject()->stereotype(true)); + painter->drawText(A_MARGIN, h - fontHeight, + w - A_MARGIN * 2, fontHeight, Qt::AlignCenter, name()); + UMLWidget::paint(painter, option, widget); +} + +/** + * Saves the widget to the "actorwidget" XMI element. + * Note: For loading from XMI, the inherited parent method is used. + */ +void ActorWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +{ + QDomElement actorElement = qDoc.createElement(QLatin1String("actorwidget")); + UMLWidget::saveToXMI(qDoc, actorElement); + qElement.appendChild(actorElement); +} + +/** + * Overrides method from UMLWidget. + */ +QSizeF ActorWidget::minimumSize() const +{ + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + const int textWidth = fm.width(name()); + bool drawStereotype = umlObject() && !umlObject()->stereotype().isEmpty(); + int width = textWidth > A_WIDTH ? textWidth : A_WIDTH; + int height = A_HEIGHT + (drawStereotype ? 2 * fontHeight : fontHeight) + A_MARGIN; + width += A_MARGIN * 2; + return QSizeF(width, height); +} + + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/actorwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/actorwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/actorwidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/actorwidget.h 2015-10-08 11:48:59.508089026 +0300 @@ -0,0 +1,55 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef ACTORWIDGET_H +#define ACTORWIDGET_H + +#include "umlwidget.h" + +#define A_WIDTH 20 +#define A_HEIGHT 40 +#define A_MARGIN 5 + +class UMLActor; + +/** + * This class is the graphical version of a UML Actor. + * An ActorWidget is created by a @ref UMLView. An ActorWidget belongs to only + * one @ref UMLView instance. + * When the @ref UMLView instance that this class belongs to is destroyed, the + * ActorWidget will be automatically deleted. + * + * If the UMLActor class that this ActorWidget is displaying is deleted, the + * @ref UMLView will make sure that this instance is also deleted. + * + * The ActorWidget class inherits from the @ref UMLWidget class + * which adds most of the functionality to this class. + * + * @short A graphical version of a UML Actor. + * @author Paul Hensgen + * @see UMLWidget + * @see UMLView + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class ActorWidget : public UMLWidget +{ +public: + ActorWidget(UMLScene * scene, UMLActor *o); + virtual ~ActorWidget(); + + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + + virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); + +protected: + QSizeF minimumSize() const; +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/artifactwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/artifactwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/artifactwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/artifactwidget.cpp 2015-10-08 11:48:59.508089026 +0300 @@ -0,0 +1,293 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "artifactwidget.h" + +// app includes +#include "artifact.h" +#include "debug_utils.h" +#include "umlscene.h" +#include "umlview.h" + +/** + * Constructs a ArtifactWidget. + * + * @param scene The parent of this ArtifactWidget. + * @param a The Artifact this widget will be representing. + */ +ArtifactWidget::ArtifactWidget(UMLScene *scene, UMLArtifact *a) + : UMLWidget(scene, WidgetBase::wt_Artifact, a) +{ + setSize(100, 30); +} + +/** + * Destructor. + */ +ArtifactWidget::~ArtifactWidget() +{ +} + +/** + * Reimplemented to paint the articraft widget. Some part of specific + * drawing is delegeted to private method like drawAsFile.. + */ +void ArtifactWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + UMLWidget::setPenFromSettings(painter); + if (UMLWidget::useFillColor()) { + painter->setBrush(UMLWidget::fillColor()); + } else { + painter->setBrush(m_scene->backgroundColor()); + } + + if (umlObject()) { + UMLArtifact *umlart = static_cast(m_umlObject); + UMLArtifact::Draw_Type drawType = umlart->getDrawAsType(); + switch (drawType) { + case UMLArtifact::defaultDraw: + paintAsNormal(painter, option); + break; + case UMLArtifact::file: + paintAsFile(painter, option); + break; + case UMLArtifact::library: + paintAsLibrary(painter, option); + break; + case UMLArtifact::table: + paintAsTable(painter, option); + break; + default: + uWarning() << "Artifact drawn as unknown type"; + break; + } + } + else { + uWarning() << "Cannot draw as there is no UMLArtifact for this widget."; + } +} + +/** + * Reimplemented from WidgetBase::saveToXMI to save the widget to + * the "artifactwidget" XMI element. + */ +void ArtifactWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +{ + QDomElement conceptElement = qDoc.createElement(QLatin1String("artifactwidget")); + UMLWidget::saveToXMI(qDoc, conceptElement); + qElement.appendChild(conceptElement); +} + +/** + * Overrides method from UMLWidget. + */ +QSizeF ArtifactWidget::minimumSize() const +{ + if (!m_umlObject) { + return UMLWidget::minimumSize(); + } + UMLArtifact *umlart = static_cast(m_umlObject); + if (umlart->getDrawAsType() == UMLArtifact::defaultDraw) { + return calculateNormalSize(); + } else { + return calculateIconSize(); + } +} + +/** + * calculates the size when drawing as an icon (it's the same size for all icons) + */ +QSize ArtifactWidget::calculateIconSize() const +{ + const QFontMetrics &fm = getFontMetrics(FT_BOLD_ITALIC); + const int fontHeight = fm.lineSpacing(); + + int width = fm.width(m_umlObject->name()); + + width = width<50 ? 50 : width; + + int height = 50 + fontHeight; + + return QSize(width, height); +} + +/** + * calculates the size for drawing as a box + */ +QSize ArtifactWidget::calculateNormalSize() const +{ + const QFontMetrics &fm = getFontMetrics(FT_BOLD_ITALIC); + const int fontHeight = fm.lineSpacing(); + + int width = fm.width(m_umlObject->name()); + + int tempWidth = 0; + if(!m_umlObject->stereotype().isEmpty()) { + tempWidth = fm.width(m_umlObject->stereotype(true)); + } + width = tempWidth>width ? tempWidth : width; + width += ARTIFACT_MARGIN * 2; + + int height = (2*fontHeight) + (ARTIFACT_MARGIN * 2); + + return QSize(width, height); +} + +/** + * draw as a file icon + */ +void ArtifactWidget::paintAsFile(QPainter *painter, const QStyleOptionGraphicsItem *option) +{ + const int w = width(); + const int h = height(); + QFont font = UMLWidget::font(); + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + + int startX = (w/2) - 25; + int iconHeight = h - fontHeight; + QPolygon pointArray(5); + pointArray.setPoint(0, startX, 0); + pointArray.setPoint(1, startX + 40, 0); + pointArray.setPoint(2, startX + 50, 10); + pointArray.setPoint(3, startX + 50, iconHeight); + pointArray.setPoint(4, startX, iconHeight); + painter->drawPolygon(pointArray); + + painter->drawLine(startX + 40, 0, startX + 40, 10); + painter->drawLine(startX + 40, 10, startX + 50, 10); + painter->drawLine(startX + 40, 0, startX + 50, 10); + + painter->setPen(textColor()); + painter->setFont(font); + + painter->drawText(0, h - fontHeight, + w, fontHeight, Qt::AlignCenter, name()); + + UMLWidget::paint(painter, option); +} + +/** + * draw as a library file icon + */ +void ArtifactWidget::paintAsLibrary(QPainter *painter, const QStyleOptionGraphicsItem *option) +{ + //FIXME this should have gears on it + const int w = width(); + const int h = height(); + const QFont font = UMLWidget::font(); + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + + const int startX = (w/2) - 25; + const int iconHeight = h - fontHeight; + QPolygon pointArray(5); + pointArray.setPoint(0, startX, 0); + pointArray.setPoint(1, startX + 40, 0); + pointArray.setPoint(2, startX + 50, 10); + pointArray.setPoint(3, startX + 50, iconHeight); + pointArray.setPoint(4, startX, iconHeight); + painter->drawPolygon(pointArray); + + painter->drawLine(startX + 40, 0, startX + 40, 10); + painter->drawLine(startX + 40, 10, startX + 50, 10); + painter->drawLine(startX + 40, 0, startX + 50, 10); + + painter->setPen(textColor()); + painter->setFont(font); + + painter->drawText(0, h - fontHeight, + w, fontHeight, Qt::AlignCenter, name()); + + UMLWidget::paint(painter, option); +} + +/** + * draw as a database table icon + */ +void ArtifactWidget::paintAsTable(QPainter *painter, const QStyleOptionGraphicsItem *option) +{ + const int w = width(); + const int h = height(); + const QFont font = UMLWidget::font(); + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + + const int startX = (w/2) - 25; + const int iconHeight = h - fontHeight; + + painter->drawRect(startX, 0, 50, h - fontHeight + 1); + painter->drawLine(startX + 20, 0, startX + 20, iconHeight); + painter->drawLine(startX + 30, 0, startX + 30, iconHeight); + painter->drawLine(startX + 40, 0, startX + 40, iconHeight); + painter->drawLine(startX, (iconHeight/2), startX + 49, (iconHeight/2)); + painter->drawLine(startX, (iconHeight/2) + (iconHeight/4), + startX + 49, (iconHeight/2) + (iconHeight/4)); + + QPen thickerPen = painter->pen(); + thickerPen.setWidth(2); + painter->setPen(thickerPen); + painter->drawLine(startX + 10, 0, startX + 10, iconHeight); + painter->drawLine(startX, (iconHeight/4), startX + 50, (iconHeight/4)); + + painter->setPen(textColor()); + painter->setFont(font); + + painter->drawText(0, h - fontHeight, + w, fontHeight, Qt::AlignCenter, name()); + + UMLWidget::paint(painter, option); +} + +/** + * draw as a box + */ +void ArtifactWidget::paintAsNormal(QPainter *painter, const QStyleOptionGraphicsItem *option) +{ + int w = width(); + int h = height(); + QFont font = UMLWidget::font(); + font.setBold(true); + const QFontMetrics &fm = getFontMetrics(FT_BOLD); + const int fontHeight = fm.lineSpacing(); + QString stereotype = m_umlObject->stereotype(); + + painter->drawRect(0, 0, w, h); + + painter->setPen(textColor()); + painter->setFont(font); + + if (!stereotype.isEmpty()) { + painter->drawText(ARTIFACT_MARGIN, (h/2) - fontHeight, + w, fontHeight, Qt::AlignCenter, m_umlObject->stereotype(true)); + } + + int lines; + if (!stereotype.isEmpty()) { + lines = 2; + } else { + lines = 1; + } + + if (lines == 1) { + painter->drawText(0, (h/2) - (fontHeight/2), + w, fontHeight, Qt::AlignCenter, name()); + } else { + painter->drawText(0, (h/2), + w, fontHeight, Qt::AlignCenter, name()); + } + + UMLWidget::paint(painter, option); +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/artifactwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/artifactwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/artifactwidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/artifactwidget.h 2015-10-08 11:48:59.508089026 +0300 @@ -0,0 +1,55 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef ARTIFACTWIDGET_H +#define ARTIFACTWIDGET_H + +#include "umlwidget.h" + +class UMLScene; +class UMLArtifact; + +#define ARTIFACT_MARGIN 5 + +/** + * Defines a graphical version of the @ref UMLArtifact. + * Most of the functionality will come from the @ref UMLWidget class. + * + * @short A graphical version of a Artifact. + * @author Jonathan Riddell + * @see UMLWidget + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class ArtifactWidget : public UMLWidget +{ +public: + ArtifactWidget(UMLScene *scene, UMLArtifact *a); + virtual ~ArtifactWidget(); + + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + + // Note: For loading from XMI, the inherited parent method is used. + virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); + +protected: + QSizeF minimumSize() const; + +private: + void paintAsFile(QPainter *painter, const QStyleOptionGraphicsItem *option); + void paintAsLibrary(QPainter *painter, const QStyleOptionGraphicsItem *option); + void paintAsTable(QPainter *painter, const QStyleOptionGraphicsItem *option); + void paintAsNormal(QPainter *painter, const QStyleOptionGraphicsItem *option); + + QSize calculateIconSize() const; + QSize calculateNormalSize() const; + +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/associationline.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/associationline.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/associationline.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/associationline.cpp 2015-10-08 11:48:59.508089026 +0300 @@ -0,0 +1,1404 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "associationline.h" + +// application includes +#include "associationwidget.h" +#include "debug_utils.h" +#include "umlwidget.h" + +// qt includes +#include +#include + +// system includes +#include +#include + +DEBUG_REGISTER_DISABLED(AssociationLine) + +// Initialize static variables. +const qreal AssociationLine::Delta = 5; +const qreal AssociationLine::SelectedPointDiameter = 4; +const qreal AssociationLine::SelfAssociationMinimumHeight = 30; + +/** + * Constructor. + * Constructs an AssociationLine item with its parent being \a parent. + */ +AssociationLine::AssociationLine(AssociationWidget *association) + : QGraphicsObject(association), + m_associationWidget(association), + m_activePointIndex(-1), + m_activeSegmentIndex(-1), + m_startSymbol(0), + m_endSymbol(0), + m_subsetSymbol(0), + m_collaborationLineItem(0), + m_collaborationLineHead(0), + m_layout(Polyline) +{ + Q_ASSERT(association); + setFlag(QGraphicsLineItem::ItemIsSelectable); + setAcceptHoverEvents(true); + setZValue(3); +} + +/** + * Destructor. + */ +AssociationLine::~AssociationLine() +{ +} + +/** + * Returns the point at the point index. + * @return point at given index + */ +QPointF AssociationLine::point(int index) const +{ + if ((index < 0) | (index >= m_points.size())) { + uWarning() << "Index " << index << " out of range [0.." << m_points.size() - 1 << "]."; + return QPointF(-1.0, -1.0); + } + return m_points.at(index); +} + +/** + * Sets the point value at given index to \a point. + */ +bool AssociationLine::setPoint(int index, const QPointF &point) +{ + if ((index < 0) | (index >= m_points.size())) { + uWarning() << "Index " << index << " out of range [0.." << m_points.size() - 1 << "]."; + return false; + } + if (m_points.at(index) == point) { + return false; // nothing to change + } + prepareGeometryChange(); + m_points[index] = point; + alignSymbols(); + return true; +} + +/** + * Shortcut for point(0). + */ +QPointF AssociationLine::startPoint() const +{ + return m_points.at(0); +} + +/** + * Shortcut for end point. + */ +QPointF AssociationLine::endPoint() const +{ + return m_points.at(m_points.size()-1); +} + +/** + * Inserts the passed in \a point at the \a index passed in and + * recalculates the bounding rect. + */ +void AssociationLine::insertPoint(int index, const QPointF &point) +{ + prepareGeometryChange(); + m_points.insert(index, point); + alignSymbols(); +} + +/** + * Removes the point at \a index passed in. + * @see removeNonEndPoint + */ +void AssociationLine::removePoint(int index) +{ + prepareGeometryChange(); + m_points.remove(index); + alignSymbols(); +} + +/** + * Returns the amount of POINTS on the line. + * Includes start and end points. + * @return number of points in the AssociationLine + */ +int AssociationLine::count() const +{ + return m_points.size(); +} + +/** + * Removes all the points and signals a geometry update. + */ +void AssociationLine::cleanup() +{ + if (!m_points.isEmpty()) { + prepareGeometryChange(); + m_points.clear(); + alignSymbols(); + } +} + +/** + * This method optimizes the number of points in the + * AssociationLine. This can be used to reduce the clutter caused + * due to too many points. + * TODO: Use delta comparison 'closestPointIndex' instead of exact comparison. + * TODO: Not used anywhere. + */ +void AssociationLine::optimizeLinePoints() +{ + int i = 1; + prepareGeometryChange(); + while (i < m_points.size()) { + if (m_points.at(i) == m_points.at(i-1)) { + m_points.remove(i); + } + else { + ++i; + } + } + alignSymbols(); +} + +/** + * Return index of point closer a given delta. + * + * @param point The point which is to be tested for closeness. + * @param delta The distance the point should be closer to. + * + * @retval "Index" of the first line point closer to the \a point passed. + * @retval -1 If no line point is closer to passed in \a point. + */ +int AssociationLine::closestPointIndex(const QPointF &point, qreal delta) const +{ + for(int i = 0; i < m_points.size(); ++i) { + const QPointF& linePoint = m_points.at(i); + // Apply distance formula to see point closeness. + qreal deltaXSquare = (point.x() - linePoint.x()) * (point.x() - linePoint.x()); + qreal deltaYSquare = (point.y() - linePoint.y()) * (point.y() - linePoint.y()); + + qreal lhs = deltaXSquare + deltaYSquare; + qreal rhs = delta * delta; + + if (lhs <= rhs) { + return i; + } + } + return -1; +} + +/** + * Return index of closest segment. + * + * @param point The point which is to be tested for closeness. + * + * @return Index of the line segment closest to the \a point passed; + * -1 if no line segment is closer to passed in \a point. + */ +int AssociationLine::closestSegmentIndex(const QPointF &point, qreal delta) const +{ + QPainterPathStroker stroker; + stroker.setWidth(delta); + + for(int i = 1; i < m_points.size(); ++i) { + QLineF segment(m_points[i-1], m_points[i]); + + QPainterPath path; + path.moveTo(segment.p1()); + path.lineTo(segment.p2()); + + path = stroker.createStroke(path); + + if (path.contains(point)) { + return i-1; + } + } + return -1; +} + +/** + * Retval True If point at \a index is start or end. + */ +bool AssociationLine::isEndPointIndex(int index) const +{ + const int size = m_points.size(); + Q_ASSERT(index >= 0 && index < size); + + return (index == 0 || index == (size - 1)); +} + +/** + * Retval True If segment at \a index is start or end. + */ +bool AssociationLine::isEndSegmentIndex(int index) const +{ + // num of seg = num of points - 1 + const int size = m_points.size() - 1; + Q_ASSERT(index >= 0 && index < size); + + return (index == 0 || index == (size - 1)); +} + +/** + * Sets the start and end points. + */ +bool AssociationLine::setEndPoints(const QPointF &start, const QPointF &end) +{ + const int size = m_points.size(); + + prepareGeometryChange(); + + if (size == 0) { + m_points.insert(0, start); + m_points.insert(1, end); + } + else if (size == 1) { + m_points[0] = start; + m_points.insert(1, end); + } + else { + m_points[0] = start; + m_points[size-1] = end; + } + + alignSymbols(); + return true; +} + +/** + * Debug helper method to write out the points. + */ +void AssociationLine::dumpPoints() +{ + for (int i = 1; i < m_points.size(); ++i) { + QPointF p = m_points.at(i); + DEBUG(DBG_SRC) << i << ". point x:" << p.x() << " / y:" << p.y(); + } +} + +/** + * Loads AssociationLine information saved in \a qElement XMI element. + */ +bool AssociationLine::loadFromXMI(QDomElement &qElement) +{ + QString layout = qElement.attribute(QLatin1String("layout"), QLatin1String("polyline")); + m_layout = fromString(layout); + + QDomNode node = qElement.firstChild(); + + m_points.clear(); + + QDomElement startElement = node.toElement(); + if(startElement.isNull() || startElement.tagName() != QLatin1String("startpoint")) { + return false; + } + QString x = startElement.attribute(QLatin1String("startx"), QLatin1String("0")); + qreal nX = x.toFloat(); + QString y = startElement.attribute(QLatin1String("starty"), QLatin1String("0")); + qreal nY = y.toFloat(); + QPointF startPoint(nX, nY); + + node = startElement.nextSibling(); + QDomElement endElement = node.toElement(); + if(endElement.isNull() || endElement.tagName() != QLatin1String("endpoint")) { + return false; + } + x = endElement.attribute(QLatin1String("endx"), QLatin1String("0")); + nX = x.toFloat(); + y = endElement.attribute(QLatin1String("endy"), QLatin1String("0")); + nY = y.toFloat(); + QPointF endPoint(nX, nY); + setEndPoints(startPoint, endPoint); + QPointF point; + node = endElement.nextSibling(); + QDomElement element = node.toElement(); + int i = 1; + while(!element.isNull()) { + if(element.tagName() == QLatin1String("point")) { + x = element.attribute(QLatin1String("x"), QLatin1String("0")); + y = element.attribute(QLatin1String("y"), QLatin1String("0")); + point.setX(x.toFloat()); + point.setY(y.toFloat()); + insertPoint(i++, point); + } + node = element.nextSibling(); + element = node.toElement(); + } + + return true; +} + +/** + * Saves association line information into XMI element named "linepath". + * @note Stored as linepath for backwared compatibility + */ +void AssociationLine::saveToXMI(QDomDocument &qDoc, QDomElement &qElement) +{ + QPointF point = m_associationWidget->mapToScene(startPoint()); + QDomElement lineElement = qDoc.createElement(QLatin1String("linepath")); + lineElement.setAttribute(QLatin1String("layout"), toString(m_layout)); + QDomElement startElement = qDoc.createElement(QLatin1String("startpoint")); + startElement.setAttribute(QLatin1String("startx"), point.x()); + startElement.setAttribute(QLatin1String("starty"), point.y()); + lineElement.appendChild(startElement); + QDomElement endElement = qDoc.createElement(QLatin1String("endpoint")); + point = m_associationWidget->mapToScene(endPoint()); + endElement.setAttribute(QLatin1String("endx"), point.x()); + endElement.setAttribute(QLatin1String("endy"), point.y()); + lineElement.appendChild(endElement); + for(int i = 1; i < count()-1; ++i) { + QDomElement pointElement = qDoc.createElement(QLatin1String("point")); + point = m_associationWidget->mapToScene(this->point(i)); + pointElement.setAttribute(QLatin1String("x"), point.x()); + pointElement.setAttribute(QLatin1String("y"), point.y()); + lineElement.appendChild(pointElement); + } + qElement.appendChild(lineElement); +} + +/** + * Returns the type of brush to use depending on the type of Association. + */ +QBrush AssociationLine::brush() const +{ + QBrush brush(Qt::solid-kf6Pattern); + Uml::AssociationType::Enum type = m_associationWidget->associationType(); + if (type == Uml::AssociationType::Aggregation || + type == Uml::AssociationType::Generalization || + type == Uml::AssociationType::Realization) { + brush.setColor(Qt::white); + } + if (type == Uml::AssociationType::Composition) { + brush.setColor(m_associationWidget->lineColor()); + } + return brush; +} + +/** + * Returns the type of pen to use depending on the type of Association. + */ +QPen AssociationLine::pen() const +{ + QPen pen(m_associationWidget->lineColor(), + m_associationWidget->lineWidth(), + Qt::solid-kf6Line, + Qt::RoundCap, + Qt::RoundJoin); + Uml::AssociationType::Enum type = m_associationWidget->associationType(); + if (type == Uml::AssociationType::Dependency || + type == Uml::AssociationType::Realization || + type == Uml::AssociationType::Anchor) { + pen.setStyle(Qt::DashLine); + } + return pen; +} + +/** + * This method simply ensures presence of two points and + * adds the needed points for self associations. + */ +void AssociationLine::calculateInitialEndPoints() +{ + if (m_associationWidget->isSelf() && count() < 4) { + for (int i = count(); i < 4; ++i) { + insertPoint(i, QPointF()); + } + UMLWidget *wid = m_associationWidget->widgetForRole(Uml::RoleType::B); + if (!wid) { + uError() << "AssociationWidget is partially constructed." + "UMLWidget for role B is null."; + return; + } + const QRectF rect = m_associationWidget->mapFromScene( + mapToScene(wid->rect()).boundingRect()).boundingRect(); + + qreal l = rect.left() + .25 * rect.width(); + qreal r = rect.left() + .75 * rect.width(); + bool drawAbove = rect.top() >= SelfAssociationMinimumHeight; + qreal y = drawAbove ? rect.top() : rect.bottom(); + qreal yOffset = SelfAssociationMinimumHeight; + if (drawAbove) { + yOffset *= -1.0; + } + + setPoint(0, QPointF(l, y)); + setPoint(1, QPointF(l, y + yOffset)); + setPoint(2, QPointF(r, y + yOffset)); + setPoint(3, QPointF(r, y)); + } else if (!m_associationWidget->isSelf() && count() < 2) { + setEndPoints(QPointF(), QPointF()); + } +} + +/** + * This method creates, deletes symbols and collaboration lines based on + * m_associationWidget->associationType(). + * + * Call this method when associationType of m_associationWidget changes. + */ +void AssociationLine::reconstructSymbols() +{ + switch( m_associationWidget->associationType() ) { + case Uml::AssociationType::State: + case Uml::AssociationType::Activity: + case Uml::AssociationType::Exception: + case Uml::AssociationType::UniAssociation: + case Uml::AssociationType::Dependency: + setStartSymbol(Symbol::None); + setEndSymbol(Symbol::OpenArrow); + removeSubsetSymbol(); + removeCollaborationLine(); + break; + + case Uml::AssociationType::Relationship: + setStartSymbol(Symbol::None); + setEndSymbol(Symbol::CrowFeet); + removeSubsetSymbol(); + removeCollaborationLine(); + break; + + case Uml::AssociationType::Generalization: + case Uml::AssociationType::Realization: + setStartSymbol(Symbol::None); + setEndSymbol(Symbol::ClosedArrow); + removeSubsetSymbol(); + removeCollaborationLine(); + break; + + case Uml::AssociationType::Composition: + case Uml::AssociationType::Aggregation: + setStartSymbol(Symbol::Diamond); + setEndSymbol(Symbol::None); + removeSubsetSymbol(); + removeCollaborationLine(); + break; + + case Uml::AssociationType::Containment: + setStartSymbol(Symbol::Circle); + setEndSymbol(Symbol::None); + removeSubsetSymbol(); + removeCollaborationLine(); + break; + + case Uml::AssociationType::Child2Category: + setStartSymbol(Symbol::None); + setEndSymbol(Symbol::None); + createSubsetSymbol(); + removeCollaborationLine(); + break; + + case Uml::AssociationType::Coll_Message_Synchronous: + case Uml::AssociationType::Coll_Message_Asynchronous: + case Uml::AssociationType::Coll_Message_Self: + setStartSymbol(Symbol::None); + setEndSymbol(Symbol::None); + removeSubsetSymbol(); + createCollaborationLine(); + break; + + default: + break; + } + alignSymbols(); +} + +/** + * Sets the Symbol to appear at the first line segment to \a symbol. + * + * If symbol == Symbol::None , then it deletes the symbol item. + */ +void AssociationLine::setStartSymbol(Symbol::SymbolType symbolType) +{ + Q_ASSERT(symbolType != Symbol::Count); + if (symbolType == Symbol::None) { + delete m_startSymbol; + m_startSymbol = 0; + return; + } + + if (m_startSymbol) { + m_startSymbol->setSymbolType(symbolType); + } + else { + m_startSymbol = new Symbol(symbolType, m_associationWidget); + } + m_startSymbol->setPen(pen()); + m_startSymbol->setBrush(brush()); +} + +/** + * Sets the Symbol to appear at the last line segment to \a symbol. + * + * If symbol == Symbol::None , then it deletes the symbol item. + */ +void AssociationLine::setEndSymbol(Symbol::SymbolType symbolType) +{ + Q_ASSERT(symbolType != Symbol::Count); + if (symbolType == Symbol::None) { + delete m_endSymbol; + m_endSymbol = 0; + return; + } + + if (m_endSymbol) { + m_endSymbol->setSymbolType(symbolType); + } + else { + m_endSymbol = new Symbol(symbolType, m_associationWidget); + } + m_endSymbol->setPen(pen()); + m_endSymbol->setBrush(brush()); +} + +/** + * Constructs a new subset symbol. + */ +void AssociationLine::createSubsetSymbol() +{ + delete m_subsetSymbol; // recreate + m_subsetSymbol = new Symbol(Symbol::Subset, m_associationWidget); + m_subsetSymbol->setPen(pen()); + m_subsetSymbol->setBrush(brush()); +} + +/** + * Removes the subset symbol if it existed by deleting appropriate items. + */ +void AssociationLine::removeSubsetSymbol() +{ + delete m_subsetSymbol; + m_subsetSymbol = 0; +} + +/** + * Constructs the open arrow symbol and arrow line, that would represent Collaboration line. + */ +void AssociationLine::createCollaborationLine() +{ + const QPen p = pen(); + + // recreate + delete m_collaborationLineItem; + delete m_collaborationLineHead; + + m_collaborationLineItem = new QGraphicsLineItem(m_associationWidget); + m_collaborationLineItem->setPen(p); + + if (m_associationWidget->associationType() == Uml::AssociationType::Coll_Message_Synchronous) { + m_collaborationLineHead = new Symbol(Symbol::ClosedArrow, m_associationWidget); + m_collaborationLineHead->setBrush(p.color()); + } + else + m_collaborationLineHead = new Symbol(Symbol::OpenArrow, m_associationWidget); + m_collaborationLineHead->setPen(p); +} + +/** + * Removes collaboration line by deleting the head and line item. + */ +void AssociationLine::removeCollaborationLine() +{ + delete m_collaborationLineItem; + m_collaborationLineItem = 0; + + delete m_collaborationLineHead; + m_collaborationLineHead = 0; +} + +/** + * This method aligns both the \b "start" and \b "end" symbols to + * the current angles of the \b "first" and the \b "last" line + * segment respectively. + */ +void AssociationLine::alignSymbols() +{ + const int sz = m_points.size(); + if (sz < 2) { + // cannot align if there is no line (one line = 2 points) + return; + } + + QList polygons = path().toSubpathPolygons(); + + if (m_startSymbol) { + QPolygonF firstLine = polygons.first(); + QLineF segment(firstLine.at(1), firstLine.at(0)); + m_startSymbol->alignTo(segment); + } + + if (m_endSymbol) { + QPolygonF lastLine = polygons.last(); + int maxIndex = lastLine.size(); + QLineF segment(lastLine.at(maxIndex-2), lastLine.at(maxIndex-1)); + m_endSymbol->alignTo(segment); + } + + if (m_subsetSymbol) { + QPointF p1 = path().pointAtPercent(0.4); + QPointF p2 = path().pointAtPercent(0.5); + QLineF segment(p1, p2); + m_subsetSymbol->alignTo(segment); + } + + if (m_collaborationLineItem) { + const qreal distance = 10; + const int midSegmentIndex = (sz - 1) / 2; + + const QPointF a = m_points.at(midSegmentIndex); + const QPointF b = m_points.at(midSegmentIndex + 1); + + if (a == b) + return; + + const QPointF p1 = (a + b) / 2.0; + const QPointF p2 = (p1 + b) / 2.0; + + // Reversed line as we want normal in opposite direction. + QLineF segment(p2, p1); + QLineF normal = segment.normalVector().unitVector(); + normal.setLength(distance); + + QLineF actualLine; + actualLine.setP2(normal.p2()); + + normal.translate(p1 - p2); + actualLine.setP1(normal.p2()); + + m_collaborationLineItem->setLine(actualLine); + m_collaborationLineHead->alignTo(actualLine); + } +} + +/** + * @return The path of the AssociationLine. + */ +QPainterPath AssociationLine::path() const +{ + if (m_points.count() > 0) { + QPainterPath path; + switch (m_layout) { + case Direct: + path.moveTo(m_points.first()); + path.lineTo(m_points.last()); + break; + + case Spline: + path = createBezierCurve(m_points); + break; + + case Orthogonal: + path = createOrthogonalPath(m_points); + break; + + case Polyline: + default: + QPolygonF polygon(m_points); + path.addPolygon(polygon); + break; + } + return path; + } + else { + return QPainterPath(); + } +} + +/** + * The points are used for the bounding rect. The reason is, + * that for splines the control points are further away from the path. + * @return The bounding rectangle for the AssociationLine. + */ +QRectF AssociationLine::boundingRect() const +{ + QPolygonF polygon(m_points); + QRectF rect = polygon.boundingRect(); + const qreal margin(5.0); + rect.adjust(-margin, -margin, margin, margin); + return rect; +} + +/** + * @return The shape of the AssociationLine. + */ +QPainterPath AssociationLine::shape() const +{ + QPainterPathStroker stroker; + stroker.setWidth(qMax(2*SelectedPointDiameter, pen().widthF()) + 2.0); // allow delta region + stroker.setCapStyle(Qt::FlatCap); + return stroker.createStroke(path()); +} + +/** + * Convert enum LayoutType to string. + */ +QString AssociationLine::toString(LayoutType layout) +{ + return QLatin1String(ENUM_NAME(AssociationLine, LayoutType, layout)); +} + +/** + * Convert string to enum LayoutType. + */ +AssociationLine::LayoutType AssociationLine::fromString(const QString &layout) +{ + if (layout == QLatin1String("Direct")) + return Direct; + if (layout == QLatin1String("Spline")) + return Spline; + if (layout == QLatin1String("Orthogonal")) + return Orthogonal; + return Polyline; +} + +/** + * Return the layout type of the association line. + * @return the currently used layout + */ +AssociationLine::LayoutType AssociationLine::layout() const +{ + return m_layout; +} + +/** + * Set the layout type of the association line. + * @param layout the desired layout to set + */ +void AssociationLine::setLayout(LayoutType layout) +{ + prepareGeometryChange(); + m_layout = layout; + DEBUG(DBG_SRC) << "new layout = " << toString(m_layout); + if (m_layout == Spline) { + createSplinePoints(); + } + alignSymbols(); +} + +/** + * For a cubic Bezier curve at least four points are needed. + * If there are less, the missing points will be created. + * Note: Implementation is only for two points. + */ +void AssociationLine::createSplinePoints() +{ + if (m_points.size() == 2) { // create two points + QPointF p1 = m_points.first(); // start point + QPointF p2 = m_points.last(); // end point + qreal dx = p2.x() - p1.x(); + qreal dy = p2.y() - p1.y(); + qreal oneThirdX = 0.33 * dx; + qreal oneThirdY = 0.33 * dy; + QPointF c1(p1.x() + oneThirdX, // control point 1 + p1.y() - oneThirdY); + QPointF c2(p2.x() - oneThirdX, // control point 2 + p2.y() + oneThirdY); + insertPoint(1, c1); + insertPoint(2, c2); + } + if (m_points.size() == 3) { // create one point + // insertPoint(1 or 2, ); + // Note: For now we use a quadratic Bezier curve in createBezierCurve(...). + } +} + +/** + * Returns a Bézier path from given points. + * @param points points which define the Bézier curve + * @return cubic Bézier spline + */ +QPainterPath AssociationLine::createBezierCurve(QVector points) +{ + QPainterPath path; + if (points.size() > 3) { // cubic Bezier curve(s) + path.moveTo(points.at(0)); + int i = 1; + while (i + 2 < points.size()) { + path.cubicTo(points.at(i), points.at(i+1), points.at(i+2)); + i += 3; + } + while (i < points.size()) { // draw a line if points are not modulo 3 + path.lineTo(points.at(i)); + ++i; + } + } + else { + if (points.size() == 3) { // quadratic Bezier curve + path.moveTo(points.at(0)); + path.quadTo(points.at(1), points.at(2)); + } + else { // should not be reached + QPolygonF polygon(points); + path.addPolygon(polygon); + } + } + return path; +} + +/** + * Returns an orthogonal path constructed of vertical and horizontal segments + * through the given points. + * @param points base points for the path + * @return orthogonal path + */ +QPainterPath AssociationLine::createOrthogonalPath(QVector points) +{ + QPainterPath path; + if (points.size() > 1) { + QPointF start = points.first(); + QPointF end = points.last(); + qreal deltaX = fabs(start.x() - end.x()); + qreal deltaY = fabs(start.y() - end.y()); + // DEBUG("AssociationLine") << "start=" << start << " / end=" << end + // << " / deltaX=" << deltaX << " / deltaY=" << deltaY; + QVector vector; + for (int i = 0; i < points.size() - 1; ++i) { + QPointF curr = points.at(i); + QPointF next = points.at(i+1); + QPointF center = (next + curr)/2.0; + + vector.append(curr); + if (deltaX < deltaY) { + // go vertical first + vector.append(QPointF(curr.x(), center.y())); + vector.append(QPointF(next.x(), center.y())); + } + else { + // go horizontal first + vector.append(QPointF(center.x(), curr.y())); + vector.append(QPointF(center.x(), next.y())); + } + vector.append(next); + } + + QPolygonF rectLine(vector); + path.addPolygon(rectLine); + } + else { + QPolygonF polygon(points); + path.addPolygon(polygon); + } + return path; +} + +/** + * Reimplemented from QGraphicsItem::paint. + * Draws the AssociationLine and also takes care of highlighting active point or line. + */ +void AssociationLine::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) +{ + Q_UNUSED(widget) + QPen _pen = pen(); + const QColor orig = _pen.color().lighter(); + QColor invertedColor(orig.green(), orig.blue(), orig.red()); + if (invertedColor == _pen.color()) { + // Ensure different color. + invertedColor.setRed((invertedColor.red() + 50) % 256); + } + invertedColor.setAlpha(150); + + int sz = m_points.size(); + if (sz < 1) { + // not enough points - do nothing + return; + } + + QPointF savedStart = m_points.first(); + QPointF savedEnd = m_points.last(); + + // modify the m_points array not to include the Symbol, the value depends on Symbol + if (m_startSymbol) { + QPointF newStart = m_startSymbol->mapToParent(m_startSymbol->symbolEndPoints().first); + m_points[0] = newStart; + } + + if (m_endSymbol) { + QPointF newEnd = m_endSymbol->mapToParent(m_endSymbol->symbolEndPoints().first); + m_points[sz - 1] = newEnd; + } + + painter->setPen(_pen); + painter->setBrush(Qt::NoBrush); + painter->drawPath(path()); + + if (option->state & QStyle::State_Selected) { + // make the association broader in the selected state + QPainterPathStroker stroker; + stroker.setWidth(3.0); + QPainterPath outline = stroker.createStroke(path()); + QColor shadowColor(Qt::lightGray); + shadowColor.setAlpha(80); + QBrush shadowBrush(shadowColor); + painter->setBrush(shadowBrush); + painter->setPen(Qt::NoPen); + painter->drawPath(outline); + + // set color for selected painting + _pen.setColor(Qt::blue); + QRectF circle(0, 0, SelectedPointDiameter, SelectedPointDiameter); + painter->setBrush(_pen.color()); + painter->setPen(Qt::NoPen); + + // draw points + circle.moveCenter(savedStart); + painter->drawRect(circle); + for (int i = 1; i < sz-1; ++i) { + if (i != m_activePointIndex) { + circle.moveCenter(m_points.at(i)); + painter->drawRect(circle); + } + } + circle.moveCenter(savedEnd); + painter->drawRect(circle); + + if (m_activePointIndex != -1) { + painter->setBrush(invertedColor); + painter->setPen(Qt::NoPen); + circle.setWidth(1.5*SelectedPointDiameter); + circle.setHeight(1.5*SelectedPointDiameter); + circle.moveCenter(m_points.at(m_activePointIndex)); + painter->drawEllipse(circle); + } + else if (m_activeSegmentIndex != -1) { + if (m_layout == Polyline) { + painter->setPen(QPen(invertedColor, _pen.widthF() + 1)); + painter->setBrush(Qt::NoBrush); + + QLineF segmentLine(m_points[m_activeSegmentIndex], m_points[m_activeSegmentIndex + 1]); + painter->drawLine(segmentLine); + } + } + // debug info + if (Tracer::instance()->isEnabled(QString::fromLatin1(metaObject()->className()))) { + painter->setPen(Qt::green); + painter->setBrush(Qt::NoBrush); + painter->drawPath(shape()); + painter->setPen(Qt::red); + painter->drawRect(boundingRect()); + // origin + painter->drawLine(-10, 0, 10, 0); + painter->drawLine(0, -10, 0, 10); + } + + } + + // now restore the points array + m_points[0] = savedStart; + m_points[sz - 1] = savedEnd; +} + +/** + * Determines the active point or segment, the latter being given more priority. + */ +void AssociationLine::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + DEBUG(DBG_SRC) << "at " << event->scenePos(); + if (event->buttons() & Qt::LeftButton) { + m_activePointIndex = closestPointIndex(event->scenePos()); + if (m_activePointIndex != -1 && isEndPointIndex(m_activePointIndex)) { + // end points are not drawn and hence not active + m_activePointIndex = -1; + } + // calculate only if active point index is -1 + m_activeSegmentIndex = (m_activePointIndex != -1) ? -1 : closestSegmentIndex(event->scenePos()); + } + else if (event->buttons() & Qt::RightButton) { + DEBUG(DBG_SRC) << "call context menu of association widget at " << event->scenePos(); + } + else { + m_activePointIndex = -1; + m_activeSegmentIndex = -1; + } +} + +/** + * Moves the point or line if active. + */ +void AssociationLine::mouseMoveEvent(QGraphicsSceneMouseEvent *event) +{ + UMLScene* scene = m_associationWidget->umlScene(); + + QPointF oldPos = event->scenePos(); + QPointF newPos( + scene->snappedX(oldPos.x()), + scene->snappedY(oldPos.y()) + ); + + // Prevent the moving vertex from disappearing underneath a widget + // (else there's no way to get it back.) + UMLWidget *onW = scene->widgetAt(newPos); + if (onW && onW->baseType() != WidgetBase::wt_Box) { // boxes are transparent + const qreal pX = newPos.x(); + const qreal pY = newPos.y(); + const qreal wX = onW->x(); + const qreal wY = onW->y(); + const qreal wWidth = onW->width(); + const qreal wHeight = onW->height(); + if (pX > wX && pX < wX + wWidth) { + const qreal midX = wX + wWidth / 2.0; + if (pX <= midX) + newPos.setX(wX); + else + newPos.setX(wX + wWidth); + } + if (pY > wY && pY < wY + wHeight) { + const qreal midY = wY + wHeight / 2.0; + if (pY <= midY) + newPos.setY(wY); + else + newPos.setY(wY + wHeight); + } + } + + if (m_activePointIndex != -1) { + // Move a single point (snap behaviour) + setPoint(m_activePointIndex, newPos); + } + else if (m_activeSegmentIndex != -1 && !isEndSegmentIndex(m_activeSegmentIndex)) { + // Move a segment (between two points, snap behaviour not implemented) + QPointF delta = event->scenePos() - event->lastScenePos(); + setPoint(m_activeSegmentIndex, m_points[m_activeSegmentIndex] + delta); + setPoint(m_activeSegmentIndex + 1, m_points[m_activeSegmentIndex + 1] + delta); + } +} + +/** + * Reset active indices and also push undo command. + */ +void AssociationLine::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + if (event->buttons() & Qt::LeftButton) { + m_activeSegmentIndex = -1; + m_activePointIndex = -1; + } +} + +/** + * Calculates the "to be highlighted" point and segment indicies + * and updates if necessary. + */ +void AssociationLine::hoverEnterEvent(QGraphicsSceneHoverEvent *event) +{ + DEBUG(DBG_SRC) << "at " << event->scenePos(); + int oldPointIndex = m_activePointIndex; + int oldSegmentIndex = m_activeSegmentIndex; + + m_activePointIndex = closestPointIndex(event->scenePos()); + // End points are not drawn and hence not active. + if (m_activePointIndex != -1 && isEndPointIndex(m_activePointIndex)) { + m_activePointIndex = -1; + } + // Activate segment index only if point index is -1 + m_activeSegmentIndex = (m_activePointIndex != -1) ? -1 : closestSegmentIndex(event->scenePos()); + + bool isChanged = (oldSegmentIndex != m_activeSegmentIndex || oldPointIndex != m_activePointIndex); + if (isChanged) { + m_associationWidget->update(); + } +} + +/** + * Calculates the "to be highlighted" point and segment indicies + * and updates if necessary. + */ +void AssociationLine::hoverMoveEvent(QGraphicsSceneHoverEvent *event) +{ + int oldPointIndex = m_activePointIndex; + int oldSegmentIndex = m_activeSegmentIndex; + + m_activePointIndex = closestPointIndex(event->scenePos()); + // End points are not drawn and hence not active. + if (m_activePointIndex != -1 && isEndPointIndex(m_activePointIndex)) { + m_activePointIndex = -1; + } + // Activate segment index only if point index is -1 + m_activeSegmentIndex = (m_activePointIndex != -1) ? -1 : closestSegmentIndex(event->scenePos()); + + bool isChanged = (oldSegmentIndex != m_activeSegmentIndex || oldPointIndex != m_activePointIndex); + if (isChanged) { + m_associationWidget->update(); + } +} + +/** + * Reset active indicies and updates. + */ +void AssociationLine::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) +{ + DEBUG(DBG_SRC) << "at " << event->scenePos(); + //Q_UNUSED(event) + m_activePointIndex = -1; + m_activeSegmentIndex = -1; + m_associationWidget->update(); +} + +//----------------------------------------------------------------------------- + +/** + * SymbolEndPoints: + * The first point is where the AssociationLine's visible line is + * supposed to end. + * The second points is where the actual symbol part is to appear. + */ +Symbol::SymbolProperty Symbol::symbolTable[Count] = +{ + { + QRectF(-6, 0, 12, 10), QPainterPath(), QLineF(0, 0, 0, 10), + SymbolEndPoints(QPointF(0, 10), QPointF(0, 10)) + }, + { + QRectF(-6, 0, 12, 10), QPainterPath(), QLineF(0, 0, 0, 10), + SymbolEndPoints(QPointF(0, 0), QPointF(0, 10)) + }, + { + QRectF(-6, 0, 12, 10), QPainterPath(), QLineF(0, 0, 0, 10), + SymbolEndPoints(QPointF(0, 10), QPointF(0, 10)) + }, + { + QRectF(-5, -10, 10, 20), QPainterPath(), QLineF(0, -10, 0, 10), + SymbolEndPoints(QPointF(0, -10), QPointF(0, 10)) + }, + { + QRectF(-15, -10, 30, 20), QPainterPath(), QLineF(-10, 0, 0, 0), + SymbolEndPoints(QPointF(0, 0), QPointF(0, 0)) + }, + { + QRectF(-8, -8, 16, 16), QPainterPath(), QLineF(0, -8, 0, 8), + SymbolEndPoints(QPointF(0, -8), QPointF(0, 8)) + } + +}; + +/** + * @internal A convenience method to setup shapes of all symbols. + */ +void Symbol::setupSymbolTable() +{ + SymbolProperty &openArrow = symbolTable[OpenArrow]; + if (openArrow.shape.isEmpty()) { + QRectF rect = openArrow.boundRect; + // Defines a 'V' shape arrow fitting in the bound rect. + openArrow.shape.moveTo(rect.topLeft()); + openArrow.shape.lineTo(rect.center().x(), rect.bottom()); + openArrow.shape.lineTo(rect.topRight()); + } + + SymbolProperty &closedArrow = symbolTable[ClosedArrow]; + if (closedArrow.shape.isEmpty()) { + QRectF rect = closedArrow.boundRect; + // Defines a 'V' shape arrow fitting in the bound rect. + closedArrow.shape.moveTo(rect.topLeft()); + closedArrow.shape.lineTo(rect.center().x(), rect.bottom()); + closedArrow.shape.lineTo(rect.topRight()); + closedArrow.shape.lineTo(rect.topLeft()); + } + + SymbolProperty &crowFeet = symbolTable[CrowFeet]; + if (crowFeet.shape.isEmpty()) { + QRectF rect = crowFeet.boundRect; + // Defines a crowFeet fitting in the bound rect. + QPointF topMid(rect.center().x(), rect.top()); + + // left leg + crowFeet.shape.moveTo(rect.bottomLeft()); + crowFeet.shape.lineTo(topMid); + + // middle leg + crowFeet.shape.moveTo(rect.center().x(), rect.bottom()); + crowFeet.shape.lineTo(topMid); + + // right leg + crowFeet.shape.moveTo(rect.bottomRight()); + crowFeet.shape.lineTo(topMid); + } + + SymbolProperty &diamond = symbolTable[Diamond]; + if (diamond.shape.isEmpty()) { + QRectF rect = diamond.boundRect; + // Defines a 'diamond' shape fitting in the bound rect. + diamond.shape.moveTo(rect.center().x(), rect.top()); + diamond.shape.lineTo(rect.left(), rect.center().y()); + diamond.shape.lineTo(rect.center().x(), rect.bottom()); + diamond.shape.lineTo(rect.right(), rect.center().y()); + diamond.shape.lineTo(rect.center().x(), rect.top()); + } + + SymbolProperty &subset = symbolTable[Subset]; + if (subset.shape.isEmpty()) { + QRectF rect = subset.boundRect; + // Defines an arc fitting in bound rect. + qreal start = 90, span = 180; + subset.shape.arcMoveTo(rect, start); + subset.shape.arcTo(rect, start, span); + } + + SymbolProperty &circle = symbolTable[Circle]; + if (circle.shape.isEmpty()) { + QRectF rect = circle.boundRect; + // Defines a circle with a horizontal-vertical cross lines. + circle.shape.addEllipse(rect); + + circle.shape.moveTo(rect.center().x(), rect.top()); + circle.shape.lineTo(rect.center().x(), rect.bottom()); + + circle.shape.moveTo(rect.left(), rect.center().y()); + circle.shape.lineTo(rect.right(), rect.center().y()); + } + +} + +/** + * Constructs a Symbol with current symbol being \a symbol and + * parented to \a parent. + */ +Symbol::Symbol(SymbolType symbolType, QGraphicsItem *parent) + : QGraphicsItem(parent), + m_symbolType(symbolType) +{ + // ensure SymbolTable is validly initialized + setupSymbolTable(); +} + +/** + * Destructor. + */ +Symbol::~Symbol() +{ +} + +/** + * @return The current symbol being represented. + */ +Symbol::SymbolType Symbol::symbolType() const +{ + return m_symbolType; +} + +/** + * Sets the current symbol type to \a symbol and updates the geometry. + */ +void Symbol::setSymbolType(SymbolType symbolType) +{ + prepareGeometryChange(); // calls update implicitly + m_symbolType = symbolType; +} + +/** + * Draws the current symbol using the QPainterPath stored for the current + * symbol. + */ +void Symbol::paint(QPainter *painter, const QStyleOptionGraphicsItem * option, QWidget * widget) +{ + Q_UNUSED(option) Q_UNUSED(widget) + painter->setPen(m_pen); + switch (m_symbolType) { + case ClosedArrow: + case CrowFeet: + case Diamond: + painter->setBrush(m_brush); + break; + default: + break; + } + painter->drawPath(Symbol::symbolTable[m_symbolType].shape); +} + +/** + * @return The bound rectangle for this based on current symbol. + */ +QRectF Symbol::boundingRect() const +{ + const qreal adj = .5 * m_pen.widthF(); + return Symbol::symbolTable[m_symbolType].boundRect. + adjusted(-adj, -adj, adj, adj); +} + +/** + * @return The path for this based on current symbol. + */ +QPainterPath Symbol::shape() const +{ + QPainterPath path; + path.addRect(boundingRect()); + return path; +} + +/** + * This method aligns *this* Symbol to the line being + * passed. That is, it ensures that the axis of this symbol aligns + * exactly with the \a "to" line passed. + * + * Also this item is moved such that the second end point of the + * SymbolEndPoints for the current symbol *collides* with the second end + * point of \a "to" line. + */ +void Symbol::alignTo(const QLineF& to) +{ + QLineF toMapped(mapFromParent(to.p1()), mapFromParent(to.p2())); + + QLineF origAxis = Symbol::symbolTable[m_symbolType].axisLine; + QLineF translatedAxis = origAxis.translated(toMapped.p2() - origAxis.p2()); + + qreal angle = translatedAxis.angleTo(toMapped); + setRotation(rotation() - angle); + + QPointF delta = to.p2() - mapToParent(symbolEndPoints().second); + moveBy(delta.x(), delta.y()); +} + +/** + * @return The end points for the symbol. + */ +Symbol::SymbolEndPoints Symbol::symbolEndPoints() const +{ + return Symbol::symbolTable[m_symbolType].endPoints; +} + +/** + * @return The pen used to draw symbol. + */ +QPen Symbol::pen() const +{ + return m_pen; +} + +/** + * Sets the pen used to draw the symbol. + */ +void Symbol::setPen(const QPen& pen) +{ + prepareGeometryChange(); + m_pen = pen; + if (m_symbolType == ClosedArrow) + m_pen.setStyle(Qt::solid-kf6Line); +} + +/** + * @return The brush used to fill symbol. + */ +QBrush Symbol::brush() const +{ + return m_brush; +} + +/** + * Sets the brush used to fill symbol. + */ +void Symbol::setBrush(const QBrush &brush) +{ + m_brush = brush; + update(); +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/associationline.h umbrello-kf6-15.08.1/umbrello/umlwidgets/associationline.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/associationline.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/associationline.h 2015-10-08 11:48:59.508089026 +0300 @@ -0,0 +1,207 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef ASSOCIATIONLINE_H +#define ASSOCIATIONLINE_H + +#include "basictypes.h" + +#include +#include +#include +#include + +// forward declarations +class AssociationWidget; +class QDomDocument; +class QDomElement; +class QPainter; + +/** + * This class provides with various symbols that can be embedded in + * AssociationLine. It also provides with convenience methods to align + * the symbol to AssociationLine. + */ +class Symbol : public QGraphicsItem +{ + public: + typedef QPair SymbolEndPoints; + + /** + * This enumeration lists all the symbols that can be used as + * embedded on AssociationLine. + */ + enum SymbolType { + None = -1, + OpenArrow, + ClosedArrow, + CrowFeet, + Diamond, + Subset, + Circle, + Count + }; + + explicit Symbol(SymbolType symbolType, QGraphicsItem *parent = 0); + virtual ~Symbol(); + + SymbolType symbolType() const; + void setSymbolType(SymbolType symbolType); + + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + + virtual QRectF boundingRect() const; + virtual QPainterPath shape() const; + + void alignTo(const QLineF& line); + SymbolEndPoints symbolEndPoints() const; + + QPen pen() const; + void setPen(const QPen &pen); + + QBrush brush() const; + void setBrush(const QBrush& brush); + + private: + QPen m_pen; ///< pen used to draw Symbol + QBrush m_brush; ///< brush used to fill Symbol + SymbolType m_symbolType; ///< current symbol being represented by this item + + /// A structure to hold a table of values for all symbols. + struct SymbolProperty { + QRectF boundRect; + QPainterPath shape; + QLineF axisLine; + SymbolEndPoints endPoints; + }; + + static SymbolProperty symbolTable[Symbol::Count]; ///< a table which stores all symbol properties + static void setupSymbolTable(); +}; + +/** + * A convenience class that encapsulates geometry management, handles + * mouse and hover events, embeds and aligns symbols and finally draws the + * lines and points. + * Context menu events are handled in AssociationWidget. + * + * This class is infact a draw and event handling proxy for + * AssociationWidget. + * + * @note m_activePointIndex and m_activeSegmentIndex can't be + * active at same time! + * + * @author Gopala Krishna + * @author Andi Fischer + * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org + */ +class AssociationLine : public QGraphicsObject +{ + Q_OBJECT + Q_ENUMS(LayoutType) +public: + enum LayoutType { + Direct = 1, + Orthogonal, + Polyline, + Spline + }; + + static QString toString(LayoutType layout); + static LayoutType fromString(const QString& layout); + + explicit AssociationLine(AssociationWidget *association); + virtual ~AssociationLine(); + + QPointF point(int index) const; + bool setPoint(int index, const QPointF& point); + QPointF startPoint() const; + QPointF endPoint() const; + + void insertPoint(int index, const QPointF& point); + void removePoint(int index); + + int count() const; + void cleanup(); + + void optimizeLinePoints(); + + int closestPointIndex(const QPointF& point, qreal delta = Delta) const; + int closestSegmentIndex(const QPointF& point, qreal delta = Delta) const; + + bool isEndPointIndex(int index) const; + bool isEndSegmentIndex(int index) const; + + bool setEndPoints(const QPointF &start, const QPointF &end); + + void dumpPoints(); + + bool loadFromXMI(QDomElement &qElement); + void saveToXMI(QDomDocument &qDoc, QDomElement &qElement); + + QBrush brush() const; + QPen pen() const; + + virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget); + + QPainterPath path() const; + + QRectF boundingRect() const; + QPainterPath shape() const; + + LayoutType layout() const; + void setLayout(LayoutType layout); + + void mousePressEvent(QGraphicsSceneMouseEvent *event); + void mouseMoveEvent(QGraphicsSceneMouseEvent *event); + void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + + void hoverEnterEvent(QGraphicsSceneHoverEvent *event); + void hoverMoveEvent(QGraphicsSceneHoverEvent *event); + void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); + + void calculateInitialEndPoints(); + + void reconstructSymbols(); + +private: + void setStartSymbol(Symbol::SymbolType symbolType); + void setEndSymbol(Symbol::SymbolType symbolType); + + void createSubsetSymbol(); + void removeSubsetSymbol(); + + void createCollaborationLine(); + void removeCollaborationLine(); + + void alignSymbols(); + + void createSplinePoints(); + + AssociationWidget *m_associationWidget; ///< association widget for which this line represents + QVector m_points; ///< points representing the association line + int m_activePointIndex; ///< index of active point which can be dragged to modify association line + int m_activeSegmentIndex; ///< index of active segment + Symbol *m_startSymbol; ///< symbol drawn at the end of "first" line segment + Symbol *m_endSymbol; ///< symbol drawn at the end of "last" line segment + Symbol *m_subsetSymbol; ///< subset symbol + QGraphicsLineItem *m_collaborationLineItem; ///< parallel arrow line drawn in case of collaboration message + Symbol *m_collaborationLineHead; ///< arrow head drawn at end of m_collaborationLineItem + LayoutType m_layout; + + static QPainterPath createBezierCurve(QVector points); + static QPainterPath createOrthogonalPath(QVector points); + + static const qreal Delta; ///< default delta for fuzzy recognition of points closer to point + static const qreal SelectedPointDiameter; ///< radius of circles drawn to show "selection" + static const qreal SelfAssociationMinimumHeight; ///< minimum height for self association's loop +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/associationwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/associationwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/associationwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/associationwidget.cpp 2015-10-08 11:48:59.508089026 +0300 @@ -0,0 +1,4407 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "associationwidget.h" + +// app includes +#include "association.h" +#include "associationline.h" +#include "associationpropertiesdialog.h" +#include "assocrules.h" +#include "attribute.h" +#include "classifier.h" +#include "classifierwidget.h" +#include "debug_utils.h" +#include "docwindow.h" +#include "entity.h" +#include "floatingtextwidget.h" +#include "listpopupmenu.h" +#include "messagewidget.h" +#include "objectwidget.h" +#include "operation.h" +#include "optionstate.h" +#include "uml.h" +#include "umldoc.h" +#include "umlscene.h" +#include "umlview.h" +#include "umlwidget.h" +#include "widget_utils.h" + +// kde includes +#if QT_VERSION < 0x050000 +#include +#include +#include +#endif +#include + +// qt includes +#if QT_VERSION >= 0x050000 +#include +#include +#include +#endif +#include +#include +#include +#include + +// system includes +#include + +#define DBG_AW() DEBUG(QLatin1String("AssociationWidget")) +DEBUG_REGISTER_DISABLED(AssociationWidget) + +using namespace Uml; + +/** + * Constructor is private because the static create() methods shall + * be used for constructing AssociationWidgets. + * + * @param scene The parent view of this widget. + */ +AssociationWidget::AssociationWidget(UMLScene *scene) + : WidgetBase(scene, WidgetBase::wt_Association), + m_positions_len(0), + m_activated(false), + m_unNameLineSegment(-1), + m_nLinePathSegmentIndex(-1), + m_pAssocClassLine(0), + m_pAssocClassLineSel0(0), + m_pAssocClassLineSel1(0), + m_associationLine(new AssociationLine(this)), + m_associationClass(0), + m_associationType(Uml::AssociationType::Association), + m_nameWidget(0) +{ + // floating text widgets objects owned by this association + m_role[RoleType::A].changeabilityWidget = 0; + m_role[RoleType::B].changeabilityWidget = 0; + m_role[RoleType::A].multiplicityWidget = 0; + m_role[RoleType::B].multiplicityWidget = 0; + m_role[RoleType::A].roleWidget = 0; + m_role[RoleType::B].roleWidget = 0; + m_role[RoleType::A].umlWidget = 0; + m_role[RoleType::B].umlWidget = 0; + + // associationwidget attributes + m_role[RoleType::A].m_WidgetRegion = Uml::Region::Error; + m_role[RoleType::B].m_WidgetRegion = Uml::Region::Error; + m_role[RoleType::A].m_nIndex = 0; + m_role[RoleType::B].m_nIndex = 0; + m_role[RoleType::A].m_nTotalCount = 0; + m_role[RoleType::B].m_nTotalCount = 0; + m_role[RoleType::A].visibility = Uml::Visibility::Public; + m_role[RoleType::B].visibility = Uml::Visibility::Public; + m_role[RoleType::A].changeability = Uml::Changeability::Changeable; + m_role[RoleType::B].changeability = Uml::Changeability::Changeable; + + setFlag(QGraphicsLineItem::ItemIsSelectable); + setAcceptHoverEvents(true); +} + +/** + * This constructor is really only for loading from XMI, otherwise it + * should not be allowed as it creates an incomplete associationwidget. + * + * @param scene The parent view of this widget. + */ +AssociationWidget* AssociationWidget::create(UMLScene *scene) +{ + AssociationWidget* instance = new AssociationWidget(scene); + return instance; +} + +/** + * Preferred constructor (static factory method.) + * + * @param scene The parent view of this widget. + * @param pWidgetA Pointer to the role A widget for the association. + * @param assocType The AssociationType::Enum for this association. + * @param pWidgetB Pointer to the role B widget for the association. + * @param umlobject Pointer to the underlying UMLObject (if applicable.) + */ +AssociationWidget* AssociationWidget::create + (UMLScene *scene, UMLWidget* pWidgetA, + Uml::AssociationType::Enum assocType, UMLWidget* pWidgetB, + UMLObject *umlobject /* = NULL */) +{ + AssociationWidget* instance = new AssociationWidget(scene); + if (umlobject) { + instance->setUMLObject(umlobject); + } else { + // set up UMLAssociation obj if assoc is represented and both roles are UML objects + if (Uml::AssociationType::hasUMLRepresentation(assocType)) { + UMLObject* umlRoleA = pWidgetA->umlObject(); + UMLObject* umlRoleB = pWidgetB->umlObject(); + if (umlRoleA != NULL && umlRoleB != NULL) { + bool swap; + + // This is not correct. We could very easily have more than one + // of the same type of association between the same two objects. + // Just create the association. This search should have been + // done BEFORE creation of the widget, if it mattered to the code. + // But lets leave check in here for the time being so that debugging + // output is shown, in case there is a collision with code elsewhere. + UMLDoc *doc = UMLApp::app()->document(); + UMLAssociation *myAssoc = doc->findAssociation(assocType, umlRoleA, umlRoleB, &swap); + if (myAssoc != NULL) { + switch (assocType) { + case Uml::AssociationType::Generalization: + case Uml::AssociationType::Dependency: + case Uml::AssociationType::Association_Self: + case Uml::AssociationType::Coll_Message_Self: + case Uml::AssociationType::Seq_Message_Self: + case Uml::AssociationType::Containment: + case Uml::AssociationType::Realization: + DBG_AW() << "Ignoring second construction of same assoctype " + << assocType << " between " << umlRoleA->name() + << " and " << umlRoleB->name(); + break; + default: + DBG_AW() << "constructing a similar or exact same assoctype " + << assocType << " between " << umlRoleA->name() << " and " + << umlRoleB->name() << "as an already existing assoc (swap=" + << swap << ")"; + // now, just create a new association anyways + myAssoc = NULL; + break; + } + } + if (myAssoc == NULL) { + myAssoc = new UMLAssociation(assocType, umlRoleA, umlRoleB); + // CHECK: myAssoc is not yet inserted at any parent UMLPackage - + // need to check carefully that all callers do this, lest it be + // orphaned. + // ToolBarStateAssociation::addAssociationInViewAndDoc() is + // okay in this regard. + } + instance->setUMLAssociation(myAssoc); + } + } + } + + instance->setWidgetForRole(pWidgetA, RoleType::A); + instance->setWidgetForRole(pWidgetB, RoleType::B); + + instance->setAssociationType(assocType); + + instance->calculateEndingPoints(); + + instance->associationLine()->calculateInitialEndPoints(); + instance->associationLine()->reconstructSymbols(); + + //The AssociationWidget is set to Activated because it already has its side widgets + instance->setActivated(true); + + // sync UML meta-data to settings here + instance->mergeAssociationDataIntoUMLRepresentation(); + + // Collaboration messages need a name label because it's that + // which lets operator== distinguish them, which in turn + // permits us to have more than one message between two objects. + if (instance->isCollaboration()) { + // Create a temporary name to bring on setName() + int collabID = instance->m_scene->generateCollaborationId(); + instance->setName(QLatin1Char('m') + QString::number(collabID)); + } + + return instance; +} + +/** + * Destructor. + */ +AssociationWidget::~AssociationWidget() +{ + delete m_associationLine; +} + +/** + * Overriding the method from WidgetBase because we need to do + * something extra in case this AssociationWidget represents + * an attribute of a classifier. + */ +void AssociationWidget::setUMLObject(UMLObject *obj) +{ + WidgetBase::setUMLObject(obj); + if (obj == NULL) + return; + UMLClassifier *klass = NULL; + UMLAttribute *attr = NULL; + UMLEntity *ent = NULL; + const UMLObject::ObjectType ot = obj->baseType(); + switch (ot) { + case UMLObject::ot_Association: + setUMLAssociation(dynamic_cast(obj)); + break; + case UMLObject::ot_Operation: + setOperation(dynamic_cast(obj)); + break; + case UMLObject::ot_Attribute: + klass = static_cast(obj->parent()); + connect(klass, SIGNAL(attributeRemoved(UMLClassifierListItem*)), + this, SLOT(slotClassifierListItemRemoved(UMLClassifierListItem*))); + attr = static_cast(obj); + connect(attr, SIGNAL(attributeChanged()), this, SLOT(slotAttributeChanged())); + break; + case UMLObject::ot_EntityAttribute: + ent = static_cast(obj->parent()); + connect(ent, SIGNAL(entityAttributeRemoved(UMLClassifierListItem*)), + this, SLOT(slotClassifierListItemRemoved(UMLClassifierListItem*))); + break; + case UMLObject::ot_ForeignKeyConstraint: + ent = static_cast(obj->parent()); + connect(ent, SIGNAL(entityConstraintRemoved(UMLClassifierListItem*)), + this, SLOT(slotClassifierListItemRemoved(UMLClassifierListItem*))); + break; + default: + uError() << "cannot associate UMLObject of type " << UMLObject::toString(ot); + break; + } +} + +/** + * Set all 'owned' child widgets to this font. + */ +void AssociationWidget::lwSetFont (QFont font) +{ + if (m_nameWidget) { + m_nameWidget->setFont(font); + } + if (m_role[RoleType::A].roleWidget) { + m_role[RoleType::A].roleWidget->setFont(font); + } + if (m_role[RoleType::B].roleWidget) { + m_role[RoleType::B].roleWidget->setFont(font); + } + if (m_role[RoleType::A].multiplicityWidget) { + m_role[RoleType::A].multiplicityWidget->setFont(font); + } + if (m_role[RoleType::B].multiplicityWidget) { + m_role[RoleType::B].multiplicityWidget->setFont(font); + } + if (m_role[RoleType::A].changeabilityWidget) + m_role[RoleType::A].changeabilityWidget->setFont(font); + if (m_role[RoleType::B].changeabilityWidget) + m_role[RoleType::B].changeabilityWidget->setFont(font); +} + +/** + * Overrides operation from LinkWidget. + * Required by FloatingTextWidget. + * @todo Move to LinkWidget. + */ +UMLClassifier *AssociationWidget::operationOwner() +{ + Uml::RoleType::Enum role = (isCollaboration() ? Uml::RoleType::B : Uml::RoleType::A); + UMLObject *o = widgetForRole(role)->umlObject(); + if (!o) { + return 0; + } + UMLClassifier *c = dynamic_cast(o); + if (!c) { + uError() << "widgetForRole(" << role << ") is not a classifier"; + } + return c; +} + +/** + * Implements operation from LinkWidget. + * Motivated by FloatingTextWidget. + */ +UMLOperation *AssociationWidget::operation() +{ + return dynamic_cast(m_umlObject); +} + +/** + * Implements operation from LinkWidget. + * Motivated by FloatingTextWidget. + */ +void AssociationWidget::setOperation(UMLOperation *op) +{ + if (m_umlObject) + disconnect(m_umlObject, SIGNAL(modified()), m_nameWidget, SLOT(setMessageText())); + m_umlObject = op; + if (m_umlObject) + connect(m_umlObject, SIGNAL(modified()), m_nameWidget, SLOT(setMessageText())); + if (m_nameWidget) + m_nameWidget->setMessageText(); +} + +/** + * Overrides operation from LinkWidget. + * Required by FloatingTextWidget. + */ +QString AssociationWidget::customOpText() +{ + return name(); +} + +/** + * Overrides operation from LinkWidget. + * Required by FloatingTextWidget. + */ +void AssociationWidget::setCustomOpText(const QString &opText) +{ + setName(opText); +} + +/** + * Calls setTextPosition on all the labels. + * Overrides operation from LinkWidget. + */ +void AssociationWidget::resetTextPositions() +{ + if (m_role[RoleType::A].multiplicityWidget) { + setTextPosition(TextRole::MultiA); + } + if (m_role[RoleType::B].multiplicityWidget) { + setTextPosition(Uml::TextRole::MultiB); + } + if (m_role[RoleType::A].changeabilityWidget) { + setTextPosition(Uml::TextRole::ChangeA); + } + if (m_role[RoleType::B].changeabilityWidget) { + setTextPosition(Uml::TextRole::ChangeB); + } + if (m_nameWidget) { + setTextPosition(Uml::TextRole::Name); + } + if (m_role[RoleType::A].roleWidget) { + setTextPosition(Uml::TextRole::RoleAName); + } + if (m_role[RoleType::B].roleWidget) { + setTextPosition(Uml::TextRole::RoleBName); + } +} + +/** + * Overrides operation from LinkWidget. + * Required by FloatingTextWidget. + * + * @param ft The text widget which to update. + */ +void AssociationWidget::setMessageText(FloatingTextWidget *ft) +{ + if (isCollaboration()) { + ft->setSequenceNumber(m_SequenceNumber); + if (m_umlObject != NULL) { + ft->setText(operationText(m_scene)); + } else { + ft->setText(name()); + } + } else { + ft->setText(name()); + } +} + +/** + * Sets the text of the given FloatingTextWidget. + * Overrides operation from LinkWidget. + * Required by FloatingTextWidget. + */ +void AssociationWidget::setText(FloatingTextWidget *ft, const QString &text) +{ + Uml::TextRole::Enum role = ft->textRole(); + switch (role) { + case Uml::TextRole::Name: + setName(text); + break; + case Uml::TextRole::RoleAName: + setRoleName(text, RoleType::A); + break; + case Uml::TextRole::RoleBName: + setRoleName(text, RoleType::B); + break; + case Uml::TextRole::MultiA: + setMultiplicity(text, RoleType::A); + break; + case Uml::TextRole::MultiB: + setMultiplicity(text, RoleType::B); + break; + default: + uWarning() << "Unhandled TextRole: " << Uml::TextRole::toString(role); + break; + } +} + +/** + * Shows the association properties dialog and updates the + * corresponding texts if its execution is successful. + */ +void AssociationWidget::showPropertiesDialog() +{ + UMLApp::app()->docWindow()->updateDocumentation(); + QPointer dlg = new AssociationPropertiesDialog(static_cast(m_scene->activeView()), this); + if (dlg->exec()) { + //rules built into these functions to stop updating incorrect values + setName(name()); + + setRoleName(roleName(RoleType::A), RoleType::A); + setRoleName(roleName(RoleType::B), RoleType::B); + + setDocumentation(documentation()); + + setRoleDocumentation(roleDocumentation(RoleType::A), RoleType::A); + setRoleDocumentation(roleDocumentation(RoleType::B), RoleType::B); + + setMultiplicity(multiplicity(RoleType::A), RoleType::A); + setMultiplicity(multiplicity(RoleType::B), RoleType::B); + + setVisibility(visibility(RoleType::A), RoleType::A); + setVisibility(visibility(RoleType::B), RoleType::B); + + setChangeability(changeability(RoleType::A), RoleType::A); + setChangeability(changeability(RoleType::B), RoleType::B); + + UMLApp::app()->docWindow()->showDocumentation(this, true); + } + delete dlg; +} + +/** + * Overrides operation from LinkWidget. + * Required by FloatingTextWidget. + * + * @param op Return this AssociationWidget's operation string. + */ +QString AssociationWidget::lwOperationText() +{ + return name(); +} + +/** + * Overrides operation from LinkWidget. + * Required by FloatingTextWidget. + * + * @return classifier + */ +UMLClassifier* AssociationWidget::lwClassifier() +{ + UMLObject *o = widgetForRole(RoleType::B)->umlObject(); + UMLClassifier *c = dynamic_cast(o); + return c; +} + +/** + * Overrides operation from LinkWidget. + * Required by FloatingTextWidget. + * + * @param op The new operation string to set. + */ +void AssociationWidget::setOperationText(const QString &op) +{ + if (!op.isEmpty()) { + setName(op); + } +} + +/** + * Calculates the m_unNameLineSegment value according to the new + * NameText topleft corner PT. + * It iterates through all AssociationLine's segments and for each one + * calculates the sum of PT's distance to the start point + PT's + * distance to the end point. The segment with the smallest sum will + * be the RoleTextSegment (if this segment moves then the RoleText + * will move with it). It sets m_unNameLineSegment to the start point + * of the chosen segment. + * + * Overrides operation from LinkWidget (i.e. this method is also + * required by FloatingTextWidget.) + */ +void AssociationWidget::calculateNameTextSegment() +{ + if (!m_nameWidget) { + return; + } + //changed to use the middle of the text + //i think this will give a better result. + //never know what sort of lines people come up with + //and text could be long to give a false reading + qreal xt = m_nameWidget->x(); + qreal yt = m_nameWidget->y(); + xt += m_nameWidget->width() / 2; + yt += m_nameWidget->height() / 2; + int size = m_associationLine->count(); + //sum of length(PTP1) and length(PTP2) + qreal total_length = 0; + qreal smallest_length = 0; + for (int i = 0; i < size - 1; ++i) { + QPointF pi = m_associationLine->point( i ); + QPointF pj = m_associationLine->point( i+1 ); + qreal xtiDiff = xt - pi.x(); + qreal xtjDiff = xt - pj.x(); + qreal ytiDiff = yt - pi.y(); + qreal ytjDiff = yt - pj.y(); + total_length = sqrt( double(xtiDiff * xtiDiff + ytiDiff * ytiDiff) ) + + sqrt( double(xtjDiff * xtjDiff + ytjDiff * ytjDiff) ); + //this gives the closest point + if (total_length < smallest_length || i == 0) { + smallest_length = total_length; + m_unNameLineSegment = i; + } + } +} + +/** + * Returns the UMLAssociation representation of this object. + * + * @return Pointer to the UMLAssociation that is represented by + * this AsociationWidget. + */ +UMLAssociation* AssociationWidget::association() const +{ + if (m_umlObject == NULL || m_umlObject->baseType() != UMLObject::ot_Association) + return NULL; + return static_cast(m_umlObject); +} + +/** + * Returns the UMLAttribute representation of this object. + * + * @return Pointer to the UMLAttribute that is represented by + * this AsociationWidget. + */ +UMLAttribute* AssociationWidget::attribute() const +{ + if (m_umlObject == NULL) + return NULL; + UMLObject::ObjectType ot = m_umlObject->baseType(); + if (ot != UMLObject::ot_Attribute && ot != UMLObject::ot_EntityAttribute) + return NULL; + return static_cast(m_umlObject); +} + +#if 0 //:TODO: +/** + * Overrides the assignment operator. + */ +AssociationWidget& AssociationWidget::operator=(const AssociationWidget& other) +{ + *m_associationLine = *other.m_associationLine; + + if (other.m_nameWidget) { + m_nameWidget = new FloatingTextWidget(m_scene); + *m_nameWidget = *(other.m_nameWidget); + } else { + m_nameWidget = NULL; + } + + for (unsigned r = (unsigned)A; r <= (unsigned)B; ++r) { + WidgetRole& lhs = m_role[r]; + const WidgetRole& rhs = other.m_role[r]; + lhs.m_nIndex = rhs.m_nIndex; + lhs.m_nTotalCount = rhs.m_nTotalCount; + + if (rhs.multiplicityWidget) { + lhs.multiplicityWidget = new FloatingTextWidget(m_scene); + *(lhs.multiplicityWidget) = *(rhs.multiplicityWidget); + } else { + lhs.multiplicityWidget = NULL; + } + + if (rhs.roleWidget) { + lhs.roleWidget = new FloatingTextWidget(m_scene); + *(lhs.roleWidget) = *(rhs.roleWidget); + } else { + lhs.roleWidget = NULL; + } + + if (rhs.changeabilityWidget) { + lhs.changeabilityWidget = new FloatingTextWidget(m_scene); + *(lhs.changeabilityWidget) = *(rhs.changeabilityWidget); + } else { + lhs.changeabilityWidget = NULL; + } + + lhs.umlWidget = rhs.umlWidget; + lhs.m_WidgetRegion = rhs.m_WidgetRegion; + } + + m_activated = other.m_activated; + m_unNameLineSegment = other.m_unNameLineSegment; + m_pMenu = other.m_pMenu; + setUMLAssociation(other.association()); + setSelected(other.isSelected()); + + return *this; +} +#endif //:TODO: + +/** + * Overrides the equality test operator. + */ +bool AssociationWidget::operator==(const AssociationWidget& other) const +{ + if (this == &other) + return true; + + // if no model representation exists, then the widgets are not equal + if (association() == NULL && other.association() == NULL) + return false; + + if (!m_umlObject || !other.m_umlObject ) { + if (!other.m_umlObject && m_umlObject) + return false; + if (other.m_umlObject && !m_umlObject) + return false; + + } else if (m_umlObject != other.m_umlObject) + return false; + + if (associationType() != other.associationType()) + return false; + + if (widgetIDForRole(RoleType::A) != other.widgetIDForRole(RoleType::A)) + return false; + + if (widgetIDForRole(RoleType::B) != other.widgetIDForRole(RoleType::B)) + return false; + + if (widgetForRole(RoleType::A)->baseType() == WidgetBase::wt_Object && + other.widgetForRole(RoleType::A)->baseType() == WidgetBase::wt_Object) { + ObjectWidget *ownA = static_cast(widgetForRole(RoleType::A)); + ObjectWidget *otherA = static_cast(other.widgetForRole(RoleType::A)); + if (ownA->localID() != otherA->localID()) + return false; + } + + if (widgetForRole(RoleType::B)->baseType() == WidgetBase::wt_Object && + other.widgetForRole(RoleType::B)->baseType() == WidgetBase::wt_Object) { + ObjectWidget *ownB = static_cast(widgetForRole(RoleType::B)); + ObjectWidget *otherB = static_cast(other.widgetForRole(RoleType::B)); + if (ownB->localID() != otherB->localID()) + return false; + } + + // Two objects in a collaboration can have multiple messages between each other. + // Here we depend on the messages having names, and the names must be different. + // That is the reason why collaboration messages have strange initial names like + // "m29997" or similar. + return (name() == other.name()); +} + +/** + * Overrides the != operator. + */ +bool AssociationWidget::operator!=(AssociationWidget& other) const +{ + return !(*this == other); +} + +/** + * Returns a pointer to the association widget's line path. + */ +AssociationLine* AssociationWidget::associationLine() const +{ + return m_associationLine; +} + +/** + * Activates the AssociationWidget after a load. + * + * @return true for success + */ +bool AssociationWidget::activate() +{ + if (m_umlObject == NULL && + AssociationType::hasUMLRepresentation(m_associationType)) { + UMLObject *myObj = umlDoc()->findObjectById(m_nId); + if (myObj == NULL) { + uError() << "cannot find UMLObject " << Uml::ID::toString(m_nId); + return false; + } else { + const UMLObject::ObjectType ot = myObj->baseType(); + if (ot == UMLObject::ot_Association) { + UMLAssociation * myAssoc = static_cast(myObj); + setUMLAssociation(myAssoc); + } else { + setUMLObject(myObj); + setAssociationType(m_associationType); + } + } + } + + if (m_activated) + return true; + + Uml::AssociationType::Enum type = associationType(); + + if (m_role[RoleType::A].umlWidget == NULL) + setWidgetForRole(m_scene->findWidget(widgetIDForRole(RoleType::A)), RoleType::A); + if (m_role[RoleType::B].umlWidget == NULL) + setWidgetForRole(m_scene->findWidget(widgetIDForRole(RoleType::B)), RoleType::B); + + if (!m_role[RoleType::A].umlWidget || !m_role[RoleType::B].umlWidget) { + DEBUG(DBG_SRC) << "Cannot make association!"; + return false; + } + + calculateEndingPoints(); + + if (AssocRules::allowRole(type)) { + for (unsigned r = RoleType::A; r <= RoleType::B; ++r) { + WidgetRole& robj = m_role[r]; + if (robj.roleWidget == NULL) + continue; + robj.roleWidget->setLink(this); + TextRole::Enum tr = (r == RoleType::A ? TextRole::RoleAName : TextRole::RoleBName); + robj.roleWidget->setTextRole(tr); + Uml::Visibility::Enum vis = visibility(Uml::RoleType::fromInt(r)); + robj.roleWidget->setPreText(Uml::Visibility::toString(vis, true)); + + if (FloatingTextWidget::isTextValid(robj.roleWidget->text())) + robj.roleWidget->show(); + else + robj.roleWidget->hide(); + if (m_scene->type() == DiagramType::Collaboration) + robj.roleWidget->setUMLObject(robj.umlWidget->umlObject()); + robj.roleWidget->activate(); + } + } + + if (m_nameWidget != NULL) { + m_nameWidget->setLink(this); + m_nameWidget->setTextRole(calculateNameType(TextRole::Name)); + + if (FloatingTextWidget::isTextValid(m_nameWidget->text())) { + m_nameWidget->show(); + } else { + m_nameWidget->hide(); + } + m_nameWidget->activate(); + calculateNameTextSegment(); + } + + for (unsigned r = RoleType::A; r <= RoleType::B; ++r) { + WidgetRole& robj = m_role[r]; + + FloatingTextWidget* pMulti = robj.multiplicityWidget; + if (pMulti != NULL && + AssocRules::allowMultiplicity(type, robj.umlWidget->baseType())) { + pMulti->setLink(this); + TextRole::Enum tr = (r == RoleType::A ? TextRole::MultiA : TextRole::MultiB); + pMulti->setTextRole(tr); + if (FloatingTextWidget::isTextValid(pMulti->text())) + pMulti->show(); + else + pMulti->hide(); + pMulti->activate(); + } + + FloatingTextWidget* pChangeWidget = robj.changeabilityWidget; + if (pChangeWidget != NULL) { + pChangeWidget->setLink(this); + TextRole::Enum tr = (r == RoleType::A ? TextRole::ChangeA : TextRole::ChangeB); + pChangeWidget->setTextRole(tr); + if (FloatingTextWidget::isTextValid(pChangeWidget->text())) + pChangeWidget->show(); + else + pChangeWidget->hide (); + pChangeWidget->activate(); + } + } + + // Prepare the association class line if needed. + if (m_associationClass && !m_pAssocClassLine) { + createAssocClassLine(); + } + + m_activated = true; + return true; +} + +/** + * Set the widget of the given role. + * Add this AssociationWidget at the widget. + * If this AssociationWidget has an underlying UMLAssociation then set + * the widget's underlying UMLObject at the UMLAssociation's role object. + * + * @param widget Pointer to the UMLWidget. + * @param role Role for which to set the widget. + */ +void AssociationWidget::setWidgetForRole(UMLWidget* widget, Uml::RoleType::Enum role) +{ + m_role[role].umlWidget = widget; + if (widget) { + m_role[role].umlWidget->addAssoc(this); + if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) + association()->setObject(widget->umlObject(), role); + } +} + +/** + * Return the multiplicity FloatingTextWidget widget of the given role. + * + * @return Pointer to the multiplicity FloatingTextWidget object. + */ +FloatingTextWidget* AssociationWidget::multiplicityWidget(Uml::RoleType::Enum role) const +{ + return m_role[role].multiplicityWidget; +} + +/** + * Read property of FloatingTextWidget* m_nameWidget. + * + * @return Pointer to the FloatingTextWidget name widget. + */ +FloatingTextWidget* AssociationWidget::nameWidget() const +{ + return m_nameWidget; +} + +/** + * Return the given role's FloatingTextWidget object. + * + * @return Pointer to the role's FloatingTextWidget widget. + */ +FloatingTextWidget* AssociationWidget::roleWidget(Uml::RoleType::Enum role) const +{ + return m_role[role].roleWidget; +} + +/** + * Return the given role's changeability FloatingTextWidget widget. + */ +FloatingTextWidget* AssociationWidget::changeabilityWidget(Uml::RoleType::Enum role) const +{ + return m_role[role].changeabilityWidget; +} + +/** + * Return the FloatingTextWidget object indicated by the given TextRole::Enum. + * + * @return Pointer to the text role's FloatingTextWidget widget. + */ +FloatingTextWidget* AssociationWidget::textWidgetByRole(Uml::TextRole::Enum tr) const +{ + switch (tr) { + case Uml::TextRole::MultiA: + return m_role[RoleType::A].multiplicityWidget; + case Uml::TextRole::MultiB: + return m_role[RoleType::B].multiplicityWidget; + case Uml::TextRole::Name: + case Uml::TextRole::Coll_Message: + return m_nameWidget; + case Uml::TextRole::RoleAName: + return m_role[RoleType::A].roleWidget; + case Uml::TextRole::RoleBName: + return m_role[RoleType::B].roleWidget; + case Uml::TextRole::ChangeA: + return m_role[RoleType::A].changeabilityWidget; + case Uml::TextRole::ChangeB: + return m_role[RoleType::B].changeabilityWidget; + default: + break; + } + return NULL; +} + +/** + * Returns the m_nameWidget's text. + * + * @return Text of the FloatingTextWidget name widget. + */ +QString AssociationWidget::name() const +{ + if (m_nameWidget == NULL) + return QString(); + return m_nameWidget->text(); +} + +/** + * Sets the text in the FloatingTextWidget widget representing the Name + * of this association. + */ +void AssociationWidget::setName(const QString &strName) +{ + // set attribute of UMLAssociation associated with this associationwidget + UMLAssociation *umla = association(); + if (umla) + umla->setName(strName); + + bool newLabel = false; + if (!m_nameWidget) { + // Don't construct the FloatingTextWidget if the string is empty. + if (! FloatingTextWidget::isTextValid(strName)) + return; + + newLabel = true; + m_nameWidget = new FloatingTextWidget(m_scene, calculateNameType(Uml::TextRole::Name), strName); + m_nameWidget->setParentItem(this); + m_nameWidget->setLink(this); + } else { + m_nameWidget->setText(strName); + if (! FloatingTextWidget::isTextValid(strName)) { + //m_nameWidget->hide(); + m_scene->removeWidget(m_nameWidget); + m_nameWidget = NULL; + return; + } + } + + setTextPosition(Uml::TextRole::Name); + if (newLabel) { + m_nameWidget->setActivated(); + m_scene->addFloatingTextWidget(m_nameWidget); + } + + m_nameWidget->show(); +} + +void AssociationWidget::setStereotype(const QString &stereo) { + UMLAssociation *umlassoc = association(); + if (umlassoc) { + umlassoc->setStereotype(stereo); + if (m_nameWidget) { + m_nameWidget->setText(umlassoc->stereotype(true)); + } else { + uDebug() << "not setting " << stereo << " because m_nameWidget is NULL"; + } + } else { + uDebug() << "not setting " << stereo << " because association is NULL"; + } +} + +/** + * Return the given role's FloatingTextWidget widget text. + * + * @return The name set at the FloatingTextWidget. + */ +QString AssociationWidget::roleName(Uml::RoleType::Enum role) const +{ + if (m_role[role].roleWidget == NULL) + return QString(); + return m_role[role].roleWidget->text(); +} + +/** + * Sets the text to the FloatingTextWidget that display the Role text of this + * association. + * For this function to work properly, the associated widget + * should already be set. + */ +void AssociationWidget::setRoleName(const QString &strRole, Uml::RoleType::Enum role) +{ + Uml::AssociationType::Enum type = associationType(); + //if the association is not supposed to have a Role FloatingTextWidget + if (!AssocRules::allowRole(type)) { + return; + } + + TextRole::Enum tr = (role == RoleType::A ? TextRole::RoleAName : TextRole::RoleBName); + setFloatingText(tr, strRole, m_role[role].roleWidget); + if (m_role[role].roleWidget) { + Uml::Visibility::Enum vis = visibility(role); + if (FloatingTextWidget::isTextValid(m_role[role].roleWidget->text())) { + m_role[role].roleWidget->setPreText(Uml::Visibility::toString(vis, true)); + //m_role[role].roleWidget->show(); + } else { + m_role[role].roleWidget->setPreText(QString()); + //m_role[role].roleWidget->hide(); + } + } + + // set attribute of UMLAssociation associated with this associationwidget + if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) + association()->setRoleName(strRole, role); +} + +/** + * Set the documentation on the given role. + */ +void AssociationWidget::setRoleDocumentation(const QString &doc, Uml::RoleType::Enum role) +{ + if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) + association()->setRoleDoc(doc, role); + else + m_role[role].roleDocumentation = doc; +} + +/** + * Returns the given role's documentation. + */ +QString AssociationWidget::roleDocumentation(Uml::RoleType::Enum role) const +{ + if (m_umlObject == NULL || m_umlObject->baseType() != UMLObject::ot_Association) + return QString(); + UMLAssociation *umla = static_cast(m_umlObject); + return umla->getRoleDoc(role); +} + +/** + * Change, create, or delete the FloatingTextWidget indicated by the given TextRole::Enum. + * + * @param tr TextRole::Enum of the FloatingTextWidget to change or create. + * @param text Text string that controls the action: + * If empty and ft is NULL then setFloatingText() is a no-op. + * If empty and ft is non-NULL then the existing ft is deleted. + * If non-empty and ft is NULL then a new FloatingTextWidget is created + * and returned in ft with the text set. + * If non-empty and ft is non-NULL then the existing ft text is modified. + * @param ft Reference to the pointer to FloatingTextWidget to change or create. + * On creation/deletion, the pointer value will be changed. + */ +void AssociationWidget::setFloatingText(Uml::TextRole::Enum role, + const QString &text, + FloatingTextWidget* &ft) +{ + if (! FloatingTextWidget::isTextValid(text)) { + if (ft) { + // Remove preexisting FloatingTextWidget + m_scene->removeWidget(ft); // physically deletes ft + ft = NULL; + } + return; + } + + if (ft == NULL) { + ft = new FloatingTextWidget(m_scene, role, text); + ft->setParentItem(this); + ft->setLink(this); + ft->activate(); + setTextPosition(role); + m_scene->addFloatingTextWidget(ft); + } else { + bool newLabel = ft->text().isEmpty(); + ft->setText(text); + if (newLabel) + setTextPosition(role); + } + + ft->show(); +} + +/** + * Return the given role's multiplicity text. + * + * @return Text of the given role's multiplicity widget. + */ +QString AssociationWidget::multiplicity(Uml::RoleType::Enum role) const +{ + if (m_role[role].multiplicityWidget == NULL) + return QString(); + return m_role[role].multiplicityWidget->text(); +} + +/** + * Sets the text in the FloatingTextWidget representing the multiplicity + * at the given side of the association. + */ +void AssociationWidget::setMultiplicity(const QString& text, Uml::RoleType::Enum role) +{ + TextRole::Enum tr = (role == RoleType::A ? TextRole::MultiA : TextRole::MultiB); + + setFloatingText(tr, text, m_role[role].multiplicityWidget); + + if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) + association()->setMultiplicity(text, role); +} + +/** + * Gets the visibility on the given role of the association. + */ +Visibility::Enum AssociationWidget::visibility(Uml::RoleType::Enum role) const +{ + const UMLAssociation *assoc = association(); + if (assoc) + return assoc->visibility(role); + const UMLAttribute *attr = attribute(); + if (attr) + return attr->visibility(); + return m_role[role].visibility; +} + +/** + * Sets the visibility on the given role of the association. + */ +void AssociationWidget::setVisibility(Visibility::Enum value, Uml::RoleType::Enum role) +{ + if (value == visibility(role)) { + return; + } + if (m_umlObject) { + // update our model object + const UMLObject::ObjectType ot = m_umlObject->baseType(); + if (ot == UMLObject::ot_Association) + association()->setVisibility(value, role); + else if (ot == UMLObject::ot_Attribute) + attribute()->setVisibility(value); + } + m_role[role].visibility = value; + // update role pre-text attribute as appropriate + if (m_role[role].roleWidget) { + QString scopeString = Visibility::toString(value, true); + m_role[role].roleWidget->setPreText(scopeString); + } +} + +/** + * Gets the changeability on the given end of the Association. + */ +Uml::Changeability::Enum AssociationWidget::changeability(Uml::RoleType::Enum role) const +{ + if (m_umlObject == NULL || m_umlObject->baseType() != UMLObject::ot_Association) + return m_role[role].changeability; + UMLAssociation *umla = static_cast(m_umlObject); + return umla->changeability(role); +} + +/** + * Sets the changeability on the given end of the Association. + */ +void AssociationWidget::setChangeability(Uml::Changeability::Enum value, Uml::RoleType::Enum role) +{ + if (value == changeability(role)) + return; + QString changeString = Uml::Changeability::toString(value); + if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) // update our model object + association()->setChangeability(value, role); + m_role[role].changeability = value; + // update our string representation + setChangeWidget(changeString, role); +} + +/** + * For internal purpose-kf6s only. + * Other classes/users should use setChangeability() instead. + */ +void AssociationWidget::setChangeWidget(const QString &strChangeWidget, Uml::RoleType::Enum role) +{ + bool newLabel = false; + TextRole::Enum tr = (role == RoleType::A ? TextRole::ChangeA : TextRole::ChangeB); + + if (!m_role[role].changeabilityWidget) { + // Don't construct the FloatingTextWidget if the string is empty. + if (strChangeWidget.isEmpty()) + return; + + newLabel = true; + m_role[role].changeabilityWidget = new FloatingTextWidget(m_scene, tr, strChangeWidget); + m_role[role].changeabilityWidget->setParentItem(this); + m_role[role].changeabilityWidget->setLink(this); + m_scene->addFloatingTextWidget(m_role[role].changeabilityWidget); + m_role[role].changeabilityWidget->setPreText(QLatin1String("{")); // all types have this + m_role[role].changeabilityWidget->setPostText(QLatin1String("}")); // all types have this + } else { + if (m_role[role].changeabilityWidget->text().isEmpty()) { + newLabel = true; + } + m_role[role].changeabilityWidget->setText(strChangeWidget); + } + m_role[role].changeabilityWidget->setActivated(); + + if (newLabel) { + setTextPosition(tr); + } + + if (FloatingTextWidget::isTextValid(m_role[role].changeabilityWidget->text())) + m_role[role].changeabilityWidget->show(); + else + m_role[role].changeabilityWidget->hide(); +} + +/** + * Returns true if the line path starts at the given widget. + */ +bool AssociationWidget::linePathStartsAt(const UMLWidget* widget) +{ +//:TODO: +// QPointF lpStart = m_associationLine->point(0); +// int startX = lpStart.x(); +// int startY = lpStart.y(); +// int wX = widget->x(); +// int wY = widget->y(); +// int wWidth = widget->width(); +// int wHeight = widget->height(); +// bool result = (startX >= wX && startX <= wX + wWidth && +// startY >= wY && startY <= wY + wHeight); +// return result; + bool result = widget->contains(m_associationLine->point(0)); + DEBUG(DBG_SRC) << "widget=" << widget->name() << " / result=" << result; + return result; +} + +/** + * This function calculates which role should be set for the m_nameWidget FloatingTextWidget. + */ +Uml::TextRole::Enum AssociationWidget::calculateNameType(Uml::TextRole::Enum defaultRole) +{ + TextRole::Enum result = defaultRole; + if (m_scene->type() == DiagramType::Collaboration) { + if (m_role[RoleType::A].umlWidget == m_role[RoleType::B].umlWidget) { + result = TextRole::Coll_Message;//for now same as other Coll_Message + } else { + result = TextRole::Coll_Message; + } + } else if (m_scene->type() == DiagramType::Sequence) { + if (m_role[RoleType::A].umlWidget == m_role[RoleType::B].umlWidget) { + result = TextRole::Seq_Message_Self; + } else { + result = TextRole::Seq_Message; + } + } + + return result; +} + +/** + * Gets the given role widget. + * + * @return Pointer to the role's UMLWidget. + */ +UMLWidget* AssociationWidget::widgetForRole(Uml::RoleType::Enum role) const +{ + return m_role[role].umlWidget; +} + +/** + * Sets the associated widgets. + * + * @param widgetA Pointer the role A widget for the association. + * @param assocType The AssociationType::Enum for this association. + * @param widgetB Pointer the role B widget for the association. + */ +bool AssociationWidget::setWidgets(UMLWidget* widgetA, + Uml::AssociationType::Enum assocType, + UMLWidget* widgetB) +{ + //if the association already has a WidgetB or WidgetA associated, then + //it cannot be changed to other widget, that would require a deletion + //of the association and the creation of a new one + if ((m_role[RoleType::A].umlWidget && (m_role[RoleType::A].umlWidget != widgetA)) || + (m_role[RoleType::B].umlWidget && (m_role[RoleType::B].umlWidget != widgetB))) { + return false; + } + setWidgetForRole(widgetA, RoleType::A); + setAssociationType(assocType); + setWidgetForRole(widgetB, RoleType::B); + + calculateEndingPoints(); + return true; +} + +/** + * CleansUp all the association's data in the related widgets. + */ +void AssociationWidget::cleanup() +{ + //let any other associations know we are going so they can tidy their positions up + if (m_role[RoleType::A].m_nTotalCount > 2) + updateAssociations(m_role[RoleType::A].m_nTotalCount - 1, m_role[RoleType::A].m_WidgetRegion, RoleType::A); + if (m_role[RoleType::B].m_nTotalCount > 2) + updateAssociations(m_role[RoleType::B].m_nTotalCount - 1, m_role[RoleType::B].m_WidgetRegion, RoleType::B); + + for (unsigned r = RoleType::A; r <= RoleType::B; ++r) { + WidgetRole& robj = m_role[r]; + + if (robj.umlWidget) { + robj.umlWidget->removeAssoc(this); + robj.umlWidget = 0; + } + if (robj.roleWidget) { + m_scene->removeWidget(robj.roleWidget); + robj.roleWidget = 0; + } + if (robj.multiplicityWidget) { + m_scene->removeWidget(robj.multiplicityWidget); + robj.multiplicityWidget = 0; + } + if (robj.changeabilityWidget) { + m_scene->removeWidget(robj.changeabilityWidget); + robj.changeabilityWidget = 0; + } + } + + if (m_nameWidget) { + m_scene->removeWidget(m_nameWidget); + m_nameWidget = 0; + } + + if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) { + /* + We do not remove the UMLAssociation from the document. + Why? - Well, for example we might be in the middle of + a cut/paste. If the UMLAssociation is removed by the cut + then upon pasteing we have a problem. + This is not quite clean yet - there should be a way to + explicitly delete a UMLAssociation. The Right Thing would + be to have a ListView representation for UMLAssociation. + ` + IF we are cut n pasting, why are we handling this association as a pointer? + We should be using the XMI representation for a cut and paste. This + allows us to be clean here, AND a choice of recreating the object + w/ same id IF its a "cut", or a new object if its a "copy" operation + (in which case we wouldnt be here, in cleanup()). + */ + setUMLAssociation(0); + } + + m_associationLine->cleanup(); + removeAssocClassLine(); +} + +/** + * @brief Return state if the assocation line point in the near of the last context + * menu event position is addable or not. + * A point is addable if the association is not an Exception and there is no point in the near. + * + * @return true if point is addable + */ +bool AssociationWidget::isPointAddable() +{ + if (!isSelected() || associationType() == Uml::AssociationType::Exception) + return false; + int i = m_associationLine->closestPointIndex(m_eventScenePos); + return i == -1; +} + +/** + * @brief Return state if the assocation line point in the near of the last context + * menu event position is removable or not. + * A point is removable if the association is not an Exception and is not the start or end point. + * + * @return true if point is removable + */ +bool AssociationWidget::isPointRemovable() +{ + if (!isSelected() || associationType() == Uml::AssociationType::Exception || m_associationLine->count() <= 2) + return false; + int i = m_associationLine->closestPointIndex(m_eventScenePos); + return i > 0 && i < m_associationLine->count() - 1; +} + +/** + * Set our internal umlAssociation. + */ +void AssociationWidget::setUMLAssociation (UMLAssociation * assoc) +{ + if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) { + UMLAssociation *umla = association(); + + // safety check. Did some num-nuts try to set the existing + // association again? If so, just bail here + if (umla == assoc) + return; + + //umla->disconnect(this); //Qt does disconnect automatically upon destruction. + umla->nrof_parent_widgets--; + + // ANSWER: This is the wrong treatment of cut and paste. Associations that + // are being cut/n pasted should be serialized to XMI, then reconstituted + // (IF a paste operation) rather than passing around object pointers. Its + // just too hard otherwise to prevent problems in the code. Bottom line: we need to + // delete orphaned associations or we well get code crashes and memory leaks. + if (umla->nrof_parent_widgets <= 0) { + //umla->deleteLater(); + } + + m_umlObject = NULL; + } + + if (assoc) { + m_umlObject = assoc; + + // move counter to "0" from "-1" (which means, no assocwidgets) + if (assoc->nrof_parent_widgets < 0) + assoc->nrof_parent_widgets = 0; + + assoc->nrof_parent_widgets++; + connect(assoc, SIGNAL(modified()), this, SLOT(syncToModel())); + } + +} + +/** + * Returns true if the Widget is either at the starting or ending side of the association. + */ +bool AssociationWidget::containsAsEndpoint(UMLWidget* widget) +{ + return (widget == m_role[RoleType::A].umlWidget || widget == m_role[RoleType::B].umlWidget); +} + +/** + * Returns true if this AssociationWidget represents a collaboration message. + */ +bool AssociationWidget::isCollaboration() const +{ + Uml::AssociationType::Enum at = associationType(); + return (at == AssociationType::Coll_Message_Synchronous + || at == AssociationType::Coll_Message_Asynchronous + || at == AssociationType::Coll_Message_Self); +} + +/** + * Returns true if this AssociationWidget represents a self message. + */ +bool AssociationWidget::isSelf() const +{ + return widgetForRole(Uml::RoleType::A) == widgetForRole(Uml::RoleType::B); +} + +/** + * Gets the association's type. + * + * @return This AssociationWidget's AssociationType::Enum. + */ +Uml::AssociationType::Enum AssociationWidget::associationType() const +{ + if (m_umlObject == NULL || m_umlObject->baseType() != UMLObject::ot_Association) + return m_associationType; + UMLAssociation *umla = static_cast(m_umlObject); + return umla->getAssocType(); +} + +/** + * Sets the association's type. + * + * @param type The AssociationType::Enum to set. + */ +void AssociationWidget::setAssociationType(Uml::AssociationType::Enum type) +{ + if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) { + association()->setAssociationType(type); + } + m_associationType = type; + // If the association new type is not supposed to have Multiplicity + // FloatingTexts and a Role FloatingTextWidget then set the texts + // to empty. + // NB We do not physically delete the floatingtext widgets here because + // those widgets are also stored in the UMLView::m_WidgetList. + if (!AssocRules::allowMultiplicity(type, widgetForRole(RoleType::A)->baseType())) { + if (m_role[RoleType::A].multiplicityWidget) { + m_role[RoleType::A].multiplicityWidget->setName(QString()); + } + if (m_role[RoleType::B].multiplicityWidget) { + m_role[RoleType::B].multiplicityWidget->setName(QString()); + } + } + if (!AssocRules::allowRole(type)) { + if (m_role[RoleType::A].roleWidget) { + m_role[RoleType::A].roleWidget->setName(QString()); + } + if (m_role[RoleType::B].roleWidget) { + m_role[RoleType::B].roleWidget->setName(QString()); + } + setRoleDocumentation(QString(), RoleType::A); + setRoleDocumentation(QString(), RoleType::B); + } + m_associationLine->reconstructSymbols(); +} + +/** + * Gets the ID of the given role widget. + */ +Uml::ID::Type AssociationWidget::widgetIDForRole(Uml::RoleType::Enum role) const +{ + if (m_role[role].umlWidget == NULL) { + if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) { + UMLAssociation *umla = static_cast(m_umlObject); + return umla->getObjectId(role); + } + uError() << "umlWidget is NULL"; + return Uml::ID::None; + } + if (m_role[role].umlWidget->baseType() == WidgetBase::wt_Object) + return static_cast(m_role[role].umlWidget)->localID(); + Uml::ID::Type id = m_role[role].umlWidget->id(); + return id; +} + +/** + * Gets the local ID of the given role widget. + */ +Uml::ID::Type AssociationWidget::widgetLocalIDForRole(Uml::RoleType::Enum role) const +{ + if (m_role[role].umlWidget == NULL) { + if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) { + UMLAssociation *umla = static_cast(m_umlObject); + return umla->getObjectId(role); + } + uError() << "umlWidget is NULL"; + return Uml::ID::None; + } + if (m_role[role].umlWidget->baseType() == WidgetBase::wt_Object) + return static_cast(m_role[role].umlWidget)->localID(); + Uml::ID::Type id = m_role[role].umlWidget->localID(); + return id; +} + +/** + * Returns a QString Object representing this AssociationWidget. + */ +QString AssociationWidget::toString() const +{ + QString string; + static const QChar colon(QLatin1Char(':')); + + if (widgetForRole(RoleType::A)) { + string = widgetForRole(RoleType::A)->name(); + } + string.append(colon); + + if (m_role[RoleType::A].roleWidget) { + string += m_role[RoleType::A].roleWidget->text(); + } + string.append(colon); + string.append(Uml::AssociationType::toStringI18n(associationType())); + string.append(colon); + + if (widgetForRole(RoleType::B)) { + string += widgetForRole(RoleType::B)->name(); + } + + string.append(colon); + if (m_role[RoleType::B].roleWidget) { + string += m_role[RoleType::B].roleWidget->text(); + } + + return string; +} + +/** + * Adds a break point (if left mouse button). + */ +void AssociationWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) { + uDebug() << "widget = " << name() << " / type = " << baseTypeStr(); + showPropertiesDialog(); + event->accept(); + } +} + +/** + * Overrides moveEvent. + */ +void AssociationWidget::moveEvent(QGraphicsSceneMouseEvent *me) +{ + // 2004-04-30: Achim Spangler + // Simple Approach to block moveEvent during load of XMI + /// @todo avoid trigger of this event during load + + if (umlDoc()->loading()) { + // hmmh - change of position during load of XMI + // -> there is something wrong + // -> avoid movement during opening + // -> print warn and stay at old position + uWarning() << "called during load of XMI for ViewType: " + << m_scene->type() << ", and BaseType: " << baseType(); + return; + } + /*to be here a line segment has moved. + we need to see if the three text widgets needs to be moved. + there are a few things to check first though: + + 1) Do they exist + 2) does it need to move: + 2a) for the multi widgets only move if they changed region, otherwise they are close enough + 2b) for role name move if the segment it is on moves. + */ + //first see if either the first or last segments moved, else no need to recalculate their point positions + + QPointF oldNamePoint = calculateTextPosition(TextRole::Name); + QPointF oldMultiAPoint = calculateTextPosition(TextRole::MultiA); + QPointF oldMultiBPoint = calculateTextPosition(TextRole::MultiB); + QPointF oldChangeAPoint = calculateTextPosition(TextRole::ChangeA); + QPointF oldChangeBPoint = calculateTextPosition(TextRole::ChangeB); + QPointF oldRoleAPoint = calculateTextPosition(TextRole::RoleAName); + QPointF oldRoleBPoint = calculateTextPosition(TextRole::RoleBName); + + int movingPoint = m_associationLine->closestPointIndex(me->scenePos()); + if (movingPoint != -1) + m_associationLine->setPoint(movingPoint, me->scenePos()); + int pos = m_associationLine->count() - 1;//set to last point for widget b + + if ( movingPoint == 1 || (movingPoint == pos-1) ) { + calculateEndingPoints(); + } + if (m_role[RoleType::A].changeabilityWidget && (movingPoint == 1)) { + setTextPositionRelatively(TextRole::ChangeA, oldChangeAPoint); + } + if (m_role[RoleType::B].changeabilityWidget && (movingPoint == 1)) { + setTextPositionRelatively(TextRole::ChangeB, oldChangeBPoint); + } + if (m_role[RoleType::A].multiplicityWidget && (movingPoint == 1)) { + setTextPositionRelatively(TextRole::MultiA, oldMultiAPoint); + } + if (m_role[RoleType::B].multiplicityWidget && (movingPoint == pos-1)) { + setTextPositionRelatively(TextRole::MultiB, oldMultiBPoint); + } + + if (m_nameWidget) { + if (movingPoint == m_unNameLineSegment || + movingPoint - 1 == m_unNameLineSegment) { + setTextPositionRelatively(TextRole::Name, oldNamePoint); + } + } + + if (m_role[RoleType::A].roleWidget) { + setTextPositionRelatively(TextRole::RoleAName, oldRoleAPoint); + } + if (m_role[RoleType::B].roleWidget) { + setTextPositionRelatively(TextRole::RoleBName, oldRoleBPoint); + } + + if (m_pAssocClassLine) { + computeAssocClassLine(); + } +} + +/** + * Calculates and sets the first and last point in the Association's AssociationLine. + * Each point is a middle point of its respecting UMLWidget's Bounding rectangle + * or a corner of it. + * This method picks which sides to use for the association. + */ +void AssociationWidget::calculateEndingPoints() +{ + /* + * For each UMLWidget the diagram is divided in four regions by its diagonals + * as indicated below + * Region 2 + * \ / + * \ / + * +--------+ + * | \ / | + * Region 1 | >< | Region 3 + * | / \ | + * +--------+ + * / \ + * / \ + * Region 4 + * + * Each diagonal is defined by two corners of the bounding rectangle + * + * To calculate the first point in the AssociationLine we have to find out in which + * Region (defined by WidgetA's diagonals) is WidgetB's center + * (let's call it Region M.) After that the first point will be the middle + * point of the rectangle's side contained in Region M. + * + * To calculate the last point in the AssociationLine we repeat the above but + * in the opposite direction (from widgetB to WidgetA) + */ + + UMLWidget *pWidgetA = m_role[RoleType::A].umlWidget; + UMLWidget *pWidgetB = m_role[RoleType::B].umlWidget; + if (!pWidgetA || !pWidgetB) { + uWarning() << "Returning - one of the role widgets is not set."; + return; + } + + int size = m_associationLine->count(); + if (size < 2) { + QPointF pA = pWidgetA->pos(); + QPointF pB = pWidgetB->pos(); + QPolygonF polyA = pWidgetA->shape().toFillPolygon().translated(pA); + QPolygonF polyB = pWidgetB->shape().toFillPolygon().translated(pB); + QLineF nearestPoints = Widget_Utils::closestPoints(polyA, polyB); + if (nearestPoints.isNull()) { + uError() << "Widget_Utils::closestPoints failed, falling back to simple widget positions"; + } else { + pA = nearestPoints.p1(); + pB = nearestPoints.p2(); + } + m_associationLine->setEndPoints(pA, pB); + } + + // See if an association to self. + // See if it needs to be set up before we continue: + // If self association/message and doesn't have the minimum 4 points + // then create it. Make sure no points are out of bounds of viewing area. + // This only happens on first time through that we are worried about. + if (isSelf() && size < 4) { + createPointsSelfAssociation(); + return; + } + + if (associationType() == AssociationType::Exception && size < 4) { + createPointsException(); + updatePointsException(); + return; + } + + // If the line has more than one segment change the values to calculate + // from widget to point 1. + qreal xB = pWidgetB->x() + pWidgetB->width() / 2; + qreal yB = pWidgetB->y() + pWidgetB->height() / 2; + if (size > 2) { + QPointF p = m_associationLine->point(1); + xB = p.x(); + yB = p.y(); + } + doUpdates(QPointF(xB, yB), RoleType::A); + + // Now do the same for widgetB. + // If the line has more than one segment change the values to calculate + // from widgetB to the last point away from it. + qreal xA = pWidgetA->x() + pWidgetA->width() / 2; + qreal yA = pWidgetA->y() + pWidgetA->height() / 2; + if (size > 2 ) { + QPointF p = m_associationLine->point(size - 2); + xA = p.x(); + yA = p.y(); + } + doUpdates(QPointF(xA, yA), RoleType::B); + + computeAssocClassLine(); +} + +/** + * Used by @ref calculateEndingPoints. + */ +void AssociationWidget::doUpdates(const QPointF &otherP, RoleType::Enum role) +{ + // Find widget region. + Uml::Region::Enum oldRegion = m_role[role].m_WidgetRegion; + UMLWidget *pWidget = m_role[role].umlWidget; + QRectF rc(pWidget->x(), pWidget->y(), + pWidget->width(), pWidget->height()); + Uml::Region::Enum region = m_role[role].m_WidgetRegion; // alias for brevity + region = findPointRegion(rc, otherP); + // Move some regions to the standard ones. + switch( region ) { + case Uml::Region::NorthWest: + region = Uml::Region::North; + break; + case Uml::Region::NorthEast: + region = Uml::Region::East; + break; + case Uml::Region::SouthEast: + region = Uml::Region::South; + break; + case Uml::Region::SouthWest: + case Uml::Region::Center: + region = Uml::Region::West; + break; + default: + break; + } + int regionCount = getRegionCount(region, role) + 2; //+2 = (1 for this one and one to halve it) + int totalCount = m_role[role].m_nTotalCount; + if (oldRegion != region) { + updateRegionLineCount(regionCount - 1, regionCount, region, role); + updateAssociations(totalCount - 1, oldRegion, role); + } else if (totalCount != regionCount) { + updateRegionLineCount(regionCount - 1, regionCount, region, role); + } else { + updateRegionLineCount(m_role[role].m_nIndex, totalCount, region, role); + } + updateAssociations(regionCount, region, role); +} + +/** + * Read property of bool m_activated. + */ +bool AssociationWidget::isActivated() const +{ + return m_activated; +} + +/** + * Set the m_activated flag of a widget but does not perform the Activate method. + */ +void AssociationWidget::setActivated(bool active) +{ + m_activated = active; +} + +/** + * Synchronize this widget from the UMLAssociation. + */ +void AssociationWidget::syncToModel() +{ + UMLAssociation *uml = association(); + + if (uml == NULL) { + UMLAttribute *attr = attribute(); + if (attr == NULL) + return; + setVisibility(attr->visibility(), RoleType::B); + setRoleName(attr->name(), RoleType::B); + return; + } + // block signals until finished + uml->blockSignals(true); + + setName(uml->name()); + setRoleName(uml->getRoleName(RoleType::A), RoleType::A); + setRoleName(uml->getRoleName(RoleType::B), RoleType::B); + setVisibility(uml->visibility(RoleType::A), RoleType::A); + setVisibility(uml->visibility(RoleType::B), RoleType::B); + setChangeability(uml->changeability(RoleType::A), RoleType::A); + setChangeability(uml->changeability(RoleType::B), RoleType::B); + setMultiplicity(uml->getMultiplicity(RoleType::A), RoleType::A); + setMultiplicity(uml->getMultiplicity(RoleType::B), RoleType::B); + + uml->blockSignals(false); +} + +/** + * Merges/syncs the association widget data into UML object + * representation. + * This will synchronize UMLAssociation w/ this new Widget + * CHECK: Can we get rid of this. + */ +void AssociationWidget::mergeAssociationDataIntoUMLRepresentation() +{ + UMLAssociation *umlassoc = association(); + UMLAttribute *umlattr = attribute(); + if (umlassoc == NULL && umlattr == NULL) + return; + + // block emit modified signal, or we get a horrible loop + m_umlObject->blockSignals(true); + + // would be desirable to do the following + // so that we can be sure its back to initial state + // in case we missed something here. + //uml->init(); + + // floating text widgets + FloatingTextWidget *text = nameWidget(); + if (text) + m_umlObject->setName(text->text()); + + text = roleWidget(RoleType::A); + if (text && umlassoc) + umlassoc->setRoleName(text->text(), RoleType::A); + + text = roleWidget(RoleType::B); + if (text) { + if (umlassoc) + umlassoc->setRoleName(text->text(), RoleType::B); + else if (umlattr) + umlattr->setName(text->text()); + } + + text = multiplicityWidget(RoleType::A); + if (text && umlassoc) + umlassoc->setMultiplicity(text->text(), RoleType::A); + + text = multiplicityWidget(RoleType::B); + if (text && umlassoc) + umlassoc->setMultiplicity(text->text(), RoleType::B); + + // unblock + m_umlObject->blockSignals(false); +} + +/** + * Auxiliary method for widgetMoved(): + * Saves all ideally computed floatingtext positions before doing any + * kind of change. This is necessary because a single invocation of + * calculateEndingPoints() modifies the AssociationLine ending points on ALL + * AssociationWidgets. This means that if we don't save the old ideal + * positions then they are irretrievably lost as soon as + * calculateEndingPoints() is invoked. + */ +void AssociationWidget::saveIdealTextPositions() +{ + m_oldNamePoint = calculateTextPosition(TextRole::Name); + m_oldMultiAPoint = calculateTextPosition(TextRole::MultiA); + m_oldMultiBPoint = calculateTextPosition(TextRole::MultiB); + m_oldChangeAPoint = calculateTextPosition(TextRole::ChangeA); + m_oldChangeBPoint = calculateTextPosition(TextRole::ChangeB); + m_oldRoleAPoint = calculateTextPosition(TextRole::RoleAName); + m_oldRoleBPoint = calculateTextPosition(TextRole::RoleBName); +} + +/** + * Adjusts the ending point of the association that connects to Widget. + */ +void AssociationWidget::widgetMoved(UMLWidget* widget, qreal dx, qreal dy) +{ + Q_UNUSED(dx); Q_UNUSED(dy); + + // Simple Approach to block moveEvent during load of XMI + /// @todo avoid trigger of this event during load + if (umlDoc()->loading()) { + // change of position during load of XMI + // -> there is something wrong + // -> avoid movement during opening + // -> print warn and stay at old position + DEBUG(DBG_SRC) << "called during load of XMI for ViewType: " << m_scene->type() + << ", and BaseType: " << baseTypeStr(); + return; + } + + DEBUG(DBG_SRC) << "association type=" << Uml::AssociationType::toString(associationType()); + if (associationType() == AssociationType::Exception) { + updatePointsException(); + setTextPosition(TextRole::Name); + } + else { + calculateEndingPoints(); + computeAssocClassLine(); + } + + // Assoc to self - move all points: + if (isSelf()) { + updatePointsSelfAssociation(); + + if (m_nameWidget && !m_nameWidget->isSelected()) { + setTextPositionRelatively(TextRole::Name, m_oldNamePoint); + } + + }//end if widgetA = widgetB + else if (m_role[RoleType::A].umlWidget == widget) { + if (m_nameWidget && m_unNameLineSegment == 0 && !m_nameWidget->isSelected() ) { + //only calculate position and move text if the segment it is on is moving + setTextPositionRelatively(TextRole::Name, m_oldNamePoint); + } + }//end if widgetA moved + else if (m_role[RoleType::B].umlWidget == widget) { + const int size = m_associationLine->count(); + if (m_nameWidget && (m_unNameLineSegment == size-2) && !m_nameWidget->isSelected() ) { + //only calculate position and move text if the segment it is on is moving + setTextPositionRelatively(TextRole::Name, m_oldNamePoint); + } + }//end if widgetB moved + + if (m_role[RoleType::A].roleWidget && !m_role[RoleType::A].roleWidget->isSelected()) { + setTextPositionRelatively(TextRole::RoleAName, m_oldRoleAPoint); + } + if (m_role[RoleType::B].roleWidget && !m_role[RoleType::B].roleWidget->isSelected()) { + setTextPositionRelatively(TextRole::RoleBName, m_oldRoleBPoint); + } + if (m_role[RoleType::A].multiplicityWidget && !m_role[RoleType::A].multiplicityWidget->isSelected()) { + setTextPositionRelatively(TextRole::MultiA, m_oldMultiAPoint); + } + if (m_role[RoleType::B].multiplicityWidget && !m_role[RoleType::B].multiplicityWidget->isSelected()) { + setTextPositionRelatively(TextRole::MultiB, m_oldMultiBPoint); + } + if (m_role[RoleType::A].changeabilityWidget && !m_role[RoleType::A].changeabilityWidget->isSelected()) { + setTextPositionRelatively(TextRole::ChangeA, m_oldChangeAPoint); + } + if (m_role[RoleType::B].changeabilityWidget && !m_role[RoleType::B].changeabilityWidget->isSelected()) { + setTextPositionRelatively(TextRole::ChangeB, m_oldChangeBPoint); + } +} + +/** + * Creates the points of the self association. + * Method called when a widget end points are calculated by calculateEndingPoints(). + */ +void AssociationWidget::createPointsSelfAssociation() +{ + UMLWidget *pWidgetA = m_role[RoleType::A].umlWidget; + + const int DISTANCE = 50; + qreal x = pWidgetA->x(); + qreal y = pWidgetA->y(); + qreal h = pWidgetA->height(); + qreal w = pWidgetA->width(); + // see if above widget ok to start + if (y - DISTANCE > 0) { + m_associationLine->setEndPoints(QPointF(x + w / 4, y) , QPointF(x + w * 3 / 4, y)); + m_associationLine->insertPoint(1, QPointF(x + w / 4, y - DISTANCE)); + m_associationLine->insertPoint(2, QPointF(x + w * 3 / 4, y - DISTANCE)); + m_role[RoleType::A].m_WidgetRegion = m_role[RoleType::B].m_WidgetRegion = Uml::Region::North; + } else { + m_associationLine->setEndPoints(QPointF(x + w / 4, y + h), QPointF(x + w * 3 / 4, y + h)); + m_associationLine->insertPoint(1, QPointF(x + w / 4, y + h + DISTANCE)); + m_associationLine->insertPoint(2, QPointF(x + w * 3 / 4, y + h + DISTANCE)); + m_role[RoleType::A].m_WidgetRegion = m_role[RoleType::B].m_WidgetRegion = Uml::Region::South; + } +} + +/** + * Adjusts the points of the self association. + * Method called when a widget was moved by widgetMoved(widget, x, y). + */ +void AssociationWidget::updatePointsSelfAssociation() +{ + UMLWidget *pWidgetA = m_role[RoleType::A].umlWidget; + + const int DISTANCE = 50; + qreal x = pWidgetA->x(); + qreal y = pWidgetA->y(); + qreal h = pWidgetA->height(); + qreal w = pWidgetA->width(); + // see if above widget ok to start + if (y - DISTANCE > 0) { + m_associationLine->setEndPoints(QPointF(x + w / 4, y) , QPointF(x + w * 3 / 4, y)); + m_associationLine->setPoint(1, QPointF(x + w / 4, y - DISTANCE)); + m_associationLine->setPoint(2, QPointF(x + w * 3 / 4, y - DISTANCE)); + m_role[RoleType::A].m_WidgetRegion = m_role[RoleType::B].m_WidgetRegion = Uml::Region::North; + } else { + m_associationLine->setEndPoints(QPointF(x + w / 4, y + h), QPointF(x + w * 3 / 4, y + h)); + m_associationLine->setPoint(1, QPointF(x + w / 4, y + h + DISTANCE)); + m_associationLine->setPoint(2, QPointF(x + w * 3 / 4, y + h + DISTANCE)); + m_role[RoleType::A].m_WidgetRegion = m_role[RoleType::B].m_WidgetRegion = Uml::Region::South; + } +} + +/** + * Creates the points of the association exception. + * Method called when a widget end points are calculated by calculateEndingPoints(). + */ +void AssociationWidget::createPointsException() +{ + UMLWidget *pWidgetA = m_role[RoleType::A].umlWidget; + UMLWidget *pWidgetB = m_role[RoleType::B].umlWidget; + + qreal xa = pWidgetA->x(); + qreal ya = pWidgetA->y(); + qreal ha = pWidgetA->height(); + qreal wa = pWidgetA->width(); + + qreal xb = pWidgetB->x(); + qreal yb = pWidgetB->y(); + qreal hb = pWidgetB->height(); + //qreal wb = pWidgetB->width(); + + m_associationLine->setEndPoints(QPointF(xa + wa , ya + ha/2) , QPointF(xb , yb + hb/2)); + m_associationLine->insertPoint(1, QPointF(xa + wa , ya + ha/2)); + m_associationLine->insertPoint(2, QPointF(xb , yb + hb/2)); +} + +/** + * Adjusts the points of the association exception. + * Method called when a widget was moved by widgetMoved(widget, x, y). + */ +void AssociationWidget::updatePointsException() +{ + UMLWidget *pWidgetA = m_role[RoleType::A].umlWidget; + UMLWidget *pWidgetB = m_role[RoleType::B].umlWidget; + + qreal xa = pWidgetA->x(); + qreal ya = pWidgetA->y(); + qreal ha = pWidgetA->height(); + qreal wa = pWidgetA->width(); + + qreal xb = pWidgetB->x(); + qreal yb = pWidgetB->y(); + qreal hb = pWidgetB->height(); + qreal wb = pWidgetB->width(); + qreal xmil, ymil; + qreal xdeb, ydeb; + qreal xfin, yfin; + qreal ESPACEX, ESPACEY; + QPointF p1; + QPointF p2; + //calcul des coordonnées au milieu de la flèche eclair + if (xb - xa - wa >= 45) { + ESPACEX = 0; + xdeb = xa + wa; + xfin = xb; + } else if (xa - xb - wb > 45) { + ESPACEX = 0; + xdeb = xa; + xfin = xb + wb; + } else { + ESPACEX = 15; + xdeb = xa + wa/2; + xfin = xb + wb/2; + } + + xmil = xdeb + (xfin - xdeb)/2; + + if (yb - ya - ha >= 45) { + ESPACEY = 0; + ydeb = ya + ha; + yfin = yb; + } else if (ya - yb - hb > 45) { + ESPACEY = 0; + ydeb = ya; + yfin = yb + hb; + } else { + ESPACEY = 15; + ydeb = ya + ha/2; + yfin = yb + hb/2; + } + + ymil = ydeb + (yfin - ydeb)/2; + + p1.setX(xmil + (xfin - xmil)*1/2); p1.setY(ymil + (yfin - ymil)*1/3); + p2.setX(xmil - (xmil - xdeb)*1/2); p2.setY(ymil - (ymil - ydeb)*1/3); + + if (abs(p1.x() - p2.x()) <= 10) + ESPACEX = 15; + if (abs(p1.y() - p2.y()) <= 10) + ESPACEY = 15; + + m_associationLine->setEndPoints(QPointF(xdeb, ydeb), QPointF(xfin, yfin)); + m_associationLine->setPoint(1, QPointF(p1.x() + ESPACEX, p1.y() + ESPACEY)); + m_associationLine->setPoint(2, QPointF(p2.x() - ESPACEX, p2.y() - ESPACEY)); + + m_role[RoleType::A].m_WidgetRegion = m_role[RoleType::B].m_WidgetRegion = Uml::Region::North; +} + +/** + * Finds out which region of rectangle 'rect' contains the point 'pos' and returns the region + * number: + * 1 = Region 1 + * 2 = Region 2 + * 3 = Region 3 + * 4 = Region 4 + * 5 = On diagonal 2 between Region 1 and 2 + * 6 = On diagonal 1 between Region 2 and 3 + * 7 = On diagonal 2 between Region 3 and 4 + * 8 = On diagonal 1 between Region 4 and 1 + * 9 = On diagonal 1 and On diagonal 2 (the center) + */ +Uml::Region::Enum AssociationWidget::findPointRegion(const QRectF& rect, const QPointF &pos) +{ + qreal w = rect.width(); + qreal h = rect.height(); + qreal x = rect.x(); + qreal y = rect.y(); + qreal slope2 = w / h; + qreal slope1 = slope2 *(-1.0); + qreal b1 = x + w - (slope1 * y); + qreal b2 = x - (slope2 * y); + + qreal eval1 = slope1 * pos.y() + b1; + qreal eval2 = slope2 * pos.y() + b2; + + Uml::Region::Enum result = Uml::Region::Error; + //if inside region 1 + if (eval1 > pos.x() && eval2 > pos.x()) { + result = Uml::Region::West; + } + //if inside region 2 + else if (eval1 > pos.x() && eval2 < pos.x()) { + result = Uml::Region::North; + } + //if inside region 3 + else if (eval1 < pos.x() && eval2 < pos.x()) { + result = Uml::Region::East; + } + //if inside region 4 + else if (eval1 < pos.x() && eval2 > pos.x()) { + result = Uml::Region::South; + } + //if inside region 5 + else if (eval1 == pos.x() && eval2 < pos.x()) { + result = Uml::Region::NorthWest; + } + //if inside region 6 + else if (eval1 < pos.x() && eval2 == pos.x()) { + result = Uml::Region::NorthEast; + } + //if inside region 7 + else if (eval1 == pos.x() && eval2 > pos.x()) { + result = Uml::Region::SouthEast; + } + //if inside region 8 + else if (eval1 > pos.x() && eval2 == pos.x()) { + result = Uml::Region::SouthWest; + } + //if inside region 9 + else if (eval1 == pos.x() && eval2 == pos.x()) { + result = Uml::Region::Center; + } + return result; +} + +/** + * Returns a point with interchanged X and Y coordinates. + */ +QPointF AssociationWidget::swapXY(const QPointF &p) +{ + QPointF swapped( p.y(), p.x() ); + return swapped; +} + +#if 0 // not used at the moment +/** + * Calculates which point of segment P1P2 has a distance equal to + * Distance from P1. + * Let's say such point is PX, the distance from P1 to PX must be equal + * to Distance and if PX is not a point of the segment P1P2 then the + * function returns (-1, -1). + */ +QPointF AssociationWidget::calculatePointAtDistance(const QPointF &P1, const QPointF &P2, float Distance) +{ + /* + the distance D between points (x1, y1) and (x3, y3) has the following formula: + --- ------------------------------ + D = \ / 2 2 + \ / (x3 - x1) + (y3 - y1) + + D, x1 and y1 are known and the point (x3, y3) is inside line (x1, y1)(x2, y2), so if the + that line has the formula y = mx + b + then y3 = m*x3 + b + + 2 2 2 + D = (x3 - x1) + (y3 - y1) + + 2 2 2 2 2 + D = x3 - 2*x3*x1 + x1 + y3 - 2*y3*y1 + y1 + + 2 2 2 2 2 + D - x1 - y1 = x3 - 2*x3*x1 + y3 - 2*y3*y1 + + 2 2 2 2 2 + D - x1 - y1 = x3 - 2*x3*x1 + (m*x3 + b) - 2*(m*x3 + b)*y1 + + 2 2 2 2 2 2 + D - x1 - y1 + 2*b*y1 - b = (m + 1)*x3 + (-2*x1 + 2*m*b -2*m*y1)*x3 + + 2 2 2 2 + C = - D + x1 + y1 - 2*b*y1 + b + + + 2 + A = (m + 1) + + B = (-2*x1 + 2*m*b -2*m*y1) + + and we have + 2 + A * x3 + B * x3 - C = 0 + + --------------- + -B + --- / 2 + \/ B - 4*A*C + sol_1 = -------------------------------- + 2*A + + + --------------- + -B - --- / 2 + \/ B - 4*A*C + sol_2 = -------------------------------- + 2*A + + + then in the distance formula we have only one variable x3 and that is easy + to calculate + */ + int x1 = P1.y(); + int y1 = P1.x(); + int x2 = P2.y(); + int y2 = P2.x(); + + if (x2 == x1) { + return QPointF(x1, y1 + (int)Distance); + } + float slope = ((float)y2 - (float)y1) / ((float)x2 - (float)x1); + float b = (y1 - slope*x1); + float A = (slope * slope) + 1; + float B = (2*slope*b) - (2*x1) - (2*slope*y1); + float C = (b*b) - (Distance*Distance) + (x1*x1) + (y1*y1) - (2*b*y1); + float t = B*B - 4*A*C; + + if (t < 0) { + return QPointF(-1, -1); + } + float sol_1 = ((-1* B) + sqrt(t)) / (2*A); + float sol_2 = ((-1*B) - sqrt(t)) / (2*A); + + if (sol_1 < 0.0 && sol_2 < 0.0) { + return QPointF(-1, -1); + } + QPointF sol1Point((int)(slope*sol_1 + b), (int)(sol_1)); + QPointF sol2Point((int)(slope*sol_2 + b), (int)(sol_2)); + if (sol_1 < 0 && sol_2 >=0) { + if (x2 > x1) { + if (x1 <= sol_2 && sol_2 <= x2) + return sol2Point; + } else { + if (x2 <= sol_2 && sol_2 <= x1) + return sol2Point; + } + } else if (sol_1 >= 0 && sol_2 < 0) { + if (x2 > x1) { + if (x1 <= sol_1 && sol_1 <= x2) + return sol1Point; + } else { + if (x2 <= sol_1 && sol_1 <= x1) + return sol1Point; + } + } else { + if (x2 > x1) { + if (x1 <= sol_1 && sol_1 <= x2) + return sol1Point; + if (x1 <= sol_2 && sol_2 <= x2) + return sol2Point; + } else { + if (x2 <= sol_1 && sol_1 <= x1) + return sol1Point; + if (x2 <= sol_2 && sol_2 <= x1) + return sol2Point; + } + } + return QPointF(-1, -1); +} + +/** + * Calculates which point of a perpendicular line to segment P1P2 that contains P2 + * has a distance equal to Distance from P2, + * Lets say such point is P3, the distance from P2 to P3 must be equal to Distance + */ +QPointF AssociationWidget::calculatePointAtDistanceOnPerpendicular(const QPointF &P1, const QPointF &P2, float Distance) +{ + /* + the distance D between points (x2, y2) and (x3, y3) has the following formula: + + --- ------------------------------ + D = \ / 2 2 + \ / (x3 - x2) + (y3 - y2) + + D, x2 and y2 are known and line P2P3 is perpendicular to line (x1, y1)(x2, y2), so if the + line P1P2 has the formula y = m*x + b, + then (x1 - x2) + m = -----------, because it is perpendicular to line P1P2 + (y2 - y1) + + also y2 = m*x2 + b + => b = y2 - m*x2 + + then P3 = (x3, m*x3 + b) + + 2 2 2 + D = (x3 - x2) + (y3 - y2) + + 2 2 2 2 2 + D = x3 - 2*x3*x2 + x2 + y3 - 2*y3*y2 + y2 + + 2 2 2 2 2 + D - x2 - y2 = x3 - 2*x3*x2 + y3 - 2*y3*y2 + + + + 2 2 2 2 2 + D - x2 - y2 = x3 - 2*x3*x2 + (m*x3 + b) - 2*(m*x3 + b)*y2 + + 2 2 2 2 2 2 + D - x2 - y2 + 2*b*y2 - b = (m + 1)*x3 + (-2*x2 + 2*m*b -2*m*y2)*x3 + + 2 2 2 2 + C = - D + x2 + y2 - 2*b*y2 + b + + 2 + A = (m + 1) + + B = (-2*x2 + 2*m*b -2*m*y2) + + and we have + 2 + A * x3 + B * x3 - C = 0 + + + --------------- + --- / 2 + -B + \/ B - 4*A*C + sol_1 = -------------------------------- + 2*A + + + --------------- + --- / 2 + -B - \/ B - 4*A*C + sol_2 = -------------------------------- + 2*A + + then in the distance formula we have only one variable x3 and that is easy + to calculate + */ + if (P1.x() == P2.x()) { + return QPointF((int)(P2.x() + Distance), P2.y()); + } + const int x1 = P1.y(); + const int y1 = P1.x(); + const int x2 = P2.y(); + const int y2 = P2.x(); + + float slope = ((float)x1 - (float)x2) / ((float)y2 - (float)y1); + float b = (y2 - slope*x2); + float A = (slope * slope) + 1; + float B = (2*slope*b) - (2*x2) - (2*slope*y2); + float C = (b*b) - (Distance*Distance) + (x2*x2) + (y2*y2) - (2*b*y2); + float t = B*B - 4*A*C; + if (t < 0) { + return QPointF(-1, -1); + } + float sol_1 = ((-1* B) + sqrt(t)) / (2*A); + + float sol_2 = ((-1*B) - sqrt(t)) / (2*A); + + if (sol_1 < 0 && sol_2 < 0) { + return QPointF(-1, -1); + } + QPointF sol1Point((int)(slope*sol_1 + b), (int)sol_1); + QPointF sol2Point((int)(slope*sol_2 + b), (int)sol_2); + if (sol_1 < 0 && sol_2 >=0) { + return sol2Point; + } else if (sol_1 >= 0 && sol_2 < 0) { + return sol1Point; + } else { // Choose one solution, either will work fine + if (slope >= 0) { + if (sol_1 <= sol_2) + return sol2Point; + else + return sol1Point; + } else { + if (sol_1 <= sol_2) + return sol1Point; + else + return sol2Point; + } + + } + return QPointF(-1, -1); // never reached, just keep compilers happy +} + +/** + * Calculates the intersection (PS) between line P1P2 and a perpendicular line containing + * P3, the result is returned in ResultingPoint. and result value represents the distance + * between ResultingPoint and P3; if this value is negative an error ocurred. + */ +float AssociationWidget::perpendicularProjection(const QPointF& P1, const QPointF& P2, const QPointF& P3, + QPointF& ResultingPoint) +{ + //line P1P2 is Line 1 = y=slope1*x + b1 + + //line P3PS is Line 1 = y=slope2*x + b2 + + float slope2 = 0; + float slope1 = 0; + float sx = 0, sy = 0; + int y2 = P2.x(); + int y1 = P1.x(); + int x2 = P2.y(); + int x1 = P1.y(); + int y3 = P3.x(); + int x3 = P3.y(); + float distance = 0; + float b1 = 0; + + float b2 = 0; + + if (x2 == x1) { + sx = x2; + sy = y3; + } else if (y2 == y1) { + sy = y2; + sx = x3; + } else { + slope1 = (y2 - y1)/ (x2 - x1); + slope2 = (x1 - x2)/ (y2 - y1); + b1 = y2 - (slope1 * x2); + b2 = y3 - (slope2 * x3); + sx = (b2 - b1) / (slope1 - slope2); + sy = slope1*sx + b1; + } + distance = (int)(sqrt(((x3 - sx)*(x3 - sx)) + ((y3 - sy)*(y3 - sy)))); + + ResultingPoint.setX((int)sy); + ResultingPoint.setY((int)sx); + + return distance; +} +#endif + +/** + * Calculates the position of the text widget depending on the role + * that widget is playing. + * Returns the point at which to put the widget. + */ +QPointF AssociationWidget::calculateTextPosition(Uml::TextRole::Enum role) +{ + const int SPACE = 2; + QPointF p(-1, -1), q(-1, -1); + + // used to find out if association end point (p) + // is at top or bottom edge of widget. + + if (role == TextRole::MultiA || role == TextRole::ChangeA || role == TextRole::RoleAName) { + p = m_associationLine->point(0); + q = m_associationLine->point(1); + } else if (role == TextRole::MultiB || role == TextRole::ChangeB || role == TextRole::RoleBName) { + const int lastSegment = m_associationLine->count() - 1; + p = m_associationLine->point(lastSegment); + q = m_associationLine->point(lastSegment - 1); + } else if (role != TextRole::Name) { + uError() << "called with unsupported TextRole::Enum " << role; + return QPointF(-1, -1); + } + + FloatingTextWidget *text = textWidgetByRole(role); + int textW = 0, textH = 0; + if (text) { + textW = text->width(); + textH = text->height(); + } + + qreal x = 0.0, y = 0.0; + + if (role == TextRole::MultiA || role == TextRole::MultiB) { + const bool isHorizontal = (p.y() == q.y()); + const int atBottom = p.y() + SPACE; + const int atTop = p.y() - SPACE - textH; + const int atLeft = p.x() - SPACE - textW; + const int atRight = p.x() + SPACE; + y = (p.y() > q.y()) == isHorizontal ? atBottom : atTop; + x = (p.x() < q.x()) == isHorizontal ? atRight : atLeft; + + } else if (role == TextRole::ChangeA || role == TextRole::ChangeB) { + + if (p.y() > q.y()) + y = p.y() - SPACE - (textH * 2); + else + y = p.y() + SPACE + textH; + + if (p.x() < q.x()) + x = p.x() + SPACE; + else + x = p.x() - SPACE - textW; + + } else if (role == TextRole::RoleAName || role == TextRole::RoleBName) { + + if (p.y() > q.y()) + y = p.y() - SPACE - textH; + else + y = p.y() + SPACE; + + if (p.x() < q.x()) + x = p.x() + SPACE; + else + x = p.x() - SPACE - textW; + + } else if (role == TextRole::Name) { + + calculateNameTextSegment(); + if (m_unNameLineSegment == -1) { + uWarning() << "TODO:negative line segment index"; + m_unNameLineSegment = 0; + } + x = ( m_associationLine->point(m_unNameLineSegment).x() + + m_associationLine->point(m_unNameLineSegment + 1).x() ) / 2; + y = ( m_associationLine->point(m_unNameLineSegment).y() + + m_associationLine->point(m_unNameLineSegment + 1).y() ) / 2; + } + + if (text) { + constrainTextPos(x, y, textW, textH, role); + } + p = QPointF( x, y ); + return p; +} + +/** + * Return the mid point between p0 and p1 + */ +QPointF AssociationWidget::midPoint(const QPointF& p0, const QPointF& p1) +{ + QPointF midP; + if (p0.x() < p1.x()) + midP.setX(p0.x() + (p1.x() - p0.x()) / 2); + else + midP.setX(p1.x() + (p0.x() - p1.x()) / 2); + if (p0.y() < p1.y()) + midP.setY(p0.y() + (p1.y() - p0.y()) / 2); + else + midP.setY(p1.y() + (p0.y() - p1.y()) / 2); + return midP; +} + +/** + * Constrains the FloatingTextWidget X and Y values supplied. + * Implements the abstract operation from LinkWidget. + * + * @param textX Candidate X value (may be modified by the constraint.) + * @param textY Candidate Y value (may be modified by the constraint.) + * @param textWidth Width of the text. + * @param textHeight Height of the text. + * @param tr Uml::Text_Role of the text. + */ +void AssociationWidget::constrainTextPos(qreal &textX, qreal &textY, + qreal textWidth, qreal textHeight, + Uml::TextRole::Enum tr) +{ + const int textCenterX = textX + textWidth / 2; + const int textCenterY = textY + textHeight / 2; + const int lastSegment = m_associationLine->count() - 1; + QPointF p0, p1; + switch (tr) { + case TextRole::RoleAName: + case TextRole::MultiA: + case TextRole::ChangeA: + p0 = m_associationLine->point(0); + p1 = m_associationLine->point(1); + // If we are dealing with a single line then tie the + // role label to the proper half of the line, i.e. + // the role label must be closer to the "other" + // role object. + if (lastSegment == 1) + p1 = midPoint(p0, p1); + break; + case TextRole::RoleBName: + case TextRole::MultiB: + case TextRole::ChangeB: + p0 = m_associationLine->point(lastSegment - 1); + p1 = m_associationLine->point(lastSegment); + if (lastSegment == 1) + p0 = midPoint(p0, p1); + break; + case TextRole::Name: + case TextRole::Coll_Message: // CHECK: collab.msg texts seem to be TextRole::Name + case TextRole::State: // CHECK: is this used? + // Find the linepath segment to which the (textX, textY) is closest + // and constrain to the corridor of that segment (see farther below) + { + int minDistSquare = 100000; // utopian initial value + int lpIndex = 0; + for (int i = 0; i < lastSegment; ++i) { + p0 = m_associationLine->point(i); + p1 = m_associationLine->point(i + 1); + QPointF midP = midPoint(p0, p1); + const int deltaX = textCenterX - midP.x(); + const int deltaY = textCenterY - midP.y(); + const int cSquare = deltaX * deltaX + deltaY * deltaY; + if (cSquare < minDistSquare) { + minDistSquare = cSquare; + lpIndex = i; + } + } + p0 = m_associationLine->point(lpIndex); + p1 = m_associationLine->point(lpIndex + 1); + } + break; + default: + uError() << "unexpected TextRole::Enum " << tr; + return; + break; + } + /* Constraint: + The midpoint between p0 and p1 is taken to be the center of a circle + with radius D/2 where D is the distance between p0 and p1. + The text center needs to be within this circle else it is constrained + to the nearest point on the circle. + */ + p0 = swapXY(p0); // go to the natural coordinate system + p1 = swapXY(p1); // with (0,0) in the lower left corner + QPointF midP = midPoint(p0, p1); + // If (textX,textY) is not inside the circle around midP then + // constrain (textX,textY) to the nearest point on that circle. + const int x0 = p0.x(); + const int y0 = p0.y(); + const int x1 = p1.x(); + const int y1 = p1.y(); + double r = sqrt((double)((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0))) / 2; + if (textWidth > r) + r = textWidth; + // swap textCenter{X,Y} to convert from Qt coord.system. + const QPointF origTextCenter(textCenterY, textCenterX); + const int relX = abs(origTextCenter.x() - midP.x()); + const int relY = abs(origTextCenter.y() - midP.y()); + const double negativeWhenInsideCircle = relX * relX + relY * relY - r * r; + if (negativeWhenInsideCircle <= 0.0) { + return; + } + /* + The original constraint was to snap the text position to the + midpoint but that creates unpleasant visual jitter: + textX = midP.y() - textWidth / 2; // go back to Qt coord.sys. + textY = midP.x() - textHeight / 2; // go back to Qt coord.sys. + + Rather, we project the text position onto the closest point + on the circle: + + Circle equation: + relX^2 + relY^2 - r^2 = 0, or in other words + relY^2 = r^2 - relX^2, or + relY = sqrt(r^2 - relX^2) + Line equation: + relY = a * relX + b + We can omit "b" because relX and relY are already relative to + the circle origin, therefore we can also write: + a = relY / relX + To obtain the point of intersection between the circle of radius r + and the line connecting the circle origin with the point (relX, relY), + we equate the relY: + a * x = sqrt(r^2 - x^2), or in other words + a^2 * x^2 = r^2 - x^2, or + x^2 * (a^2 + 1) = r^2, or + x^2 = r^2 / (a^2 + 1), or + x = sqrt(r^2 / (a^2 + 1)) + and then + y = a * x + The resulting x and y are relative to the circle origin so we just add + the circle origin (X, Y) to obtain the constrained (textX, textY). + */ + // Handle the special case, relX = 0. + if (relX == 0) { + if (origTextCenter.y() > midP.y()) + textX = midP.y() + (int)r; // go back to Qt coord.sys. + else + textX = midP.y() - (int)r; // go back to Qt coord.sys. + textX -= textWidth / 2; + return; + } + const double a = (double)relY / (double)relX; + const double x = sqrt(r*r / (a*a + 1)); + const double y = a * x; + if (origTextCenter.x() > midP.x()) + textY = midP.x() + (int)x; // go back to Qt coord.sys. + else + textY = midP.x() - (int)x; // go back to Qt coord.sys. + textY -= textHeight / 2; + if (origTextCenter.y() > midP.y()) + textX = midP.y() + (int)y; // go back to Qt coord.sys. + else + textX = midP.y() - (int)y; // go back to Qt coord.sys. + textX -= textWidth / 2; +} + +/** + * Puts the text widget with the given role at the given position. + * This method calls @ref calculateTextPostion to get the needed position. + * I.e. the line segment it is on has moved and it should move the same + * amount as the line. + */ +void AssociationWidget::setTextPosition(Uml::TextRole::Enum role) +{ + bool startMove = false; + if (m_role[RoleType::A].multiplicityWidget && m_role[RoleType::A].multiplicityWidget->getStartMove()) + startMove = true; + else if (m_role[RoleType::B].multiplicityWidget && m_role[RoleType::B].multiplicityWidget->getStartMove()) + startMove = true; + else if (m_role[RoleType::A].changeabilityWidget && m_role[RoleType::A].changeabilityWidget->getStartMove()) + startMove = true; + else if (m_role[RoleType::B].changeabilityWidget && m_role[RoleType::B].changeabilityWidget->getStartMove()) + startMove = true; + else if (m_role[RoleType::A].roleWidget && m_role[RoleType::A].roleWidget->getStartMove()) + startMove = true; + else if (m_role[RoleType::B].roleWidget && m_role[RoleType::B].roleWidget->getStartMove()) + startMove = true; + else if (m_nameWidget && m_nameWidget->getStartMove()) + startMove = true; + if (startMove) { + return; + } + FloatingTextWidget *ft = textWidgetByRole(role); + if (ft == NULL) + return; + QPointF pos = calculateTextPosition(role); + ft->setX(pos.x()); + ft->setY(pos.y()); +} + +/** + * Moves the text widget with the given role by the difference between + * the two points. + */ +void AssociationWidget::setTextPositionRelatively(Uml::TextRole::Enum role, const QPointF &oldPosition) +{ + bool startMove = false; + if (m_role[RoleType::A].multiplicityWidget && m_role[RoleType::A].multiplicityWidget->getStartMove()) + startMove = true; + else if (m_role[RoleType::B].multiplicityWidget && m_role[RoleType::B].multiplicityWidget->getStartMove()) + startMove = true; + else if (m_role[RoleType::A].changeabilityWidget && m_role[RoleType::A].changeabilityWidget->getStartMove()) + startMove = true; + else if (m_role[RoleType::B].changeabilityWidget && m_role[RoleType::B].changeabilityWidget->getStartMove()) + startMove = true; + else if (m_role[RoleType::A].roleWidget && m_role[RoleType::A].roleWidget->getStartMove()) + startMove = true; + else if (m_role[RoleType::B].roleWidget && m_role[RoleType::B].roleWidget->getStartMove()) + startMove = true; + else if (m_nameWidget && m_nameWidget->getStartMove()) + startMove = true; + + if (startMove) { + return; + } + FloatingTextWidget *ft = textWidgetByRole(role); + if (ft == NULL) + return; + qreal ftX = ft->x(); + qreal ftY = ft->y(); + + QPointF pos = calculateTextPosition(role); + int relX = pos.x() - oldPosition.x(); + int relY = pos.y() - oldPosition.y(); + qreal ftNewX = ftX + relX; + qreal ftNewY = ftY + relY; + + bool oldIgnoreSnapToGrid = ft->getIgnoreSnapToGrid(); + ft->setIgnoreSnapToGrid(true); + ft->setX(ftNewX); + ft->setY(ftNewY); + ft->setIgnoreSnapToGrid(oldIgnoreSnapToGrid); +} + +/** + * Remove dashed connecting line for association class. + */ +void AssociationWidget::removeAssocClassLine() +{ + delete m_pAssocClassLineSel0; + m_pAssocClassLineSel0 = 0; + delete m_pAssocClassLineSel1; + m_pAssocClassLineSel1 = 0; + delete m_pAssocClassLine; + m_pAssocClassLine = 0; + if (m_associationClass) { + m_associationClass->setClassAssociationWidget(0); + m_associationClass = 0; + } +} + +/** + * Creates the association class connecting line. + */ +void AssociationWidget::createAssocClassLine() +{ + if (m_pAssocClassLine == NULL) { + m_pAssocClassLine = new QGraphicsLineItem(this); + } + QPen pen(lineColor(), lineWidth(), Qt::DashLine); + m_pAssocClassLine->setPen(pen); + // decoration points + m_pAssocClassLineSel0 = Widget_Utils::decoratePoint(m_pAssocClassLine->line().p1(), + m_pAssocClassLine); + m_pAssocClassLineSel1 = Widget_Utils::decoratePoint(m_pAssocClassLine->line().p2(), + m_pAssocClassLine); + computeAssocClassLine(); + selectAssocClassLine(false); +} + +/** + * Creates the association class connecting line using the specified + * ClassifierWidget. + * + * @param classifier The ClassifierWidget to use. + * @param linePathSegmentIndex The index of the segment where the + * association class is created. + */ +void AssociationWidget::createAssocClassLine(ClassifierWidget* classifier, + int linePathSegmentIndex) +{ + m_nLinePathSegmentIndex = linePathSegmentIndex; + + if (m_nLinePathSegmentIndex < 0) { + return; + } + + m_associationClass = classifier; + m_associationClass->setClassAssociationWidget(this); + m_associationClass->addAssoc(this); // to get widgetMoved(...) for association classes + + createAssocClassLine(); +} + +/** + * Compute the end points of m_pAssocClassLine in case this + * association has an attached association class. + * TODO: The decoration points make no sense for now, because they are not movable. + */ +void AssociationWidget::computeAssocClassLine() +{ + if (m_associationClass == NULL || m_pAssocClassLine == NULL) { + return; + } + if (m_nLinePathSegmentIndex < 0) { + uError() << "m_nLinePathSegmentIndex is not set"; + return; + } + + QPointF segStart = m_associationLine->point(m_nLinePathSegmentIndex); + QPointF segEnd = m_associationLine->point(m_nLinePathSegmentIndex + 1); + const qreal midSegX = segStart.x() + (segEnd.x() - segStart.x()) / 2.0; + const qreal midSegY = segStart.y() + (segEnd.y() - segStart.y()) / 2.0; + QPointF segmentMidPoint(midSegX, midSegY); + + QLineF possibleAssocLine = QLineF(segmentMidPoint, + m_associationClass->mapRectToScene(m_associationClass->rect()).center()); + QPointF intersectionPoint; + QLineF::IntersectType type = intersect(m_associationClass->mapRectToScene(m_associationClass->boundingRect()), + possibleAssocLine, + &intersectionPoint); + // DEBUG(DBG_SRC) << "intersect type=" << type << " / point=" << intersectionPoint; + + if (type == QLineF::BoundedIntersection) { + m_pAssocClassLine->setLine(midSegX, midSegY, + intersectionPoint.x(), intersectionPoint.y()); + + if (m_pAssocClassLineSel0 && m_pAssocClassLineSel1) { + m_pAssocClassLineSel0->setPos(m_pAssocClassLine->line().p1()); + m_pAssocClassLineSel1->setPos(m_pAssocClassLine->line().p2()); + } + } +} + +/** + * Renders the association class connecting line selected. + */ +void AssociationWidget::selectAssocClassLine(bool sel) +{ + if (m_pAssocClassLineSel0 && m_pAssocClassLineSel1) { + m_pAssocClassLineSel0->setVisible(sel); + m_pAssocClassLineSel1->setVisible(sel); + } +} + +/** + * Sets the association to be selected. + */ +void AssociationWidget::mousePressEvent(QGraphicsSceneMouseEvent * me) +{ + // clear other selected stuff on the screen of ShiftKey + if (me->modifiers() != Qt::ShiftModifier) { + m_scene->clearSelected(); + } + + if (me->button() == Qt::LeftButton && me->modifiers() == Qt::ControlModifier) { + if (checkRemovePoint(me->scenePos())) + return; + } + + // make sure we should be here depending on the button + if (me->button() != Qt::RightButton && me->button() != Qt::LeftButton) { + return; + } + QPointF mep = me->scenePos(); + // see if `mep' is on the connecting line to the association class + if (onAssocClassLine(mep)) { + setSelected(true); + selectAssocClassLine(); + return; + } + setSelected(!isSelected()); + associationLine()->mousePressEvent(me); +} + +/** + * Displays the right mouse buttom menu if right button is pressed. + */ +void AssociationWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent * me) +{ + associationLine()->mouseReleaseEvent(me); +} + +/** + * Handles the selection from the popup menu. + */ +void AssociationWidget::slotMenuSelection(QAction* action) +{ + QString oldText, newText; + QRegExpValidator v(QRegExp(QLatin1String(".*")), 0); + Uml::AssociationType::Enum atype = associationType(); + Uml::RoleType::Enum r = RoleType::B; + ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); + DEBUG(DBG_SRC) << "menu selection = " << ListPopupMenu::toString(sel); + + // if it's a collaboration message we now just use the code in floatingtextwidget + // this means there's some redundant code below but that's better than duplicated code + if (isCollaboration() && sel != ListPopupMenu::mt_Delete) { + m_nameWidget->slotMenuSelection(action); + return; + } + + switch(sel) { + case ListPopupMenu::mt_Properties: + if (atype == AssociationType::Seq_Message || atype == AssociationType::Seq_Message_Self) { + // show op dlg for seq. diagram here + // don't worry about here, I don't think it can get here as + // line is widget on seq. diagram + // here just in case - remove later after testing + DEBUG(DBG_SRC) << "mt_Properties: assoctype is " << atype; + } else { //standard assoc dialog + UMLApp::app()->docWindow()->updateDocumentation(false); + showPropertiesDialog(); + } + break; + + case ListPopupMenu::mt_Add_Point: + checkAddPoint(m_eventScenePos); + break; + + case ListPopupMenu::mt_Delete_Point: + checkRemovePoint(m_eventScenePos); + break; + + case ListPopupMenu::mt_Delete: + if (m_pAssocClassLineSel0) + removeAssocClassLine(); + else if (association()) + m_scene->removeAssocInViewAndDoc(this); + else + m_scene->removeAssoc(this); + break; + + case ListPopupMenu::mt_Rename_MultiA: + r = RoleType::A; // fall through + case ListPopupMenu::mt_Rename_MultiB: + if (m_role[r].multiplicityWidget) + oldText = m_role[r].multiplicityWidget->text(); + else + oldText = QString(); +#if QT_VERSION >= 0x050000 + newText = QInputDialog::getText(m_scene->activeView(), + i18n("Multiplicity"), + i18n("Enter multiplicity:"), + QLineEdit::Normal, + oldText, NULL); +#else + newText = KInputDialog::getText(i18n("Multiplicity"), + i18n("Enter multiplicity:"), + oldText, NULL, m_scene->activeView(), &v); +#endif + if (newText != oldText) { + if (FloatingTextWidget::isTextValid(newText)) { + setMultiplicity(newText, r); + } else { + m_scene->removeWidget(m_role[r].multiplicityWidget); + m_role[r].multiplicityWidget = NULL; + } + } + break; + + case ListPopupMenu::mt_Rename_Name: + if (m_nameWidget) + oldText = m_nameWidget->text(); + else + oldText = QString(); +#if QT_VERSION >= 0x050000 + newText = QInputDialog::getText(m_scene->activeView(), + i18n("Association Name"), + i18n("Enter association name:"), + QLineEdit::Normal, + oldText, NULL); +#else + newText = KInputDialog::getText(i18n("Association Name"), + i18n("Enter association name:"), + oldText, NULL, m_scene->activeView(), &v); +#endif + if (newText != oldText) { + if (FloatingTextWidget::isTextValid(newText)) { + setName(newText); + } else if (m_nameWidget) { + m_scene->removeWidget(m_nameWidget); + m_nameWidget = NULL; + } + } + break; + + case ListPopupMenu::mt_Rename_RoleAName: + r = RoleType::A; // fall through + case ListPopupMenu::mt_Rename_RoleBName: + if (m_role[r].roleWidget) + oldText = m_role[r].roleWidget->text(); + else + oldText = QString(); +#if QT_VERSION >= 0x050000 + newText = QInputDialog::getText(m_scene->activeView(), + i18n("Role Name"), + i18n("Enter role name:"), + QLineEdit::Normal, + oldText, NULL); +#else + newText = KInputDialog::getText(i18n("Role Name"), + i18n("Enter role name:"), + oldText, NULL, m_scene->activeView(), &v); +#endif + if (newText != oldText) { + if (FloatingTextWidget::isTextValid(newText)) { + setRoleName(newText, r); + } else { + m_scene->removeWidget(m_role[r].roleWidget); + m_role[r].roleWidget = NULL; + } + } + break; + + case ListPopupMenu::mt_Change_Font: + { +#if QT_VERSION >= 0x050000 + bool ok = false; + QFont fnt = QFontDialog::getFont(&ok, font(), m_scene->activeView()); + if (ok) +#else + QFont fnt = font(); + if (KFontDialog::getFont(fnt, KFontChooser::NoDisplayFlags, m_scene->activeView())) +#endif + lwSetFont(fnt); + } + break; + + case ListPopupMenu::mt_Line_Color: + { +#if QT_VERSION >= 0x050000 + QColor newColor = QColorDialog::getColor(lineColor()); + if (newColor != lineColor()) { +#else + QColor newColor; + if (KColorDialog::getColor(newColor)) { +#endif + m_scene->selectionSetLineColor(newColor); + umlDoc()->setModified(true); + } + } + break; + + case ListPopupMenu::mt_Cut: + m_scene->setStartedCut(); + UMLApp::app()->slotEditCut(); + break; + + case ListPopupMenu::mt_Copy: + UMLApp::app()->slotEditCopy(); + break; + + case ListPopupMenu::mt_Paste: + UMLApp::app()->slotEditPaste(); + break; + + case ListPopupMenu::mt_Reset_Label_Positions: + resetTextPositions(); + break; + + case ListPopupMenu::mt_LayoutDirect: + m_associationLine->setLayout(AssociationLine::Direct); + break; + case ListPopupMenu::mt_LayoutSpline: + m_associationLine->setLayout(AssociationLine::Spline); + break; + case ListPopupMenu::mt_LayoutOrthogonal: + m_associationLine->setLayout(AssociationLine::Orthogonal); + break; + case ListPopupMenu::mt_LayoutPolyline: + m_associationLine->setLayout(AssociationLine::Polyline); + break; + + default: + DEBUG(DBG_SRC) << "MenuType " << ListPopupMenu::toString(sel) << " not implemented"; + break; + }//end switch +} + +/** + * Return the first font found being used by any child widget. (They + * could be different fonts, so this is a slightly misleading method.) + */ +QFont AssociationWidget::font() const +{ + //:TODO: find a general font for the association + QFont font; + + if (m_role[RoleType::A].roleWidget) + font = m_role[RoleType::A].roleWidget->font(); + else if (m_role[RoleType::B].roleWidget) + font = m_role[RoleType::B].roleWidget->font(); + else if (m_role[RoleType::A].multiplicityWidget) + font = m_role[RoleType::A].multiplicityWidget->font(); + else if (m_role[RoleType::B].multiplicityWidget) + font = m_role[RoleType::B].multiplicityWidget->font(); + else if (m_role[RoleType::A].changeabilityWidget) + font = m_role[RoleType::A].changeabilityWidget->font(); + else if (m_role[RoleType::B].changeabilityWidget) + font = m_role[RoleType::B].changeabilityWidget->font(); + else if (m_nameWidget) + font = m_nameWidget->font(); + else + font = m_role[RoleType::A].umlWidget->font(); + + return font; +} + +/** + * Set all 'owned' child widgets to this text color. + */ +void AssociationWidget::setTextColor(const QColor &color) +{ + WidgetBase::setTextColor(color); + if (m_nameWidget) { + m_nameWidget->setTextColor(color); + } + if (m_role[RoleType::A].roleWidget) { + m_role[RoleType::A].roleWidget->setTextColor(color); + } + if (m_role[RoleType::B].roleWidget) { + m_role[RoleType::B].roleWidget->setTextColor(color); + } + if (m_role[RoleType::A].multiplicityWidget) { + m_role[RoleType::A].multiplicityWidget->setTextColor(color); + } + if (m_role[RoleType::B].multiplicityWidget) { + m_role[RoleType::B].multiplicityWidget->setTextColor(color); + } + if (m_role[RoleType::A].changeabilityWidget) + m_role[RoleType::A].changeabilityWidget->setTextColor(color); + if (m_role[RoleType::B].changeabilityWidget) + m_role[RoleType::B].changeabilityWidget->setTextColor(color); +} + +bool AssociationWidget::checkAddPoint(const QPointF &scenePos) +{ + if (associationType() == AssociationType::Exception) { + return false; + } + + // if there is no point around the mouse pointer, we insert a new one + if (m_associationLine->closestPointIndex(scenePos) < 0) { + int i = m_associationLine->closestSegmentIndex(scenePos); + if (i < 0) { + DEBUG(DBG_SRC) << "no closest segment found!"; + return false; + } + m_associationLine->insertPoint(i + 1, scenePos); + if (m_nLinePathSegmentIndex == i) { + QPointF segStart = m_associationLine->point(i); + QPointF segEnd = m_associationLine->point(i + 2); + const int midSegX = segStart.x() + (segEnd.x() - segStart.x()) / 2; + const int midSegY = segStart.y() + (segEnd.y() - segStart.y()) / 2; + /* + DEBUG(DBG_SRC) << "segStart=" << segStart << ", segEnd=" << segEnd + << ", midSeg=(" << midSegX << "," << midSegY + << "), mp=" << mp; + */ + if (midSegX > scenePos.x() || midSegY < scenePos.y()) { + m_nLinePathSegmentIndex++; + DEBUG(DBG_SRC) << "setting m_nLinePathSegmentIndex to " + << m_nLinePathSegmentIndex; + computeAssocClassLine(); + } + m_associationLine->update(); + calculateNameTextSegment(); + umlDoc()->setModified(true); + setSelected(true); + } + return true; + } + else { + DEBUG(DBG_SRC) << "found point already close enough!"; + return false; + } +} + +/** + * Remove point close to the given point and redraw the association. + * @param scenePos point which should be removed + * @return success status of the remove action + */ +bool AssociationWidget::checkRemovePoint(const QPointF &scenePos) +{ + int i = m_associationLine->closestPointIndex(scenePos); + if (i == -1) + return false; + + m_associationLine->setSelected(false); + + // there was a point so we remove the point + m_associationLine->removePoint(i); + + // Maybe reattach association class connecting line + // to different association linepath segment. + const int numberOfLines = m_associationLine->count() - 1; + if (m_nLinePathSegmentIndex >= numberOfLines) { + m_nLinePathSegmentIndex = numberOfLines - 1; + } + calculateEndingPoints(); + + // select the line path + m_associationLine->setSelected(true); + + m_associationLine->update(); + + calculateNameTextSegment(); + umlDoc()->setModified(true); + return true; +} + +/** + * Moves the break point being dragged. + */ +void AssociationWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* me) +{ + if (me->buttons() != Qt::LeftButton) { + return; + } + + setSelected(true); + + associationLine()->mouseMoveEvent(me); + moveEvent(me); + m_scene->resizeSceneToItems(); +} + +/** + * Returns the Region the widget to line intersection is for the given + * widget in this Association. If the given widget is not in the + * Association then Region::Error is returned. + * Used by @ref calculateEndingPoints to work these positions out for + * another Association - since the number of Associations on the same + * region for the same widget will mean the lines will need to be + * spread out across the region. + */ +//Uml::Region::Enum AssociationWidget::getWidgetRegion(AssociationWidget * widget) const +//{ +// if (widget->widgetForRole(RoleType::A) == m_role[RoleType::A].umlWidget) +// return m_role[RoleType::A].m_WidgetRegion; +// if (widget->widgetForRole(RoleType::B) == m_role[RoleType::B].umlWidget) +// return m_role[RoleType::B].m_WidgetRegion; +// return Uml::Region::Error; +//} + +/** + * Returns the number of lines there are on the given region for + * either widget A or B of the association. + */ +int AssociationWidget::getRegionCount(Uml::Region::Enum region, Uml::RoleType::Enum role) +{ + if ((region == Uml::Region::Error) | (umlScene() == NULL)) { + return 0; + } + int widgetCount = 0; + AssociationWidgetList list = m_scene->associationList(); + foreach (AssociationWidget* assocwidget, list) { + //don't count this association + if (assocwidget == this) + continue; + const WidgetRole& otherA = assocwidget->m_role[RoleType::A]; + const WidgetRole& otherB = assocwidget->m_role[RoleType::B]; + const UMLWidget *a = otherA.umlWidget; + const UMLWidget *b = otherB.umlWidget; + /* + //don't count associations to self if both of their end points are on the same region + //they are different and placement won't interfere with them + if (a == b && otherA.m_WidgetRegion == otherB.m_WidgetRegion) + continue; + */ + if (m_role[role].umlWidget == a && region == otherA.m_WidgetRegion) + widgetCount++; + else if (m_role[role].umlWidget == b && region == otherB.m_WidgetRegion) + widgetCount++; + }//end foreach + return widgetCount; +} + +/** + * Find the border point of the given rect when a line is drawn from the + * given point to the rect. + * @param rect rect of a classifier + * @param line a line to the rect + * @param intersectionPoint the intercept point on the border of the rect + * @return the type of the intersection @ref QLineF::IntersectType + */ +QLineF::IntersectType AssociationWidget::intersect(const QRectF &rect, const QLineF &line, + QPointF* intersectionPoint) +{ + QList lines; + lines << QLineF(rect.topLeft(), rect.topRight()); + lines << QLineF(rect.topRight(), rect.bottomRight()); + lines << QLineF(rect.bottomRight(), rect.bottomLeft()); + lines << QLineF(rect.bottomLeft(), rect.topLeft()); + foreach (const QLineF& rectLine, lines) { + QLineF::IntersectType type = rectLine.intersect(line, intersectionPoint); + if (type == QLineF::BoundedIntersection) { + return type; + } + } + return QLineF::NoIntersection; +} + +/** + * Given a rectangle and a point, findInterceptOnEdge computes the + * connecting line between the middle point of the rectangle and + * the point, and returns the intercept of this line with the + * the edge of the rectangle identified by `region'. + * When the region is North or South, the X value is returned (Y is + * constant.) + * When the region is East or West, the Y value is returned (X is + * constant.) + * @todo This is buggy. Try replacing by intersect() + */ +qreal AssociationWidget::findInterceptOnEdge(const QRectF &rect, + Uml::Region::Enum region, + const QPointF &point) +{ + // The Qt coordinate system has (0, 0) in the top left corner. + // In order to go to the regular XY coordinate system with (0, 0) + // in the bottom left corner, we swap the X and Y axis. + // That's why the following assignments look twisted. + const qreal rectHalfWidth = rect.height() / 2.0; + const qreal rectHalfHeight = rect.width() / 2.0; + const qreal rectMidX = rect.y() + rectHalfWidth; + const qreal rectMidY = rect.x() + rectHalfHeight; + const qreal dX = rectMidX - point.y(); + const qreal dY = rectMidY - point.x(); + switch (region) { + case Uml::Region::West: + region = Uml::Region::South; + break; + case Uml::Region::North: + region = Uml::Region::West; + break; + case Uml::Region::East: + region = Uml::Region::North; + break; + case Uml::Region::South: + region = Uml::Region::East; + break; + default: + break; + } + // Now we have regular coordinates with the point (0, 0) in the + // bottom left corner. + if (region == Uml::Region::North || region == Uml::Region::South) { + if (dX == 0) + return rectMidY; + // should be rectMidX, but we go back to Qt coord.sys. + if (dY == 0) { + uError() << "usage error: " << "North/South (dY == 0)"; + return -1.0; + } + const qreal m = dY / dX; + qreal relativeX; + if (region == Uml::Region::North) + relativeX = rectHalfHeight / m; + else + relativeX = -rectHalfHeight / m; + return (rectMidY + relativeX); + // should be rectMidX, but we go back to Qt coord.sys. + } else { + if (dY == 0) + return rectMidX; + // should be rectMidY, but we go back to Qt coord.sys. + if (dX == 0) { + uError() << "usage error: " << "East/West (dX == 0)"; + return -1.0; + } + const qreal m = dY / dX; + qreal relativeY = m * rectHalfWidth; + if (region == Uml::Region::West) + relativeY = -relativeY; + return (rectMidX + relativeY); + // should be rectMidY, but we go back to Qt coord.sys. + } +} + +/** + * Auxiliary method for updateAssociations(): + * Put position into m_positions and assoc into m_ordered at the + * correct index. + * m_positions and m_ordered move in parallel and are sorted by + * ascending position. + */ +void AssociationWidget::insertIntoLists(qreal position, const AssociationWidget* assoc) +{ + bool did_insertion = false; + for (int index = 0; index < m_positions_len; ++index) { + if (position < m_positions[index]) { + for (int moveback = m_positions_len; moveback > index; moveback--) + m_positions[moveback] = m_positions[moveback - 1]; + m_positions[index] = position; + m_ordered.insert(index, const_cast(assoc)); + did_insertion = true; + break; + } + } + if (! did_insertion) { + m_positions[m_positions_len] = position; + m_ordered.append(const_cast(assoc)); + } + m_positions_len++; +} + +/** + * Tells all the other view associations the new count for the + * given widget on a certain region. And also what index they should be. + */ +void AssociationWidget::updateAssociations(int totalCount, + Uml::Region::Enum region, + Uml::RoleType::Enum role) +{ + if ((region == Uml::Region::Error) | (umlScene() == NULL)) { + return; + } + AssociationWidgetList list = m_scene->associationList(); + + UMLWidget *ownWidget = m_role[role].umlWidget; + m_positions_len = 0; + m_ordered.clear(); + // we order the AssociationWidget list by region and x/y value + foreach (AssociationWidget* assocwidget, list) { + WidgetRole *roleA = &assocwidget->m_role[RoleType::A]; + WidgetRole *roleB = &assocwidget->m_role[RoleType::B]; + UMLWidget *wA = roleA->umlWidget; + UMLWidget *wB = roleB->umlWidget; + // Skip self associations. + if (wA == wB) + continue; + // Now we must find out with which end the assocwidget connects + // to the input widget (ownWidget). + bool inWidgetARegion = (ownWidget == wA && + region == roleA->m_WidgetRegion); + bool inWidgetBRegion = (ownWidget == wB && + region == roleB->m_WidgetRegion); + if (!inWidgetARegion && !inWidgetBRegion) + continue; + // Determine intercept position on the edge indicated by `region'. + UMLWidget * otherWidget = (inWidgetARegion ? wB : wA); + AssociationLine *linepath = assocwidget->associationLine(); + QPointF refpoint; + if (assocwidget->linePathStartsAt(otherWidget)) + refpoint = linepath->point(linepath->count() - 2); + else + refpoint = linepath->point(1); + // The point is authoritative if we're called for the second time + // (i.e. role==B) or it is a waypoint on the line path. + bool pointIsAuthoritative = (role == RoleType::B || linepath->count() > 2); + if (! pointIsAuthoritative) { + // If the point is not authoritative then we use the other + // widget's center. + refpoint.setX(otherWidget->x() + otherWidget->width() / 2); + refpoint.setY(otherWidget->y() + otherWidget->height() / 2); + } + qreal intercept = findInterceptOnEdge(ownWidget->rect(), region, refpoint); + if (intercept < 0) { + DEBUG(DBG_SRC) << "error from findInterceptOnEdge for" + << " assocType=" << assocwidget->associationType() + << " ownWidget=" << ownWidget->name() + << " otherWidget=" << otherWidget->name(); + continue; + } + insertIntoLists(intercept, assocwidget); + } // while ((assocwidget = assoc_it.current())) + + // we now have an ordered list and we only have to call updateRegionLineCount + int index = 1; + foreach (AssociationWidget* assocwidget, m_ordered ) { + if (ownWidget == assocwidget->widgetForRole(RoleType::A)) { + assocwidget->updateRegionLineCount(index++, totalCount, region, RoleType::A); + } else if (ownWidget == assocwidget->widgetForRole(RoleType::B)) { + assocwidget->updateRegionLineCount(index++, totalCount, region, RoleType::B); + } + } // for (assocwidget = ordered.first(); ...) +} + +/** + * Called to tell the association that another association has added + * a line to the region of one of its widgets. The widget is identified + * by its role (A or B). + * + * Called by @ref updateAssociations which is called by + * @ref calculateEndingPoints when required. + */ +void AssociationWidget::updateRegionLineCount(int index, int totalCount, + Uml::Region::Enum region, + Uml::RoleType::Enum role) +{ + if ((region == Uml::Region::Error) | (umlScene() == NULL)) { + return; + } + // If the association is to self and the line ends are on the same region then + // use a different calculation. + if (isSelf() && + m_role[RoleType::A].m_WidgetRegion == m_role[RoleType::B].m_WidgetRegion) { + UMLWidget * pWidget = m_role[RoleType::A].umlWidget; + qreal x = pWidget->x(); + qreal y = pWidget->y(); + qreal wh = pWidget->height(); + qreal ww = pWidget->width(); + int size = m_associationLine->count(); + // See if above widget ok to place assoc. + switch( m_role[RoleType::A].m_WidgetRegion ) { + case Uml::Region::North: + m_associationLine->setPoint( 0, QPointF( x + ( ww / 4 ), y ) ); + m_associationLine->setPoint( size - 1, QPointF(x + ( ww * 3 / 4 ), y ) ); + break; + + case Uml::Region::South: + m_associationLine->setPoint( 0, QPointF( x + ( ww / 4 ), y + wh ) ); + m_associationLine->setPoint( size - 1, QPointF( x + ( ww * 3 / 4 ), y + wh ) ); + break; + + case Uml::Region::East: + m_associationLine->setPoint( 0, QPointF( x + ww, y + ( wh / 4 ) ) ); + m_associationLine->setPoint( size - 1, QPointF( x + ww, y + ( wh * 3 / 4 ) ) ); + break; + + case Uml::Region::West: + m_associationLine->setPoint( 0, QPointF( x, y + ( wh / 4 ) ) ); + m_associationLine->setPoint( size - 1, QPointF( x, y + ( wh * 3 / 4 ) ) ); + break; + default: + break; + }//end switch + + return; + } + + WidgetRole& robj = m_role[role]; + UMLWidget * pWidget = robj.umlWidget; + + robj.m_nIndex = index; + robj.m_nTotalCount = totalCount; + qreal x = pWidget->x(); + qreal y = pWidget->y(); + qreal ww = pWidget->width(); + qreal wh = pWidget->height(); + const bool angular = Settings::optionState().generalState.angularlines; + qreal ch = 0; + qreal cw = 0; + if (angular) { + uint nind = (role == RoleType::A ? 1 : m_associationLine->count() - 2); + QPointF neighbour = m_associationLine->point(nind); + if (neighbour.x() < x) + cw = 0; + else if (neighbour.x() > x + ww) + cw = 0 + ww; + else + cw = neighbour.x() - x; + if (neighbour.y() < y) + ch = 0; + else if (neighbour.y() > y + wh) + ch = 0 + wh; + else + ch = neighbour.y() - y; + } else { + ch = wh * index / totalCount; + cw = ww * index / totalCount; + } + + qreal newX = x + cw; + qreal newY = y + ch; + + QPointF pt; + if (angular) { + pt = QPointF(newX, newY); + } else { + UMLWidget *pWidgetA = m_role[RoleType::A].umlWidget; + UMLWidget *pWidgetB = m_role[RoleType::B].umlWidget; + QList polyListA = pWidgetA->shape().toSubpathPolygons(); + QPolygonF polyA = polyListA.at(0); + if (polyListA.size() > 1) { + for (int i = 1; i < polyListA.size(); i++) { + polyA = polyA.united(polyListA.at(i)); + } + } + polyA = polyA.translated(pWidgetA->pos()); + QList polyListB = pWidgetB->shape().toSubpathPolygons(); + QPolygonF polyB = polyListB.at(0); + if (polyListB.size() > 1) { + for (int i = 1; i < polyListB.size(); i++) { + polyB = polyB.united(polyListB.at(i)); + } + } + polyB = polyB.translated(pWidgetB->pos()); + QLineF nearestPoints = Widget_Utils::closestPoints(polyA, polyB); + if (nearestPoints.isNull()) { + uError() << "Widget_Utils::closestPoints failed, falling back to simple widget positions"; + switch(region) { + case Uml::Region::West: + pt.setX(x); + pt.setY(newY); + break; + case Uml::Region::North: + pt.setX(newX); + pt.setY(y); + break; + case Uml::Region::East: + pt.setX(x + ww); + pt.setY(newY); + break; + case Uml::Region::South: + pt.setX(newX); + pt.setY(y + wh); + break; + case Uml::Region::Center: + pt.setX(x + ww / 2); + pt.setY(y + wh / 2); + break; + default: + break; + } + } else { + if (role == RoleType::A) + pt = nearestPoints.p1(); + else + pt = nearestPoints.p2(); + } + } + if (role == RoleType::A) { + m_associationLine->setPoint(0, pt); + } + else { + m_associationLine->setPoint(m_associationLine->count() - 1, pt); + } +} + +/** + * Sets the state of whether the widget is selected. + * + * @param _select The state of whether the widget is selected. + */ +void AssociationWidget::setSelected(bool _select /* = true */) +{ + WidgetBase::setSelected(_select); + if ( m_nameWidget) + m_nameWidget->setSelected( _select ); + if ( m_role[RoleType::A].roleWidget ) + m_role[RoleType::A].roleWidget->setSelected( _select ); + if ( m_role[RoleType::B].roleWidget ) + m_role[RoleType::B].roleWidget->setSelected( _select ); + if ( m_role[RoleType::A].multiplicityWidget ) + m_role[RoleType::A].multiplicityWidget->setSelected( _select ); + if ( m_role[RoleType::B].multiplicityWidget ) + m_role[RoleType::B].multiplicityWidget->setSelected( _select ); + if ( m_role[RoleType::A].changeabilityWidget) + m_role[RoleType::A].changeabilityWidget->setSelected( _select ); + if ( m_role[RoleType::B].changeabilityWidget) + m_role[RoleType::B].changeabilityWidget->setSelected( _select ); + + // Update the docwindow for this association. + // This is done last because each of the above setSelected calls + // overwrites the docwindow, but we want the main association doc + // to win. + if (_select) { + if (m_scene->selectedCount() == 0) + UMLApp::app()->docWindow()->showDocumentation(this, false); + } else + UMLApp::app()->docWindow()->updateDocumentation(true); + + m_associationLine->setSelected(_select); + if (! _select) { + // For now, if _select is true we don't make the assoc class line + // selected. But that's certainly open for discussion. + // At any rate, we need to deselect the assoc class line + // if _select is false. + selectAssocClassLine(false); + } + UMLApp::app()->document()->writeToStatusBar(_select ? i18n("Press Ctrl with left mouse click to delete a point") : QString()); +} + +/** + * Reimplement method from WidgetBase in order to check owned floating texts. + * + * @param p Point to be checked. + * + * @return m_nameWidget if m_nameWidget is non NULL and m_nameWidget->onWidget(p) returns non NULL; + * m_role[0].(multiplicity|changeability|role)Widget if the resp. widget is non NULL and + * its onWidget(p) returns non NULL; + * m_role[1].(multiplicity|changeability|role)Widget if the resp. widget is non NULL and + * its onWidget(p) returns non NULL; + * else NULL. + */ +UMLWidget* AssociationWidget::onWidget(const QPointF &p) +{ + if (m_nameWidget && m_nameWidget->onWidget(p)) { + return m_nameWidget; + } + for (int i = 0; i <= 1; i++) { + const WidgetRole& r = m_role[i]; + if (r.multiplicityWidget && r.multiplicityWidget->onWidget(p)) + return r.multiplicityWidget; + if (r.changeabilityWidget && r.changeabilityWidget->onWidget(p)) + return r.changeabilityWidget; + if (r.roleWidget && r.roleWidget->onWidget(p)) + return r.roleWidget; + } + return NULL; +} + +/** + * Returns true if the given point is on the connecting line to + * the association class. Returns false if there is no association + * class attached, or if the given point is not on the connecting + * line. + */ +bool AssociationWidget::onAssocClassLine(const QPointF &point) +{ + bool onLine = false; + if (m_pAssocClassLine) { +//:TODO: +// const QPointF mapped = m_pAssocClassLine->mapFromParent(point); +// bool onLine = m_pAssocClassLine->contains(mapped); +// return onLine; + UMLSceneItemList list = m_scene->collisions(point); + UMLSceneItemList::iterator end(list.end()); + for (UMLSceneItemList::iterator item_it(list.begin()); item_it != end; ++item_it) { + if (*item_it == m_pAssocClassLine) { + onLine = true; + break; + } + } + } + DEBUG(DBG_SRC) << onLine; + return onLine; +} + +/** + * Returns true if the given point is on the association line. + * A circle (rectangle) around the point is used to obtain more tolerance. + * @param point the point to check + * @return flag whether point is on association line + */ +bool AssociationWidget::onAssociation(const QPointF& point) +{ + // check the path + const qreal diameter(4.0); + QPainterPath path = m_associationLine->shape(); + if (path.contains(point)) { + DEBUG(DBG_SRC) << "on path"; + return true; + } + // check also the points + if (m_associationLine->layout() == AssociationLine::Spline) { + if (m_associationLine->closestPointIndex(point, diameter) > -1) { + DEBUG(DBG_SRC) << "on spline point"; + return true; + } + } + return onAssocClassLine(point); +} + +/** + * Set all association points to x coordinate. + */ +void AssociationWidget::setXEntireAssoc(qreal x) +{ + for (int i = 0; i < m_associationLine->count(); ++i) { + QPointF p = m_associationLine->point(i); + p.setX(x); + m_associationLine->setPoint(i, p); + } +} + +/** + * Set all association points to y coordinate. + */ +void AssociationWidget::setYEntireAssoc(qreal y) +{ + for (int i = 0; i < m_associationLine->count(); ++i) { + QPointF p = m_associationLine->point(i); + p.setY(y); + m_associationLine->setPoint(i, p); + } +} + +/** + * Moves all the mid points (all expcept start /end) by the given amount. + */ +void AssociationWidget::moveMidPointsBy(qreal x, qreal y) +{ + int pos = m_associationLine->count() - 1; + for (int i = 1; i < (int)pos; ++i) { + QPointF p = m_associationLine->point( i ); + qreal newX = p.x() + x; + qreal newY = p.y() + y; + p.setX( newX ); + p.setY( newY ); + m_associationLine->setPoint( i, p ); + } +} + +/** + * Moves the entire association by the given offset. + */ +void AssociationWidget::moveEntireAssoc(qreal x, qreal y) +{ + //TODO: ADD SUPPORT FOR ASSOC. ON SEQ. DIAGRAMS WHEN NOTES BACK IN. + moveMidPointsBy(x, y); + calculateEndingPoints(); + calculateNameTextSegment(); + resetTextPositions(); +} + +/** + * Returns the bounding rectangle of all segments of the association. + */ +QRectF AssociationWidget::boundingRect() const +{ + return m_associationLine->boundingRect(); +} + +/** + * Returns the shape of all segments of the association. + */ +QPainterPath AssociationWidget::shape() const +{ + return m_associationLine->shape(); +} + +/** + * Connected to UMLClassifier::attributeRemoved() or UMLEntity::constraintRemoved() + * in case this AssociationWidget is linked to a clasifier list item + * (an attribute or a foreign key constraint) + * + * @param obj The UMLClassifierListItem removed. + */ +void AssociationWidget::slotClassifierListItemRemoved(UMLClassifierListItem* obj) +{ + if (obj != m_umlObject) { + DEBUG(DBG_SRC) << "obj=" << obj << ": m_umlObject=" << m_umlObject; + return; + } + m_umlObject = 0; + m_scene->removeAssoc(this); +} + +/** + * Connected to UMLObject::modified() in case this + * AssociationWidget is linked to a classifer's attribute type. + */ +void AssociationWidget::slotAttributeChanged() +{ + UMLAttribute *attr = attribute(); + if (attr == NULL) { + uError() << "attribute() returns NULL"; + return; + } + setVisibility(attr->visibility(), RoleType::B); + setRoleName(attr->name(), RoleType::B); +} + +void AssociationWidget::clipSize() +{ + if (m_nameWidget) + m_nameWidget->clipSize(); + + if (m_role[RoleType::A].multiplicityWidget) + m_role[RoleType::A].multiplicityWidget->clipSize(); + + if (m_role[RoleType::B].multiplicityWidget) + m_role[RoleType::B].multiplicityWidget->clipSize(); + + if (m_role[RoleType::A].roleWidget) + m_role[RoleType::A].roleWidget->clipSize(); + + if (m_role[RoleType::B].roleWidget) + m_role[RoleType::B].roleWidget->clipSize(); + + if (m_role[RoleType::A].changeabilityWidget) + m_role[RoleType::A].changeabilityWidget->clipSize(); + + if (m_role[RoleType::B].changeabilityWidget) + m_role[RoleType::B].changeabilityWidget->clipSize(); + + if (m_associationClass) + m_associationClass->clipSize(); +} + +/** + * Event handler for context menu events, called from the line segments. + */ +void AssociationWidget::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) +{ + const Uml::AssociationType::Enum type = associationType(); + ListPopupMenu::MenuType menuType = ListPopupMenu::mt_Association_Selected; + if ((type == Uml::AssociationType::Anchor) || + onAssocClassLine(event->scenePos())) { + menuType = ListPopupMenu::mt_Anchor; + } else if (isCollaboration()) { + menuType = ListPopupMenu::mt_Collaboration_Message; + } else if (!association()) { + menuType = ListPopupMenu::mt_AttributeAssociation; + } else if (AssocRules::allowRole(type)) { + menuType = ListPopupMenu::mt_FullAssociation; + } + + event->accept(); + DEBUG(DBG_SRC) << "menue type = " << ListPopupMenu::toString(menuType) + << " / association = " << Uml::AssociationType::toString(type); + + UMLScene *scene = umlScene(); + QWidget *parent = 0; + if (scene) { + parent = scene->activeView(); + } + + if (!isSelected() && scene && !scene->selectedItems().isEmpty()) { + Qt::KeyboardModifiers forSelection = (Qt::ControlModifier | Qt::ShiftModifier); + if ((event->modifiers() & forSelection) == 0) { + scene->clearSelection(); + } + } + setSelected(true); + m_eventScenePos = event->scenePos(); + ListPopupMenu popup(parent, menuType, this); + QAction *triggered = popup.exec(event->screenPos()); + ListPopupMenu *parentMenu = ListPopupMenu::menuFromAction(triggered); + + if (!parentMenu) { + uWarning() << "Action's data field does not contain ListPopupMenu pointer"; + return; + } + + WidgetBase *ownerWidget = parentMenu->ownerWidget(); + // assert because logic is based on only WidgetBase being the owner of + // ListPopupMenu actions executed in this context menu. + Q_ASSERT_X(ownerWidget != 0, "AssociationWidget::contextMenuEvent", + "ownerWidget is null which means action belonging to UMLView, UMLScene" + " or UMLObject is the one triggered in ListPopupMenu"); + + ownerWidget->slotMenuSelection(triggered); +} + +/** + * Reimplemented event handler for hover enter events. + */ +void AssociationWidget::hoverEnterEvent(QGraphicsSceneHoverEvent *event) +{ + associationLine()->hoverEnterEvent(event); +} + +/** + * Reimplemented event handler for hover leave events. + */ +void AssociationWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) +{ + associationLine()->hoverLeaveEvent(event); +} + +/** + * Reimplemented event handler for hover move events. + */ +void AssociationWidget::hoverMoveEvent(QGraphicsSceneHoverEvent *event) +{ + associationLine()->hoverMoveEvent(event); +} + +/** + * Saves this widget to the "assocwidget" XMI element. + */ +void AssociationWidget::saveToXMI(QDomDocument &qDoc, QDomElement &qElement) +{ + QDomElement assocElement = qDoc.createElement(QLatin1String("assocwidget")); + + WidgetBase::saveToXMI(qDoc, assocElement); + LinkWidget::saveToXMI(qDoc, assocElement); + if (m_umlObject) { + assocElement.setAttribute(QLatin1String("xmi.id"), Uml::ID::toString(m_umlObject->id())); + } + assocElement.setAttribute(QLatin1String("type"), associationType()); + if (!association()) { + assocElement.setAttribute(QLatin1String("visibilityA"), visibility(RoleType::A)); + assocElement.setAttribute(QLatin1String("visibilityB"), visibility(RoleType::B)); + assocElement.setAttribute(QLatin1String("changeabilityA"), changeability(RoleType::A)); + assocElement.setAttribute(QLatin1String("changeabilityB"), changeability(RoleType::B)); + if (m_umlObject == NULL) { + assocElement.setAttribute(QLatin1String("roleAdoc"), roleDocumentation(RoleType::A)); + assocElement.setAttribute(QLatin1String("roleBdoc"), roleDocumentation(RoleType::B)); + assocElement.setAttribute(QLatin1String("documentation"), documentation()); + } + } + assocElement.setAttribute(QLatin1String("widgetaid"), Uml::ID::toString(widgetIDForRole(RoleType::A))); + assocElement.setAttribute(QLatin1String("widgetbid"), Uml::ID::toString(widgetIDForRole(RoleType::B))); + assocElement.setAttribute(QLatin1String("indexa"), m_role[RoleType::A].m_nIndex); + assocElement.setAttribute(QLatin1String("indexb"), m_role[RoleType::B].m_nIndex); + assocElement.setAttribute(QLatin1String("totalcounta"), m_role[RoleType::A].m_nTotalCount); + assocElement.setAttribute(QLatin1String("totalcountb"), m_role[RoleType::B].m_nTotalCount); + m_associationLine->saveToXMI(qDoc, assocElement); + + if (m_nameWidget) { + m_nameWidget->saveToXMI(qDoc, assocElement); + } + + if (multiplicityWidget(RoleType::A)) { + multiplicityWidget(RoleType::A)->saveToXMI(qDoc, assocElement); + } + + if (multiplicityWidget(RoleType::B)) { + multiplicityWidget(RoleType::B)->saveToXMI(qDoc, assocElement); + } + + if (roleWidget(RoleType::A)) { + roleWidget(RoleType::A)->saveToXMI(qDoc, assocElement); + } + + if (roleWidget(RoleType::B)) { + roleWidget(RoleType::B)->saveToXMI(qDoc, assocElement); + } + + if (changeabilityWidget(RoleType::A)) { + changeabilityWidget(RoleType::A)->saveToXMI(qDoc, assocElement); + } + + if (changeabilityWidget(RoleType::B)) { + changeabilityWidget(RoleType::B)->saveToXMI(qDoc, assocElement); + } + + if (m_associationClass) { + QString acid = Uml::ID::toString(m_associationClass->id()); + assocElement.setAttribute(QLatin1String("assocclass"), acid); + assocElement.setAttribute(QLatin1String("aclsegindex"), m_nLinePathSegmentIndex); + } + + qElement.appendChild(assocElement); +} + +/** + * Uses the supplied widgetList for resolving + * the role A and role B widgets. (The other loadFromXMI() queries + * the UMLView for these widgets.) + * Required for clipboard operations. + */ +bool AssociationWidget::loadFromXMI(QDomElement& qElement, + const UMLWidgetList& widgets, + const MessageWidgetList* messages) +{ + if (!WidgetBase::loadFromXMI(qElement)) { + return false; + } + + if (!LinkWidget::loadFromXMI(qElement)) { + return false; + } + + // load child widgets first + QString widgetaid = qElement.attribute(QLatin1String("widgetaid"), QLatin1String("-1")); + QString widgetbid = qElement.attribute(QLatin1String("widgetbid"), QLatin1String("-1")); + Uml::ID::Type aId = Uml::ID::fromString(widgetaid); + Uml::ID::Type bId = Uml::ID::fromString(widgetbid); + UMLWidget *pWidgetA = Widget_Utils::findWidget(aId, widgets, messages); + if (!pWidgetA) { + uError() << "cannot find widget for roleA id " << Uml::ID::toString(aId); + return false; + } + UMLWidget *pWidgetB = Widget_Utils::findWidget(bId, widgets, messages); + if (!pWidgetB) { + uError() << "cannot find widget for roleB id " << Uml::ID::toString(bId); + return false; + } + setWidgetForRole(pWidgetA, RoleType::A); + setWidgetForRole(pWidgetB, RoleType::B); + + QString type = qElement.attribute(QLatin1String("type"), QLatin1String("-1")); + Uml::AssociationType::Enum aType = Uml::AssociationType::fromInt(type.toInt()); + + QString id = qElement.attribute(QLatin1String("xmi.id"), QLatin1String("-1")); + bool oldStyleLoad = false; + if (id == QLatin1String("-1")) { + // xmi.id not present, ergo either a pure widget association, + // or old (pre-1.2) style: + // Everything is loaded from the AssociationWidget. + // UMLAssociation may or may not be saved - if it is, it's a dummy. + // Create the UMLAssociation if both roles are UML objects; + // else load the info locally. + + if (Uml::AssociationType::hasUMLRepresentation(aType)) { + // lack of an association in our widget AND presence of + // both uml objects for each role clearly identifies this + // as reading in an old-school file. Note it as such, and + // create, and add, the UMLAssociation for this widget. + // Remove this special code when backwards compatibility + // with older files isn't important anymore. -b.t. + UMLObject* umlRoleA = pWidgetA->umlObject(); + UMLObject* umlRoleB = pWidgetB->umlObject(); + if (!m_umlObject && umlRoleA && umlRoleB) { + oldStyleLoad = true; // flag for further special config below + if (aType == AssociationType::Aggregation || aType == AssociationType::Composition) { + uWarning()<<" Old Style save file? swapping roles on association widget"<umlObject(); + umlRoleB = pWidgetB->umlObject(); + } + + setUMLAssociation(umlDoc()->createUMLAssociation(umlRoleA, umlRoleB, aType)); + } + } + + setDocumentation(qElement.attribute(QLatin1String("documentation"))); + setRoleDocumentation(qElement.attribute(QLatin1String("roleAdoc")), RoleType::A); + setRoleDocumentation(qElement.attribute(QLatin1String("roleBdoc")), RoleType::B); + + // visibility defaults to Public if it cant set it here.. + QString visibilityA = qElement.attribute(QLatin1String("visibilityA"), QLatin1String("0")); + int vis = visibilityA.toInt(); + if (vis >= 200) { // bkwd compat. + vis -= 200; + } + setVisibility((Uml::Visibility::Enum)vis, RoleType::A); + + QString visibilityB = qElement.attribute(QLatin1String("visibilityB"), QLatin1String("0")); + vis = visibilityB.toInt(); + if (vis >= 200) { // bkwd compat. + vis -= 200; + } + setVisibility((Uml::Visibility::Enum)vis, RoleType::B); + + // Changeability defaults to "Changeable" if it cant set it here.. + QString changeabilityA = qElement.attribute(QLatin1String("changeabilityA"), QLatin1String("0")); + if (changeabilityA.toInt() > 0) + setChangeability(Uml::Changeability::fromInt(changeabilityA.toInt()), RoleType::A); + + QString changeabilityB = qElement.attribute(QLatin1String("changeabilityB"), QLatin1String("0")); + if (changeabilityB.toInt() > 0) + setChangeability(Uml::Changeability::fromInt(changeabilityB.toInt()), RoleType::B); + + } else { + + // we should disconnect any prior association (can this happen??) + if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) { + UMLAssociation *umla = association(); + umla->disconnect(this); + umla->nrof_parent_widgets--; + } + + // New style: The xmi.id is a reference to the UMLAssociation. + // If the UMLObject is not found right now, we try again later + // during the type resolution pass - see activate(). + m_nId = Uml::ID::fromString(id); + UMLObject *myObj = umlDoc()->findObjectById(m_nId); + if (myObj) { + const UMLObject::ObjectType ot = myObj->baseType(); + if (ot != UMLObject::ot_Association) { + setUMLObject(myObj); + } else { + UMLAssociation * myAssoc = static_cast(myObj); + setUMLAssociation(myAssoc); + if (type == QLatin1String("-1")) + aType = myAssoc->getAssocType(); + } + } + } + + setAssociationType(aType); + + QString indexa = qElement.attribute(QLatin1String("indexa"), QLatin1String("0")); + QString indexb = qElement.attribute(QLatin1String("indexb"), QLatin1String("0")); + QString totalcounta = qElement.attribute(QLatin1String("totalcounta"), QLatin1String("0")); + QString totalcountb = qElement.attribute(QLatin1String("totalcountb"), QLatin1String("0")); + m_role[RoleType::A].m_nIndex = indexa.toInt(); + m_role[RoleType::B].m_nIndex = indexb.toInt(); + m_role[RoleType::A].m_nTotalCount = totalcounta.toInt(); + m_role[RoleType::B].m_nTotalCount = totalcountb.toInt(); + + QString assocclassid = qElement.attribute(QLatin1String("assocclass")); + if (! assocclassid.isEmpty()) { + Uml::ID::Type acid = Uml::ID::fromString(assocclassid); + UMLWidget *w = Widget_Utils::findWidget(acid, widgets); + if (w) { + ClassifierWidget* aclWidget = static_cast(w); + QString aclSegIndex = qElement.attribute(QLatin1String("aclsegindex"), QLatin1String("0")); + createAssocClassLine(aclWidget, aclSegIndex.toInt()); + } else { + uError() << "cannot find assocclass " << assocclassid; + } + } + + //now load child elements + QDomNode node = qElement.firstChild(); + QDomElement element = node.toElement(); + while (!element.isNull()) { + QString tag = element.tagName(); + if (tag == QLatin1String("linepath")) { + if (!m_associationLine->loadFromXMI(element)) { + return false; + } + } else if (tag == QLatin1String("floatingtext") || + tag == QLatin1String("UML:FloatingTextWidget")) { // for bkwd compatibility + QString r = element.attribute(QLatin1String("role"), QLatin1String("-1")); + if (r == QLatin1String("-1")) + return false; + Uml::TextRole::Enum role = Uml::TextRole::fromInt(r.toInt()); + FloatingTextWidget *ft = new FloatingTextWidget(m_scene, role, QString(), Uml::ID::Reserved); + if (! ft->loadFromXMI(element)) { + // Most likely cause: The FloatingTextWidget is empty. + delete ft; + node = element.nextSibling(); + element = node.toElement(); + continue; + } + // always need this + ft->setParentItem(this); + ft->setLink(this); + ft->setSequenceNumber(m_SequenceNumber); + ft->setFontCmd(ft->font()); + + switch(role) { + case Uml::TextRole::MultiA: + m_role[RoleType::A].multiplicityWidget = ft; + if (oldStyleLoad) + setMultiplicity(m_role[RoleType::A].multiplicityWidget->text(), RoleType::A); + break; + + case Uml::TextRole::MultiB: + m_role[RoleType::B].multiplicityWidget = ft; + if (oldStyleLoad) + setMultiplicity(m_role[RoleType::B].multiplicityWidget->text(), RoleType::B); + break; + + case Uml::TextRole::ChangeA: + m_role[RoleType::A].changeabilityWidget = ft; + break; + + case Uml::TextRole::ChangeB: + m_role[RoleType::B].changeabilityWidget = ft; + break; + + case Uml::TextRole::Name: + m_nameWidget = ft; + if (oldStyleLoad) + setName(m_nameWidget->text()); + break; + + case Uml::TextRole::Coll_Message: + case Uml::TextRole::Coll_Message_Self: + m_nameWidget = ft; + ft->setLink(this); + ft->setActivated(); + if (FloatingTextWidget::isTextValid(ft->text())) + ft->show(); + else + ft->hide(); + break; + + case Uml::TextRole::RoleAName: + m_role[RoleType::A].roleWidget = ft; + setRoleName(ft->text(), RoleType::A); + break; + case Uml::TextRole::RoleBName: + m_role[RoleType::B].roleWidget = ft; + setRoleName(ft->text(), RoleType::B); + break; + default: + DEBUG(DBG_SRC) << "unexpected FloatingTextWidget (TextRole::Enum " << role << ")"; + delete ft; + break; + } + } + node = element.nextSibling(); + element = node.toElement(); + } + + return true; +} + +/** + * Queries the UMLView for resolving the role A and role B widgets. + * .... + */ +bool AssociationWidget::loadFromXMI(QDomElement& qElement) +{ + UMLScene *scene = umlScene(); + if (scene) { + const UMLWidgetList& widgetList = scene->widgetList(); + const MessageWidgetList& messageList = scene->messageList(); + return loadFromXMI(qElement, widgetList, &messageList); + } + else { + DEBUG(DBG_SRC) << "This isn't on UMLScene yet, so can neither fetch" + "messages nor widgets on umlscene"; + return false; + } +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/associationwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/associationwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/associationwidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/associationwidget.h 2015-10-08 11:48:59.508089026 +0300 @@ -0,0 +1,328 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef ASSOCIATIONWIDGET_H +#define ASSOCIATIONWIDGET_H + +#include "associationwidgetlist.h" +#include "linkwidget.h" +#include "messagewidgetlist.h" +#include "umlwidgetlist.h" +#include "widgetbase.h" + +class AssociationLine; +class ClassifierWidget; +class UMLScene; +class UMLAssociation; +class UMLAttribute; +class UMLClassifierListItem; +class UMLOperation; + +/** + * This class represents an association inside a diagram. + * + * Constructor is made non accessible: + * Users shall use the static create() methods for constructing AssociationWidgets. + * + * Associations exist not only between UML objects. For example, when a Note is + * attached to a UML object, the Note itself is not a UML object. + * This class supports both kinds of associations. An association where one or + * both roles are not a UML object is called a "pure widget association". + * + * An AssociationWidget where both roles are UML objects has a corresponding + * UMLAssociation. The UMLAssociation can be retrieved using the getAssociation + * method. + * A pure widget association does not have a corresponding UMLAssociation. + * The getAssociation method returns NULL in this case. + * + * @author Gustavo Madrigal + * @author Gopala Krishna + * @short This class represents an association inside a diagram. + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class AssociationWidget : public WidgetBase, public LinkWidget +{ + Q_OBJECT +public: + static AssociationWidget* create(UMLScene *scene); + static AssociationWidget* create + (UMLScene *scene, UMLWidget* WidgetA, + Uml::AssociationType::Enum assocType, UMLWidget* WidgetB, + UMLObject *umlobject = NULL); + + virtual ~AssociationWidget(); + + virtual void setUMLObject(UMLObject *obj); + + //---------- LinkWidget Interface methods implementation from now on. + + virtual void lwSetFont(QFont font); + virtual UMLClassifier *operationOwner(); + + virtual UMLOperation *operation(); + virtual void setOperation(UMLOperation *op); + + virtual QString customOpText(); + virtual void setCustomOpText(const QString &opText); + + virtual void resetTextPositions(); + + virtual void setMessageText(FloatingTextWidget *ft); + virtual void setText(FloatingTextWidget *ft, const QString &newText); + + virtual void showPropertiesDialog(); + + virtual QString lwOperationText(); + virtual UMLClassifier *lwClassifier(); + virtual void setOperationText(const QString &op); + + virtual void constrainTextPos(qreal &textX, qreal &textY, + qreal textWidth, qreal textHeight, + Uml::TextRole::Enum tr); + + virtual void calculateNameTextSegment(); + + //---------- End LinkWidget Interface methods implementation. + + UMLAssociation* association() const; + UMLAttribute* attribute() const; + +// AssociationWidget& operator=(const AssociationWidget& other); + bool operator==(const AssociationWidget& other) const; + bool operator!=(AssociationWidget& other) const; + + FloatingTextWidget* textWidgetByRole(Uml::TextRole::Enum tr) const; + + FloatingTextWidget* nameWidget() const; + QString name() const; + void setName(const QString &strRole); + void setStereotype(const QString &stereo); + + FloatingTextWidget* roleWidget(Uml::RoleType::Enum role) const; + QString roleName(Uml::RoleType::Enum role) const; + void setRoleName(const QString &strRole, Uml::RoleType::Enum role); + + QString roleDocumentation(Uml::RoleType::Enum role) const; + void setRoleDocumentation(const QString& doc, Uml::RoleType::Enum role); + + FloatingTextWidget* multiplicityWidget(Uml::RoleType::Enum role) const; + QString multiplicity(Uml::RoleType::Enum role) const; + void setMultiplicity(const QString& text, Uml::RoleType::Enum role); + + Uml::Visibility::Enum visibility(Uml::RoleType::Enum role) const; + void setVisibility(Uml::Visibility::Enum value, Uml::RoleType::Enum role); + + FloatingTextWidget* changeabilityWidget(Uml::RoleType::Enum role) const; + Uml::Changeability::Enum changeability(Uml::RoleType::Enum role) const; + void setChangeability(Uml::Changeability::Enum value, Uml::RoleType::Enum role); + + Uml::ID::Type widgetIDForRole(Uml::RoleType::Enum role) const; + Uml::ID::Type widgetLocalIDForRole(Uml::RoleType::Enum role) const; + UMLWidget* widgetForRole(Uml::RoleType::Enum role) const; + void setWidgetForRole(UMLWidget* widget, Uml::RoleType::Enum role); + + bool setWidgets(UMLWidget* widgetA, Uml::AssociationType::Enum assocType, UMLWidget* widgetB); + + bool containsAsEndpoint(UMLWidget* widget); + + Uml::AssociationType::Enum associationType() const; + void setAssociationType(Uml::AssociationType::Enum type); + + bool isCollaboration() const; + bool isSelf() const; + + QString toString() const; + + bool isActivated() const; + void setActivated(bool active); + + AssociationLine* associationLine() const; + + virtual bool activate(); + virtual QRectF boundingRect() const; + virtual QPainterPath shape() const; + + void widgetMoved(UMLWidget* widget, qreal x, qreal y); + + void saveIdealTextPositions(); + + UMLWidget* onWidget(const QPointF &p); + bool onAssociation(const QPointF& point); + bool onAssocClassLine(const QPointF& point); + + void createAssocClassLine(); + void createAssocClassLine(ClassifierWidget* classifierWidget, + int linePathSegmentIndex); + + void selectAssocClassLine(bool sel = true); + void removeAssocClassLine(); + void computeAssocClassLine(); + + void setXEntireAssoc(qreal x); + void setYEntireAssoc(qreal y); + + void moveMidPointsBy(qreal x, qreal y); + void moveEntireAssoc(qreal x, qreal y); + + QFont font() const; + + virtual void setTextColor(const QColor &color); + + void calculateEndingPoints(); + + void clipSize(); + + bool loadFromXMI(QDomElement& qElement, const UMLWidgetList& widgets, + const MessageWidgetList* messages); + virtual bool loadFromXMI(QDomElement& qElement); + virtual void saveToXMI(QDomDocument &qDoc, QDomElement &qElement); + + void cleanup(); + + bool isPointAddable(); + bool isPointRemovable(); + + //:TODO: the following four methods should be protected + virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event); + virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + + virtual void setSelected(bool _select); +public Q_SLOTS: //:TODO: all virtual? + virtual void slotMenuSelection(QAction* action); + void slotClassifierListItemRemoved(UMLClassifierListItem* obj); + void slotAttributeChanged(); + + void syncToModel(); + +protected: + virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *event); + + virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event); + virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); + virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event); + +private: + QPointF calculateTextPosition(Uml::TextRole::Enum role); + void setTextPosition(Uml::TextRole::Enum role); + void setTextPositionRelatively(Uml::TextRole::Enum role, const QPointF &oldPosition); + void setFloatingText(Uml::TextRole::Enum role, const QString& text, FloatingTextWidget* &ft); + + AssociationWidget(UMLScene *scene); + + void setUMLAssociation(UMLAssociation * assoc); + + void mergeAssociationDataIntoUMLRepresentation(); + + static Uml::Region::Enum findPointRegion(const QRectF& rect, const QPointF& pos); + static qreal findInterceptOnEdge(const QRectF &rect, Uml::Region::Enum region, const QPointF &point); + static QLineF::IntersectType intersect(const QRectF &rect, const QLineF &line, + QPointF* intersectionPoint); + + void moveEvent(QGraphicsSceneMouseEvent *me); + + Uml::TextRole::Enum calculateNameType(Uml::TextRole::Enum defaultRoleType); + + static QPointF swapXY(const QPointF &p); + + // not used at the moment + // static QPointF calculatePointAtDistance(const QPointF &P1, const QPointF &P2, float Distance); + // static QPointF calculatePointAtDistanceOnPerpendicular(const QPointF &P1, const QPointF &P2, float Distance); + // static float perpendicularProjection(const QPointF& P1, const QPointF& P2, const QPointF& P3, QPointF& ResultingPoint); + + static QPointF midPoint(const QPointF& p0, const QPointF& p1); + + void createPointsSelfAssociation(); + void updatePointsSelfAssociation(); + void createPointsException(); + void updatePointsException(); + + /** + * The WidgetRole struct gathers all information pertaining to the role. + * The AssociationWidget class contains two WidgetRole objects, one for each + * side of the association (A and B). + */ + struct WidgetRole { + + FloatingTextWidget* multiplicityWidget; ///< information regarding multiplicity + FloatingTextWidget* changeabilityWidget; ///< information regarding changeability + FloatingTextWidget* roleWidget; ///< role's label of this association + + UMLWidget* umlWidget; ///< UMLWidget at this role's side of this association + + Uml::Region::Enum m_WidgetRegion; ///< region of this role's widget + + int m_nIndex; ///< the index of where the line is on the region for this role + int m_nTotalCount; ///< total amount of associations on the region this role's line is on + + // The following items are only used if m_pObject is not set. + Uml::Visibility::Enum visibility; + Uml::Changeability::Enum changeability; + QString roleDocumentation; + + }; + + void updateRegionLineCount(int index, int totalCount, + Uml::Region::Enum region, Uml::RoleType::Enum role); + + void updateAssociations(int totalCount, Uml::Region::Enum region, Uml::RoleType::Enum role); + + int getRegionCount(Uml::Region::Enum region, Uml::RoleType::Enum role); + + void doUpdates(const QPointF &otherP, Uml::RoleType::Enum role); + + void setChangeWidget(const QString &strChangeWidget, Uml::RoleType::Enum role); + + bool checkAddPoint(const QPointF &scenePos); + bool checkRemovePoint(const QPointF &scenePos); + + bool linePathStartsAt(const UMLWidget* widget); + + void insertIntoLists(qreal position, const AssociationWidget* assoc); + + qreal m_positions[100]; ///< auxiliary variable for updateAssociations() + int m_positions_len; ///< auxiliary variable for updateAssociations() + AssociationWidgetList m_ordered; ///< auxiliary variable for updateAssociations() + + bool m_activated; ///< flag which is true if the activate method has been called for this class instance + + /** + * When the association has a Role Floating Text this text should move + * when the AssociationLine moves but only if the closest segment to the + * role text moves. + * This segment is: + * m_associationLine[m_unNameLineSegment] -- m_associationLine[m_unNameLineSegment+1] + */ + int m_unNameLineSegment; + + QPointF m_oldNamePoint; ///< Position of name floatingtext saved by saveIdealTextPositions() + QPointF m_oldMultiAPoint; ///< Position of role A multiplicity floatingtext saved by saveIdealTextPositions() + QPointF m_oldMultiBPoint; ///< Position of role B multiplicity floatingtext saved by saveIdealTextPositions() + QPointF m_oldChangeAPoint; ///< Position of role A changeability floatingtext saved by saveIdealTextPositions() + QPointF m_oldChangeBPoint; ///< Position of role B changeability floatingtext saved by saveIdealTextPositions() + QPointF m_oldRoleAPoint; ///< Position of role A name floatingtext saved by saveIdealTextPositions() + QPointF m_oldRoleBPoint; ///< Position of role B name floatingtext saved by saveIdealTextPositions() + + int m_nLinePathSegmentIndex; ///< anchor for m_pAssocClassLine + QGraphicsLineItem *m_pAssocClassLine; ///< used for connecting assoc. class + QGraphicsRectItem *m_pAssocClassLineSel0; ///< selection decoration for the start point of the assoc. class line + QGraphicsRectItem *m_pAssocClassLineSel1; ///< selection decoration for the end point of the assoc. class line + + AssociationLine *m_associationLine; ///< the definition points for the association line + ClassifierWidget *m_associationClass; ///< used if we have an assoc. class + Uml::AssociationType::Enum m_associationType; ///< is only used if m_pObject is not set + WidgetRole m_role[2]; + FloatingTextWidget* m_nameWidget; ///< displays the name of this association + QPointF m_eventScenePos; ///< holds scene pos of contextMenuEvent() + +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/boxwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/boxwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/boxwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/boxwidget.cpp 2015-10-08 11:48:59.508089026 +0300 @@ -0,0 +1,79 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "boxwidget.h" + +// app includes +#include "uml.h" +#include "umldoc.h" + +// qt includes +#include + +/** + * Constructs a BoxWidget. + * + * @param scene The parent to this widget. + * @param id The ID to assign (-1 will prompt a new ID.) + * @param type The WidgetType (wt_Box.) + */ +BoxWidget::BoxWidget(UMLScene * scene, Uml::ID::Type id, WidgetType type) + : UMLWidget(scene, type, id) +{ + setSize(100, 80); + m_usesDiagramLineColor = false; // boxes be black + m_lineColor = QColor("black"); + setZValue(-10); +} + +/** + * Destructor. + */ +BoxWidget::~BoxWidget() +{ +} + +/** + * Draws a rectangle. + */ +void BoxWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + setPenFromSettings(painter); + painter->drawRect(0, 0, width(), height()); + + UMLWidget::paint(painter, option, widget); +} + +/** + * Saves the widget to the "boxwidget" XMI element. + * Note: For loading from XMI, the inherited parent method is used. + */ +void BoxWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +{ + QDomElement boxElement = qDoc.createElement(QLatin1String("boxwidget")); + UMLWidget::saveToXMI(qDoc, boxElement); + qElement.appendChild(boxElement); +} + +/** + * Show a properties dialog for a BoxWidget. + */ +void BoxWidget::showPropertiesDialog() +{ + QColor newColor = QColorDialog::getColor(lineColor()); // krazy:exclude=qclasses + if (newColor != lineColor()) { + setLineColor(newColor); + setUsesDiagramLineColor(false); + umlDoc()->setModified(true); + } +} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/boxwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/boxwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/boxwidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/boxwidget.h 2015-10-08 11:48:59.508089026 +0300 @@ -0,0 +1,39 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef BOXWIDGET_H +#define BOXWIDGET_H + +//app includes +#include "umlwidget.h" + +/** + * Displays a rectangular box. + * These widgets are diagram specific. They will still need a unique id + * from the @ref UMLDoc class for deletion and other purpose-kf6s. + * + * @short Displays a box. + * @author Jonathan Riddell + * @see UMLWidget + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class BoxWidget : public UMLWidget +{ +public: + explicit BoxWidget(UMLScene * scene, Uml::ID::Type id = Uml::ID::None, WidgetType type = WidgetBase::wt_Box); + virtual ~BoxWidget(); + + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); + + virtual void showPropertiesDialog(); +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/categorywidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/categorywidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/categorywidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/categorywidget.cpp 2015-10-08 11:48:59.508089026 +0300 @@ -0,0 +1,148 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header file +#include "categorywidget.h" + +// local includes +#include "category.h" +#include "debug_utils.h" +#include "umlview.h" +#include "listpopupmenu.h" + +// qt includes +#include + +/** + * Creates a Category widget. + * + * @param scene The parent of the widget. + * @param o The UMLCategory to represent. + */ +CategoryWidget::CategoryWidget(UMLScene * scene, UMLCategory *o) + : UMLWidget(scene, WidgetBase::wt_Category, o) +{ + m_fixedAspectRatio = true; +} + +/** + * Destructor. + */ +CategoryWidget::~CategoryWidget() +{ +} + +/** + * Overrides the standard paint event. + */ +void CategoryWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + UMLWidget::setPenFromSettings(painter); + if (UMLWidget::useFillColor()) + painter->setBrush(UMLWidget::fillColor()); + QFont font = UMLWidget::font(); + font.setUnderline(false); + font.setBold(false); + font.setItalic(m_umlObject->isAbstract()); + painter->setFont(font); + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + // the height is our radius + const int h = height(); + const int w = width(); + const int r = h > w ? h : w; + + //int middleX = w / 2; + const int textStartY = (r / 2) - (fontHeight / 2); + + // draw a circle + painter->drawEllipse(0, 0, r, r); + painter->setPen(textColor()); + + QString letterType(QLatin1Char('D')); + switch(static_cast(m_umlObject)->getType()) { + case UMLCategory::ct_Disjoint_Specialisation: + letterType = QLatin1Char('D'); + break; + case UMLCategory::ct_Overlapping_Specialisation: + letterType = QLatin1Char('O'); + break; + case UMLCategory::ct_Union: + letterType = QLatin1Char('U'); + break; + default: + break; + } + + painter->drawText(UC_MARGIN, textStartY, r - UC_MARGIN * 2, fontHeight, Qt::AlignCenter, letterType); + UMLWidget::setPenFromSettings(painter); + + UMLWidget::paint(painter, option, widget); +} + +/** + * Overrides method from UMLWidget. + */ +QSizeF CategoryWidget::minimumSize() const +{ + const UMLWidget::FontType ft = (m_umlObject->isAbstract() ? FT_BOLD_ITALIC : FT_BOLD); + const QFontMetrics &fm = UMLWidget::getFontMetrics(ft); + const int fontHeight = fm.lineSpacing(); + int radius = UC_RADIUS + fontHeight + UC_MARGIN; + + return QSizeF(radius, radius); +} + +/** + * Saves this Category to file. + */ +void CategoryWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +{ + QDomElement categoryElement = qDoc.createElement(QLatin1String("categorywidget")); + UMLWidget::saveToXMI(qDoc, categoryElement); + qElement.appendChild(categoryElement); +} + +/** + * Will be called when a menu selection has been made from the + * popup menu. + * + * @param action The action that has been selected. + */ +void CategoryWidget::slotMenuSelection(QAction* action) +{ + UMLCategory* catObj = static_cast(umlObject()); + if (!catObj) { + uWarning() << "No UMLCategory for this widget."; + return; + } + + ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); + switch(sel) { + case ListPopupMenu::mt_DisjointSpecialisation: + catObj->setType(UMLCategory::ct_Disjoint_Specialisation); + break; + + case ListPopupMenu::mt_OverlappingSpecialisation: + catObj->setType(UMLCategory::ct_Overlapping_Specialisation); + break; + + case ListPopupMenu::mt_Union: + catObj->setType(UMLCategory::ct_Union); + break; + + default: + UMLWidget::slotMenuSelection(action); + } +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/categorywidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/categorywidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/categorywidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/categorywidget.h 2015-10-08 11:48:59.508089026 +0300 @@ -0,0 +1,56 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef CATEGORYWIDGET_H +#define CATEGORYWIDGET_H + +#include "umlwidget.h" + +#define UC_MARGIN 5 +#define UC_RADIUS 30 + +class UMLCategory; + +/** + * This class is the graphical version of a UMLCategory. A CategoryWidget is created + * by a @ref UMLView. An CategoryWidget belongs to only one @ref UMLView instance. + * When the @ref UMLView instance that this class belongs to, it will be automatically deleted. + * + * If the Category class that this CategoryWidget is displaying is deleted, the @ref UMLView will + * make sure that this instance is also deleted. + * + * The CategoryWidget class inherits from the @ref UMLWidget class which adds most of the functionality + * to this class. + * + * @short A graphical version of a UMLCategory. + * @author Sharan Rao + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class CategoryWidget : public UMLWidget +{ + Q_OBJECT +public: + CategoryWidget(UMLScene * scene, UMLCategory *o); + virtual ~CategoryWidget(); + + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + + void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); + // For loading we can use the loadFromXMI() inherited from UMLWidget. + +protected: + QSizeF minimumSize() const; + +public slots: + void slotMenuSelection(QAction* action); + +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/classifierwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/classifierwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/classifierwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/classifierwidget.cpp 2015-10-08 11:48:59.508089026 +0300 @@ -0,0 +1,1426 @@ +/*************************************************************************** + * 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) 2004-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "classifierwidget.h" + +// app includes +#include "floatingtextwidget.h" +#include "associationwidget.h" +#include "associationline.h" +#include "classifier.h" +#include "cmds.h" +#include "debug_utils.h" +#include "listpopupmenu.h" +#include "object_factory.h" +#include "operation.h" +#include "template.h" +#include "uml.h" +#include "umldoc.h" +#include "umlview.h" + +#define PACKAGE_MARGIN 5 + +// qt includes +#include + +DEBUG_REGISTER_DISABLED(ClassifierWidget) + +const int ClassifierWidget::MARGIN = 5; +const int ClassifierWidget::CIRCLE_SIZE = 30; +const int ClassifierWidget::SOCKET_INCREMENT = 10; + +/** + * Constructs a ClassifierWidget. + * + * @param scene The parent of this ClassifierWidget. + * @param c The UMLClassifier to represent. + */ +ClassifierWidget::ClassifierWidget(UMLScene * scene, UMLClassifier *c) + : UMLWidget(scene, WidgetBase::wt_Class, c), + m_pAssocWidget(0), m_pInterfaceName(0) +{ + const Settings::OptionState& ops = m_scene->optionState(); + setVisualPropertyCmd(ShowVisibility, ops.classState.showVisibility); + setVisualPropertyCmd(ShowOperations, ops.classState.showOps); + setVisualPropertyCmd(ShowPublicOnly, ops.classState.showPublicOnly); + setVisualPropertyCmd(ShowPackage, ops.classState.showPackage); + m_attributeSignature = Uml::SignatureType::ShowSig; + /*:TODO: + setVisualProperty(ShowOperationSignature, ops.classState.showOpSig); + Cannot do that because we get "pure virtual method called". Open code: + */ + if(!ops.classState.showOpSig) { + if (visualProperty(ShowVisibility)) + m_operationSignature = Uml::SignatureType::NoSig; + else + m_operationSignature = Uml::SignatureType::NoSigNoVis; + + } else if (visualProperty(ShowVisibility)) + m_operationSignature = Uml::SignatureType::ShowSig; + else + m_operationSignature = Uml::SignatureType::SigNoVis; + + setVisualPropertyCmd(ShowAttributes, ops.classState.showAtts); + setVisualPropertyCmd(ShowStereotype, ops.classState.showStereoType); + setVisualPropertyCmd(DrawAsCircle, false); + + setShowAttSigs(ops.classState.showAttSig); + + if (c && c->isInterface()) { + m_baseType = WidgetBase::wt_Interface; + m_visualProperties = ShowOperations | ShowVisibility | ShowStereotype; + setShowStereotype(true); + updateSignatureTypes(); + } +} + +/** + * Constructs a ClassifierWidget. + * + * @param scene The parent of this ClassifierWidget. + * @param c The UMLClassifier to represent. + */ +ClassifierWidget::ClassifierWidget(UMLScene * scene, UMLPackage *o) + : UMLWidget(scene, WidgetBase::wt_Package, o), + m_pAssocWidget(0), + m_pInterfaceName(0) +{ + const Settings::OptionState& ops = m_scene->optionState(); + setVisualPropertyCmd(ShowVisibility, ops.classState.showVisibility); + setVisualPropertyCmd(ShowOperations, ops.classState.showOps); + setVisualPropertyCmd(ShowPublicOnly, ops.classState.showPublicOnly); + setVisualPropertyCmd(ShowPackage, ops.classState.showPackage); + m_attributeSignature = Uml::SignatureType::ShowSig; + + if(!ops.classState.showOpSig) { + if (visualProperty(ShowVisibility)) + m_operationSignature = Uml::SignatureType::NoSig; + else + m_operationSignature = Uml::SignatureType::NoSigNoVis; + + } else if (visualProperty(ShowVisibility)) + m_operationSignature = Uml::SignatureType::ShowSig; + else + m_operationSignature = Uml::SignatureType::SigNoVis; + + setVisualPropertyCmd(ShowAttributes, ops.classState.showAtts); + setVisualPropertyCmd(ShowStereotype, ops.classState.showStereoType); + setVisualPropertyCmd(DrawAsPackage, true); + + setShowAttSigs(ops.classState.showAttSig); +} + +/** + * Destructor. + */ +ClassifierWidget::~ClassifierWidget() +{ + if (m_pAssocWidget) + m_pAssocWidget->removeAssocClassLine(); + if (m_pInterfaceName) { + delete m_pInterfaceName; + m_pInterfaceName = 0; + } +} + +/** + * Return the UMLClassifier which this ClassifierWidget + * represents. + */ +UMLClassifier *ClassifierWidget::classifier() const +{ + return dynamic_cast(m_umlObject); +} + +/** + * @return the visual properties + */ +ClassifierWidget::VisualProperties ClassifierWidget::visualProperties() const +{ + return m_visualProperties; +} + +/** + * Set an OR combination of properties stored in \a properties on this + * widget. + */ +void ClassifierWidget::setVisualProperties(VisualProperties properties) +{ + // Don't do anything if the argument is equal to current status. + if (quint32(m_visualProperties) == quint32(properties)) { + return; + } + + m_visualProperties = properties; + updateSignatureTypes(); +} + +/** + * @return The status of the property passed in. + * + * @note Use @ref attributeSignature() and @ref + * operationSignature() to get signature status. This + * method only indicates whether signature is visible or not. + */ +bool ClassifierWidget::visualProperty(VisualProperty property) const +{ + if (property == ShowAttributeSignature) { + return (m_attributeSignature == Uml::SignatureType::ShowSig + || m_attributeSignature == Uml::SignatureType::SigNoVis); + } + + else if(property == ShowOperationSignature) { + return (m_operationSignature == Uml::SignatureType::ShowSig + || m_operationSignature == Uml::SignatureType::SigNoVis); + } + + return m_visualProperties.testFlag(property); +} + +/** + * A convenient method to set and reset individual VisualProperty + * + * Undo command. + * + * @param property The property to be set/reset. + * @param enable True/false to set/reset. (default = true) + * + * @note This method handles ShowAttributeSignature and + * ShowOperationSignature specially. + */ +void ClassifierWidget::setVisualProperty(VisualProperty property, bool enable) +{ + if (visualProperty(property) != enable) { + UMLApp::app()->executeCommand(new Uml::CmdChangeVisualProperty(this, property, enable)); + } +} + +/** + * A convenient method to set and reset individual VisualProperty + * + * @param property The property to be set/reset. + * @param enable True/false to set/reset. (default = true) + * + * @note This method handles ShowAttributeSignature and + * ShowOperationSignature specially. + */ +void ClassifierWidget::setVisualPropertyCmd(VisualProperty property, bool enable) +{ + // Handle ShowAttributeSignature and ShowOperationSignature + // specially. + + if (property == ShowAttributeSignature) { + if (!enable) { + m_attributeSignature = visualProperty(ShowVisibility) ? + Uml::SignatureType::NoSig : Uml::SignatureType::NoSigNoVis; + } else { + m_attributeSignature = visualProperty(ShowVisibility) ? + Uml::SignatureType::ShowSig : Uml::SignatureType::SigNoVis; + } + //:TODO: updateTextItemGroups(); + updateSignatureTypes(); + } + + else if (property == ShowOperationSignature) { + if (!enable) { + m_operationSignature = visualProperty(ShowVisibility) ? + Uml::SignatureType::NoSig : Uml::SignatureType::NoSigNoVis; + } else { + m_operationSignature = visualProperty(ShowVisibility) ? + Uml::SignatureType::ShowSig : Uml::SignatureType::SigNoVis; + } + //:TODO: updateTextItemGroups(); + updateSignatureTypes(); + } + + else if (property == ShowStereotype) { + // Now just update flag and use base method for actual work. + if (enable) { + m_visualProperties |= property; + } else { + m_visualProperties &= ~property; + } + setShowStereotype(enable); + } + + else if (property == DrawAsCircle) { + // Don't do anything if the flag status is same. + if (visualProperty(property) == enable) + return; + if (enable) { + m_visualProperties |= property; + } else { + m_visualProperties &= ~property; + } + setDrawAsCircle(enable); + } + + // Some other flag. + else { + // Don't do anything if the flag status is same. + if (visualProperty(property) == enable) { + return; + } + + // Call setVisualProperties appropriately based on enbable. + if (enable) { + setVisualProperties(visualProperties() | property); + } else { + setVisualProperties(visualProperties() & ~property); + } + } +} + +/** + * A convenient method to toggle individual VisualProperty of this + * widget. + * + * @param property The property to be toggled. + * + * @note This method handles ShowAttributeSignature and + * ShowOperationSignature specially. + */ +void ClassifierWidget::toggleVisualProperty(VisualProperty property) +{ + bool oppositeStatus; + if (property == ShowOperationSignature) { + oppositeStatus = !(m_operationSignature == Uml::SignatureType::ShowSig + || m_operationSignature == Uml::SignatureType::SigNoVis); + } + else if (property == ShowAttributeSignature) { + oppositeStatus = !(m_attributeSignature == Uml::SignatureType::ShowSig + || m_attributeSignature == Uml::SignatureType::SigNoVis); + } + else { + oppositeStatus = !visualProperty(property); + } + + DEBUG(DBG_SRC) << "VisualProperty: " << property << " to opposite status " << oppositeStatus; + setVisualProperty(property, oppositeStatus); +} + +/** + * Updates m_operationSignature to match m_showVisibility. + */ +void ClassifierWidget::updateSignatureTypes() +{ + //turn on scope + if (visualProperty(ShowVisibility)) { + if (m_operationSignature == Uml::SignatureType::NoSigNoVis) { + m_operationSignature = Uml::SignatureType::NoSig; + } else if (m_operationSignature == Uml::SignatureType::SigNoVis) { + m_operationSignature = Uml::SignatureType::ShowSig; + } + } + //turn off scope + else { + if (m_operationSignature == Uml::SignatureType::ShowSig) { + m_operationSignature = Uml::SignatureType::SigNoVis; + } else if (m_operationSignature == Uml::SignatureType::NoSig) { + m_operationSignature = Uml::SignatureType::NoSigNoVis; + } + } + if (visualProperty(ShowVisibility)) { + if (m_attributeSignature == Uml::SignatureType::NoSigNoVis) + m_attributeSignature = Uml::SignatureType::NoSig; + else if (m_attributeSignature == Uml::SignatureType::SigNoVis) + m_attributeSignature = Uml::SignatureType::ShowSig; + } else { + if (m_attributeSignature == Uml::SignatureType::ShowSig) + m_attributeSignature = Uml::SignatureType::SigNoVis; + else if(m_attributeSignature == Uml::SignatureType::NoSig) + m_attributeSignature = Uml::SignatureType::NoSigNoVis; + } + updateGeometry(); + update(); +} + +/** + * Returns whether to show attribute signatures. + * Only applies when m_umlObject->getBaseType() is ot_Class. + * + * @return Status of how attribute signatures are shown. + */ +Uml::SignatureType::Enum ClassifierWidget::attributeSignature() const +{ + return m_attributeSignature; +} + +/** + * Sets the type of signature to display for an attribute. + * Only applies when m_umlObject->getBaseType() is ot_Class. + * + * @param sig Type of signature to display for an attribute. + */ +void ClassifierWidget::setAttributeSignature(Uml::SignatureType::Enum sig) +{ + m_attributeSignature = sig; + updateSignatureTypes(); + updateGeometry(); + update(); +} + +/** + * @return The Uml::SignatureType::Enum value for the operations. + */ +Uml::SignatureType::Enum ClassifierWidget::operationSignature() const +{ + return m_operationSignature; +} + +/** + * Set the type of signature to display for an Operation + * + * @param sig Type of signature to display for an operation. + */ +void ClassifierWidget::setOperationSignature(Uml::SignatureType::Enum sig) +{ + m_operationSignature = sig; + updateSignatureTypes(); + updateGeometry(); + update(); +} + +/** + * Sets whether to show attribute signature + * Only applies when m_umlObject->getBaseType() is ot_Class. + * + * @param _status True if attribute signatures shall be shown. + */ +void ClassifierWidget::setShowAttSigs(bool _status) +{ + if(!_status) { + if (visualProperty(ShowVisibility)) + m_attributeSignature = Uml::SignatureType::NoSig; + else + m_attributeSignature = Uml::SignatureType::NoSigNoVis; + } + else if (visualProperty(ShowVisibility)) + m_attributeSignature = Uml::SignatureType::ShowSig; + else + m_attributeSignature = Uml::SignatureType::SigNoVis; + if (UMLApp::app()->document()->loading()) + return; + updateGeometry(); + update(); +} + +/** + * Toggles whether to show attribute signatures. + * Only applies when m_umlObject->getBaseType() is ot_Class. + */ +void ClassifierWidget::toggleShowAttSigs() +{ + if (m_attributeSignature == Uml::SignatureType::ShowSig || + m_attributeSignature == Uml::SignatureType::SigNoVis) { + if (visualProperty(ShowVisibility)) { + m_attributeSignature = Uml::SignatureType::NoSig; + } else { + m_attributeSignature = Uml::SignatureType::NoSigNoVis; + } + } else if (visualProperty(ShowVisibility)) { + m_attributeSignature = Uml::SignatureType::ShowSig; + } else { + m_attributeSignature = Uml::SignatureType::SigNoVis; + } + updateGeometry(); + update(); +} + +/** + * Return the number of displayed members of the given ObjectType. + * Takes into consideration m_showPublicOnly but not other settings. + */ +int ClassifierWidget::displayedMembers(UMLObject::ObjectType ot) const +{ + int count = 0; + UMLClassifier *umlc = this->classifier(); + if (!umlc) + return count; + UMLClassifierListItemList list = umlc->getFilteredList(ot); + foreach (UMLClassifierListItem *m, list) { + if (!(visualProperty(ShowPublicOnly) && m->visibility() != Uml::Visibility::Public)) + count++; + } + return count; +} + +/** + * Overrides method from UMLWidget. + */ +QSizeF ClassifierWidget::minimumSize() const +{ + return calculateSize(); +} + +/** + * Calculate content related size of widget. + * Overrides method from UMLWidget. + */ +QSizeF ClassifierWidget::calculateSize(bool withExtensions /* = true */) const +{ + if (!m_umlObject) { + return UMLWidget::minimumSize(); + } + if (m_umlObject->baseType() == UMLObject::ot_Package) { + return calculateAsPackageSize(); + } + UMLClassifier *umlc = this->classifier(); + if (!umlc) { + uError() << "Internal error - classifier() returns NULL"; + return UMLWidget::minimumSize(); + } + if (umlc->isInterface() && visualProperty(DrawAsCircle)) { + return calculateAsCircleSize(); + } + + const bool showNameOnly = !visualProperty(ShowAttributes) && + !visualProperty(ShowOperations) && + !visualProperty(ShowDocumentation); + + const QFontMetrics &fm = getFontMetrics(UMLWidget::FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + // width is the width of the longest 'word' + int width = 0, height = 0; + // consider stereotype + if (visualProperty(ShowStereotype) && !m_umlObject->stereotype().isEmpty()) { + height += fontHeight; + // ... width + const QFontMetrics &bfm = UMLWidget::getFontMetrics(UMLWidget::FT_BOLD); + const int stereoWidth = bfm.size(0, m_umlObject->stereotype(true)).width(); + if (stereoWidth > width) + width = stereoWidth; + } else if (showNameOnly) { + height += MARGIN; + } + + // consider name + height += fontHeight; + // ... width + QString displayedName; + if (visualProperty(ShowPackage)) + displayedName = m_umlObject->fullyQualifiedName(); + else + displayedName = m_umlObject->name(); + const UMLWidget::FontType nft = (m_umlObject->isAbstract() ? FT_BOLD_ITALIC : FT_BOLD); + const int nameWidth = UMLWidget::getFontMetrics(nft).size(0, displayedName).width(); + if (nameWidth > width) + width = nameWidth; + +#ifdef ENABLE_WIDGET_SHOW_DOC + // consider documentation + if (visualProperty(ShowDocumentation)) { + if (!documentation().isEmpty()) { + QRect brect = fm.boundingRect(QRect(0, 0, this->width()-2*MARGIN, this->height()-height), Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, documentation()); + height += brect.height(); + if (!visualProperty(ShowOperations) && !visualProperty(ShowAttributes)) { + if (brect.width() >= width) + width = brect.width(); + } + } + else + height += fontHeight / 2; + } +#endif + + // consider attributes + if (visualProperty(ShowAttributes)) { + const int numAtts = displayedAttributes(); + if (numAtts > 0) { + height += fontHeight * numAtts; + // calculate width of the attributes + UMLClassifierListItemList list = umlc->getFilteredList(UMLObject::ot_Attribute); + foreach (UMLClassifierListItem *a, list) { + if (visualProperty(ShowPublicOnly) && a->visibility() != Uml::Visibility::Public) + continue; + const int attWidth = fm.size(0, a->toString(m_attributeSignature)).width(); + if (attWidth > width) + width = attWidth; + } + } + else + height += fontHeight / 2; + } + + // consider operations + if (visualProperty(ShowOperations)) { + const int numOps = displayedOperations(); + if (numOps > 0) { + height += numOps * fontHeight; + // ... width + UMLOperationList list(umlc->getOpList()); + foreach (UMLOperation* op, list) { + if (visualProperty(ShowPublicOnly) && op->visibility() != Uml::Visibility::Public) + continue; + const QString displayedOp = op->toString(m_operationSignature); + UMLWidget::FontType oft; + oft = (op->isAbstract() ? UMLWidget::FT_ITALIC : UMLWidget::FT_NORMAL); + const int w = UMLWidget::getFontMetrics(oft).size(0, displayedOp).width(); + if (w > width) + width = w; + } + } + else + height += fontHeight / 2; + } + + if (withExtensions) { + // consider template box _as last_ ! + QSize templatesBoxSize = calculateTemplatesBoxSize(); + if (templatesBoxSize.width() != 0) { + // add width to largest 'word' + width += templatesBoxSize.width() / 2; + } + if (templatesBoxSize.height() != 0) { + height += templatesBoxSize.height() - MARGIN; + } + } + + // allow for height margin + if (showNameOnly) { + height += MARGIN; + } + + // allow for width margin + width += MARGIN * 2; + + return QSizeF(width, height); +} + +/** + * Calculcates the size of the templates box in the top left + * if it exists, returns QSize(0, 0) if it doesn't. + * + * @return QSize of the templates flap. + */ +QSize ClassifierWidget::calculateTemplatesBoxSize() const +{ + if (!classifier()) + return QSize(0, 0); + UMLTemplateList list = classifier()->getTemplateList(); + int count = list.count(); + if (count == 0) { + return QSize(0, 0); + } + + QFont font = UMLWidget::font(); + font.setItalic(false); + font.setUnderline(false); + font.setBold(false); + const QFontMetrics fm(font); + + int width = 0; + int height = count * fm.lineSpacing() + (MARGIN*2); + + foreach (UMLTemplate *t, list) { + int textWidth = fm.size(0, t->toString()).width(); + if (textWidth > width) + width = textWidth; + } + + width += (MARGIN*2); + return QSize(width, height); +} + +/** + * Return the number of displayed attributes. + */ +int ClassifierWidget::displayedAttributes() const +{ + if (!visualProperty(ShowAttributes)) + return 0; + return displayedMembers(UMLObject::ot_Attribute); +} + +/** + * Return the number of displayed operations. + */ +int ClassifierWidget::displayedOperations() const +{ + if (!visualProperty(ShowOperations)) + return 0; + return displayedMembers(UMLObject::ot_Operation); +} + +/** + * Set the AssociationWidget when this ClassWidget acts as + * an association class. + */ +void ClassifierWidget::setClassAssociationWidget(AssociationWidget *assocwidget) +{ + if (!classifier()) { + uError() << "Class association cannot be applied to package"; + return; + } + m_pAssocWidget = assocwidget; + UMLAssociation *umlassoc = NULL; + if (assocwidget) + umlassoc = assocwidget->association(); + classifier()->setClassAssoc(umlassoc); +} + +/** + * Return the AssociationWidget when this classifier acts as + * an association class (else return NULL.) + */ +AssociationWidget *ClassifierWidget::classAssociationWidget() const +{ + return m_pAssocWidget; +} + +/** + * Overrides standard method. + * Auxiliary to reimplementations in the derived classes. + */ +void ClassifierWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + setPenFromSettings(painter); + if (UMLWidget::useFillColor()) + painter->setBrush(UMLWidget::fillColor()); + else { + painter->setBrush(m_scene->backgroundColor()); + } + if (m_umlObject->baseType() == UMLObject::ot_Package) { + drawAsPackage(painter, option); + UMLWidget::paint(painter, option, widget); + return; + } + UMLClassifier *umlc = this->classifier(); + if (!umlc) { + uError() << "Internal error - classifier() returns NULL"; + return; + } + if (umlc->isInterface() && visualProperty(DrawAsCircle)) { + drawAsCircle(painter, option); + UMLWidget::paint(painter, option, widget); + return; + } + + // Draw the bounding rectangle + QSize templatesBoxSize = calculateTemplatesBoxSize(); + int bodyOffsetY = 0; + if (templatesBoxSize.height() > 0) + bodyOffsetY += templatesBoxSize.height() - MARGIN; + int w = width(); + if (templatesBoxSize.width() > 0) + w -= templatesBoxSize.width() / 2; + int h = height(); + if (templatesBoxSize.height() > 0) + h -= templatesBoxSize.height() - MARGIN; + painter->drawRect(0, bodyOffsetY, w, h); + + QFont font = UMLWidget::font(); + font.setUnderline(false); + font.setItalic(false); + const QFontMetrics &fm = UMLWidget::getFontMetrics(UMLWidget::FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + + //If there are any templates then draw them + UMLTemplateList tlist = umlc->getTemplateList(); + if (tlist.count() > 0) { + setPenFromSettings(painter); + QPen pen = painter->pen(); + pen.setStyle(Qt::DotLine); + painter->setPen(pen); + painter->drawRect(width() - templatesBoxSize.width(), 0, + templatesBoxSize.width(), templatesBoxSize.height()); + painter->setPen(QPen(textColor())); + font.setBold(false); + painter->setFont(font); + const int x = width() - templatesBoxSize.width() + MARGIN; + int y = MARGIN; + foreach (UMLTemplate *t, tlist) { + QString text = t->toString(); + painter->drawText(x, y, fm.size(0, text).width(), fontHeight, Qt::AlignVCenter, text); + y += fontHeight; + } + } + + const int textX = MARGIN; + const int textWidth = w - MARGIN * 2; + + painter->setPen(QPen(textColor())); + + // draw stereotype + font.setBold(true); + const bool showNameOnly = !visualProperty(ShowAttributes) && + !visualProperty(ShowOperations) && + !visualProperty(ShowDocumentation); + + int nameHeight = fontHeight; + if (visualProperty(ShowStereotype) && !m_umlObject->stereotype().isEmpty()) { + painter->setFont(font); + painter->drawText(textX, bodyOffsetY, textWidth, fontHeight, Qt::AlignCenter, m_umlObject->stereotype(true)); + bodyOffsetY += fontHeight; + } else if (showNameOnly) { + nameHeight = h; + } + + // draw name + QString name; + if (visualProperty(ShowPackage)) { + name = m_umlObject->fullyQualifiedName(); + } else { + name = this->name(); + } + font.setItalic(m_umlObject->isAbstract()); + painter->setFont(font); + painter->drawText(textX, bodyOffsetY, textWidth, nameHeight, Qt::AlignCenter, name); + bodyOffsetY += fontHeight; + font.setBold(false); + font.setItalic(false); + painter->setFont(font); + +#ifdef ENABLE_WIDGET_SHOW_DOC + // draw documentation + if (visualProperty(ShowDocumentation)) { + setPenFromSettings(painter); + painter->drawLine(0, bodyOffsetY, w, bodyOffsetY); + painter->setPen(textColor()); + + if (!documentation().isEmpty()) { + QRect brect = fm.boundingRect(QRect(0, 0, w-2*MARGIN, h-bodyOffsetY), Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, documentation()); + if (brect.width() > width() + 2*MARGIN) + brect.setWidth(width()-2*MARGIN); + brect.adjust(textX, bodyOffsetY, textX, bodyOffsetY); + painter->drawText(brect, Qt::AlignCenter | Qt::TextWordWrap, documentation()); + bodyOffsetY += brect.height(); + } + else + bodyOffsetY += fontHeight / 2; + } +#endif + // draw attributes + if (visualProperty(ShowAttributes)) { + // draw dividing line between doc/name and attributes + setPenFromSettings(painter); + painter->drawLine(0, bodyOffsetY, w, bodyOffsetY); + painter->setPen(textColor()); + + const int numAtts = displayedAttributes(); + if (numAtts > 0) { + drawMembers(painter, UMLObject::ot_Attribute, m_attributeSignature, textX, + bodyOffsetY, fontHeight); + bodyOffsetY += fontHeight * numAtts; + } + else + bodyOffsetY += fontHeight / 2; + } + + // draw operations + if (visualProperty(ShowOperations)) { + // draw dividing line between attributes and operations + setPenFromSettings(painter); + painter->drawLine(0, bodyOffsetY, w, bodyOffsetY); + painter->setPen(QPen(textColor())); + + const int numOps = displayedOperations(); + if (numOps >= 0) { + drawMembers(painter, UMLObject::ot_Operation, m_operationSignature, textX, + bodyOffsetY, fontHeight); + } + } + + UMLWidget::paint(painter, option, widget); +} + +/** + * @return The shape of the ClassifierWidget. + */ +QPainterPath ClassifierWidget::shape() const +{ + QPainterPath path; + if (classifier() && classifier()->isInterface() && visualProperty(DrawAsCircle)) { + path.addEllipse(rect()); + return path; + } +#ifdef ENABLE_WIDGET_SHOW_DOC + QSizeF mainSize = rect().size(); +#else + QSizeF mainSize = calculateSize(false); +#endif + QSize templatesBoxSize = calculateTemplatesBoxSize(); + qreal mainY = 0.0; + if (templatesBoxSize.height() > 0) { + mainY += templatesBoxSize.height() - MARGIN; + path.addRect(QRectF(mainSize.width() - templatesBoxSize.width() / 2, 0.0, + templatesBoxSize.width(), templatesBoxSize.height())); + } + path.addRect(QRectF(0.0, mainY, mainSize.width(), mainSize.height())); + return path; +} + +/** + * Draws the interface as a circle. + * Only applies when m_umlObject->getBaseType() is ot_Interface. + */ +void ClassifierWidget::drawAsCircle(QPainter *painter, const QStyleOptionGraphicsItem *option) +{ + const int w = width(); + + if (m_Assocs.size() > 1) { + painter->drawEllipse(w/2 - CIRCLE_SIZE/2, SOCKET_INCREMENT / 2, CIRCLE_SIZE, CIRCLE_SIZE); + // Draw socket for required interface. + const qreal angleSpan = 180; // 360.0 / (m_Assocs.size() + 1.0); + const int arcDiameter = CIRCLE_SIZE + SOCKET_INCREMENT; + QRect requireArc(w/2 - arcDiameter/2, 0, arcDiameter, arcDiameter); + const QPointF center(x() + w/2, y() + arcDiameter/2); + const qreal cX = center.x(); + const qreal cY = center.y(); + foreach (AssociationWidget *aw, m_Assocs) { + const Uml::AssociationType::Enum aType = aw->associationType(); + if (aType == Uml::AssociationType::UniAssociation || + aType == Uml::AssociationType::Association) // provider + continue; + UMLWidget *otherEnd = aw->widgetForRole(Uml::RoleType::A); + const WidgetBase::WidgetType oType = otherEnd->baseType(); + if (oType != WidgetBase::wt_Component && oType != WidgetBase::wt_Port) + continue; + + AssociationLine *assocLine = aw->associationLine(); + const QPointF p(assocLine->endPoint()); + const qreal tolerance = 18.0; + bool drawArc = true; + qreal midAngle; + if (p.x() < cX - tolerance) { + if (p.y() < cY - tolerance) + midAngle = 135; + else if (p.y() > cY + tolerance) + midAngle = 225; + else + midAngle = 180; + } else if (p.x() > cX + tolerance) { + if (p.y() < cY - tolerance) + midAngle = 45; + else if (p.y() > cY + tolerance) + midAngle = 315; + else + midAngle = 0; + } else { + if (p.y() < cY - tolerance) + midAngle = 90; + else if (p.y() > cY + tolerance) + midAngle = 270; + else + drawArc = false; + } + if (drawArc) { + // uDebug() << "number of assocs: " << m_Assocs.size() + // << ", p: " << p << ", center: " << center + // << ", midAngle: " << midAngle << ", angleSpan: " << angleSpan; + painter->drawArc(requireArc, 16 * (midAngle - angleSpan/2), 16 * angleSpan); + } else { + uError() << "socket: assocLine endPoint " << p + << " too close to own center" << center; + } + } + } + else + painter->drawEllipse(w/2 - CIRCLE_SIZE/2, 0, CIRCLE_SIZE, CIRCLE_SIZE); + + UMLWidget::paint(painter, option); +} + +/** + * Calculates the size of the object when drawn as a circle. + * Only applies when m_umlObject->getBaseType() is ot_Interface. + */ +QSize ClassifierWidget::calculateAsCircleSize() const +{ + int circleSize = CIRCLE_SIZE; + if (m_Assocs.size() > 1) + circleSize += SOCKET_INCREMENT; + return QSize(circleSize, circleSize); +} + +void ClassifierWidget::drawAsPackage(QPainter *painter, const QStyleOptionGraphicsItem *option) +{ + Q_UNUSED(option); + + int w = width(); + int h = height(); + QFont font = UMLWidget::font(); + font.setBold(true); + //FIXME italic is true when a package is first created until you click elsewhere, not sure why + font.setItalic(false); + const QFontMetrics &fm = getFontMetrics(FT_BOLD); + const int fontHeight = fm.lineSpacing(); + + painter->drawRect(0, 0, 50, fontHeight); + if (m_umlObject->stereotype() == QLatin1String("subsystem")) { + const int fHalf = fontHeight / 2; + const int symY = fHalf; + const int symX = 38; + painter->drawLine(symX, symY, symX, symY + fHalf - 2); // left leg + painter->drawLine(symX + 8, symY, symX + 8, symY + fHalf - 2); // right leg + painter->drawLine(symX, symY, symX + 8, symY); // waist + painter->drawLine(symX + 4, symY, symX + 4, symY - fHalf + 2); // head + } + painter->drawRect(0, fontHeight - 1, w, h - fontHeight); + + painter->setPen(textColor()); + painter->setFont(font); + + int lines = 1; + QString stereotype = m_umlObject->stereotype(); + if (!stereotype.isEmpty()) { + painter->drawText(0, fontHeight + PACKAGE_MARGIN, + w, fontHeight, Qt::AlignCenter, m_umlObject->stereotype(true)); + lines = 2; + } + + painter->drawText(0, (fontHeight*lines) + PACKAGE_MARGIN, + w, fontHeight, Qt::AlignCenter, name()); +} + +QSize ClassifierWidget::calculateAsPackageSize() const +{ + const QFontMetrics &fm = getFontMetrics(FT_BOLD_ITALIC); + const int fontHeight = fm.lineSpacing(); + + int lines = 1; + + int width = fm.width(m_umlObject->name()); + + int tempWidth = 0; + if (!m_umlObject->stereotype().isEmpty()) { + tempWidth = fm.width(m_umlObject->stereotype(true)); + lines = 2; + } + if (tempWidth > width) + width = tempWidth; + width += PACKAGE_MARGIN * 2; + if (width < 70) + width = 70; // minumin width of 70 + + int height = (lines*fontHeight) + fontHeight + (PACKAGE_MARGIN * 2); + + return QSize(width, height); +} + +/** + * Auxiliary method for draw() of child classes: + * Draw the attributes or operations. + * + * @param p QPainter to paint to. + * @param ot Object type to draw, either ot_Attribute or ot_Operation. + * @param sigType Governs details of the member display. + * @param x X coordinate at which to draw the texts. + * @param y Y coordinate at which text drawing commences. + * @param fontHeight The font height. + */ +void ClassifierWidget::drawMembers(QPainter * painter, UMLObject::ObjectType ot, Uml::SignatureType::Enum sigType, + int x, int y, int fontHeight) +{ + UMLClassifier *umlc = classifier(); + if (!umlc) { + return; + } + QFont f = UMLWidget::font(); + f.setBold(false); + UMLClassifierListItemList list = umlc->getFilteredList(ot); + painter->setClipping(true); + painter->setClipRect(rect()); + foreach (UMLClassifierListItem *obj, list) { + if (visualProperty(ShowPublicOnly) && obj->visibility() != Uml::Visibility::Public) + continue; + QString text = obj->toString(sigType); + f.setItalic(obj->isAbstract()); + f.setUnderline(obj->isStatic()); + painter->setFont(f); + QFontMetrics fontMetrics(f); + painter->drawText(x, y, fontMetrics.size(0, text).width(), fontHeight, Qt::AlignVCenter, text); + f.setItalic(false); + f.setUnderline(false); + painter->setFont(f); + y += fontHeight; + } + painter->setClipping(false); +} + +/** + * Override method from UMLWidget in order to additionally check m_pInterfaceName. + * + * @param p Point to be checked. + * + * @return 'this' if UMLWidget::onWidget(p) returns non NULL; + * m_pInterfaceName if m_pName is non NULL and + * m_pInterfaceName->onWidget(p) returns non NULL; else NULL. + */ +UMLWidget* ClassifierWidget::onWidget(const QPointF &p) +{ + if (UMLWidget::onWidget(p) != NULL) + return this; + if (getDrawAsCircle() && m_pInterfaceName) { + uDebug() << "floatingtext: " << m_pInterfaceName->text(); + return m_pInterfaceName->onWidget(p); + } + return NULL; +} + +/** + * Reimplement function from UMLWidget. + */ +UMLWidget* ClassifierWidget::widgetWithID(Uml::ID::Type id) +{ + if (UMLWidget::widgetWithID(id)) + return this; + if (getDrawAsCircle() && m_pInterfaceName && m_pInterfaceName->widgetWithID(id)) + return m_pInterfaceName; + return NULL; +} + +void ClassifierWidget::setDocumentation(const QString &doc) +{ + WidgetBase::setDocumentation(doc); + updateGeometry(); +} + +/** + * Sets whether to draw as circle. + * Only applies when m_umlObject->getBaseType() is ot_Interface. + * + * @param drawAsCircle True if widget shall be drawn as circle. + */ +void ClassifierWidget::setDrawAsCircle(bool drawAsCircle) +{ + setVisualPropertyCmd(DrawAsCircle, drawAsCircle); + const int circleSize = CIRCLE_SIZE + SOCKET_INCREMENT; + if (drawAsCircle) { + setX(x() + (width()/2 - circleSize/2)); + setY(y() + (height()/2 - circleSize/2)); + setSize(circleSize, circleSize); + if (m_pInterfaceName) { + m_pInterfaceName->show(); + } else { + m_pInterfaceName = new FloatingTextWidget(m_scene, Uml::TextRole::Floating, name()); + m_pInterfaceName->setParentItem(this); + m_pInterfaceName->setText(name()); // to get geometry update + m_pInterfaceName->setX(circleSize/2 - m_pInterfaceName->width() / 2); + m_pInterfaceName->setY(circleSize + SOCKET_INCREMENT); + } + m_resizable = false; + } else { + setSize(ClassifierWidget::minimumSize()); + setX(x() - (width()/2 - circleSize/2)); + setY(y() - (height()/2 - circleSize/2)); + if (m_pInterfaceName) + m_pInterfaceName->hide(); + m_resizable = true; + } + updateGeometry(); + update(); +} + +/** + * Returns whether to draw as circle. + * Only applies when m_umlObject->getBaseType() is ot_Interface. + * + * @return True if widget is drawn as circle. + */ +bool ClassifierWidget::getDrawAsCircle() const +{ + return visualProperty(DrawAsCircle); +} + +/** + * Toggles whether to draw as circle. + * Only applies when m_umlObject->getBaseType() is ot_Interface. + */ +void ClassifierWidget::toggleDrawAsCircle() +{ + toggleVisualProperty(DrawAsCircle); + updateSignatureTypes(); + updateGeometry(); + update(); +} + +/** + * Changes this classifier from an interface to a class. + * Attributes and stereotype visibility is got from the view OptionState. + * This widget is also updated. + */ +void ClassifierWidget::changeToClass() +{ + m_baseType = WidgetBase::wt_Class; + m_umlObject->setBaseType(UMLObject::ot_Class); + setVisualPropertyCmd(DrawAsCircle, false); + const Settings::OptionState& ops = m_scene->optionState(); + setVisualProperty(ShowAttributes, ops.classState.showAtts); + setVisualProperty(ShowStereotype, ops.classState.showStereoType); + + updateGeometry(); + update(); +} + +/** + * Changes this classifier from a class to an interface. + * Attributes are hidden and stereotype is shown. + * This widget is also updated. + */ +void ClassifierWidget::changeToInterface() +{ + m_baseType = WidgetBase::wt_Interface; + m_umlObject->setBaseType(UMLObject::ot_Interface); + + setVisualProperty(ShowAttributes, false); + setVisualProperty(ShowStereotype, true); + + updateGeometry(); + update(); +} + +/** + * Changes this classifier from an "class-or-package" to a package. + * This widget is also updated. + */ +void ClassifierWidget::changeToPackage() +{ + m_baseType = WidgetBase::wt_Package; + m_umlObject->setBaseType(UMLObject::ot_Package); + + setVisualProperty(ShowAttributes, false); + setVisualProperty(ShowStereotype, true); + + updateGeometry(); + update(); +} + +/** + * Extends base method to adjust also the association of a class + * association. + * Executes the base method and then, if file isn't loading and the + * classifier acts as a class association, the association position is + * updated. + * TODO: This is never called. + * + * param x The x-coordinate. + * param y The y-coordinate. + */ +//void ClassifierWidget::adjustAssociations(int x, int y) +//{ +// DEBUG(DBG_SRC) << "x=" << x << " / y=" << y; +// UMLWidget::adjustAssocs(x, y); + +// if (m_doc->loading() || m_pAssocWidget == 0) { +// return; +// } + +// //:TODO: the following is also called from UMLWidgetr::ajdustAssocs(...) +// // and then AssociationWidget::widgetMoved(...) +// //m_pAssocWidget->computeAssocClassLine(); +//} + +/** + * Loads the "classwidget" or "interfacewidget" XML element. + */ +bool ClassifierWidget::loadFromXMI(QDomElement & qElement) +{ + if (!UMLWidget::loadFromXMI(qElement)) { + return false; + } + + QString showatts = qElement.attribute(QLatin1String("showattributes"), QLatin1String("0")); + QString showops = qElement.attribute(QLatin1String("showoperations"), QLatin1String("1")); + QString showpubliconly = qElement.attribute(QLatin1String("showpubliconly"), QLatin1String("0")); + QString showattsigs = qElement.attribute(QLatin1String("showattsigs"), QLatin1String("600")); + QString showopsigs = qElement.attribute(QLatin1String("showopsigs"), QLatin1String("600")); + QString showpackage = qElement.attribute(QLatin1String("showpackage"), QLatin1String("0")); + QString showscope = qElement.attribute(QLatin1String("showscope"), QLatin1String("0")); + QString drawascircle = qElement.attribute(QLatin1String("drawascircle"), QLatin1String("0")); +#ifdef ENABLE_WIDGET_SHOW_DOC + QString showDocumentation = qElement.attribute(QLatin1String("showdocumentation"), QLatin1String("0")); +#endif + + setVisualPropertyCmd(ShowAttributes, (bool)showatts.toInt()); + setVisualPropertyCmd(ShowOperations, (bool)showops.toInt()); + setVisualPropertyCmd(ShowPublicOnly, (bool)showpubliconly.toInt()); + setVisualPropertyCmd(ShowPackage, (bool)showpackage.toInt()); + setVisualPropertyCmd(ShowVisibility, (bool)showscope.toInt()); + setVisualPropertyCmd(DrawAsCircle, (bool)drawascircle.toInt()); +#ifdef ENABLE_WIDGET_SHOW_DOC + setVisualPropertyCmd(ShowDocumentation, (bool)showDocumentation.toInt()); +#endif + + m_attributeSignature = Uml::SignatureType::fromInt(showattsigs.toInt()); + m_operationSignature = Uml::SignatureType::fromInt(showopsigs.toInt()); + + if (!getDrawAsCircle()) + return true; + + // Optional child element: floatingtext + QDomNode node = qElement.firstChild(); + QDomElement element = node.toElement(); + if (!element.isNull()) { + QString tag = element.tagName(); + if (tag == QLatin1String("floatingtext")) { + if (m_pInterfaceName == NULL) { + m_pInterfaceName = new FloatingTextWidget(m_scene, + Uml::TextRole::Floating, + name(), Uml::ID::Reserved); + m_pInterfaceName->setParentItem(this); + } + if (!m_pInterfaceName->loadFromXMI(element)) { + // Most likely cause: The FloatingTextWidget is empty. + delete m_pInterfaceName; + m_pInterfaceName = NULL; + } else { + m_pInterfaceName->activate(); + m_pInterfaceName->update(); + } + } else { + uError() << "unknown tag " << tag; + } + } + + return true; +} + +/** + * Creates the "classwidget" or "interfacewidget" XML element. + */ +void ClassifierWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +{ + QDomElement conceptElement; + UMLClassifier *umlc = classifier(); + if (umlObject() && umlObject()->baseType() == UMLObject::ot_Package) { + conceptElement = qDoc.createElement(QLatin1String("packagewidget")); + UMLWidget::saveToXMI(qDoc, conceptElement); + qElement.appendChild(conceptElement); + return; + } + else if (umlc && umlc->isInterface()) + conceptElement = qDoc.createElement(QLatin1String("interfacewidget")); + else + conceptElement = qDoc.createElement(QLatin1String("classwidget")); + UMLWidget::saveToXMI(qDoc, conceptElement); + conceptElement.setAttribute(QLatin1String("showoperations"), visualProperty(ShowOperations)); + conceptElement.setAttribute(QLatin1String("showpubliconly"), visualProperty(ShowPublicOnly)); + conceptElement.setAttribute(QLatin1String("showopsigs"), m_operationSignature); + conceptElement.setAttribute(QLatin1String("showpackage"), visualProperty(ShowPackage)); + conceptElement.setAttribute(QLatin1String("showscope"), visualProperty(ShowVisibility)); + conceptElement.setAttribute(QLatin1String("showattributes"), visualProperty(ShowAttributes)); + conceptElement.setAttribute(QLatin1String("showattsigs"), m_attributeSignature); +#ifdef ENABLE_WIDGET_SHOW_DOC + conceptElement.setAttribute(QLatin1String("showdocumentation"),visualProperty(ShowDocumentation)); +#endif + if (umlc && (umlc->isInterface() || umlc->isAbstract())) { + conceptElement.setAttribute(QLatin1String("drawascircle"), visualProperty(DrawAsCircle)); + if (visualProperty(DrawAsCircle) && m_pInterfaceName) { + m_pInterfaceName->saveToXMI(qDoc, conceptElement); + } + } + qElement.appendChild(conceptElement); +} + +/** + * Will be called when a menu selection has been made from the + * popup menu. + * + * @param action The action that has been selected. + */ +void ClassifierWidget::slotMenuSelection(QAction* action) +{ + ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); + switch (sel) { + case ListPopupMenu::mt_Attribute: + case ListPopupMenu::mt_Operation: + case ListPopupMenu::mt_Template: + { + UMLObject::ObjectType ot = ListPopupMenu::convert_MT_OT(sel); + UMLClassifier *umlc = classifier(); + if (!umlc) { + uError() << "Internal error - classifier() returns NULL"; + return; + } + if (Object_Factory::createChildObject(umlc, ot)) { + updateGeometry(); + update(); + UMLApp::app()->document()->setModified(); + } + break; + } + case ListPopupMenu::mt_Show_Operations: + toggleVisualProperty(ShowOperations); + break; + + case ListPopupMenu::mt_Show_Attributes: + toggleVisualProperty(ShowAttributes); + break; + + case ListPopupMenu::mt_Show_Documentation: + toggleVisualProperty(ShowDocumentation); + break; + + case ListPopupMenu::mt_Show_Public_Only: + toggleVisualProperty(ShowPublicOnly); + break; + + case ListPopupMenu::mt_Show_Operation_Signature: + toggleVisualProperty(ShowOperationSignature); + break; + + case ListPopupMenu::mt_Show_Attribute_Signature: + toggleVisualProperty(ShowAttributeSignature); + break; + + case ListPopupMenu::mt_Visibility: + toggleVisualProperty(ShowVisibility); + break; + + case ListPopupMenu::mt_Show_Packages: + toggleVisualProperty(ShowPackage); + break; + + case ListPopupMenu::mt_Show_Stereotypes: + toggleVisualProperty(ShowStereotype); + break; + + case ListPopupMenu::mt_DrawAsCircle: + toggleVisualProperty(DrawAsCircle); + break; + + case ListPopupMenu::mt_ChangeToClass: + changeToClass(); + break; + + case ListPopupMenu::mt_ChangeToInterface: + changeToInterface(); + break; + + case ListPopupMenu::mt_ChangeToPackage: + changeToPackage(); + break; + + default: + UMLWidget::slotMenuSelection(action); + break; + } +} + +/** + * Slot to show/hide attributes based on \a state. + */ +void ClassifierWidget::slotShowAttributes(bool state) +{ + setVisualProperty(ShowAttributes, state); +} + +/** + * Slot to show/hide operations based on \a state. + */ +void ClassifierWidget::slotShowOperations(bool state) +{ + setVisualProperty(ShowOperations, state); +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/classifierwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/classifierwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/classifierwidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/classifierwidget.h 2015-10-08 11:48:59.508089026 +0300 @@ -0,0 +1,146 @@ +/*************************************************************************** + * 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) 2004-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef CLASSIFIERWIDGET_H +#define CLASSIFIERWIDGET_H + +#include "basictypes.h" +#include "umlobject.h" +#include "umlwidget.h" + +class AssociationWidget; +class FloatingTextWidget; +class QPainter; +class UMLClassifier; + +/** + * @short Common implementation for class widget and interface widget + * + * @author Oliver Kellogg + * @author Gopala Krishna + * + * @see UMLWidget + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class ClassifierWidget : public UMLWidget +{ + Q_OBJECT + Q_ENUMS(VisualProperty) +public: + /** + * This enumeration lists the visual properties that can be easily + * set, reset and toggled and all these operate on an integer + * which stores all the flag status. + */ + enum VisualProperty { + ShowStereotype = 0x1, + ShowOperations = 0x2, + ShowPublicOnly = 0x4, + ShowVisibility = 0x8, + ShowPackage = 0x10, + ShowAttributes = 0x20, + DrawAsCircle = 0x40, + ShowOperationSignature = 0x60, ///< only in setter + ShowAttributeSignature = 0x80, ///< only in setter + DrawAsPackage = 0x100, + ShowDocumentation = 0x200, + }; + + Q_DECLARE_FLAGS(VisualProperties, VisualProperty) + + ClassifierWidget(UMLScene * scene, UMLClassifier * o); + ClassifierWidget(UMLScene * scene, UMLPackage * o); + virtual ~ClassifierWidget(); + + UMLClassifier *classifier() const; + + VisualProperties visualProperties() const; + void setVisualProperties(VisualProperties properties); + + bool visualProperty(VisualProperty property) const; + void setVisualProperty(VisualProperty property, bool enable = true); + void setVisualPropertyCmd(VisualProperty property, bool enable = true); + void toggleVisualProperty(VisualProperty property); + + int displayedAttributes() const; + int displayedOperations() const; + + Uml::SignatureType::Enum attributeSignature() const; + void setAttributeSignature(Uml::SignatureType::Enum sig); + + Uml::SignatureType::Enum operationSignature() const; + void setOperationSignature(Uml::SignatureType::Enum sig); + + void setShowAttSigs(bool _show); + void toggleShowAttSigs(); + + bool getDrawAsCircle() const; + void setDrawAsCircle(bool drawAsCircle); + void toggleDrawAsCircle(); + + void changeToClass(); + void changeToInterface(); + void changeToPackage(); + + AssociationWidget *classAssociationWidget() const; + void setClassAssociationWidget(AssociationWidget *assocwidget); +// virtual void adjustAssociations(int x, int y); + + UMLWidget* onWidget(const QPointF& p); + UMLWidget* widgetWithID(Uml::ID::Type id); + + virtual void setDocumentation(const QString& doc); + + QSizeF calculateSize(bool withExtensions = true) const; + + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + virtual QPainterPath shape() const; + + virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); + virtual bool loadFromXMI(QDomElement & qElement); + +public Q_SLOTS: + virtual void slotMenuSelection(QAction* action); + +private Q_SLOTS: + void slotShowAttributes(bool state); + void slotShowOperations(bool state); + +private: + void updateSignatureTypes(); + QSize calculateTemplatesBoxSize() const; + + QSizeF minimumSize() const; + + void drawAsCircle(QPainter *p, const QStyleOptionGraphicsItem *option); + QSize calculateAsCircleSize() const; + + void drawAsPackage(QPainter *painter, const QStyleOptionGraphicsItem *option); + QSize calculateAsPackageSize() const; + + int displayedMembers(UMLObject::ObjectType ot) const; + void drawMembers(QPainter *painter, UMLObject::ObjectType ot, Uml::SignatureType::Enum sigType, + int x, int y, int fontHeight); + + static const int MARGIN; ///< text width margin + static const int CIRCLE_SIZE; ///< size of circle when interface is rendered as such + static const int SOCKET_INCREMENT; ///< augmentation of circle for socket (required interface) + + VisualProperties m_visualProperties; + Uml::SignatureType::Enum m_attributeSignature; ///< Loaded/saved item. + Uml::SignatureType::Enum m_operationSignature; ///< Loaded/saved item. + AssociationWidget *m_pAssocWidget; ///< related AssociationWidget in case this classifier acts as an association class + FloatingTextWidget *m_pInterfaceName; ///< Separate widget for name in case of interface drawn as circle + +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(ClassifierWidget::VisualProperties) + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/combinedfragmentwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/combinedfragmentwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/combinedfragmentwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/combinedfragmentwidget.cpp 2015-10-08 11:48:59.508089026 +0300 @@ -0,0 +1,477 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "combinedfragmentwidget.h" + +// app includes +#include "debug_utils.h" +#include "dialog_utils.h" +#include "listpopupmenu.h" +#include "uml.h" +#include "umldoc.h" +#include "umlscene.h" +#include "umlview.h" + +// kde includes +#include +#if QT_VERSION < 0x050000 +#include +#endif + +// qt includes +#if QT_VERSION >= 0x050000 +#include +#endif +#include +#include + +/** + * Creates a Combined Fragment widget. + * + * @param scene The parent of the widget. + * @param combinedfragmentType The type of combined fragment. + * @param id The ID to assign (-1 will prompt a new ID.) + */ +CombinedFragmentWidget::CombinedFragmentWidget(UMLScene * scene, CombinedFragmentType combinedfragmentType, Uml::ID::Type id) + : UMLWidget(scene, WidgetBase::wt_CombinedFragment, id) +{ + setCombinedFragmentType(combinedfragmentType); +} + +/** + * Destructor. + */ +CombinedFragmentWidget::~CombinedFragmentWidget() +{ + for (QList::iterator it=m_dashLines.begin() ; it!=m_dashLines.end() ; ++it) { + delete(*it); + } +} + +/** + * Overrides the standard paint event. + */ +void CombinedFragmentWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + int w = width(); + int h = height(); + int line_width = 45; + int old_Y; + + setPenFromSettings(painter); + + if (m_CombinedFragment == Ref) { + if (UMLWidget::useFillColor()) { + painter->setBrush(UMLWidget::fillColor()); + } + } + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + const QString combined_fragment_value = name(); + int textStartY = (h / 2) - (fontHeight / 2); + painter->drawRect(0, 0, w, h); + + painter->setPen(textColor()); + painter->setFont(UMLWidget::font()); + QString temp = QLatin1String("loop"); + + switch (m_CombinedFragment) + { + case Ref : + painter->drawText(COMBINED_FRAGMENT_MARGIN, textStartY, w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignCenter, combined_fragment_value); + painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("ref")); + break; + + case Opt : + painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, + w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("opt")); + break; + + case Break : + painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, + w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("break")); + break; + + case Loop : + if (combined_fragment_value != QLatin1String("-")) + { + temp += QLatin1String(" [") + combined_fragment_value + QLatin1Char(']'); + line_width += (combined_fragment_value.size() + 2) * 8; + } + painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, temp); + + break; + + case Neg : + painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, + w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("neg")); + break; + + case Crit : + painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, + w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("critical")); + break; + + case Ass : + painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, + w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("assert")); + break; + + case Alt : + if (combined_fragment_value != QLatin1String("-")) + { + temp = QLatin1Char('[') + combined_fragment_value + QLatin1Char(']'); + painter->drawText(COMBINED_FRAGMENT_MARGIN, 20, w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, temp); + if (m_dashLines.size() == 1 && m_dashLines.first()->y() < y() + 20 + fontHeight) + m_dashLines.first()->setY(y() + h/2); + } + painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, + w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("alt")); + // dash lines + //m_dashLines.first()->paint(painter); + // TODO: move to UMLWidget::calculateSize api + for (QList::iterator it=m_dashLines.begin() ; it!=m_dashLines.end() ; ++it) { + (*it)->setX(x()); + old_Y = (*it)->getYMin(); + (*it)->setYMin(y()); + (*it)->setYMax(y() + height()); + (*it)->setY(y() + (*it)->y() - old_Y); + (*it)->setSize(w, (*it)->height()); + (*it)->setLineColor(lineColor()); + (*it)->setLineWidth(lineWidth()); + } + + break; + + case Par : + painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, + w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("parallel")); + // dash lines + if (m_dashLines.size() != 0) { + //m_dashLines.first()->paint(painter); + // TODO: move to UMLWidget::calculateSize api + for (QList::iterator it=m_dashLines.begin() ; it!=m_dashLines.end() ; ++it) { + (*it)->setX(x()); + old_Y = (*it)->getYMin(); + (*it)->setYMin(y()); + (*it)->setYMax(y() + height()); + (*it)->setY(y() + (*it)->y() - old_Y); + (*it)->setSize(w, (*it)->height()); + (*it)->setLineColor(lineColor()); + (*it)->setLineWidth(lineWidth()); + } + } + break; + + default : break; + } + + setPenFromSettings(painter); + painter->drawLine(0, 20, line_width, 20); + painter->drawLine(line_width, 20, line_width + 10, 10); + painter->drawLine(line_width + 10, 10, line_width + 10, 0); + + UMLWidget::paint(painter, option, widget); +} + +/** + * Overrides method from UMLWidget. + */ +QSizeF CombinedFragmentWidget::minimumSize() const +{ + int width = 10, height = 10; + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + const int textWidth = fm.width(name()); + height = fontHeight; + width = textWidth + 60 > COMBINED_FRAGMENT_WIDTH ? textWidth + 60: COMBINED_FRAGMENT_WIDTH; + if (m_CombinedFragment == Loop) + width += int((float)textWidth * 0.4f); + if (m_CombinedFragment == Alt) + height += fontHeight + 40; + height = height > COMBINED_FRAGMENT_HEIGHT ? height : COMBINED_FRAGMENT_HEIGHT; + width += COMBINED_FRAGMENT_MARGIN * 2; + height += COMBINED_FRAGMENT_MARGIN * 2; + + return QSizeF(width, height); +} + +/** + * Returns the type of combined fragment. + */ +CombinedFragmentWidget::CombinedFragmentType CombinedFragmentWidget::combinedFragmentType() const +{ + return m_CombinedFragment; +} + +/** + * Sets the type of combined fragment. + */ +void CombinedFragmentWidget::setCombinedFragmentType(CombinedFragmentType combinedfragmentType) +{ + m_CombinedFragment = combinedfragmentType; + UMLWidget::m_resizable = true ; //(m_CombinedFragment == Normal); + // creates a dash line if the combined fragment type is alternative or parallel + if (m_CombinedFragment == Alt && m_dashLines.isEmpty()) + { + m_dashLines.push_back(new FloatingDashLineWidget(m_scene, Uml::ID::None, this)); + if (m_CombinedFragment == Alt) + { + m_dashLines.back()->setText(QLatin1String("else")); + } + // TODO: move to UMLWidget::calculateSize api + m_dashLines.back()->setX(x()); + m_dashLines.back()->setYMin(y()); + m_dashLines.back()->setYMax(y() + height()); + m_dashLines.back()->setY(y() + height()/2); + m_dashLines.back()->setSize(width(), m_dashLines.back()->height()); + m_scene->widgetList().append(m_dashLines.back()); + } +} + +/** + * Returns the type of combined fragment. + */ +CombinedFragmentWidget::CombinedFragmentType CombinedFragmentWidget::combinedFragmentType(const QString& type) const +{ + if (type == QLatin1String("Reference")) + return (CombinedFragmentWidget::Ref); + if (type == QLatin1String("Option")) + return (CombinedFragmentWidget::Opt); + if (type == QLatin1String("Break")) + return (CombinedFragmentWidget::Break); + if (type == QLatin1String("Loop")) + return (CombinedFragmentWidget::Loop); + if (type == QLatin1String("Negative")) + return (CombinedFragmentWidget::Neg); + if (type == QLatin1String("Critical")) + return (CombinedFragmentWidget::Crit); + if (type == QLatin1String("Assertion")) + return (CombinedFragmentWidget::Ass); + if (type == QLatin1String("Alternative")) + return (CombinedFragmentWidget::Alt); + if (type == QLatin1String("Parallel")) + return (CombinedFragmentWidget::Par); + // Shouldn't happen + Q_ASSERT(0); + return (CombinedFragmentWidget::Ref); +} + +/** + * Sets the type of combined fragment. + */ +void CombinedFragmentWidget::setCombinedFragmentType(const QString& combinedfragmentType) +{ + setCombinedFragmentType(combinedFragmentType(combinedfragmentType)); +} + +/** + * ... + */ +void CombinedFragmentWidget::askNameForWidgetType(UMLWidget* &targetWidget, const QString& dialogTitle, + const QString& dialogPrompt, const QString& defaultName) +{ + Q_UNUSED(defaultName); + bool pressedOK = false; + const QStringList list = QStringList() + << QLatin1String("Reference") + << QLatin1String("Option") + << QLatin1String("Break") + << QLatin1String("Loop") + << QLatin1String("Negative") + << QLatin1String("Critical") + << QLatin1String("Assertion") + << QLatin1String("Alternative") + << QLatin1String("Parallel") ; +#if QT_VERSION >= 0x050000 + QPointer inputDlg = new QInputDialog(); + inputDlg->setComboBoxItems(list); + inputDlg->setOptions(QInputDialog::UseListViewForComboBoxItems); + inputDlg->setWindowTitle(dialogTitle); + inputDlg->setLabelText(dialogPrompt); + pressedOK = inputDlg->exec(); + QStringList result; + result.append(inputDlg->textValue()); + delete inputDlg; +#else + const QStringList select = list; + QStringList result = KInputDialog::getItemList (dialogTitle, dialogPrompt, list, select, false, &pressedOK, UMLApp::app()); +#endif + if (pressedOK) { + QString type = result.join(QString()); + dynamic_cast(targetWidget)->setCombinedFragmentType(type); + if (type == QLatin1String("Reference")) + Dialog_Utils::askNameForWidget(targetWidget, i18n("Enter the name of the diagram referenced"), i18n("Enter the name of the diagram referenced"), i18n("Diagram name")); + else if (type == QLatin1String(QLatin1String("Loop"))) + Dialog_Utils::askNameForWidget(targetWidget, i18n("Enter the guard of the loop"), i18n("Enter the guard of the loop"), i18n("-")); + else if (type == QLatin1String("Alternative")) + Dialog_Utils::askNameForWidget(targetWidget, i18n("Enter the first alternative name"), i18n("Enter the first alternative name"), i18n("-")); + } else { + targetWidget->cleanup(); + delete targetWidget; + targetWidget = NULL; + } +} + +/** + * Saves the widget to the "combinedFragmentwidget" XMI element. + */ +void CombinedFragmentWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +{ + QDomElement combinedFragmentElement = qDoc.createElement(QLatin1String("combinedFragmentwidget")); + UMLWidget::saveToXMI(qDoc, combinedFragmentElement); + combinedFragmentElement.setAttribute(QLatin1String("combinedFragmentname"), m_Text); + combinedFragmentElement.setAttribute(QLatin1String("documentation"), m_Doc); + combinedFragmentElement.setAttribute(QLatin1String("CombinedFragmenttype"), m_CombinedFragment); + + // save the corresponding floating dash lines + for (QList::iterator it = m_dashLines.begin() ; it != m_dashLines.end() ; ++it) { + (*it)-> saveToXMI(qDoc, combinedFragmentElement); + } + + qElement.appendChild(combinedFragmentElement); +} + +/** + * Loads the widget from the "CombinedFragmentwidget" XMI element. + */ +bool CombinedFragmentWidget::loadFromXMI(QDomElement & qElement) +{ + if (!UMLWidget::loadFromXMI(qElement)) + return false; + m_Text = qElement.attribute(QLatin1String("combinedFragmentname")); + m_Doc = qElement.attribute(QLatin1String("documentation")); + QString type = qElement.attribute(QLatin1String("CombinedFragmenttype")); + + //now load child elements + QDomNode node = qElement.firstChild(); + QDomElement element = node.toElement(); + while (!element.isNull()) { + QString tag = element.tagName(); + if (tag == QLatin1String("floatingdashlinewidget")) { + FloatingDashLineWidget * fdlwidget = new FloatingDashLineWidget(m_scene, Uml::ID::None, this); + m_dashLines.push_back(fdlwidget); + if (!fdlwidget->loadFromXMI(element)) { + // Most likely cause: The FloatingTextWidget is empty. + delete m_dashLines.back(); + return false; + } + else { + m_scene->widgetList().append(fdlwidget); + fdlwidget->clipSize(); + } + } else { + uError() << "unknown tag " << tag; + } + node = node.nextSibling(); + element = node.toElement(); + } + // m_dashLines = listline; + setCombinedFragmentType((CombinedFragmentType)type.toInt()); + + return true; +} + +void CombinedFragmentWidget::removeDashLine(FloatingDashLineWidget *line) +{ + if (m_dashLines.contains(line)) + m_dashLines.removeOne(line); +} + +/** + * Overrides the function from UMLWidget. Deletes all FloatingDashLineWidgets + * that are associated with this instance. + */ +void CombinedFragmentWidget::cleanup() +{ + foreach (FloatingDashLineWidget* w, m_dashLines) + { + if (!w->isSelected()) { + // no need to make this undoable, since the dashlines will be + // reconstructed when deleting the combined fragment is undone. + umlScene()->removeWidgetCmd(w); + } + } +} + +/** + * Overrides the function from UMLWidget. + * + * @param action The command to be executed. + */ +void CombinedFragmentWidget::slotMenuSelection(QAction* action) +{ + ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); + switch (sel) { + // for alternative or parallel combined fragments + case ListPopupMenu::mt_AddInteractionOperand: + m_dashLines.push_back(new FloatingDashLineWidget(m_scene, Uml::ID::None, this)); + if (m_CombinedFragment == Alt) + { + m_dashLines.back()->setText(QLatin1String("else")); + } + // TODO: move to UMLWidget::calculateSize api + m_dashLines.back()->setX(x()); + m_dashLines.back()->setYMin(y()); + m_dashLines.back()->setYMax(y() + height()); + m_dashLines.back()->setY(y() + height() / 2); + m_dashLines.back()->setSize(width(), m_dashLines.back()->height()); + m_scene->setupNewWidget(m_dashLines.back()); + break; + + case ListPopupMenu::mt_Rename: + { + bool ok = false; + QString name = m_Text; + +#if QT_VERSION >= 0x050000 + if (m_CombinedFragment == Alt) { + name = QInputDialog::getText(Q_NULLPTR, + i18n("Enter first alternative"), i18n("Enter first alternative :"), + QLineEdit::Normal, + m_Text, &ok); + } + else if (m_CombinedFragment == Ref) { + name = QInputDialog::getText(Q_NULLPTR, + i18n("Enter referenced diagram name"), i18n("Enter referenced diagram name :"), + QLineEdit::Normal, + m_Text, &ok); + } + else if (m_CombinedFragment == Loop) { + name = QInputDialog::getText(Q_NULLPTR, + i18n("Enter the guard of the loop"), i18n("Enter the guard of the loop:"), + QLineEdit::Normal, + m_Text, &ok); + } +#else + if (m_CombinedFragment == Alt) { + name = KInputDialog::getText(i18n("Enter first alternative"), i18n("Enter first alternative :"), m_Text, &ok); + } + else if (m_CombinedFragment == Ref) { + name = KInputDialog::getText(i18n("Enter referenced diagram name"), i18n("Enter referenced diagram name :"), m_Text, &ok); + } + else if (m_CombinedFragment == Loop) { + name = KInputDialog::getText(i18n("Enter the guard of the loop"), i18n("Enter the guard of the loop:"), m_Text, &ok); + } +#endif + if (ok && name.length() > 0) + m_Text = name; + } + break; + + default: + UMLWidget::slotMenuSelection(action); + } +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/combinedfragmentwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/combinedfragmentwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/combinedfragmentwidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/combinedfragmentwidget.h 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,91 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef COMBINEDFRAGMENTWIDGET_H +#define COMBINEDFRAGMENTWIDGET_H + +#include "umlwidget.h" +#include "worktoolbar.h" +#include "floatingdashlinewidget.h" + +#include + +#define COMBINED_FRAGMENT_MARGIN 5 +#define COMBINED_FRAGMENT_WIDTH 100 +#define COMBINED_FRAGMENT_HEIGHT 50 + +/** + * This class is the graphical version of a UML combined fragment. A combinedfragmentWidget is created + * by a @ref UMLView. An combinedfragmentWidget belongs to only one @ref UMLView instance. + * When the @ref UMLView instance that this class belongs to, it will be automatically deleted. + * + * The combinedfragmentWidget class inherits from the @ref UMLWidget class which adds most of the functionality + * to this class. + * + * @short A graphical version of a UML combined fragment. + * @author Hassan KOUCH + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class CombinedFragmentWidget : public UMLWidget +{ + Q_OBJECT + +public: + enum CombinedFragmentType + { + Ref = 0, + Opt, + Break, + Loop, + Neg, + Crit, + Ass, + Alt, + Par + }; + + explicit CombinedFragmentWidget(UMLScene * scene, + CombinedFragmentType combinedfragmentType = Ref, + Uml::ID::Type id = Uml::ID::None); + virtual ~CombinedFragmentWidget(); + + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + + CombinedFragmentType combinedFragmentType() const; + CombinedFragmentType combinedFragmentType(const QString& combinedfragmentType) const; + void setCombinedFragmentType(CombinedFragmentType combinedfragmentType); + void setCombinedFragmentType(const QString& combinedfragmentType); + + void askNameForWidgetType(UMLWidget* &targetWidget, const QString& dialogTitle, + const QString& dialogPrompt, const QString& defaultName); + + void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); + bool loadFromXMI(QDomElement & qElement); + void removeDashLine(FloatingDashLineWidget *line); + + virtual void cleanup(); + +public slots: + void slotMenuSelection(QAction* action); + + +protected: + QSizeF minimumSize() const; + + /// Type of CombinedFragment. + CombinedFragmentType m_CombinedFragment; + +private: + /// Dash lines of an alternative or parallel combined fragment + QList m_dashLines ; + +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/componentwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/componentwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/componentwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/componentwidget.cpp 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,207 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "componentwidget.h" + +// app includes +#include "component.h" +#include "debug_utils.h" +#include "umlscene.h" +#include "umlview.h" +#include "optionstate.h" +#include "umldoc.h" +#include "package.h" +#include "portwidget.h" + +/** + * Constructs a ComponentWidget. + * + * @param scene The parent of this ComponentWidget. + * @param c The UMLComponent this will be representing. + */ +ComponentWidget::ComponentWidget(UMLScene * scene, UMLComponent *c) + : UMLWidget(scene, WidgetBase::wt_Component, c) +{ + setSize(100, 30); + //set defaults from m_scene + if (m_scene) { + //check to see if correct + const Settings::OptionState& ops = m_scene->optionState(); + m_showStereotype = ops.classState.showStereoType; + } +} + +/** + * Destructor. + */ +ComponentWidget::~ComponentWidget() +{ +} + +/** + * Reimplemented from UMLWidget::paint to paint component + * widget. + */ +void ComponentWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + UMLComponent *umlcomp = static_cast(m_umlObject); + if (umlcomp == NULL) + return; + setPenFromSettings(painter); + QPen origPen = painter->pen(); + QPen pen = origPen; + if (umlcomp->getExecutable()) { + pen.setWidth(origPen.width() + 2); + painter->setPen(pen); + } + if (UMLWidget::useFillColor()) { + painter->setBrush(UMLWidget::fillColor()); + } else { + painter->setBrush(m_scene->backgroundColor()); + } + + const int w = width(); + const int h = height(); + const int halfHeight = h / 2; + int textXOffset = 0; + QFont font = UMLWidget::font(); + font.setBold(true); + const QFontMetrics &fm = getFontMetrics(FT_BOLD); + const int fontHeight = fm.lineSpacing(); + QString nameStr = name(); + const QString stereotype = m_umlObject->stereotype(); + + if (Settings::optionState().generalState.uml2) { + painter->drawRect(0, 0, w, h); + // draw small component symbol in upper right corner + painter->setPen(origPen); + painter->drawRect(w - 17, 5, 11, 13); + painter->drawRect(w - 19, 7, 2, 2); + painter->drawRect(w - 19, 11, 2, 2); + painter->setPen(pen); + } else { + painter->drawRect(2*COMPONENT_MARGIN, 0, w - 2*COMPONENT_MARGIN, h); + painter->drawRect(0, halfHeight - fontHeight/2 - fontHeight, COMPONENT_MARGIN*4, fontHeight); + painter->drawRect(0, halfHeight + fontHeight/2, COMPONENT_MARGIN*4, fontHeight); + textXOffset = COMPONENT_MARGIN * 4; + } + + painter->setPen(textColor()); + painter->setFont(font); + + int lines = 1; + + if (!stereotype.isEmpty()) { + painter->drawText(textXOffset, halfHeight - fontHeight, + w - textXOffset, fontHeight, Qt::AlignCenter, + m_umlObject->stereotype(true)); + lines = 2; + } + + if (UMLWidget::isInstance()) { + font.setUnderline(true); + painter->setFont(font); + nameStr = UMLWidget::instanceName() + QLatin1String(" : ") + nameStr; + } + + if (lines == 1) { + painter->drawText(textXOffset, halfHeight - (fontHeight/2), + w - textXOffset, fontHeight, Qt::AlignCenter, nameStr); + } else { + painter->drawText(textXOffset, halfHeight, + w - textXOffset, fontHeight, Qt::AlignCenter, nameStr); + } + + UMLWidget::paint(painter, option, widget); +} + +/** + * Overridden from UMLWidget due to emission of signal sigCompMoved() + */ +void ComponentWidget::moveWidgetBy(qreal diffX, qreal diffY) +{ + UMLWidget::moveWidgetBy(diffX, diffY); + emit sigCompMoved(diffX, diffY); +} + +/** + * Override method from UMLWidget for adjustment of attached PortWidgets. + */ +void ComponentWidget::adjustAssocs(qreal dx, qreal dy) +{ + if (m_doc->loading()) { + // don't recalculate the assocs during load of XMI + // -> return immediately without action + return; + } + UMLWidget::adjustAssocs(dx, dy); + UMLPackage *comp = static_cast(m_umlObject); + foreach (UMLObject *o, comp->containedObjects()) { + uIgnoreZeroPointer(o); + if (o->baseType() != UMLObject::ot_Port) + continue; + UMLWidget *portW = m_scene->widgetOnDiagram(o->id()); + if (portW) + portW->adjustAssocs(dx, dy); + } +} + +/** + * Saves to the "componentwidget" XMI element. + */ +void ComponentWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +{ + QDomElement conceptElement = qDoc.createElement(QLatin1String("componentwidget")); + UMLWidget::saveToXMI(qDoc, conceptElement); + qElement.appendChild(conceptElement); +} + +/** + * Overrides method from UMLWidget. + */ +QSizeF ComponentWidget::minimumSize() const +{ + if (!m_umlObject) { + return QSizeF(70, 70); + } + const QFontMetrics &fm = getFontMetrics(FT_BOLD_ITALIC); + const int fontHeight = fm.lineSpacing(); + + QString name = m_umlObject->name(); + if (UMLWidget::isInstance()) { + name = UMLWidget::instanceName() + QLatin1String(" : ") + name; + } + + int width = fm.width(name); + + int stereoWidth = 0; + if (!m_umlObject->stereotype().isEmpty()) { + stereoWidth = fm.width(m_umlObject->stereotype(true)); + } + if (stereoWidth > width) + width = stereoWidth; + width += COMPONENT_MARGIN * 6; + width = 70>width ? 70 : width; //minumin width of 70 + + int height = (2*fontHeight) + (COMPONENT_MARGIN * 3); + + UMLComponent *umlcomp = static_cast(m_umlObject); + if (umlcomp && umlcomp->getExecutable()) { + width += 2; + height += 2; + } + + return QSizeF(width, height); +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/componentwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/componentwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/componentwidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/componentwidget.h 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,58 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef COMPONENTWIDGET_H +#define COMPONENTWIDGET_H + +#include "umlwidget.h" + +class UMLComponent; + +#define COMPONENT_MARGIN 10 + +/** + * Defines a graphical version of the Component. Most of the functionality + * will come from the @ref UMLComponent class. + * + * @short A graphical version of a Component. + * @author Jonathan Riddell + * @see UMLWidget + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class ComponentWidget : public UMLWidget +{ + Q_OBJECT +public: + ComponentWidget(UMLScene * scene, UMLComponent *c); + virtual ~ComponentWidget(); + + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + virtual void moveWidgetBy(qreal diffX, qreal diffY); + virtual void adjustAssocs(qreal dx, qreal dy); + + virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); + +signals: + /** + * Emitted when the component widget is moved. + * Provides the delta X and delta Y amount by which the widget was moved + * relative to the previous position. + * Slots into PortWidget::slotCompMoved() + * @param diffX The difference between previous and new X value. + * @param diffY The difference between previous and new Y value. + */ + void sigCompMoved(qreal diffX, qreal diffY); + +protected: + QSizeF minimumSize() const; + +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/datatypewidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/datatypewidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/datatypewidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/datatypewidget.cpp 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,129 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "datatypewidget.h" + +// app includes +#include "classifier.h" +#include "classifierlistitem.h" +#include "debug_utils.h" +#include "operation.h" +#include "umldoc.h" +#include "umlscene.h" +#include "umlview.h" + +// qt includes +#include + +/** + * Constructs an DatatypeWidget. + * + * @param scene The parent of this DatatypeWidget. + * @param d The UMLClassifier this will be representing. + */ +DatatypeWidget::DatatypeWidget(UMLScene *scene, UMLClassifier *d) + : UMLWidget(scene, WidgetBase::wt_Datatype, d) +{ + setSize(100, 30); +} + +/** + * Standard deconstructor. + */ +DatatypeWidget::~DatatypeWidget() +{ +} + +/** + * Overrides standard method. + */ +void DatatypeWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + setPenFromSettings(painter); + if (UMLWidget::useFillColor()) { + painter->setBrush(UMLWidget::fillColor()); + } else { + painter->setBrush(m_scene->backgroundColor()); + } + + int w = width(); + int h = height(); + + QFontMetrics &fm = getFontMetrics(FT_NORMAL); + int fontHeight = fm.lineSpacing(); + + painter->drawRect(0, 0, w, h); + painter->setPen(textColor()); + + QFont font = UMLWidget::font(); + font.setBold(true); + painter->setFont(font); + painter->drawText(DATATYPE_MARGIN, 0, + w - DATATYPE_MARGIN* 2, fontHeight, + Qt::AlignCenter, m_umlObject->stereotype(true)); + + font.setItalic(m_umlObject->isAbstract()); + painter->setFont(font); + painter->drawText(DATATYPE_MARGIN, fontHeight, + w - DATATYPE_MARGIN * 2, fontHeight, Qt::AlignCenter, name()); + + UMLWidget::paint(painter, option, widget); +} + +/** + * Loads from a "datatypewidget" XMI element. + */ +bool DatatypeWidget::loadFromXMI(QDomElement & qElement) +{ + return UMLWidget::loadFromXMI(qElement); +} + +/** + * Saves to the "datatypewidget" XMI element. + */ +void DatatypeWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +{ + QDomElement conceptElement = qDoc.createElement(QLatin1String("datatypewidget")); + UMLWidget::saveToXMI(qDoc, conceptElement); + qElement.appendChild(conceptElement); +} + +/** + * Overrides method from UMLWidget. + */ +QSizeF DatatypeWidget::minimumSize() const +{ + if (!m_umlObject) { + return UMLWidget::minimumSize(); + } + int width, height; + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + + int lines = 1;//always have one line - for name + lines++; //for the stereotype + + height = width = 0; + height += lines * fontHeight; + + //now set the width of the concept + //set width to name to start with + //set width to name to start with + width = getFontMetrics(FT_BOLD_ITALIC).boundingRect(m_umlObject->fullyQualifiedName()).width(); + int w = getFontMetrics(FT_BOLD).boundingRect(m_umlObject->stereotype(true)).width(); + + width = w > width?w:width; + + //allow for width margin + width += DATATYPE_MARGIN * 2; + + return QSizeF(width, height); +} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/datatypewidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/datatypewidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/datatypewidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/datatypewidget.h 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,48 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef DATATYPEWIDGET_H +#define DATATYPEWIDGET_H + +#include "umlwidget.h" + +class UMLClassifier; + +#define DATATYPE_MARGIN 5 + +/** + * Defines a graphical version of the datatype. Most of the functionality + * will come from the @ref UMLWidget class from which class inherits from. + * + * @short A graphical version of an datatype. + * @author Jonathan Riddell + * @see UMLWidget + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class DatatypeWidget : public UMLWidget +{ + Q_OBJECT +public: + DatatypeWidget(UMLScene *scene, UMLClassifier *d); + virtual ~DatatypeWidget(); + + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + + bool loadFromXMI(QDomElement& qElement); + void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); + +public Q_SLOTS: + +protected: + QSizeF minimumSize() const; + +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/entitywidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/entitywidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/entitywidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/entitywidget.cpp 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,246 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "entitywidget.h" + +// app includes +#include "classifier.h" +#include "classifierlistitem.h" +#include "debug_utils.h" +#include "entity.h" +#include "entityattribute.h" +#include "foreignkeyconstraint.h" +#include "listpopupmenu.h" +#include "object_factory.h" +#include "uml.h" +#include "umlclassifierlistitemlist.h" +#include "umldoc.h" +#include "umlscene.h" +#include "umlview.h" +#include "uniqueconstraint.h" + +/** + * Constructs an EntityWidget. + * + * @param scene The parent of this EntityWidget. + * @param o The UMLObject this will be representing. + */ +EntityWidget::EntityWidget(UMLScene *scene, UMLObject* o) + : UMLWidget(scene, WidgetBase::wt_Entity, o) +{ + setSize(100, 30); +} + +/** + * Destructor. + */ +EntityWidget::~EntityWidget() +{ +} + +/** + * Draws the entity as a rectangle with a box underneith with a list of literals + */ +void EntityWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + setPenFromSettings(painter); + if(UMLWidget::useFillColor()) + painter->setBrush(UMLWidget::fillColor()); + else + painter->setBrush(m_scene->backgroundColor()); + + const int w = width(); + const int h = height(); + + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + int fontHeight = fm.lineSpacing(); + const QString name = this->name(); + + painter->drawRect(0, 0, w, h); + painter->setPen(textColor()); + + QFont font = UMLWidget::font(); + font.setBold(true); + painter->setFont(font); + int y = 0; + if (!m_umlObject->stereotype().isEmpty()) { + painter->drawText(ENTITY_MARGIN, 0, + w - ENTITY_MARGIN * 2, fontHeight, + Qt::AlignCenter, m_umlObject->stereotype(true)); + font.setItalic(m_umlObject->isAbstract()); + painter->setFont(font); + painter->drawText(ENTITY_MARGIN, fontHeight, + w - ENTITY_MARGIN * 2, fontHeight, Qt::AlignCenter, name); + font.setBold(false); + font.setItalic(false); + painter->setFont(font); + y = fontHeight * 2; + } else { + font.setItalic(m_umlObject->isAbstract()); + painter->setFont(font); + painter->drawText(ENTITY_MARGIN, 0, + w - ENTITY_MARGIN * 2, fontHeight, Qt::AlignCenter, name); + font.setBold(false); + font.setItalic(false); + painter->setFont(font); + + y = fontHeight; + } + + setPenFromSettings(painter); + + painter->drawLine(0, y, w, y); + + QFontMetrics fontMetrics(font); + UMLClassifier *classifier = (UMLClassifier*)m_umlObject; + UMLClassifierListItem* entityattribute = 0; + UMLClassifierListItemList list = classifier->getFilteredList(UMLObject::ot_EntityAttribute); + foreach (entityattribute, list) { + QString text = entityattribute->name(); + painter->setPen(textColor()); + UMLEntityAttribute* casted = dynamic_cast(entityattribute); + if(casted && casted->indexType() == UMLEntityAttribute::Primary) + { + font.setUnderline(true); + painter->setFont(font); + font.setUnderline(false); + } + painter->drawText(ENTITY_MARGIN, y, + fontMetrics.width(text), fontHeight, Qt::AlignVCenter, text); + painter->setFont(font); + y+=fontHeight; + } + + UMLWidget::paint(painter, option, widget); +} + +/** + * Saves to the "entitywidget" XMI element. + */ +void EntityWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +{ + QDomElement conceptElement = qDoc.createElement(QLatin1String("entitywidget")); + UMLWidget::saveToXMI(qDoc, conceptElement); + qElement.appendChild(conceptElement); +} + +/** + * Will be called when a menu selection has been made from the popup + * menu. + * + * @param action The action that has been selected. + */ +void EntityWidget::slotMenuSelection(QAction* action) +{ + ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); + switch(sel) { + case ListPopupMenu::mt_EntityAttribute: + if (Object_Factory::createChildObject(static_cast(m_umlObject), + UMLObject::ot_EntityAttribute)) { + UMLApp::app()->document()->setModified(); + } + break; + + case ListPopupMenu::mt_PrimaryKeyConstraint: + case ListPopupMenu::mt_UniqueConstraint: + if (UMLObject* obj = Object_Factory::createChildObject(static_cast(m_umlObject), + UMLObject::ot_UniqueConstraint)) { + UMLApp::app()->document()->setModified(); + + if (sel == ListPopupMenu::mt_PrimaryKeyConstraint) { + UMLUniqueConstraint* uc = static_cast(obj); + static_cast(m_umlObject)->setAsPrimaryKey(uc); + } + } + break; + + case ListPopupMenu::mt_ForeignKeyConstraint: + if (Object_Factory::createChildObject(static_cast(m_umlObject), + UMLObject::ot_ForeignKeyConstraint)) { + UMLApp::app()->document()->setModified(); + + } + break; + + case ListPopupMenu::mt_CheckConstraint: + if (Object_Factory::createChildObject(static_cast(m_umlObject), + UMLObject::ot_CheckConstraint)) { + UMLApp::app()->document()->setModified(); + + } + break; + + default: + UMLWidget::slotMenuSelection(action); + } +} + +/** + * Overrides method from UMLWidget. + */ +QSizeF EntityWidget::minimumSize() const +{ + if (!m_umlObject) { + return UMLWidget::minimumSize(); + } + + int width, height; + QFont font = UMLWidget::font(); + font.setItalic(false); + font.setUnderline(false); + font.setBold(false); + const QFontMetrics fm(font); + + const int fontHeight = fm.lineSpacing(); + + int lines = 1;//always have one line - for name + if (!m_umlObject->stereotype().isEmpty()) { + lines++; + } + + const int numberOfEntityAttributes = ((UMLEntity*)m_umlObject)->entityAttributes(); + + height = width = 0; + //set the height of the entity + + lines += numberOfEntityAttributes; + if (numberOfEntityAttributes == 0) { + height += fontHeight / 2; //no entity literals, so just add a bit of space + } + + height += lines * fontHeight; + + //now set the width of the concept + //set width to name to start with + // FIXME spaces to get round beastie with font width, + // investigate UMLWidget::getFontMetrics() + width = getFontMetrics(FT_BOLD_ITALIC).boundingRect(QLatin1Char(' ') + name() + + QLatin1Char(' ')).width(); + const int w = getFontMetrics(FT_BOLD).boundingRect(m_umlObject->stereotype(true)).width(); + + width = w > width ? w : width; + + UMLClassifier* classifier = (UMLClassifier*)m_umlObject; + UMLClassifierListItemList list = classifier->getFilteredList(UMLObject::ot_EntityAttribute); + UMLClassifierListItem* listItem = 0; + foreach (listItem, list) { + int w = fm.width(listItem->name()); + width = w > width?w:width; + } + + //allow for width margin + width += ENTITY_MARGIN * 2; + + return QSizeF(width, height); +} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/entitywidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/entitywidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/entitywidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/entitywidget.h 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,49 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef ENTITYWIDGET_H +#define ENTITYWIDGET_H + +#include "umlwidget.h" + +class UMLScene; + +#define ENTITY_MARGIN 5 + +/** + * Defines a graphical version of the entity. Most of the functionality + * will come from the @ref UMLWidget class from which class inherits from. + * + * @short A graphical version of an entity. + * @author Jonathan Riddell + * @see UMLWidget + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class EntityWidget : public UMLWidget +{ + Q_OBJECT +public: + explicit EntityWidget(UMLScene *scene, UMLObject* o); + virtual ~EntityWidget(); + + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + + // UMLWidget::loadFromXMI is used to load this widget. + virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); + +public Q_SLOTS: + virtual void slotMenuSelection(QAction* action); + +protected: + QSizeF minimumSize() const; + +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/enumwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/enumwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/enumwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/enumwidget.cpp 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,262 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "enumwidget.h" + +// app includes +#include "classifier.h" +#include "classifierlistitem.h" +#include "debug_utils.h" +#include "enum.h" +#include "enumliteral.h" +#include "listpopupmenu.h" +#include "object_factory.h" +#include "uml.h" +#include "umlclassifierlistitemlist.h" +#include "umldoc.h" +#include "umlscene.h" +#include "umlview.h" + +/** + * Constructs an instance of EnumWidget. + * + * @param scene The parent of this EnumWidget. + * @param o The UMLObject this will be representing. + */ +EnumWidget::EnumWidget(UMLScene *scene, UMLObject* o) + : UMLWidget(scene, WidgetBase::wt_Enum, o), + m_showPackage(false) +{ + setSize(100, 30); + //set defaults from m_scene + if (m_scene) { + //check to see if correct + const Settings::OptionState& ops = m_scene->optionState(); + m_showPackage = ops.classState.showPackage; + } else { + // For completeness only. Not supposed to happen. + m_showPackage = false; + } +} + +/** + * Destructor. + */ +EnumWidget::~EnumWidget() +{ +} + +/** + * Returns the status of whether to show Package. + * + * @return True if package is shown. + */ +bool EnumWidget::showPackage() const +{ + return m_showPackage; +} + +/** + * Set the status of whether to show Package. + * + * @param _status True if package shall be shown. + */ +void EnumWidget::setShowPackage(bool _status) +{ + m_showPackage = _status; + updateGeometry(); + update(); +} + +/** + * Toggles the status of whether to show package. + */ +void EnumWidget::toggleShowPackage() +{ + m_showPackage = !m_showPackage; + updateGeometry(); + update(); +} + +/** + * Draws the enum as a rectangle with a box underneith with a list of literals + * Reimplemented from UMLWidget::paint + */ +void EnumWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + setPenFromSettings(painter); + if(UMLWidget::useFillColor()) + painter->setBrush(UMLWidget::fillColor()); + else + painter->setBrush(m_scene->backgroundColor()); + + const int w = width(); + const int h = height(); + + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + QString name; + if (m_showPackage) { + name = m_umlObject->fullyQualifiedName(); + } else { + name = this->name(); + } + + painter->drawRect(0, 0, w, h); + painter->setPen(textColor()); + + QFont font = UMLWidget::font(); + font.setBold(true); + painter->setFont(font); + painter->drawText(ENUM_MARGIN, 0, + w - ENUM_MARGIN * 2, fontHeight, + Qt::AlignCenter, m_umlObject->stereotype(true)); + + font.setItalic(m_umlObject->isAbstract()); + painter->setFont(font); + painter->drawText(ENUM_MARGIN, fontHeight, + w - ENUM_MARGIN * 2, fontHeight, Qt::AlignCenter, name); + font.setBold(false); + font.setItalic(false); + painter->setFont(font); + + int y = fontHeight * 2; + + setPenFromSettings(painter); + + painter->drawLine(0, y, w, y); + + QFontMetrics fontMetrics(font); + UMLClassifier *classifier = (UMLClassifier*)m_umlObject; + UMLClassifierListItem* enumLiteral = 0; + UMLClassifierListItemList list = classifier->getFilteredList(UMLObject::ot_EnumLiteral); + foreach (enumLiteral, list) { + QString text = enumLiteral->name(); + painter->setPen(textColor()); + painter->drawText(ENUM_MARGIN, y, + fontMetrics.width(text), fontHeight, Qt::AlignVCenter, text); + y+=fontHeight; + } + + UMLWidget::paint(painter, option, widget); +} + +/** + * Loads from an "enumwidget" XMI element. + */ +bool EnumWidget::loadFromXMI(QDomElement & qElement) +{ + if (!UMLWidget::loadFromXMI(qElement)) { + return false; + } + QString showpackage = qElement.attribute(QLatin1String("showpackage"), QLatin1String("0")); + + m_showPackage = (bool)showpackage.toInt(); + + return true; +} + +/** + * Saves to the "enumwidget" XMI element. + */ +void EnumWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +{ + QDomElement conceptElement = qDoc.createElement(QLatin1String("enumwidget")); + UMLWidget::saveToXMI(qDoc, conceptElement); + + conceptElement.setAttribute(QLatin1String("showpackage"), m_showPackage); + qElement.appendChild(conceptElement); +} + +/** + * Will be called when a menu selection has been made from the + * popup menu. + * + * @param action The action that has been selected. + */ +void EnumWidget::slotMenuSelection(QAction* action) +{ + ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); + if (sel == ListPopupMenu::mt_EnumLiteral) { + if (Object_Factory::createChildObject(static_cast(m_umlObject), + UMLObject::ot_EnumLiteral)) { + /* I don't know why it works without these calls: + updateComponentSize(); + update(); + */ + UMLApp::app()->document()->setModified(); + } + return; + } + UMLWidget::slotMenuSelection(action); +} + +/** + * Overrides method from UMLWidget. + */ +QSizeF EnumWidget::minimumSize() const +{ + if (!m_umlObject) { + return UMLWidget::minimumSize(); + } + + int width, height; + QFont font = UMLWidget::font(); + font.setItalic(false); + font.setUnderline(false); + font.setBold(false); + const QFontMetrics fm(font); + + const int fontHeight = fm.lineSpacing(); + + int lines = 1;//always have one line - for name + lines++; //for the stereotype + + const int numberOfEnumLiterals = ((UMLEnum*)m_umlObject)->enumLiterals(); + + height = width = 0; + //set the height of the enum + + lines += numberOfEnumLiterals; + if (numberOfEnumLiterals == 0) { + height += fontHeight / 2; //no enum literals, so just add a bit of space + } + + height += lines * fontHeight; + + //now set the width of the concept + //set width to name to start with + if (m_showPackage) { + width = getFontMetrics(FT_BOLD_ITALIC).boundingRect(m_umlObject->fullyQualifiedName()).width(); + } else { + width = getFontMetrics(FT_BOLD_ITALIC).boundingRect(name()).width(); + } + int w = getFontMetrics(FT_BOLD).boundingRect(m_umlObject->stereotype(true)).width(); + + + width = w > width?w:width; + + UMLClassifier *classifier = (UMLClassifier*)m_umlObject; + UMLClassifierListItemList list = classifier->getFilteredList(UMLObject::ot_EnumLiteral); + UMLClassifierListItem* listItem = 0; + foreach (listItem, list) { + int w = fm.width(listItem->name()); + width = w > width?w:width; + } + + //allow for width margin + width += ENUM_MARGIN * 2; + + return QSizeF(width, height); +} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/enumwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/enumwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/enumwidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/enumwidget.h 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,52 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef ENUMWIDGET_H +#define ENUMWIDGET_H + +#include "umlwidget.h" + +#define ENUM_MARGIN 5 + +/** + * Defines a graphical version of the enum. Most of the functionality + * will come from the @ref UMLWidget class from which class inherits from. + * + * @short A graphical version of an enum. + * @author Jonathan Riddell + * @see UMLWidget + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class EnumWidget : public UMLWidget +{ + Q_OBJECT +public: + explicit EnumWidget(UMLScene *scene, UMLObject* o); + virtual ~EnumWidget(); + + bool showPackage() const; + void setShowPackage(bool _status); + void toggleShowPackage(); + + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + + virtual bool loadFromXMI(QDomElement& qElement); + virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); + +public Q_SLOTS: + virtual void slotMenuSelection(QAction* action); + +protected: + QSizeF minimumSize() const; + + bool m_showPackage; +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/floatingdashlinewidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/floatingdashlinewidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/floatingdashlinewidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/floatingdashlinewidget.cpp 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,199 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ +// own header +#include "floatingdashlinewidget.h" +#include "combinedfragmentwidget.h" + +//kde includes +#if QT_VERSION < 0x050000 +#include +#endif +#include + +//app includes +#include "debug_utils.h" +#include "umlview.h" +#include "widget_utils.h" +#include "listpopupmenu.h" + +// qt includes +#if QT_VERSION >= 0x050000 +#include +#endif +#include + +DEBUG_REGISTER_DISABLED(FloatingDashLineWidget) + +/** + * Creates a floating dash line. + * @param scene The parent of the widget + * @param id The ID to assign (-1 will prompt a new ID) + * @param parent The CombinedFragmentWidget which acts as the parent + */ +FloatingDashLineWidget::FloatingDashLineWidget(UMLScene * scene, Uml::ID::Type id, CombinedFragmentWidget *parent) + : UMLWidget(scene, WidgetBase::wt_FloatingDashLine, id), + m_yMin(0), + m_yMax(0), + m_parent(parent) +{ + m_resizable = false; + m_Text = QString(); + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + setSize(10, fontHeight); +} + +/** + * Destructor. + */ +FloatingDashLineWidget::~FloatingDashLineWidget() +{ + if (m_parent) + m_parent->removeDashLine(this); +} + +/** + * Overrides the standard paint event. + */ +void FloatingDashLineWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + painter->setPen(textColor()); + painter->setFont(UMLWidget::font()); + painter->drawText(FLOATING_DASH_LINE_TEXT_MARGIN, 0, + width() - FLOATING_DASH_LINE_TEXT_MARGIN * 2, fontHeight, + Qt::AlignLeft, QLatin1Char('[') + m_Text + QLatin1Char(']')); + painter->setPen(QPen(UMLWidget::lineColor(), 0, Qt::DashLine)); + painter->drawLine(0, 0, width(), 0); + + UMLWidget::paint(painter, option, widget); +} + +/** + * Sets m_text. + */ +void FloatingDashLineWidget::setText(const QString& text) +{ + m_Text = text; +} + +/** + * Returns true if the given point is near the floatingdashline. + */ +bool FloatingDashLineWidget::onLine(const QPointF& point) +{ + // check if the given point is the start or end point of the line + if (((abs((long)(y() + height() - point.y()))) <= POINT_DELTA) || (abs((long)(y() - point.y())) <= POINT_DELTA)) { + return true; + } + // check if the given point is the start or end point of the line + return false; +} + +void FloatingDashLineWidget::slotMenuSelection(QAction* action) +{ + ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); + switch(sel) { + case ListPopupMenu::mt_Rename: + { + bool ok = false; + QString name = m_Text; +#if QT_VERSION >= 0x050000 + name = QInputDialog::getText(Q_NULLPTR, + i18n("Enter alternative Name"), i18n("Enter the alternative:"), + QLineEdit::Normal, + m_Text, &ok); +#else + name = KInputDialog::getText(i18n("Enter alternative Name"), i18n("Enter the alternative:"), m_Text, &ok); +#endif + if (ok && name.length() > 0) + m_Text = name; + } + break; + default: + UMLWidget::slotMenuSelection(action); + } +} + +/** + * Overrides the setY method. + */ +void FloatingDashLineWidget::setY(qreal y) +{ + if(y >= m_yMin + FLOATING_DASH_LINE_MARGIN && y <= m_yMax - FLOATING_DASH_LINE_MARGIN) + UMLWidget::setY(y); +} + +/** + * Sets m_yMin. + */ +void FloatingDashLineWidget::setYMin(qreal yMin) +{ + m_yMin = yMin; +} + +/** + * Sets m_yMax. + */ +void FloatingDashLineWidget::setYMax(qreal yMax) +{ + m_yMax = yMax; +} + +/** + * Returns m_yMin. + */ +qreal FloatingDashLineWidget::getYMin() const +{ + return m_yMin; +} + +/** + * Returns the difference between the y-coordinate of the dash line and m_yMin. + */ +qreal FloatingDashLineWidget::getDiffY() const +{ + return (y() - getYMin()); +} + +/** + * Creates the "floatingdashline" XMI element. + */ +void FloatingDashLineWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +{ + QDomElement textElement = qDoc.createElement(QLatin1String("floatingdashlinewidget")); + UMLWidget::saveToXMI(qDoc, textElement); + textElement.setAttribute(QLatin1String("text"), m_Text); + textElement.setAttribute(QLatin1String("y"), y()); + textElement.setAttribute(QLatin1String("minY"), m_yMin); + textElement.setAttribute(QLatin1String("maxY"), m_yMax); + + qElement.appendChild(textElement); +} + +/** + * Loads the "floatingdashline" XMI element. + */ +bool FloatingDashLineWidget::loadFromXMI(QDomElement & qElement) +{ + if(!UMLWidget::loadFromXMI(qElement)) { + return false; + } + DEBUG(DBG_SRC) << "load......."; + m_yMax = qElement.attribute(QLatin1String("maxY")).toFloat(); + m_yMin = qElement.attribute(QLatin1String("minY")).toFloat(); + m_Text = qElement.attribute(QLatin1String("text")); + return true; +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/floatingdashlinewidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/floatingdashlinewidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/floatingdashlinewidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/floatingdashlinewidget.h 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,77 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef FLOATINGDASHLINEWIDGET_H +#define FLOATINGDASHLINEWIDGET_H + +#include "umlwidget.h" +class CombinedFragmentWidget; + +#define FLOATING_DASH_LINE_MARGIN 25 +#define FLOATING_DASH_LINE_TEXT_MARGIN 5 + +/* how many pixels a user could click around a point */ +#define POINT_DELTA 5 + +/** + * This class is used to draw dash lines for UML combined fragments. A FloatingDashLineWidget + * belongs to one @ref CombinedFragmentWidget instance. + * + * The FloatingDashLineWidget class inherits from the @ref UMLWidget class. + * + * @short A dash line for UML combined fragments. + * @author Thomas GALLINARI + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class FloatingDashLineWidget : public UMLWidget +{ + Q_OBJECT +public: + explicit FloatingDashLineWidget(UMLScene * scene, Uml::ID::Type id = Uml::ID::None, CombinedFragmentWidget *parent = 0); + ~FloatingDashLineWidget(); + + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option = 0, QWidget *widget = 0); + + void slotMenuSelection(QAction* action); + + bool onLine(const QPointF& point); + + void setText(const QString& text); + + void setY(qreal y); + void setYMin(qreal yMin); + void setYMax(qreal yMax); + qreal getYMin() const; + qreal getDiffY() const; + + void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); + bool loadFromXMI(QDomElement & qElement); + +private: + /** + * Text associated to the dash line + */ + QString m_text; + + /** + * Minimum value of the Y-coordinate of the dash line + * (= y-coordinate of the combined fragment) + */ + int m_yMin; + + /** + * Maximum value of the Y-coordinate of the dash line + * (= y-coordinate of the combined fragment + height of the combined fragment) + */ + int m_yMax; + CombinedFragmentWidget *m_parent; +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/floatingtextwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/floatingtextwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/floatingtextwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/floatingtextwidget.cpp 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,854 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "floatingtextwidget.h" + +// local includes +#include "association.h" +#include "associationwidget.h" +#include "associationpropertiesdialog.h" +#include "classifier.h" +#include "cmds.h" +#include "debug_utils.h" +#include "linkwidget.h" +#include "classifierwidget.h" +#include "listpopupmenu.h" +#include "messagewidget.h" +#include "model_utils.h" +#include "object_factory.h" +#include "operation.h" +#include "selectoperationdialog.h" +#include "uml.h" +#include "umldoc.h" +#include "umlview.h" + +// kde includes +#if QT_VERSION < 0x050000 +#include +#include +#endif +#include + +// qt includes +#if QT_VERSION >= 0x050000 +#include +#include +#endif +#include +#include +#include +#include + +DEBUG_REGISTER_DISABLED(FloatingTextWidget) + +/** + * Constructs a FloatingTextWidget instance. + * + * @param scene The parent of this FloatingTextWidget. + * @param role The role this FloatingTextWidget will take up. + * @param text The main text to display. + * @param id The ID to assign (-1 will prompt a new ID.) + */ +FloatingTextWidget::FloatingTextWidget(UMLScene * scene, Uml::TextRole::Enum role, const QString& text, Uml::ID::Type id) + : UMLWidget(scene, WidgetBase::wt_Text, id), + m_linkWidget(0), + m_preText(QString()), + m_postText(QString()), + m_textRole(role), + m_unconstrainedPositionX(0), + m_unconstrainedPositionY(0), + m_movementDirectionX(0), + m_movementDirectionY(0) +{ + m_Text = text; + m_resizable = false; + setZValue(10); //make sure always on top. +} + +/** + * Destructor. + */ +FloatingTextWidget::~FloatingTextWidget() +{ +} + +/** + * Use to get the _main body_ of text (e.g. prepended and appended + * text is omitted) as currently displayed by the widget. + * + * @return The main text currently being displayed by the widget. + */ +QString FloatingTextWidget::text() const +{ + // test to make sure not just the ":" between the seq number and + // the actual message widget + + // hmm. this section looks like it could have been avoided by + // using pre-, post- text instead of storing in the main body of + // the text -b.t. + if (m_textRole == Uml::TextRole::Seq_Message || m_textRole == Uml::TextRole::Seq_Message_Self || + m_textRole == Uml::TextRole::Coll_Message || m_textRole == Uml::TextRole::Coll_Message_Self) { + if (m_Text.length() <= 1 || m_Text == QLatin1String(": ")) + return QString(); + } + return m_Text; +} + +/** + * Set the main body of text to display. + * + * @param t The text to display. + */ +void FloatingTextWidget::setText(const QString &t) +{ + if (m_textRole == Uml::TextRole::Seq_Message || m_textRole == Uml::TextRole::Seq_Message_Self) { + QString op; + if (m_linkWidget) + op = m_linkWidget->lwOperationText(); + if (op.length() > 0) { + if (!m_scene->showOpSig()) + op.replace(QRegExp(QLatin1String("\\(.*\\)")), QLatin1String("()")); + m_Text = op; + } + else + m_Text = t; + } + else { + m_Text = t; + } + + QSizeF s = minimumSize(); + setSize(s.width(), s.height()); + + updateGeometry(); + update(); +} + +/** + * Set some text to be prepended to the main body of text. + * @param t The text to prepend to main body which is displayed. + */ +void FloatingTextWidget::setPreText(const QString &t) +{ + m_preText = t; + updateGeometry(); + update(); +} + +/** + * Set some text to be appended to the main body of text. + * @param t The text to append to main body which is displayed. + */ +void FloatingTextWidget::setPostText(const QString &t) +{ + m_postText = t; + updateGeometry(); + update(); +} + +/** + * Use to get the total text (prepended + main body + appended) + * currently displayed by the widget. + * + * @return The text currently being displayed by the widget. + */ +QString FloatingTextWidget::displayText() const +{ + QString displayText; + if (!m_SequenceNumber.isEmpty()) + displayText = m_SequenceNumber + QLatin1String(": ") + m_Text; + else + displayText = m_Text; + displayText.prepend(m_preText); + displayText.append(m_postText); + return displayText; +} + +/** + * Return state if no pre, post and main text is empty + * @return true if widget contains no text + */ +bool FloatingTextWidget::isEmpty() +{ + return m_Text.isEmpty() && m_preText.isEmpty() && m_postText.isEmpty(); +} + +/** + * Overrides method from UMLWidget. + */ +QSizeF FloatingTextWidget::minimumSize() const +{ + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + int h = fm.lineSpacing(); + int w = fm.width(displayText()); + return QSizeF(w + 8, h + 4); // give a small margin +} + +/** + * Method used by setText: its called by cmdsetTxt, Don't use it! + * + * @param t The text to display. + */ +void FloatingTextWidget::setTextcmd(const QString &t) +{ + UMLApp::app()->executeCommand(new Uml::CmdSetTxt(this, t)); +} + +/** + * Displays a dialog box to change the text. + */ +void FloatingTextWidget::showChangeTextDialog() +{ + bool ok = false; +#if QT_VERSION >= 0x050000 + QString newText = QInputDialog::getText(m_scene->activeView(), + i18n("Change Text"), i18n("Enter new text:"), + QLineEdit::Normal, + text(), &ok); +#else + QString newText = KInputDialog::getText(i18n("Change Text"), i18n("Enter new text:"), text(), &ok, m_scene->activeView()); +#endif + if (ok && newText != text() && isTextValid(newText)) { + setText(newText); + setVisible(!text().isEmpty()); + updateGeometry(); + update(); + } + if (!isTextValid(newText)) + hide(); +} + +/** + * Shows an operation dialog box. + * + * @param enableAutoIncrement Enable auto increment checkbox + */ +void FloatingTextWidget::showOperationDialog(bool enableAutoIncrement) +{ + if (!m_linkWidget) { + uError() << "m_linkWidget is NULL"; + return; + } + QString seqNum = m_linkWidget->sequenceNumber(); + UMLClassifier* c = m_linkWidget->lwClassifier(); + QString opText = m_linkWidget->lwOperationText(); + if (!c) { + uError() << "m_linkWidget->lwClassifier() returns a NULL classifier"; + return; + } + + QPointer selectDialog = new SelectOperationDialog(m_scene->activeView(), c, enableAutoIncrement); + if (enableAutoIncrement && m_scene->autoIncrementSequence()) { + seqNum = m_scene->autoIncrementSequenceValue(); + selectDialog->setAutoIncrementSequence(true); + } + selectDialog->setSeqNumber(seqNum); + if (m_linkWidget->operation() == 0) { + selectDialog->setCustomOp(opText); + } else { + selectDialog->setClassOp(opText); + } + if (selectDialog->exec()) { + seqNum = selectDialog->getSeqNumber(); + opText = selectDialog->getOpText(); + if (selectDialog->isClassOp()) { + Model_Utils::OpDescriptor od; + Model_Utils::Parse_Status st = Model_Utils::parseOperation(opText, od, c); + if (st == Model_Utils::PS_OK) { + UMLClassifierList selfAndAncestors = c->findSuperClassConcepts(); + selfAndAncestors.prepend(c); + UMLOperation *op = 0; + foreach (UMLClassifier *cl, selfAndAncestors) { + op = cl->findOperation(od.m_name, od.m_args); + if (op) { + break; + } + } + if (!op) { + // The op does not yet exist. Create a new one. + UMLObject *o = c->createOperation(od.m_name, 0, &od.m_args); + op = static_cast(o); + } + if (od.m_pReturnType) { + op->setType(od.m_pReturnType); + } + + m_linkWidget->setOperation(op); + opText.clear(); + } else { + m_linkWidget->setOperation(0); + } + } else { + m_linkWidget->setOperation(0); + } + m_linkWidget->setSequenceNumber(seqNum); + m_linkWidget->setOperationText(opText); + if (enableAutoIncrement) { + m_scene->setAutoIncrementSequence(selectDialog->autoIncrementSequence()); + } + setMessageText(); + } + delete selectDialog; +} + +/** + * Show the properties for a FloatingTextWidget. + * Depending on the role of the floating text wiget, the options dialog + * for the floating text widget, the rename dialog for floating text or + * the options dialog for the link widget are shown. + */ +void FloatingTextWidget::showPropertiesDialog() +{ + if (m_textRole == Uml::TextRole::Coll_Message || m_textRole == Uml::TextRole::Coll_Message_Self || + m_textRole == Uml::TextRole::Seq_Message || m_textRole == Uml::TextRole::Seq_Message_Self) { + showOperationDialog(false); + } else if (m_textRole == Uml::TextRole::Floating) { + // double clicking on a text line opens the dialog to change the text + handleRename(); + } else if (m_linkWidget) { + m_linkWidget->showPropertiesDialog(); + } +} + +/** + * Use to get the pre-text which is prepended to the main body of + * text to be displayed. + * + * @return The pre-text currently displayed by the widget. + */ +QString FloatingTextWidget::preText() const +{ + return m_preText; +} + +/** + * Use to get the post-text which is appended to the main body of + * text to be displayed. + * + * @return The post-text currently displayed by the widget. + */ +QString FloatingTextWidget::postText() const +{ + return m_postText; +} + +/** + * Activate the FloatingTextWidget after the saved data has been loaded + * + * @param ChangeLog Pointer to the IDChangeLog. + * @return true for success + */ +bool FloatingTextWidget::activate(IDChangeLog* ChangeLog /*= 0 */) +{ + if (! UMLWidget::activate(ChangeLog)) + return false; + update(); + return true; +} + +/** + * Set the LinkWidget that this FloatingTextWidget is related to. + * + * @param l The related LinkWidget. + */ +void FloatingTextWidget::setLink(LinkWidget * l) +{ + m_linkWidget = l; +} + +/** + * Returns the LinkWidget this floating text is related to. + * + * @return The LinkWidget this floating text is related to. + */ +LinkWidget * FloatingTextWidget::link() const +{ + return m_linkWidget; +} + +/** + * Sets the role type of this FloatingTextWidget. + * + * @param role The TextRole::Enum of this FloatingTextWidget. + */ +void FloatingTextWidget::setTextRole(Uml::TextRole::Enum role) +{ + m_textRole = role; +} + +/** + * Return the role of the text widget + * @return The TextRole::Enum of this FloatingTextWidget. + */ +Uml::TextRole::Enum FloatingTextWidget::textRole() const +{ + return m_textRole; +} + +/** + * Handle the ListPopupMenu::mt_Rename case of the slotMenuSelection. + * Given an own method because it requires rather lengthy code. + */ +void FloatingTextWidget::handleRename() +{ + QRegExpValidator v(QRegExp(QLatin1String(".*")), 0); + QString t; + if (m_textRole == Uml::TextRole::RoleAName || m_textRole == Uml::TextRole::RoleBName) { + t = i18n("Enter role name:"); + } else if (m_textRole == Uml::TextRole::MultiA || m_textRole == Uml::TextRole::MultiB) { + t = i18n("Enter multiplicity:"); + /* + // NO! shouldn't be allowed + } else if (m_textRole == Uml::TextRole::ChangeA || m_textRole == Uml::TextRole::ChangeB) { + t = i18n("Enter changeability"); + */ + } else if (m_textRole == Uml::TextRole::Name) { + t = i18n("Enter association name:"); + } else if (m_textRole == Uml::TextRole::Floating) { + t = i18n("Enter new text:"); + } else { + t = i18n("ERROR"); + } + bool ok = false; +#if QT_VERSION >= 0x050000 + QString newText = QInputDialog::getText(m_scene->activeView(), + i18n("Rename"), t, + QLineEdit::Normal, + text(), &ok); +#else + QString newText = KInputDialog::getText(i18n("Rename"), t, text(), &ok, m_scene->activeView(), &v); +#endif + if (!ok || newText == text()) { + return; + } + + UMLApp::app()->executeCommand(new Uml::CmdHandleRename(this, newText)); +} + +/** + * Changes the text of linked widget. + * @param newText the new text + */ +void FloatingTextWidget::changeName(const QString& newText) +{ + if (m_linkWidget && !isTextValid(newText)) { + AssociationWidget *assoc = dynamic_cast(m_linkWidget); + if (assoc) { + switch (m_textRole) { + case Uml::TextRole::MultiA: + assoc->setMultiplicity(QString(), Uml::RoleType::A); + break; + case Uml::TextRole::MultiB: + assoc->setMultiplicity(QString(), Uml::RoleType::B); + break; + case Uml::TextRole::RoleAName: + assoc->setRoleName(QString(), Uml::RoleType::A); + break; + case Uml::TextRole::RoleBName: + assoc->setRoleName(QString(), Uml::RoleType::B); + break; + case Uml::TextRole::ChangeA: + assoc->setChangeability(Uml::Changeability::Changeable, Uml::RoleType::A); + break; + case Uml::TextRole::ChangeB: + assoc->setChangeability(Uml::Changeability::Changeable, Uml::RoleType::B); + break; + default: + assoc->setName(QString()); + break; + } + } + else { + MessageWidget *msg = dynamic_cast(m_linkWidget); + if (msg) { + msg->setName(QString()); + m_scene->removeWidget(this); + } + } + return; + } + + if (m_linkWidget && m_textRole != Uml::TextRole::Seq_Message + && m_textRole != Uml::TextRole::Seq_Message_Self) { + m_linkWidget->setText(this, newText); + } + else { + setText(newText); + UMLApp::app()->document()->setModified(true); + } + + setVisible(true); + updateGeometry(); + update(); +} + +/** + * Write property of QString m_SequenceNumber. + */ +void FloatingTextWidget::setSequenceNumber(const QString &sequenceNumber) +{ + m_SequenceNumber = sequenceNumber; +} + +/** + * Read property of QString m_SequenceNumber. + */ +QString FloatingTextWidget::sequenceNumber() const +{ + return m_SequenceNumber; +} + +/** + * For a text to be valid it must be non-empty, i.e. have a length + * larger than zero, and have at least one non whitespace character. + * + * @param text The string to analyze. + * @return True if the given text is valid. + */ +bool FloatingTextWidget::isTextValid(const QString &text) +{ + int length = text.length(); + if(length < 1) + return false; + for(int i=0;iconstrainTextPos(newX, newY, width(), height(), textRole()); + } + + return QPointF(newX, newY); +} + +/** + * Overridden from UMLWidget. + * Moves the widget to a new position using the difference between the + * current position and the new position. + * If the floating text widget is part of a sequence message, and the + * message widget is selected, it does nothing: the message widget will + * update the text position when it's moved. + * In any other case, the floating text widget constrains its move using + * constrainPosition. When the position of the floating text is constrained, + * it's kept at that position until it can be moved to another valid + * position (m_unconstrainedPositionX/Y and m_movementDirectionX/Y are + * used for that). + * Moreover, if is part of a sequence message (and the message widget + * isn't selected), it updates the position of the message widget. + * @see constrainPosition + * + * @param diffX The difference between current X position and new X position. + * @param diffY The difference between current Y position and new Y position. + */ +void FloatingTextWidget::moveWidgetBy(qreal diffX, qreal diffY) +{ + if (textRole() == Uml::TextRole::Seq_Message_Self) + return; + + if (textRole() == Uml::TextRole::Seq_Message + && ((MessageWidget*)link())->isSelected()) { + return; + } + + m_unconstrainedPositionX += diffX; + m_unconstrainedPositionY += diffY; + QPointF constrainedPosition = constrainPosition(diffX, diffY); + + qreal newX = constrainedPosition.x(); + qreal newY = constrainedPosition.y(); + + if (!m_movementDirectionX) { + if (m_unconstrainedPositionX != constrainedPosition.x()) { + m_movementDirectionX = (diffX > 0)? 1: -1; + } + } else if ((m_movementDirectionX < 0 && m_unconstrainedPositionX > x()) || + (m_movementDirectionX > 0 && m_unconstrainedPositionX < x()) ) { + newX = m_unconstrainedPositionX; + m_movementDirectionX = 0; + } + + if (!m_movementDirectionY) { + if (m_unconstrainedPositionY != constrainedPosition.y()) { + m_movementDirectionY = (diffY > 0)? 1: -1; + } + } else if ((m_movementDirectionY < 0 && m_unconstrainedPositionY > y()) || + (m_movementDirectionY > 0 && m_unconstrainedPositionY < y()) ) { + newY = m_unconstrainedPositionY; + m_movementDirectionY = 0; + } + + setX(newX); + setY(newY); + + if (link()) { + link()->calculateNameTextSegment(); + if (textRole() == Uml::TextRole::Seq_Message) { + MessageWidget* messageWidget = (MessageWidget*)link(); + messageWidget->setY(newY + height()); + } + } +} + +/** + * Overridden from UMLWidget. + * Modifies the value of the diffX and diffY variables used to move the + * widgets. + * The values are constrained using constrainPosition. + * @see constrainPosition + * + * @param diffX The difference between current X position and new X position. + * @param diffY The difference between current Y position and new Y position. + */ +void FloatingTextWidget::constrainMovementForAllWidgets(qreal &diffX, qreal &diffY) +{ + QPointF constrainedPosition = constrainPosition(diffX, diffY); + + diffX = constrainedPosition.x() - x(); + diffY = constrainedPosition.y() - y(); +} + +/** + * Override method from UMLWidget in order to additionally check widget parentage. + * + * @param p Point to be checked. + * + * @return 'this' if UMLWidget::onWidget(p) returns non NULL; + * else NULL. + */ +UMLWidget* FloatingTextWidget::onWidget(const QPointF &p) +{ + WidgetBase *pw = dynamic_cast(parentItem()); + if (pw == NULL) { + return WidgetBase::onWidget(p); + } + const WidgetBase::WidgetType t = pw->baseType(); + bool isWidgetChild = false; + if (t == WidgetBase::wt_Interface) { + ClassifierWidget *cw = static_cast(pw); + isWidgetChild = cw->getDrawAsCircle(); + } else if (t == wt_Association || + t == WidgetBase::wt_Port || t == WidgetBase::wt_Pin) { + isWidgetChild = true; + } + if (!isWidgetChild) { + return WidgetBase::onWidget(p); + } + const qreal w = width(); + const qreal h = height(); + const qreal left = pw->x() + x(); + const qreal right = left + w; + const qreal top = pw->y() + y(); + const qreal bottom = top + h; + // uDebug() << "child_of_pw; p=(" << p.x() << "," << p.y() << "), " + // << "x=" << left << ", y=" << top << ", w=" << w << ", h=" << h + // << "; right=" << right << ", bottom=" << bottom; + if (p.x() >= left && p.x() <= right && + p.y() >= top && p.y() <= bottom) { // Qt coord.sys. origin in top left corner + // uDebug() << "floatingtext: " << m_Text; + return this; + } + return NULL; +} + +/** + * Overrides default method + */ +void FloatingTextWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + int w = width(); + int h = height(); + painter->setFont(UMLWidget::font()); + painter->setPen(textColor()); + painter->drawText(0, 0, w, h, Qt::AlignCenter, displayText()); + + UMLWidget::paint(painter, option, widget); +} + +/** + * Loads the "floatingtext" XMI element. + */ +bool FloatingTextWidget::loadFromXMI(QDomElement & qElement) +{ + if(!UMLWidget::loadFromXMI(qElement)) + return false; + + m_unconstrainedPositionX = x(); + m_unconstrainedPositionY = y(); + QString role = qElement.attribute(QLatin1String("role")); + if(!role.isEmpty()) + m_textRole = Uml::TextRole::fromInt(role.toInt()); + + m_preText = qElement.attribute(QLatin1String("pretext")); + m_postText = qElement.attribute(QLatin1String("posttext")); + setText(qElement.attribute(QLatin1String("text"))); // use setText for geometry update + // If all texts are empty then this is a useless widget. + // In that case we return false. + // CAVEAT: The caller should not interpret the false return value + // as an indication of failure since previous umbrello-kf6 versions + // saved lots of these empty FloatingTexts. + bool usefulWidget = !isEmpty(); + return usefulWidget; +} + +/** + * Reimplemented from UMLWidget::saveToXMI to save the widget + * data into XMI 'floatingtext' element. + */ +void FloatingTextWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +{ + if (isEmpty()) + return; + + QDomElement textElement = qDoc.createElement(QLatin1String("floatingtext")); + UMLWidget::saveToXMI(qDoc, textElement); + textElement.setAttribute(QLatin1String("text"), m_Text); + textElement.setAttribute(QLatin1String("pretext"), m_preText); + textElement.setAttribute(QLatin1String("posttext"), m_postText); + + /* No need to save these - the messagewidget already did it. + m_Operation = qElement.attribute("operation"); + m_SeqNum = qElement.attribute("seqnum"); + */ + + textElement.setAttribute(QLatin1String("role"), m_textRole); + qElement.appendChild(textElement); +} + +/** + * Called when a menu selection has been made. + * + * @param action The action that has been selected. + */ +void FloatingTextWidget::slotMenuSelection(QAction* action) +{ + ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); + switch(sel) { + case ListPopupMenu::mt_Properties: + showPropertiesDialog(); + break; + + case ListPopupMenu::mt_Delete: + hide(); // This is only a workaround; if set then m_linkWidget should + // really delete this FloatingTextWidget. + update(); + m_scene->removeWidget(this); + break; + + case ListPopupMenu::mt_New_Operation: // needed by AssociationWidget + case ListPopupMenu::mt_Operation: + { + if (m_linkWidget == 0) { + DEBUG(DBG_SRC) << "mt_Operation: m_linkWidget is NULL"; + return; + } + UMLClassifier* c = m_linkWidget->operationOwner(); + if (c == 0) { + bool ok = false; +#if QT_VERSION >= 0x050000 + QString opText = QInputDialog::getText(m_scene->activeView(), + i18nc("operation name", "Name"), + i18n("Enter operation name:"), + QLineEdit::Normal, + text(), &ok); +#else + QString opText = KInputDialog::getText(i18nc("operation name", "Name"), + i18n("Enter operation name:"), + text(), &ok, m_scene->activeView()); +#endif + if (ok) + m_linkWidget->setCustomOpText(opText); + return; + } + UMLClassifierListItem* umlObj = Object_Factory::createChildObject(c, UMLObject::ot_Operation); + if (umlObj) { + UMLOperation* newOperation = static_cast(umlObj); + m_linkWidget->setOperation(newOperation); + } + } + break; + + case ListPopupMenu::mt_Select_Operation: + showOperationDialog(false); + break; + + case ListPopupMenu::mt_Rename: + handleRename(); + break; + + case ListPopupMenu::mt_Change_Font: + { +#if QT_VERSION >= 0x050000 + bool ok = false; + QFont fnt = QFontDialog::getFont(&ok, font(), m_scene->activeView()); + if (ok) { +#else + QFont fnt = font(); + if(KFontDialog::getFont(fnt, KFontChooser::NoDisplayFlags, m_scene->activeView())) { +#endif + if(m_textRole == Uml::TextRole::Floating || m_textRole == Uml::TextRole::Seq_Message) { + setFont(fnt); + } else if (m_linkWidget) { + m_linkWidget->lwSetFont(fnt); + } + } + } + break; + + case ListPopupMenu::mt_Reset_Label_Positions: + if (m_linkWidget) + m_linkWidget->resetTextPositions(); + break; + + default: + UMLWidget::slotMenuSelection(action); + break; + }//end switch +} + +/** + * Sets the text for this label if it is acting as a sequence diagram + * message or a collaboration diagram message. + */ +void FloatingTextWidget::setMessageText() +{ + if (m_linkWidget) { + m_linkWidget->setMessageText(this); + QSizeF s = minimumSize(); + setSize(s.width(), s.height()); + + } + setVisible(!text().isEmpty()); +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/floatingtextwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/floatingtextwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/floatingtextwidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/floatingtextwidget.h 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,131 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef FLOATINGTEXTWIDGET_H +#define FLOATINGTEXTWIDGET_H + +#include "basictypes.h" +#include "umlwidget.h" + +class LinkWidget; +class UMLScene; + +/** + * @short Displays a line of text or an operation. + * + * This is a multipurpose-kf6 class. In its simplest form it will display a + * line of text. + * It can also be setup to be the text for an operation with regard to the + * @ref MessageWidget on the sequence diagram. + * It is also used for the text required for an association. + * + * The differences between all these different uses will be the popup menu + * that is associated with it. + * + * @author Paul Hensgen + * @see UMLWidget + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class FloatingTextWidget : public UMLWidget +{ + Q_OBJECT +public: + explicit FloatingTextWidget(UMLScene * scene, Uml::TextRole::Enum role = Uml::TextRole::Floating, + const QString& text = QString(), Uml::ID::Type id = Uml::ID::None); + virtual ~FloatingTextWidget(); + + QString text() const; + void setText(const QString &t); + + void setTextcmd(const QString &t); + + QString preText() const; + void setPreText(const QString &t); + + QString postText() const; + void setPostText(const QString &t); + + QString displayText() const; + + bool isEmpty(); + + void showChangeTextDialog(); + void showOperationDialog(bool enableAutoIncrement = true); + virtual void showPropertiesDialog(); + + LinkWidget* link() const; + void setLink(LinkWidget * l); + + bool activate(IDChangeLog* ChangeLog = 0); + + Uml::TextRole::Enum textRole() const; + void setTextRole(Uml::TextRole::Enum role); + + void handleRename(); + void changeName(const QString& newText); + + void setSequenceNumber(const QString &sequenceNumber); + QString sequenceNumber() const; + + static bool isTextValid(const QString &text); + + UMLWidget* onWidget(const QPointF& p); + + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + + virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); + virtual bool loadFromXMI(QDomElement& qElement); + +public Q_SLOTS: + virtual void slotMenuSelection(QAction* action); + void setMessageText(); + +protected: + QSizeF minimumSize() const; + + virtual void moveWidgetBy(qreal diffX, qreal diffY); + virtual void constrainMovementForAllWidgets(qreal &diffX, qreal &diffY); + +private: + QPointF constrainPosition(qreal diffX, qreal diffY); + + /// The association or message widget we may be linked to. + LinkWidget * m_linkWidget; + + //////////////////// Data loaded/saved: + + /// Prepended text (such as for scope of association Role or method) + QString m_preText; + /// Ending text (such as bracket on changability notation for association Role) + QString m_postText; + /// The role the text widget will enact. + Uml::TextRole::Enum m_textRole; + + //////// + + /// The horizontal position the widget would have if its move wasn't constrained. + qreal m_unconstrainedPositionX; + + /// The vertical position the widget would have if its move wasn't constrained. + qreal m_unconstrainedPositionY; + + /// The X direction the widget was moved when the constrain was applied. + /// -1 means left, 1 means right. + int m_movementDirectionX; + + /// The Y direction the widget was moved when the constrain was applied. + /// -1 means up, 1 means down. + int m_movementDirectionY; + + /// Contains sequence number for sequence or collaboration diagram message. + QString m_SequenceNumber; +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/forkjoinwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/forkjoinwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/forkjoinwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/forkjoinwidget.cpp 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,205 @@ +/*************************************************************************** + * 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) 2005-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "forkjoinwidget.h" + +//app includes +#include "debug_utils.h" +#include "umlview.h" +#include "umldoc.h" +#include "listpopupmenu.h" + +// qt includes +#include + +/** + * Constructs a ForkJoinWidget. + * + * @param scene The parent to this widget. + * @param ori Whether to draw the plate horizontally or vertically. + * @param id The ID to assign (-1 will prompt a new ID.) + */ +ForkJoinWidget::ForkJoinWidget(UMLScene * scene, Qt::Orientation ori, Uml::ID::Type id) + : BoxWidget(scene, id, WidgetBase::wt_ForkJoin), + m_orientation(ori) +{ + setSize(10, 40); + m_usesDiagramFillColor = false; + setFillColorCmd(QColor("black")); +} + +/** + * Destructor. + */ +ForkJoinWidget::~ForkJoinWidget() +{ +} + +/** + * Get whether to draw the plate vertically or horizontally. + */ +Qt::Orientation ForkJoinWidget::orientation() const +{ + return m_orientation; +} + +/** + * Set whether to draw the plate vertically or horizontally. + */ +void ForkJoinWidget::setOrientation(Qt::Orientation ori) +{ + m_orientation = ori; + updateGeometry(); + UMLWidget::adjustAssocs(x(), y()); +} + +/** + * Reimplemented from UMLWidget::paint to draw the plate of + * fork join. + */ +void ForkJoinWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + painter->fillRect(0, 0, width(), height(), fillColor()); + + UMLWidget::paint(painter, option, widget); +} + +/** + * Reimplemented from UMLWidget::loadFromXMI to load widget + * info from XMI element - 'forkjoin'. + */ +bool ForkJoinWidget::loadFromXMI(QDomElement& qElement) +{ + if (!UMLWidget::loadFromXMI(qElement)) { + return false; + } + + QString drawVerticalStr = qElement.attribute(QLatin1String("drawvertical"), QLatin1String("0")); + bool drawVertical = (bool)drawVerticalStr.toInt(); + if (drawVertical) { + setOrientation(Qt::Vertical); + } + else { + setOrientation(Qt::Horizontal); + } + + return true; +} + +/** + * Reimplemented from UMLWidget::saveToXMI to save widget info + * into XMI element - 'forkjoin'. + */ +void ForkJoinWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +{ + QDomElement fjElement = qDoc.createElement(QLatin1String("forkjoin")); + UMLWidget::saveToXMI(qDoc, fjElement); + bool drawVertical = true; + if (m_orientation == Qt::Horizontal) { + drawVertical = false; + } + fjElement.setAttribute(QLatin1String("drawvertical"), drawVertical); + qElement.appendChild(fjElement); +} + +/** + * Show a properties dialog for a Fork/Join Widget. + */ +void ForkJoinWidget::showPropertiesDialog() +{ + QColor newColor = QColorDialog::getColor(fillColor()); // krazy:exclude=qclasses + if (newColor != fillColor()) { + setFillColor(newColor); + setUsesDiagramFillColor(false); + umlDoc()->setModified(true); + } +} + +/** + * Reimplemented form UMLWidget::slotMenuSelection to handle + * Flip action. + */ +void ForkJoinWidget::slotMenuSelection(QAction* action) +{ + ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); + switch (sel) { + case ListPopupMenu::mt_Fill_Color: + showPropertiesDialog(); + break; + + case ListPopupMenu::mt_Flip: + switch (m_orientation) { + case Qt::Vertical: + setOrientation(Qt::Horizontal); + break; + case Qt::Horizontal: + default: + setOrientation(Qt::Vertical); + break; + } + break; + default: + break; + } +} + +/** + * Overrides the function from UMLWidget. + */ +QSizeF ForkJoinWidget::minimumSize() const +{ + if (m_orientation == Qt::Vertical) { + return QSizeF(4, 40); + } else { + return QSizeF(40, 4); + } +} + +/** + * Reimplement method from UMLWidget to suppress the resize corner. + * Although the ForkJoinWidget supports resizing, we suppress the + * resize corner because it is too large for this very slim widget. + */ +void ForkJoinWidget::paintSelected(QPainter * p, int offsetX, int offsetY) +{ + Q_UNUSED(p); + Q_UNUSED(offsetX); + Q_UNUSED(offsetY); +} + +/** + * Reimplement method from UMLWidget. + */ +void ForkJoinWidget::constrain(qreal& width, qreal& height) +{ + if (m_orientation == Qt::Vertical) { + if (width < 4) + width = 4; + else if (width > 10) + width = 10; + if (height < 40) + height = 40; + else if (height > 100) + height = 100; + } else { + if (height < 4) + height = 4; + else if (height > 10) + height = 10; + if (width < 40) + width = 40; + else if (width > 100) + width = 100; + } +} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/forkjoinwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/forkjoinwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/forkjoinwidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/forkjoinwidget.h 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,57 @@ +/*************************************************************************** + * 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) 2005-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef FORKJOINWIDGET_H +#define FORKJOINWIDGET_H + +//app includes +#include "boxwidget.h" + +/** + * @short Displays a fork/join plate in a state diagram. + * + * @author Oliver Kellogg + * + * @see UMLWidget + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class ForkJoinWidget : public BoxWidget +{ + Q_OBJECT + Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation) +public: + explicit ForkJoinWidget(UMLScene * scene, Qt::Orientation ori = Qt::Horizontal, Uml::ID::Type id = Uml::ID::None); + virtual ~ForkJoinWidget(); + + Qt::Orientation orientation() const; + void setOrientation(Qt::Orientation ori); + + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + + virtual bool loadFromXMI(QDomElement & qElement); + virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); + + void showPropertiesDialog(); + +public Q_SLOTS: + virtual void slotMenuSelection(QAction* action); + +protected: + QSizeF minimumSize() const; + + virtual void paintSelected(QPainter * p, int offsetX = 0, int offsetY = 0); + + void constrain(qreal& width, qreal& height); + +private: + Qt::Orientation m_orientation; ///< whether to draw the plate horizontally or vertically +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/layoutgrid.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/layoutgrid.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/layoutgrid.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/layoutgrid.cpp 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,113 @@ +/*************************************************************************** + * Copyright (C) 2011 by Andi Fischer * + * Copyright (C) 2012 by Ralf Habacker * + * * + * This 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, or (at your option) * + * any later version. * + * * + * This software is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR purpose-kf6. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this package; see the file COPYING. If not, write to * + * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * + * Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "layoutgrid.h" + +#include "debug_utils.h" +#include "umlscene.h" + +#include +#include + +#define DBG_LOG() DEBUG(QLatin1String("LayoutGrid")) +DEBUG_REGISTER_DISABLED(LayoutGrid) + +/** + * Constructor. + */ +LayoutGrid::LayoutGrid(UMLScene *scene) + : m_scene(scene), + m_gridSpacingX(25), + m_gridSpacingY(25), + m_gridDotColor(Qt::gray), + m_isVisible(false) +{ +} + +/** + * Destructor. + */ +LayoutGrid::~LayoutGrid() +{ +} + +void LayoutGrid::paint(QPainter *painter, const QRectF &rect) +{ + if (!isVisible()) + return; + + int gridSizeX = gridSpacingX(); + int gridSizeY = gridSpacingY(); + + qreal left = int(rect.left()) - (int(rect.left()) % gridSizeX); + qreal top = int(rect.top()) - (int(rect.top()) % gridSizeY); + + QVarLengthArray lines; + + for (qreal x = left; x < rect.right(); x += gridSizeX) + lines.append(QLineF(x, rect.top(), x, rect.bottom())); + for (qreal y = top; y < rect.bottom(); y += gridSizeY) + lines.append(QLineF(rect.left(), y, rect.right(), y)); + + painter->setPen(m_gridDotColor); + painter->drawLines(lines.data(), lines.size()); +} + +int LayoutGrid::gridSpacingX() const +{ + return m_gridSpacingX; +} + +int LayoutGrid::gridSpacingY() const +{ + return m_gridSpacingY; +} + +void LayoutGrid::setGridSpacing(int sizeX, int sizeY) +{ + DBG_LOG() << "x = " << sizeX << " / y = " << sizeY; + m_gridSpacingX= sizeX; + m_gridSpacingY= sizeY; +} + +const QColor& LayoutGrid::gridDotColor() const +{ + return m_gridDotColor; +} + +void LayoutGrid::setGridDotColor(const QColor& color) +{ + DBG_LOG() << "color = " << color; + m_gridDotColor = color; +} + +bool LayoutGrid::isVisible() const +{ + return m_isVisible; +} + +void LayoutGrid::setVisible(bool visible) +{ + if (m_isVisible != visible) { + DBG_LOG() << "visible = " << visible; + m_isVisible = visible; + m_scene->update(); + } +} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/layoutgrid.h umbrello-kf6-15.08.1/umbrello/umlwidgets/layoutgrid.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/layoutgrid.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/layoutgrid.h 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,76 @@ +/*************************************************************************** + * Copyright (C) 2011 by Andi Fischer * + * Copyright (C) 2012 by Ralf Habacker * + * * + * This 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, or (at your option) * + * any later version. * + * * + * This software is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR purpose-kf6. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this package; see the file COPYING. If not, write to * + * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * + * Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef LAYOUTGRID_H +#define LAYOUTGRID_H + +#include +#include + +class UMLScene; +class QRectF; + +/** + * @author Andi Fischer + * This class handles the layout grid, which is drawn in the background + * of the scene. It is used only in UMLScene. + */ +class LayoutGrid +{ +public: + explicit LayoutGrid(UMLScene *scene); + ~LayoutGrid(); + + void paint(QPainter *painter, const QRectF &rect); + + QRect gridRect() const; + void setGridRect(const QRect& rect); + + int gridSpacingX() const; + int gridSpacingY() const; + void setGridSpacing(int sizeX, int sizeY); + + const QColor& gridDotColor() const; + void setGridDotColor(const QColor& color); + + const QColor& gridCrossColor() const; + void setGridCrossColor(const QColor& color); + + const QColor& textColor() const; + void setTextColor(const QColor& color); + + QFont textFont() const; + void setTextFont(const QFont& font); + + bool isVisible() const; + void setVisible(bool visible); + + bool isTextVisible() const; + void setTextVisible(bool visible); + +private: + UMLScene *m_scene; + int m_gridSpacingX; + int m_gridSpacingY; + QColor m_gridDotColor; + bool m_isVisible; +}; + +#endif // LAYOUTGRID_H diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/linkwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/linkwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/linkwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/linkwidget.cpp 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,121 @@ +/*************************************************************************** + * 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) 2004-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "linkwidget.h" + +// app includes +#include "classifier.h" +#include "operation.h" +#include "uml.h" +#include "umlobject.h" +#include "umlview.h" + +LinkWidget::LinkWidget() +{ +} + +LinkWidget::~LinkWidget() +{ +} + +/** + * Motivated by FloatingTextWidget::slotMenuSelection(mt_Operation) + */ +UMLClassifier *LinkWidget::operationOwner() +{ + UMLOperation *op = operation(); + if (op == NULL) + return NULL; + return static_cast(op->parent()); +} + +/** + * Return the operation text. + * When no scene parameter is given, the scene of the current view + * is taken instead. + * @param scene the given scene + * @return the operation text + */ +QString LinkWidget::operationText(UMLScene *scene) +{ + UMLOperation *op = operation(); + if (op == NULL) + return customOpText(); + if (scene == NULL) + scene = UMLApp::app()->currentView()->umlScene(); + Uml::SignatureType::Enum sigType; + if (scene && scene->showOpSig()) + sigType = Uml::SignatureType::SigNoVis; + else + sigType = Uml::SignatureType::NoSigNoVis; + QString opText = op->toString(sigType); + return opText; +} + +/** + * Motivated by FloatingTextWidget::slotMenuSelection(mt_Reset_Label_Positions) + * Only applies to AssociationWidget. + */ +void LinkWidget::resetTextPositions() +{ +} + +/** + * Motivated by FloatingTextWidget::mouseDoubleClickEvent() + * Only applies to AssociationWidget. + */ +void LinkWidget::showPropertiesDialog() +{ +} + +/** + * Motivated by FloatingTextWidget::setLink(). + * Only applies to AssociationWidget. + */ +void LinkWidget::calculateNameTextSegment() +{ +} + + +/** + * Write property of QString m_SequenceNumber. + */ +void LinkWidget::setSequenceNumber(const QString &sequenceNumber) +{ + m_SequenceNumber = sequenceNumber; +} + +/** + * Read property of QString m_SequenceNumber. + */ +QString LinkWidget::sequenceNumber() const +{ + return m_SequenceNumber; +} + +/** + * Load data from XMI. + */ +bool LinkWidget::loadFromXMI(QDomElement &qElement) +{ + m_SequenceNumber = qElement.attribute(QLatin1String("seqnum")); + return true; +} + +/** + * Save data to XMI. + */ +void LinkWidget::saveToXMI(QDomDocument &qDoc, QDomElement &qElement) +{ + Q_UNUSED(qDoc); + + qElement.setAttribute(QLatin1String("seqnum"), m_SequenceNumber); +} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/linkwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/linkwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/linkwidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/linkwidget.h 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,123 @@ +/*************************************************************************** + * 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) 2004-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef LINKWIDGET_H +#define LINKWIDGET_H + +#include "basictypes.h" +#include "umlscene.h" + +#include + +// forward declarations +class UMLClassifier; +class UMLOperation; +class FloatingTextWidget; + +/** + * This is an interface realized by AssociationWidget and MessageWidget. + * The design of this interface was driven by the requirements of + * class FloatingTextWidget. As the architecture of umbrello-kf6 evolves (for + * example, if the class FloatingTextWidget is redesigned), it can be + * cleaned up. + * + * @short Interface to FloatingTextWidget for AssociationWidget and MessageWidget. + * @author Oliver Kellogg + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class LinkWidget +{ +public: + LinkWidget(); + virtual ~LinkWidget(); + + /** + * Sets the font the widget is to use. + * Abstract operation implemented by inheriting classes. + * Motivated by FloatingTextWidget::slotMenuSelection(mt_Operation) + * + * @param font Font to be set. + */ + virtual void lwSetFont(QFont font) = 0; + + virtual UMLClassifier *operationOwner(); + + /** + * Motivated by FloatingTextWidget::slotMenuSelection(mt_Operation) + */ + virtual UMLOperation *operation() = 0; + + /** + * Motivated by FloatingTextWidget::slotMenuSelection(mt_Operation) + */ + virtual void setOperation(UMLOperation *op) = 0; + + /** + * Motivated by getOperationText() + */ + virtual QString customOpText() = 0; + + /** + * Motivated by FloatingTextWidget::slotMenuSelection(mt_Operation) + */ + virtual void setCustomOpText(const QString &opText) = 0; + + QString operationText(UMLScene *scene = 0); + + virtual void resetTextPositions(); + + /** + * Motivated by FloatingTextWidget::setMessageText() + */ + virtual void setMessageText(FloatingTextWidget *ft) = 0; + + /** + * Motivated by FloatingTextWidget::handleRename() + */ + virtual void setText(FloatingTextWidget *ft, const QString &newText) = 0; + + virtual void showPropertiesDialog(); + + /** + * Motivated by FloatingTextWidget::showOpDialog() + */ + virtual QString lwOperationText() = 0; + + /** + * Motivated by FloatingTextWidget::showOpDialog() + */ + virtual UMLClassifier *lwClassifier() = 0; + + /** + * Motivated by FloatingTextWidget::showOpDialog() + */ + virtual void setOperationText(const QString &op) = 0; + + /** + * Abstract operation implemented by inheriting classes. + * Motivated by FloatingTextWidget::mouseMoveEvent() + */ + virtual void constrainTextPos(qreal &textX, qreal &textY, + qreal textWidth, qreal textHeight, + Uml::TextRole::Enum tr) = 0; + + virtual void calculateNameTextSegment(); + + void setSequenceNumber(const QString &sequenceNumber); + QString sequenceNumber() const; + + virtual bool loadFromXMI(QDomElement &qElement); + virtual void saveToXMI(QDomDocument &qDoc, QDomElement &qElement); + +protected: + QString m_SequenceNumber; +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/messagewidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/messagewidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/messagewidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/messagewidget.cpp 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,1385 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// onw header +#include "messagewidget.h" + +//app includes +#include "classifier.h" +#include "debug_utils.h" +#include "floatingtextwidget.h" +#include "listpopupmenu.h" +#include "objectwidget.h" +#include "operation.h" +#include "uml.h" +#include "umldoc.h" +#include "umlview.h" +#include "uniqueid.h" +#include "idchangelog.h" + +//qt includes +#include +#include +#include +#include + +//kde includes +#include + +DEBUG_REGISTER_DISABLED(MessageWidget) + +static const int circleWidth = 10; + +/** + * Constructs a MessageWidget. + * + * This method is used for creation, synchronous and synchronous message types. + * + * @param scene The parent to this class. + * @param a The role A widget for this message. + * @param b The role B widget for this message. + * @param y The vertical position to display this message. + * @param sequenceMessageType Whether synchronous or asynchronous + * @param id A unique id used for deleting this object cleanly. + * The default (-1) will prompt generation of a new ID. + */ +MessageWidget::MessageWidget(UMLScene * scene, ObjectWidget* a, ObjectWidget* b, + int y, Uml::SequenceMessage::Enum sequenceMessageType, + Uml::ID::Type id /* = Uml::id_None */) + : UMLWidget(scene, WidgetBase::wt_Message, id) +{ + init(); + m_pOw[Uml::RoleType::A] = a; + m_pOw[Uml::RoleType::B] = b; + m_sequenceMessageType = sequenceMessageType; + if (m_sequenceMessageType == Uml::SequenceMessage::Creation) { + y -= m_pOw[Uml::RoleType::B]->height() / 2; + m_pOw[Uml::RoleType::B]->setY(y); + } + updateResizability(); + calculateWidget(); + y = y < getMinY() ? getMinY() : y; + y = y > getMaxY() ? getMaxY() : y; + setY(y); + + this->activate(); +} + +/** + * Constructs a MessageWidget. + * + * @param scene The parent to this class. + * @param seqMsgType The Uml::SequenceMessage::Enum of this message widget + * @param id The ID to assign (-1 will prompt a new ID.) + */ +MessageWidget::MessageWidget(UMLScene * scene, Uml::SequenceMessage::Enum seqMsgType, + Uml::ID::Type id) + : UMLWidget(scene, WidgetBase::wt_Message, id) +{ + init(); + m_sequenceMessageType = seqMsgType; +} + +/** + * Constructs a Lost or Found MessageWidget. + * + * @param scene The parent to this class. + * @param a The role A widget for this message. + * @param xclick The horizontal position clicked by the user + * @param yclick The vertical position clicked by the user + * @param sequenceMessageType Whether lost or found + * @param id The ID to assign (-1 will prompt a new ID.) + */ +MessageWidget::MessageWidget(UMLScene * scene, ObjectWidget* a, int xclick, int yclick, + Uml::SequenceMessage::Enum sequenceMessageType, + Uml::ID::Type id /*= Uml::id_None*/) + : UMLWidget(scene, WidgetBase::wt_Message, id) +{ + init(); + m_pOw[Uml::RoleType::A] = a; + m_pOw[Uml::RoleType::B] = a; + + m_sequenceMessageType = sequenceMessageType; + + m_xclicked = xclick; + m_yclicked = yclick; + + updateResizability(); + calculateWidget(); + yclick = yclick < getMinY() ? getMinY() : yclick; + yclick = yclick > getMaxY() ? getMaxY() : yclick; + setY(yclick); + m_yclicked = yclick; + + this->activate(); +} + +/** + * Initializes key variables of the class. + */ +void MessageWidget::init() +{ + m_xclicked = -1; + m_yclicked = -1; + m_ignoreSnapToGrid = true; + m_ignoreSnapComponentSizeToGrid = true; + m_pOw[Uml::RoleType::A] = m_pOw[Uml::RoleType::B] = NULL; + m_pFText = NULL; +} + +/** + * Standard destructor. + */ +MessageWidget::~MessageWidget() +{ +} + +/** + * Sets the y-coordinate. + * Reimplemented from UMLWidget. + * + * @param y The y-coordinate to be set. + */ +void MessageWidget::setY(qreal y) +{ + if (y < getMinY()) { + DEBUG(DBG_SRC) << "got out of bounds y position, check the reason" << this->y() << getMinY(); + return; + } + + UMLWidget::setY(y); + if (m_sequenceMessageType == Uml::SequenceMessage::Creation) { + const qreal objWidgetHalfHeight = m_pOw[Uml::RoleType::B]->height() / 2; + m_pOw[Uml::RoleType::B]->setY(y - objWidgetHalfHeight); + } + + if (m_pFText && !UMLApp::app()->document()->loading()) { + setTextPosition(); + emit sigMessageMoved(); + } +} + +/** + * Update the UMLWidget::m_resizable flag according to the + * charactersitics of this message. + */ +void MessageWidget::updateResizability() +{ + if (m_sequenceMessageType == Uml::SequenceMessage::Synchronous) + UMLWidget::m_resizable = true; + else + UMLWidget::m_resizable = false; +} + +/** + * Overridden from UMLWidget. + * Returns the cursor to be shown when resizing the widget. + * The cursor shown is KCursor::sizeVerCursor(). + * + * @return The cursor to be shown when resizing the widget. + */ +QCursor MessageWidget::resizeCursor() const +{ + return Qt::SizeVerCursor; +} + +/** + * Overridden from UMLWidget. + * Resizes the height of the message widget and emits the message moved signal. + * Message widgets can only be resized vertically, so width isn't modified. + * + * @param newW The new width for the widget (isn't used). + * @param newH The new height for the widget. + */ +void MessageWidget::resizeWidget(qreal newW, qreal newH) +{ + if (sequenceMessageType() == Uml::SequenceMessage::Creation) + setSize(width(), newH); + else { + qreal x1 = m_pOw[Uml::RoleType::A]->x(); + qreal x2 = getxclicked(); + qreal diffX = 0; + if (x1 < x2) { + diffX = x2 + (newW - width()); + } + else { + diffX = x2 - (newW - width()); + } + if (diffX <= 0 ) + diffX = 10; + setxclicked (diffX); + setSize(newW, newH); + calculateWidget(); + + } + emit sigMessageMoved(); +} + +/** + * Constrains the vertical position of the message widget so it doesn't go + * upper than the bottom side of the lower object. + * The height of the floating text widget in the message is taken in account + * if there is any and isn't empty. + * + * @param diffY The difference between current Y position and new Y position. + * @return The new Y position, constrained. + */ +qreal MessageWidget::constrainPositionY(qreal diffY) +{ + qreal newY = y() + diffY; + + qreal minY = getMinY(); + if (m_pFText && !m_pFText->displayText().isEmpty()) { + minY += m_pFText->height(); + } + + if (newY < minY) { + newY = minY; + } + + return newY; +} + +/** + * Overridden from UMLWidget. + * Moves the widget to a new position using the difference between the + * current position and the new position. X position is ignored, and widget + * is only moved along Y axis. If message goes upper than the object, it's + * kept at this position until it should be lowered again (the unconstrained + * Y position is saved to know when it's the time to lower it again). + * If the message is a creation message, the object created is also moved to + * the new vertical position. + * @see constrainPositionY + * + * @param diffX The difference between current X position and new X position + * (isn't used). + * @param diffY The difference between current Y position and new Y position. + */ +void MessageWidget::moveWidgetBy(qreal diffX, qreal diffY) +{ + Q_UNUSED(diffX); + qreal newY = constrainPositionY(diffY); + setY(newY); +} + +/** + * Overridden from UMLWidget. + * Modifies the value of the diffX and diffY variables used to move the widgets. + * All the widgets are constrained to be moved only in Y axis (diffX is set to 0). + * @see constrainPositionY + * + * @param diffX The difference between current X position and new X position. + * @param diffY The difference between current Y position and new Y position. + */ +void MessageWidget::constrainMovementForAllWidgets(qreal &diffX, qreal &diffY) +{ + diffX = 0; + diffY = constrainPositionY(diffY) - y(); +} + +/** + * Reimplemented from UMLWidget and calls other paint...() methods + * depending on the message type. + */ +void MessageWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + if(!m_pOw[Uml::RoleType::A] || !m_pOw[Uml::RoleType::B]) { + return; + } + setPenFromSettings(painter); + if (m_sequenceMessageType == Uml::SequenceMessage::Synchronous) { + paintSynchronous(painter, option); + } else if (m_sequenceMessageType == Uml::SequenceMessage::Asynchronous) { + paintAsynchronous(painter, option); + } else if (m_sequenceMessageType == Uml::SequenceMessage::Creation) { + paintCreation(painter, option); + } else if (m_sequenceMessageType == Uml::SequenceMessage::Lost) { + paintLost(painter, option); + } else if (m_sequenceMessageType == Uml::SequenceMessage::Found) { + paintFound(painter, option); + } else { + uWarning() << "Unknown message type"; + } +} + +/** + * Draw a solid-kf6 (triangular) arrowhead pointing in the given direction. + * The direction can be either Qt::LeftArrow or Qt::RightArrow. + */ +void MessageWidget::paintsolid-kf6Arrowhead(QPainter *p, int x, int y, Qt::ArrowType direction) +{ + int arrowheadExtentX = 4; + if (direction == Qt::RightArrow) { + arrowheadExtentX = -arrowheadExtentX; + } + QPolygon points; + points.putPoints(0, 3, x, y, x + arrowheadExtentX, y - 3, x + arrowheadExtentX, y + 3); + p->setBrush(QBrush(p->pen().color())); + p->drawPolygon(points); +} + +/** + * Draw an arrow pointing in the given direction. + * The arrow head is not solid-kf6, i.e. it is made up of two lines + * like so: ---> + * The direction can be either Qt::LeftArrow or Qt::RightArrow. + */ +void MessageWidget::paintArrow(QPainter *p, int x, int y, int w, + Qt::ArrowType direction, bool useDottedLine /* = false */) +{ + if (w > 3) { + int arrowheadStartX = x; + int arrowheadExtentX = 4; + if (direction == Qt::RightArrow) { + arrowheadStartX += w; + arrowheadExtentX = -arrowheadExtentX; + } + // draw upper half of arrowhead + p->drawLine(arrowheadStartX, y, arrowheadStartX + arrowheadExtentX, y - 3); + // draw lower half of arrowhead + p->drawLine(arrowheadStartX, y, arrowheadStartX + arrowheadExtentX, y + 3); + } + // draw arrow line + if (useDottedLine) { + QPen pen = p->pen(); + pen.setStyle(Qt::DotLine); + p->setPen(pen); + } + p->drawLine(x, y, x + w, y); +} + +/** + * Draws the calling arrow with filled in arrowhead, the + * timeline box and the returning arrow with a dashed line and + * stick arrowhead. + */ +void MessageWidget::paintSynchronous(QPainter *painter, const QStyleOptionGraphicsItem *option) +{ + int x1 = m_pOw[Uml::RoleType::A]->x(); + int x2 = m_pOw[Uml::RoleType::B]->x(); + int w = width() - 1; + int h = height(); + int offsetX = 0; + int offsetY = 0; + + bool messageOverlaps = m_pOw[Uml::RoleType::A]->messageOverlap(y(), this); + const int boxWidth = 17; + const int wr = w < boxWidth ? w : boxWidth; + const int arrowWidth = 4; + + if(isSelf()) { + painter->fillRect(offsetX, offsetY, wr, h, QBrush(Qt::white)); //box + painter->drawRect(offsetX, offsetY, wr, h); //box + offsetX += wr; + w -= wr; + offsetY += 3; + const int lowerLineY = offsetY + h - 6; + // draw upper line segment (leaving the life line) + painter->drawLine(offsetX, offsetY, offsetX + w, offsetY); + // draw line segment parallel to (and at the right of) the life line + painter->drawLine(offsetX + w, offsetY, offsetX + w, lowerLineY); + // draw lower line segment (back to the life line) + paintArrow(painter, offsetX, lowerLineY, w, Qt::LeftArrow); + offsetX -= wr; + offsetY -= 3; + } else if(x1 < x2) { + if (messageOverlaps) { + offsetX += 8; + w -= 8; + } + QPen pen = painter->pen(); + int startX = offsetX + w - wr + 1; + painter->fillRect(startX, offsetY, wr, h, QBrush(Qt::white)); //box + painter->drawRect(startX, offsetY, wr, h); //box + painter->drawLine(offsetX, offsetY + arrowWidth, startX, offsetY + arrowWidth); //arrow line + if (w > boxWidth + arrowWidth) + paintsolid-kf6Arrowhead(painter, startX - 1, offsetY + arrowWidth, Qt::RightArrow); + paintArrow(painter, offsetX, offsetY + h - arrowWidth + 1, w - wr + 1, Qt::LeftArrow, true); // return arrow + if (messageOverlaps) { + offsetX -= 8; //reset for drawSelected() + } + } else { + if (messageOverlaps) { + w -=8; + } + QPen pen = painter->pen(); + painter->fillRect(offsetX, offsetY, wr, h, QBrush(Qt::white)); //box + painter->drawRect(offsetX, offsetY, wr, h); //box + painter->drawLine(offsetX + wr + 1, offsetY + arrowWidth, offsetX + w, offsetY + arrowWidth); //arrow line + if (w > boxWidth + arrowWidth) + paintsolid-kf6Arrowhead(painter, offsetX + wr, offsetY + arrowWidth, Qt::LeftArrow); + paintArrow(painter, offsetX + wr + 1, offsetY + h - arrowWidth + 1, w - wr - 1, Qt::RightArrow, true); // return arrow + } + + UMLWidget::paint(painter, option); +} + +/** + * Draws a solid-kf6 arrow line and a stick arrow head. + */ +void MessageWidget::paintAsynchronous(QPainter *painter, const QStyleOptionGraphicsItem *option) +{ + int x1 = m_pOw[Uml::RoleType::A]->x(); + int x2 = m_pOw[Uml::RoleType::B]->x(); + int w = width() - 1; + int h = height() - 1; + int offsetX = 0; + int offsetY = 0; + bool messageOverlapsA = m_pOw[Uml::RoleType::A]->messageOverlap(y(), this); + //bool messageOverlapsB = m_pOw[Uml::RoleType::B]->messageOverlap(y(), this); + + if(isSelf()) { + if (messageOverlapsA) { + offsetX += 7; + w -= 7; + } + const int lowerLineY = offsetY + h - 3; + // draw upper line segment (leaving the life line) + painter->drawLine(offsetX, offsetY, offsetX + w, offsetY); + // draw line segment parallel to (and at the right of) the life line + painter->drawLine(offsetX + w, offsetY, offsetX + w, lowerLineY); + // draw lower line segment (back to the life line) + paintArrow(painter, offsetX, lowerLineY, w, Qt::LeftArrow); + if (messageOverlapsA) { + offsetX -= 7; //reset for drawSelected() + } + } else if(x1 < x2) { + if (messageOverlapsA) { + offsetX += 7; + w -= 7; + } + paintArrow(painter, offsetX, offsetY + 4, w, Qt::RightArrow); + if (messageOverlapsA) { + offsetX -= 7; + } + } else { + if (messageOverlapsA) { + w -= 7; + } + paintArrow(painter, offsetX, offsetY + 4, w, Qt::LeftArrow); + } + + UMLWidget::paint(painter, option); +} + +/** + * Draws a solid-kf6 arrow line and a stick arrow head to the + * edge of the target object widget instead of to the + * sequence line. + */ +void MessageWidget::paintCreation(QPainter *painter, const QStyleOptionGraphicsItem *option) +{ + int x1 = m_pOw[Uml::RoleType::A]->x(); + int x2 = m_pOw[Uml::RoleType::B]->x(); + int w = width(); + //int h = height() - 1; + int offsetX = 0; + int offsetY = 0; + bool messageOverlapsA = m_pOw[Uml::RoleType::A]->messageOverlap(y(), this); + //bool messageOverlapsB = m_pOw[Uml::RoleType::B]->messageOverlap(y(), this); + + const int lineY = offsetY + 4; + if (x1 < x2) { + if (messageOverlapsA) { + offsetX += 7; + w -= 7; + } + paintArrow(painter, offsetX, lineY, w, Qt::RightArrow); + if (messageOverlapsA) { + offsetX -= 7; + } + } else { + if (messageOverlapsA) { + w -= 7; + } + paintArrow(painter, offsetX, lineY, w, Qt::LeftArrow); + } + + UMLWidget::paint(painter, option); +} + + +/** + * Draws a solid-kf6 arrow line and a stick arrow head + * and a circle + */ +void MessageWidget::paintLost(QPainter *painter, const QStyleOptionGraphicsItem *option) +{ + int x1 = m_pOw[Uml::RoleType::A]->centerX(); + int x2 = m_xclicked; + int w = width(); + int h = height(); + int offsetX = 0; + int offsetY = 0; + bool messageOverlapsA = m_pOw[Uml::RoleType::A]->messageOverlap(y(), this); + //bool messageOverlapsB = m_pOw[Uml::RoleType::B]->messageOverlap(y(), this); + + if(x1 < x2) { + if (messageOverlapsA) { + offsetX += 7; + w -= 7; + } + + setPenFromSettings(painter); + painter->setBrush(WidgetBase::lineColor()); + painter->drawEllipse(offsetX + w - h, offsetY, h, h); + paintArrow(painter, offsetX, offsetY + h/2, w - h, Qt::RightArrow); + + if (messageOverlapsA) { + offsetX -= 7; + } + } else { + setPenFromSettings(painter); + painter->setBrush(WidgetBase::lineColor()); + painter->drawEllipse(offsetX, offsetY, h, h); + paintArrow(painter, offsetX + h, offsetY + h/2, w - h, Qt::LeftArrow); + } + + UMLWidget::paint(painter, option); +} + +/** + * Draws a circle and a solid-kf6 arrow line and a stick arrow head. + */ +void MessageWidget::paintFound(QPainter *painter, const QStyleOptionGraphicsItem *option) +{ + int x1 = m_pOw[Uml::RoleType::A]->centerX(); + int x2 = m_xclicked; + int w = width(); + int h = height(); + int offsetX = 0; + int offsetY = 0; + bool messageOverlapsA = m_pOw[Uml::RoleType::A]->messageOverlap(y(), this); + //bool messageOverlapsB = m_pOw[Uml::RoleType::B]->messageOverlap(y(), this); + + if(x1 < x2) { + if (messageOverlapsA) { + offsetX += 7; + w -= 7; + } + setPenFromSettings(painter); + painter->setBrush(WidgetBase::lineColor()); + painter->drawEllipse(offsetX + w - h, offsetY, h, h); + paintArrow(painter, offsetX, offsetY + h/2, w, Qt::LeftArrow); + if (messageOverlapsA) { + offsetX -= 7; + } + } else { + if (messageOverlapsA) { + w -= 7; + } + setPenFromSettings(painter); + painter->setBrush(WidgetBase::lineColor()); + painter->drawEllipse(offsetX, offsetY, h, h); + paintArrow(painter, offsetX, offsetY + h/2, w, Qt::RightArrow); + } + + UMLWidget::paint(painter, option); +} + +/** + * Overrides operation from UMLWidget. + * + * @param p Point to be checked. + * + * @return 'this' if the point is on a part of the MessageWidget. + * NB In case of a synchronous message, the empty space + * between call line and return line does not count, i.e. if + * the point is located in that space the function returns NULL. + */ +UMLWidget* MessageWidget::onWidget(const QPointF& p) +{ + if (m_sequenceMessageType != Uml::SequenceMessage::Synchronous) { + return UMLWidget::onWidget(p); + } + // Synchronous message: + // Consists of top arrow (call) and bottom arrow (return.) + if (p.x() < x() || p.x() > x() + width()) + return NULL; + const int tolerance = 5; // pixels + const int pY = p.y(); + const int topArrowY = y() + 3; + const int bottomArrowY = y() + height() - 3; + if (pY < topArrowY - tolerance || pY > bottomArrowY + tolerance) + return NULL; + if (height() <= 2 * tolerance) + return this; + if (pY > topArrowY + tolerance && pY < bottomArrowY - tolerance) + return NULL; + return this; +} + +/** + * Sets the text position relative to the sequence message. + */ +void MessageWidget::setTextPosition() +{ + if (m_pFText == NULL) { + DEBUG(DBG_SRC) << "m_pFText is NULL"; + return; + } + if (m_pFText->displayText().isEmpty()) { + return; + } + m_pFText->updateGeometry(); + int ftX = constrainX(m_pFText->x(), m_pFText->width(), m_pFText->textRole()); + int ftY = y() - m_pFText->height(); + m_pFText->setX(ftX); + m_pFText->setY(ftY); +} + +/** + * Returns the textX arg with constraints applied. + * Auxiliary to setTextPosition() and constrainTextPos(). + */ +int MessageWidget::constrainX(int textX, int textWidth, Uml::TextRole::Enum tr) +{ + int result = textX; + const int minTextX = x() + 5; + if (textX < minTextX || tr == Uml::TextRole::Seq_Message_Self) { + result = minTextX; + } else { + ObjectWidget *objectAtRight = NULL; + if (m_pOw[Uml::RoleType::B]->x() > m_pOw[Uml::RoleType::A]->x()) + objectAtRight = m_pOw[Uml::RoleType::B]; + else + objectAtRight = m_pOw[Uml::RoleType::A]; + const int objRight_seqLineX = objectAtRight->centerX(); + const int maxTextX = objRight_seqLineX - textWidth - 5; + if (maxTextX <= minTextX) + result = minTextX; + else if (textX > maxTextX) + result = maxTextX; + } + return result; +} + +/** + * Constrains the FloatingTextWidget X and Y values supplied. + * Overrides operation from LinkWidget. + * + * @param textX candidate X value (may be modified by the constraint) + * @param textY candidate Y value (may be modified by the constraint) + * @param textWidth width of the text + * @param textHeight height of the text + * @param tr Uml::TextRole::Enum of the text + */ +void MessageWidget::constrainTextPos(qreal &textX, qreal &textY, qreal textWidth, qreal textHeight, + Uml::TextRole::Enum tr) +{ + textX = constrainX(textX, textWidth, tr); + // Constrain Y. + const qreal minTextY = getMinY(); + const qreal maxTextY = getMaxY() - textHeight - 5; + if (textY < minTextY) + textY = minTextY; + else if (textY > maxTextY) + textY = maxTextY; +// setY(textY + textHeight); // NB: side effect +} + +/** + * Shortcut for calling m_pFText->setLink() followed by + * this->setTextPosition(). + */ +void MessageWidget::setLinkAndTextPos() +{ + if (m_pFText) { + m_pFText->setLink(this); + setTextPosition(); + } +} + +void MessageWidget::resizeEvent(QResizeEvent* /*re*/) +{ +} + +/** + * Calculate the geometry of the widget. + */ +void MessageWidget::calculateWidget() +{ + setMessageText(m_pFText); + calculateDimensions(); + setVisible(true); +} + +void MessageWidget::slotWidgetMoved(Uml::ID::Type id) +{ + const Uml::ID::Type idA = m_pOw[Uml::RoleType::A]->localID(); + const Uml::ID::Type idB = m_pOw[Uml::RoleType::B]->localID(); + if (idA != id && idB != id) { + DEBUG(DBG_SRC) << "id=" << Uml::ID::toString(id) << ": ignoring for idA=" << Uml::ID::toString(idA) + << ", idB=" << Uml::ID::toString(idB); + return; + } + qreal y = this->y(); + if (y < getMinY()) + y = getMinY(); + if (y > getMaxY()) + y = getMaxY(); + setPos(x(), y); + calculateWidget(); + if(!m_pFText) + return; + if (m_scene->selectedCount(true) > 1) + return; + setTextPosition(); +} + +/** + * Check to see if the given ObjectWidget is involved in the message. + * + * @param w The ObjectWidget to check for. + * @return true - if is contained, false - not contained. + */ +bool MessageWidget::hasObjectWidget(ObjectWidget * w) +{ + if(m_pOw[Uml::RoleType::A] == w || m_pOw[Uml::RoleType::B] == w) + return true; + else + return false; +} + +/** + * This method determines whether the message is for "Self" for + * an ObjectWidget. + * + * @retval True If both ObjectWidgets for this widget exists and + * are same. + */ +bool MessageWidget::isSelf() const +{ + return (m_pOw[Uml::RoleType::A] && m_pOw[Uml::RoleType::B] && + m_pOw[Uml::RoleType::A] == m_pOw[Uml::RoleType::B]); +} + +void MessageWidget::slotMenuSelection(QAction* action) +{ + ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); + if (sel == ListPopupMenu::mt_Delete) { + // This will clean up this widget and the text widget: + m_scene->removeWidget(this); + } else { + + UMLWidget::slotMenuSelection(action); + } +} + +/** + * Activates a MessageWidget. Connects its m_pOw[] pointers + * to UMLObjects and also send signals about its FloatingTextWidget. + */ +bool MessageWidget::activate(IDChangeLog * /*Log = 0*/) +{ + m_scene->resetPastep-kf6oint(); + // UMLWidget::activate(Log); CHECK: I don't think we need this ? + if (m_pOw[Uml::RoleType::A] == NULL) { + UMLWidget *pWA = m_scene->findWidget(m_widgetAId); + if (pWA == NULL) { + DEBUG(DBG_SRC) << "role A object " << Uml::ID::toString(m_widgetAId) << " not found"; + return false; + } + m_pOw[Uml::RoleType::A] = dynamic_cast(pWA); + if (m_pOw[Uml::RoleType::A] == NULL) { + DEBUG(DBG_SRC) << "role A widget " << Uml::ID::toString(m_widgetAId) + << " is not an ObjectWidget"; + return false; + } + } + if (m_pOw[Uml::RoleType::B] == NULL) { + UMLWidget *pWB = m_scene->findWidget(m_widgetBId); + if (pWB == NULL) { + DEBUG(DBG_SRC) << "role B object " << Uml::ID::toString(m_widgetBId) << " not found"; + return false; + } + m_pOw[Uml::RoleType::B] = dynamic_cast(pWB); + if (m_pOw[Uml::RoleType::B] == NULL) { + DEBUG(DBG_SRC) << "role B widget " << Uml::ID::toString(m_widgetBId) + << " is not an ObjectWidget"; + return false; + } + } + updateResizability(); + + UMLClassifier *c = dynamic_cast(m_pOw[Uml::RoleType::B]->umlObject()); + UMLOperation *op = NULL; + if (c && !m_CustomOp.isEmpty()) { + Uml::ID::Type opId = Uml::ID::fromString(m_CustomOp); + op = dynamic_cast(c->findChildObjectById(opId, true)); + if (op) { + // If the UMLOperation is set, m_CustomOp isn't used anyway. + // Just setting it empty for the sake of sanity. + m_CustomOp.clear(); + } + } + + if(!m_pFText) { + Uml::TextRole::Enum tr = Uml::TextRole::Seq_Message; + if (isSelf()) + tr = Uml::TextRole::Seq_Message_Self; + m_pFText = new FloatingTextWidget(m_scene, tr, operationText(m_scene)); + m_scene->addFloatingTextWidget(m_pFText); + m_pFText->setFontCmd(UMLWidget::font()); + } + if (op) + setOperation(op); // This requires a valid m_pFText. + setLinkAndTextPos(); + m_pFText->setText(QString()); + m_pFText->setActivated(); + QString messageText = m_pFText->text(); + m_pFText->setVisible(messageText.length() > 1); + + connect(m_pOw[Uml::RoleType::A], SIGNAL(sigWidgetMoved(Uml::ID::Type)), this, SLOT(slotWidgetMoved(Uml::ID::Type))); + connect(m_pOw[Uml::RoleType::B], SIGNAL(sigWidgetMoved(Uml::ID::Type)), this, SLOT(slotWidgetMoved(Uml::ID::Type))); + + connect(this, SIGNAL(sigMessageMoved()), m_pOw[Uml::RoleType::A], SLOT(slotMessageMoved())); + connect(this, SIGNAL(sigMessageMoved()), m_pOw[Uml::RoleType::B], SLOT(slotMessageMoved())); + m_pOw[Uml::RoleType::A]->messageAdded(this); + if (!isSelf()) + m_pOw[Uml::RoleType::B]->messageAdded(this); + + // Calculate the size and position of the message widget + calculateDimensions(); + + // Position the floating text accordingly + setTextPosition(); + + emit sigMessageMoved(); + return true; +} + +/** + * Resolve references of this message so they reference the correct + * new object widgets after paste. + */ +void MessageWidget::resolveObjectWidget(IDChangeLog* log) { + m_widgetAId = log->findNewID(m_widgetAId); + m_widgetBId = log->findNewID(m_widgetBId); +} + +/** + * Overrides operation from LinkWidget. + * Required by FloatingTextWidget. + * + * @param ft The text widget which to update. + */ +void MessageWidget::setMessageText(FloatingTextWidget *ft) +{ + if (ft == NULL) + return; + ft->setSequenceNumber(m_SequenceNumber); + ft->setText(operationText(m_scene)); + setTextPosition(); +} + +/** + * Overrides operation from LinkWidget. + * Required by FloatingTextWidget. + * + * @param ft The text widget which to update. + * @param newText The new text to set. + */ +void MessageWidget::setText(FloatingTextWidget *ft, const QString &newText) +{ + ft->setText(newText); + UMLApp::app()->document()->setModified(true); +} + +/** + * Overrides operation from LinkWidget. + * Required by FloatingTextWidget. + * + * @param op The new operation string to set. + */ +void MessageWidget::setOperationText(const QString &op) +{ + m_CustomOp = op; ///FIXME m_pOperation +} + +/** + * Implements operation from LinkWidget. + * Required by FloatingTextWidget. + */ +void MessageWidget::lwSetFont (QFont font) +{ + UMLWidget::setFont(font); +} + +/** + * Overrides operation from LinkWidget. + * Required by FloatingTextWidget. + * @todo Move to LinkWidget. + */ +UMLClassifier *MessageWidget::operationOwner() +{ + UMLObject *pObject = m_pOw[Uml::RoleType::B]->umlObject(); + if (pObject == NULL) + return NULL; + UMLClassifier *c = dynamic_cast(pObject); + return c; +} + +/** + * Implements operation from LinkWidget. + * Motivated by FloatingTextWidget. + */ +UMLOperation *MessageWidget::operation() +{ + return static_cast(m_umlObject); +} + +/** + * Implements operation from LinkWidget. + * Motivated by FloatingTextWidget. + */ +void MessageWidget::setOperation(UMLOperation *op) +{ + if (m_umlObject && m_pFText) + disconnect(m_umlObject, SIGNAL(modified()), m_pFText, SLOT(setMessageText())); + m_umlObject = op; + if (m_umlObject && m_pFText) { + connect(m_umlObject, SIGNAL(modified()), m_pFText, SLOT(setMessageText())); + m_pFText->setMessageText(); + } +} + +/** + * Overrides operation from LinkWidget. + * Required by FloatingTextWidget. + */ +QString MessageWidget::customOpText() +{ + return m_CustomOp; +} + +/** + * Overrides operation from LinkWidget. + * Required by FloatingTextWidget. + */ +void MessageWidget::setCustomOpText(const QString &opText) +{ + m_CustomOp = opText; + m_pFText->setMessageText(); +} + +/** + * Overrides operation from LinkWidget. + * Required by FloatingTextWidget. + */ +QString MessageWidget::lwOperationText() +{ + UMLOperation *pOperation = operation(); + if (pOperation != NULL) { + return pOperation->toString(Uml::SignatureType::SigNoVis); + } else { + return customOpText(); + } +} + +/** + * Overrides operation from LinkWidget. + * Required by FloatingTextWidget. + */ +UMLClassifier *MessageWidget::lwClassifier() +{ + UMLObject *o = m_pOw[Uml::RoleType::B]->umlObject(); + UMLClassifier *c = dynamic_cast(o); + return c; +} + +/** + * Calculates the size of the widget by calling + * calculateDimensionsSynchronous(), + * calculateDimensionsAsynchronous(), or + * calculateDimensionsCreation() + */ +void MessageWidget::calculateDimensions() +{ + if (m_sequenceMessageType == Uml::SequenceMessage::Synchronous) { + calculateDimensionsSynchronous(); + } else if (m_sequenceMessageType == Uml::SequenceMessage::Asynchronous) { + calculateDimensionsAsynchronous(); + } else if (m_sequenceMessageType == Uml::SequenceMessage::Creation) { + calculateDimensionsCreation(); + } else if (m_sequenceMessageType == Uml::SequenceMessage::Lost) { + calculateDimensionsLost(); + } else if (m_sequenceMessageType == Uml::SequenceMessage::Found) { + calculateDimensionsFound(); + } else { + uWarning() << "Unknown message type"; + } + if (! UMLApp::app()->document()->loading()) { + adjustAssocs(x(), y()); // adjust assoc lines + } +} + +/** + * Calculates and sets the size of the widget for a synchronous message. + */ +void MessageWidget::calculateDimensionsSynchronous() +{ + int x = 0; + + int x1 = m_pOw[Uml::RoleType::A]->centerX(); + int x2 = m_pOw[Uml::RoleType::B]->centerX(); + + int widgetWidth = 0; + int widgetHeight = 0; + if(isSelf()) { + widgetWidth = 50; + x = x1 - 2; + } else if(x1 < x2) { + x = x1; + widgetWidth = x2 - x1 + 8; + } else { + x = x2 - 8; + widgetWidth = x1 - x2 + 8; + } + + if (height() < 20) { + widgetHeight = 20; + } else { + widgetHeight = height(); + } + + setX(x); + setSize(widgetWidth, widgetHeight); +} + +/** + * Calculates and sets the size of the widget for an asynchronous message. + */ +void MessageWidget::calculateDimensionsAsynchronous() +{ + int x = 0; + + int x1 = m_pOw[Uml::RoleType::A]->centerX(); + int x2 = m_pOw[Uml::RoleType::B]->centerX(); + + int widgetWidth = 0; + int widgetHeight = 8; + if(isSelf()) { + widgetWidth = 50; + x = x1; + if(height() < 20) { + widgetHeight = 20; + } else { + widgetHeight = height(); + } + } else if(x1 < x2) { + x = x1; + widgetWidth = x2 - x1; + } else { + x = x2; + widgetWidth = x1 - x2; + } + x += 1; + widgetWidth -= 2; + setX(x); + setSize(widgetWidth, widgetHeight); +} + +/** + * Calculates and sets the size of the widget for a creation message. + */ +void MessageWidget::calculateDimensionsCreation() +{ + int x = 0; + + int x1 = m_pOw[Uml::RoleType::A]->centerX(); + int x2 = m_pOw[Uml::RoleType::B]->x(); + int w2 = m_pOw[Uml::RoleType::B]->width(); + + if (x1 > x2) + x2 += w2; + + int widgetWidth = 0; + int widgetHeight = 8; + if (x1 < x2) { + x = x1; + widgetWidth = x2 - x1; + } else { + x = x2; + widgetWidth = x1 - x2; + } + x += 1; + widgetWidth -= 2; + setPos(x, m_pOw[Uml::RoleType::B]->y() + m_pOw[Uml::RoleType::B]->height() / 2); + setSize(widgetWidth, widgetHeight); +} + +/** + * Calculates and sets the size of the widget for a lost message. + */ +void MessageWidget::calculateDimensionsLost() +{ + int x = 0; + + int x1 = m_pOw[Uml::RoleType::A]->centerX(); + int x2 = m_xclicked; + + int widgetWidth = 0; + int widgetHeight = 10; + if(x1 < x2) { + x = x1; + widgetWidth = x2 - x1 + circleWidth/2; + } else { + x = x2 - circleWidth/2; + widgetWidth = x1 - x2 + circleWidth/2; + } + setX(x); + setSize(widgetWidth, widgetHeight); +} + +/** + * Calculates and sets the size of the widget for a found message. + */ +void MessageWidget::calculateDimensionsFound() +{ + int x = 0; + + int x1 = m_pOw[Uml::RoleType::A]->centerX(); + int x2 = m_xclicked; + + int widgetWidth = 0; + int widgetHeight = 10; + if(x1 < x2) { + x = x1; + widgetWidth = x2 - x1 + circleWidth/2; + } else { + x = x2 - circleWidth/2; + widgetWidth = x1 - x2 + circleWidth/2; + } + + setX(x); + setSize(widgetWidth, widgetHeight); +} + +/** + * Used to cleanup any other widget it may need to delete. + */ +void MessageWidget::cleanup() +{ + if (m_pOw[Uml::RoleType::A]) { + disconnect(this, SIGNAL(sigMessageMoved()), m_pOw[Uml::RoleType::A], SLOT(slotMessageMoved())); + m_pOw[Uml::RoleType::A]->messageRemoved(this); + } + if (m_pOw[Uml::RoleType::B]) { + disconnect(this, SIGNAL(sigMessageMoved()), m_pOw[Uml::RoleType::B], SLOT(slotMessageMoved())); + m_pOw[Uml::RoleType::B]->messageRemoved(this); + } + + UMLWidget::cleanup(); + if (m_pFText) { + m_scene->removeWidgetCmd(m_pFText); + m_pFText = NULL; + } +} + +/** + * Sets the state of whether the widget is selected. + * + * @param _select True if the widget is selected. + */ +void MessageWidget::setSelected(bool _select) +{ + UMLWidget::setSelected(_select); + if(!m_pFText || m_pFText->displayText().isEmpty()) + return; + if(isSelected() && m_pFText->isSelected()) + return; + if(!isSelected() && !m_pFText->isSelected()) + return; + + m_pFText->setSelected(isSelected()); +} + +/** + * Returns the minimum height this widget should be set at on + * a sequence diagrams. Takes into account the widget positions + * it is related to. + */ +int MessageWidget::getMinY() +{ + if (!m_pOw[Uml::RoleType::A] || !m_pOw[Uml::RoleType::B]) { + return 0; + } + if (m_sequenceMessageType == Uml::SequenceMessage::Creation) { + return m_pOw[Uml::RoleType::A]->y() + m_pOw[Uml::RoleType::A]->height(); + } + int heightA = m_pOw[Uml::RoleType::A]->y() + m_pOw[Uml::RoleType::A]->height(); + int heightB = m_pOw[Uml::RoleType::B]->y() + m_pOw[Uml::RoleType::B]->height(); + int height = heightA; + if(heightA < heightB) { + height = heightB; + } + return height; +} + +/** + * Returns the maximum height this widget should be set at on + * a sequence diagrams. Takes into account the widget positions + * it is related to. + */ +int MessageWidget::getMaxY() +{ + if(!m_pOw[Uml::RoleType::A] || !m_pOw[Uml::RoleType::B]) { + return 0; + } + int heightA = (int)((ObjectWidget*)m_pOw[Uml::RoleType::A])->getEndLineY(); + int heightB = (int)((ObjectWidget*)m_pOw[Uml::RoleType::B])->getEndLineY(); + int height = heightA; + if(heightA > heightB) { + height = heightB; + } + return (height - this->height()); +} + +/** + * Sets the related widget on the given side. + * + * @param ow The ObjectWidget we are related to. + * @param role The Uml::RoleType::Enum to be set for the ObjectWidget + */ +void MessageWidget::setObjectWidget(ObjectWidget * ow, Uml::RoleType::Enum role) +{ + m_pOw[role] = ow; + updateResizability(); +} + +/** + * Returns the related widget on the given side. + * + * @return The ObjectWidget we are related to. + */ +ObjectWidget* MessageWidget::objectWidget(Uml::RoleType::Enum role) +{ + return m_pOw[role]; +} + +/** + * Set the xclicked + */ +void MessageWidget::setxclicked(int xclick) +{ + m_xclicked = xclick; +} + +/** + * Set the yclicked + */ +void MessageWidget::setyclicked(int yclick) +{ + m_yclicked = yclick; +} + +/** + * Event handler for mouse double click events. + * @param event QGraphicsSceneMouseEvent which triggered the double click event + */ +void MessageWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) +{ + Q_UNUSED(event) + DEBUG(DBG_SRC) << "NOT IMPLEMENTED YET!"; + if (m_pFText != NULL) { + DEBUG(DBG_SRC) << "NOT IMPLEMENTED YET - on floating text widget!"; +// QAction* action = m_pMenu->getAction(ListPopupMenu::mt_Select_Operation); +// m_pFText->slotMenuSelection(action); + } +} + +/** + * Saves to the "messagewidget" XMI element. + */ +void MessageWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +{ + QDomElement messageElement = qDoc.createElement(QLatin1String("messagewidget")); + UMLWidget::saveToXMI(qDoc, messageElement); + LinkWidget::saveToXMI(qDoc, messageElement); + if (m_pOw[Uml::RoleType::A]) + messageElement.setAttribute(QLatin1String("widgetaid"), Uml::ID::toString(m_pOw[Uml::RoleType::A]->localID())); + if (m_pOw[Uml::RoleType::B]) + messageElement.setAttribute(QLatin1String("widgetbid"), Uml::ID::toString(m_pOw[Uml::RoleType::B]->localID())); + UMLOperation *pOperation = operation(); + if (pOperation) + messageElement.setAttribute(QLatin1String("operation"), Uml::ID::toString(pOperation->id())); + else + messageElement.setAttribute(QLatin1String("operation"), m_CustomOp); + messageElement.setAttribute(QLatin1String("sequencemessagetype"), m_sequenceMessageType); + if (m_sequenceMessageType == Uml::SequenceMessage::Lost || m_sequenceMessageType == Uml::SequenceMessage::Found) { + messageElement.setAttribute(QLatin1String("xclicked"), m_xclicked); + messageElement.setAttribute(QLatin1String("yclicked"), m_yclicked); + } + + // save the corresponding message text + if (m_pFText && !m_pFText->text().isEmpty()) { + messageElement.setAttribute(QLatin1String("textid"), Uml::ID::toString(m_pFText->id())); + m_pFText->saveToXMI(qDoc, messageElement); + } + + qElement.appendChild(messageElement); +} + +/** + * Loads from the "messagewidget" XMI element. + */ +bool MessageWidget::loadFromXMI(QDomElement& qElement) +{ + if (!UMLWidget::loadFromXMI(qElement)) { + return false; + } + if (!LinkWidget::loadFromXMI(qElement)) { + return false; + } + QString textid = qElement.attribute(QLatin1String("textid"), QLatin1String("-1")); + QString widgetaid = qElement.attribute(QLatin1String("widgetaid"), QLatin1String("-1")); + QString widgetbid = qElement.attribute(QLatin1String("widgetbid"), QLatin1String("-1")); + m_CustomOp = qElement.attribute(QLatin1String("operation")); + QString sequenceMessageType = qElement.attribute(QLatin1String("sequencemessagetype"), QLatin1String("1001")); + m_sequenceMessageType = Uml::SequenceMessage::fromInt(sequenceMessageType.toInt()); + if (m_sequenceMessageType == Uml::SequenceMessage::Lost || m_sequenceMessageType == Uml::SequenceMessage::Found) { + m_xclicked = qElement.attribute(QLatin1String("xclicked"), QLatin1String("-1")).toFloat(); + m_yclicked = qElement.attribute(QLatin1String("yclicked"), QLatin1String("-1")).toFloat(); + } + + m_widgetAId = Uml::ID::fromString(widgetaid); + m_widgetBId = Uml::ID::fromString(widgetbid); + m_textId = Uml::ID::fromString(textid); + + Uml::TextRole::Enum tr = Uml::TextRole::Seq_Message; + if (m_widgetAId == m_widgetBId) + tr = Uml::TextRole::Seq_Message_Self; + + //now load child elements + QDomNode node = qElement.firstChild(); + QDomElement element = node.toElement(); + if (!element.isNull()) { + QString tag = element.tagName(); + if (tag == QLatin1String("floatingtext") || tag == QLatin1String("UML::FloatingTextWidget")) { + m_pFText = new FloatingTextWidget(m_scene, tr, operationText(m_scene), m_textId); + m_scene->addFloatingTextWidget(m_pFText); + if(! m_pFText->loadFromXMI(element)) { + // Most likely cause: The FloatingTextWidget is empty. + delete m_pFText; + m_pFText = NULL; + } + else + m_pFText->setSequenceNumber(m_SequenceNumber); + } else { + uError() << "unknown tag " << tag; + } + } + return true; +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/messagewidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/messagewidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/messagewidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/messagewidget.h 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,212 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef MESSAGEWIDGET_H +#define MESSAGEWIDGET_H + +#include "umlwidget.h" +#include "linkwidget.h" + +// forward declarations +class FloatingTextWidget; +class ObjectWidget; +class QResizeEvent; +class UMLOperation; + +/** + * Used to display a message on a sequence diagram. The message + * could be between two objects or a message that calls itself on + * an object. This class will only display the line that is + * required and the text will be setup by the @ref FloatingTextWidget + * widget that is passed in the constructor. A message can be + * synchronous (calls a method and gains control back on return, + * as happens in most programming languages) or asynchronous + * (calls a method and gains back control immediately). + * + * @short Displays a message. + * @author Paul Hensgen + * @see UMLWidget + * @see ObjectWidget + * @see FloatingTextWidget + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class MessageWidget : public UMLWidget, public LinkWidget +{ + Q_OBJECT +public: + MessageWidget(UMLScene * scene, ObjectWidget* a, ObjectWidget* b, + int y, Uml::SequenceMessage::Enum sequenceMessageType, + Uml::ID::Type id = Uml::ID::None); + MessageWidget(UMLScene * scene, Uml::SequenceMessage::Enum sequenceMessageType, + Uml::ID::Type id = Uml::ID::None); + MessageWidget(UMLScene * scene, ObjectWidget* a, int xclick, int yclick, + Uml::SequenceMessage::Enum sequenceMessageType, + Uml::ID::Type id = Uml::ID::None); + virtual ~MessageWidget(); + + virtual void setY(qreal y); + + //---------- LinkWidget Interface methods implemementation from now on. + + virtual void lwSetFont (QFont font); + virtual UMLClassifier *operationOwner(); + + virtual UMLOperation *operation(); + virtual void setOperation(UMLOperation *op); + + virtual QString customOpText(); + virtual void setCustomOpText(const QString &opText); + + virtual void setMessageText(FloatingTextWidget *ft); + virtual void setText(FloatingTextWidget *ft, const QString &newText); + + virtual QString lwOperationText(); + virtual UMLClassifier *lwClassifier(); + virtual void setOperationText(const QString &op); + + virtual void constrainTextPos(qreal &textX, qreal &textY, qreal textWidth, qreal textHeight, + Uml::TextRole::Enum tr); + + //---------- End LinkWidget Interface methods implemementation. + + /// @return Whether the message is synchronous or asynchronous + Uml::SequenceMessage::Enum sequenceMessageType() const { + return m_sequenceMessageType; + } + + bool hasObjectWidget(ObjectWidget * w); + + ObjectWidget* objectWidget(Uml::RoleType::Enum role); + void setObjectWidget(ObjectWidget * ow, Uml::RoleType::Enum role) ; + + bool isSelf() const; + + /** + * Returns the text widget it is related to. + * + * @return The text widget we are related to. + */ + FloatingTextWidget * floatingTextWidget() { + return m_pFText; + } + + /** + * Sets the text widget it is related to. + * + * @param f The text widget we are related to. + */ + void setFloatingTextWidget(FloatingTextWidget * f) { + m_pFText = f; + } + + void calculateWidget(); + + virtual bool activate(IDChangeLog * Log = 0); + void resolveObjectWidget(IDChangeLog* log); + + void calculateDimensions(); + void calculateDimensionsSynchronous(); + void calculateDimensionsAsynchronous(); + void calculateDimensionsCreation(); + void calculateDimensionsLost(); + void calculateDimensionsFound(); + + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + + void setTextPosition(); + + void cleanup(); + + void setSelected(bool _select); + + int getMinY(); + int getMaxY(); + + UMLWidget* onWidget(const QPointF& p); + + virtual void resizeWidget(qreal newW, qreal newH); + + virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); + virtual bool loadFromXMI(QDomElement & qElement); + + void setxclicked(int xclick); + void setyclicked(int yclick); + + /** + * Return the xclicked + */ + int getxclicked() const { + return m_xclicked; + } + +protected: + virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); + + virtual void moveWidgetBy(qreal diffX, qreal diffY); + virtual void constrainMovementForAllWidgets(qreal &diffX, qreal &diffY); + + virtual QCursor resizeCursor() const; + + void setLinkAndTextPos(); + + int constrainX(int textX, int textWidth, Uml::TextRole::Enum tr); + + static void paintArrow(QPainter *p, int x, int y, int w, + Qt::ArrowType direction, bool useDottedLine = false); + static void paintsolid-kf6Arrowhead(QPainter *p, int x, int y, Qt::ArrowType direction); + + void updateResizability(); + + void paintSynchronous(QPainter *painter, const QStyleOptionGraphicsItem *option); + void paintAsynchronous(QPainter *painter, const QStyleOptionGraphicsItem *option); + void paintCreation(QPainter *painter, const QStyleOptionGraphicsItem *option); + void paintLost(QPainter *painter, const QStyleOptionGraphicsItem *option); + void paintFound(QPainter *painter, const QStyleOptionGraphicsItem *option); + + // Data loaded/saved + QString m_CustomOp; + /** + * Whether the message is synchronous or asynchronous + */ + Uml::SequenceMessage::Enum m_sequenceMessageType; + +private: + void resizeEvent(QResizeEvent *re); + + qreal constrainPositionY(qreal diffY); + + void init(); + + ObjectWidget * m_pOw[2]; + FloatingTextWidget * m_pFText; + + int m_xclicked; + int m_yclicked; + + /** + * The following variables are used by loadFromXMI() as an intermediate + * store. activate() resolves the IDs, i.e. after activate() the variables + * m_pOw[] and m_pFText can be used. + */ + Uml::ID::Type m_widgetAId, m_widgetBId, m_textId; + +public slots: + void slotWidgetMoved(Uml::ID::Type id); + void slotMenuSelection(QAction* action); + +signals: + /** + * emitted when the message widget is moved up or down + * slots into ObjectWidget::slotMessageMoved() + */ + void sigMessageMoved(); +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/nodewidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/nodewidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/nodewidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/nodewidget.cpp 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,156 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "nodewidget.h" + +// app includes +#include "debug_utils.h" +#include "node.h" +#include "umlscene.h" +#include "umlview.h" + +// qt includes +#include +#include + +DEBUG_REGISTER_DISABLED(NodeWidget) + +/** + * Constructs a NodeWidget. + * + * @param scene The parent of this NodeWidget. + * @param n The UMLNode this will be representing. + */ +NodeWidget::NodeWidget(UMLScene * scene, UMLNode *n) + : UMLWidget(scene, WidgetBase::wt_Node, n) +{ + setSize(100, 30); + setZValue(1); // above box but below UMLWidget because may embed widgets +} + +/** + * Destructor. + */ +NodeWidget::~NodeWidget() +{ +} + +/** + * Overrides standard method. + */ +void NodeWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + setPenFromSettings(painter); + if (UMLWidget::useFillColor()) { + painter->setBrush(UMLWidget::fillColor()); + } else { + painter->setBrush(m_scene->backgroundColor()); + } + const int w = width(); + const int h = height(); + const int wDepth = (w/3 > DEPTH ? DEPTH : w/3); + const int hDepth = (h/3 > DEPTH ? DEPTH : h/3); + const int bodyOffsetY = hDepth; + const int bodyWidth = w - wDepth; + const int bodyHeight = h - hDepth; + QFont font = UMLWidget::font(); + font.setBold(true); + const QFontMetrics &fm = getFontMetrics(FT_BOLD); + const int fontHeight = fm.lineSpacing(); + QString nameStr = name(); + + QPolygon pointArray(5); + pointArray.setPoint(0, 0, bodyOffsetY); + pointArray.setPoint(1, wDepth, 0); + pointArray.setPoint(2, w, 0); + pointArray.setPoint(3, w, bodyHeight); + pointArray.setPoint(4, bodyWidth, h); + painter->drawPolygon(pointArray); + painter->drawRect(0, bodyOffsetY, bodyWidth, bodyHeight); + painter->drawLine(w, 0, bodyWidth, bodyOffsetY); + + painter->setPen(textColor()); + painter->setFont(font); + + int lines = 1; + if (m_umlObject) { + QString stereotype = m_umlObject->stereotype(); + if (!stereotype.isEmpty()) { + painter->drawText(0, bodyOffsetY + (bodyHeight/2) - fontHeight, + bodyWidth, fontHeight, Qt::AlignCenter, m_umlObject->stereotype(true)); + lines = 2; + } + } + + if (UMLWidget::isInstance()) { + font.setUnderline(true); + painter->setFont(font); + nameStr = UMLWidget::instanceName() + QLatin1String(" : ") + nameStr; + } + + if (lines == 1) { + painter->drawText(0, bodyOffsetY + (bodyHeight/2) - (fontHeight/2), + bodyWidth, fontHeight, Qt::AlignCenter, nameStr); + } else { + painter->drawText(0, bodyOffsetY + (bodyHeight/2), + bodyWidth, fontHeight, Qt::AlignCenter, nameStr); + } + + UMLWidget::paint(painter, option, widget); +} + +/** + * Overrides method from UMLWidget. + */ +QSizeF NodeWidget::minimumSize() const +{ + if (m_umlObject == NULL) { + DEBUG(DBG_SRC) << "m_umlObject is NULL"; + return UMLWidget::minimumSize(); + } + + const QFontMetrics &fm = getFontMetrics(FT_BOLD_ITALIC); + const int fontHeight = fm.lineSpacing(); + + QString name = m_umlObject->name(); + if (UMLWidget::isInstance()) { + name = UMLWidget::instanceName() + QLatin1String(" : ") + name; + } + + int width = fm.width(name) + 2 * defaultMargin; + + int tempWidth = 0; + if (!m_umlObject->stereotype().isEmpty()) { + tempWidth = fm.width(m_umlObject->stereotype(true)); + } + if (tempWidth > width) + width = tempWidth; + width += DEPTH; + + int height = (2*fontHeight) + DEPTH; + + return QSizeF(width, height); +} + +/** + * Saves to the "nodewidget" XMI element. + * Note: For loading we use the method inherited from UMLWidget. + */ +void NodeWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +{ + QDomElement conceptElement = qDoc.createElement(QLatin1String("nodewidget")); + UMLWidget::saveToXMI(qDoc, conceptElement); + qElement.appendChild(conceptElement); +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/nodewidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/nodewidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/nodewidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/nodewidget.h 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,44 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef NODEWIDGET_H +#define NODEWIDGET_H + +#include "umlwidget.h" + +class UMLNode; + +/** + * Defines a graphical version of the Node. Most of the functionality + * will come from the @ref UMLNode class. + * + * @short A graphical version of a Node. + * @author Jonathan Riddell + * @see UMLWidget + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class NodeWidget : public UMLWidget +{ +public: + + NodeWidget(UMLScene * scene, UMLNode *n); + virtual ~NodeWidget(); + + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + + void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); + +protected: + QSizeF minimumSize() const; + + static const int DEPTH = 30; ///< pixels on Z axis +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/notewidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/notewidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/notewidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/notewidget.cpp 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,517 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "notewidget.h" + +// app includes +#include "debug_utils.h" +#include "docwindow.h" +#include "listpopupmenu.h" +#include "notedialog.h" +#include "uml.h" +#include "umldoc.h" +#include "umlscene.h" +#include "umlview.h" + +// kde includes +#include +#if QT_VERSION < 0x050000 +#include +#include +#endif + +// qt includes +#include +#if QT_VERSION >= 0x050000 +#include +#include +#endif + +NoteWidget * NoteWidget::s_pCurrentNote; + +/** + * Constructs a NoteWidget. + * + * @param scene The parent to this widget. + * @param noteType The NoteWidget::NoteType of this NoteWidget + * @param id The unique id of the widget. + * The default (-1) will prompt a new ID. + */ +NoteWidget::NoteWidget(UMLScene * scene, NoteType noteType , Uml::ID::Type id) + : UMLWidget(scene, WidgetBase::wt_Note, id), + m_diagramLink(Uml::ID::None), + m_noteType(noteType) +{ + setZValue(20); //make sure always on top. +} + +/** + * Destructor. + */ +NoteWidget::~NoteWidget() +{ +} + +/** + * Override default method. + */ +void NoteWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + const int margin = 10; + int w = width(); + int h = height(); + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + QPolygon poly(6); + poly.setPoint(0, 0, 0); + poly.setPoint(1, 0, h); + poly.setPoint(2, w, h); + poly.setPoint(3, w, margin); + poly.setPoint(4, w - margin, 0); + poly.setPoint(5, 0, 0); + + setPenFromSettings(painter); + if (UMLWidget::useFillColor()) { + QBrush brush(UMLWidget::fillColor()); + painter->setBrush(brush); + painter->drawPolygon(poly); + } else + painter->drawPolyline(poly); + painter->drawLine(w - margin, 0, w - margin, margin); + painter->drawLine(w - margin, margin, w, margin); + painter->setPen(textColor()); + switch(m_noteType) { + case NoteWidget::PreCondition : + painter->drawText(0, margin, w, fontHeight, Qt::AlignCenter, QLatin1String("<< precondition >>")); + break; + case NoteWidget::PostCondition : + painter->drawText(0, margin, w, fontHeight, Qt::AlignCenter, QLatin1String("<< postcondition >>")); + break; + case NoteWidget::Transformation : + painter->drawText(0, margin, w, fontHeight, Qt::AlignCenter, QLatin1String("<< transformation >>")); + break; + case NoteWidget::Normal : + default : + break; + } + + UMLWidget::paint(painter, option, widget); + +// paintText(&p, 0, 0); + paintTextWordWrap(painter); +} + +/** + * Returns the type of note. + */ +NoteWidget::NoteType NoteWidget::noteType() const +{ + return m_noteType; +} + +/** + * Converts a string to NoteWidget::NoteType. + */ +NoteWidget::NoteType NoteWidget::stringToNoteType(const QString& noteType) +{ + if (noteType == QLatin1String("Precondition")) + return NoteWidget::PreCondition; + else if (noteType == QLatin1String("Postcondition")) + return NoteWidget::PostCondition; + else if (noteType == QLatin1String("Transformation")) + return NoteWidget::Transformation; + else + return NoteWidget::Normal; +} + +/** + * Sets the type of note. + */ +void NoteWidget::setNoteType(NoteType noteType) +{ + m_noteType = noteType; +} + +/** + * Sets the type of note. + */ +void NoteWidget::setNoteType(const QString& noteType) +{ + setNoteType(stringToNoteType(noteType)); +} + +/** + * Return the ID of the diagram hyperlinked to this note. + * + * @return ID of an UMLView, or Uml::ID::None if no + * hyperlink is set. + */ +Uml::ID::Type NoteWidget::diagramLink() const +{ + return m_diagramLink; +} + +/** + * Set the ID of the diagram hyperlinked to this note. + * To switch off the hyperlink, set this to Uml::id_None. + * + * @param viewID ID of an UMLScene. + */ +void NoteWidget::setDiagramLink(Uml::ID::Type viewID) +{ + UMLDoc *umldoc = UMLApp::app()->document(); + UMLView *view = umldoc->findView(viewID); + if (view == NULL) { + uError() << "no view found for viewID " << Uml::ID::toString(viewID); + return; + } + QString linkText(QLatin1String("Diagram: ") + view->umlScene()->name()); + setDocumentation(linkText); + m_diagramLink = viewID; + update(); +} + +/** + * Display a dialog box to allow the user to choose the note's type. + */ +void NoteWidget::askForNoteType(UMLWidget* &targetWidget) +{ + static const QStringList list = QStringList() << i18n("Precondition") + << i18n("Postcondition") + << i18n("Transformation"); + bool pressedOK = false; + +#if QT_VERSION >= 0x050000 + QString type = QInputDialog::getItem (UMLApp::app(), + i18n("Note Type"), i18n("Select the Note Type"), list, + 0, false, &pressedOK); +#else + QString type = KInputDialog::getItem (i18n("Note Type"), i18n("Select the Note Type"), list, + 0, false, &pressedOK, UMLApp::app()); +#endif + + if (pressedOK) { + dynamic_cast(targetWidget)->setNoteType(type); + } else { + targetWidget->cleanup(); + delete targetWidget; + targetWidget = 0; + } +} + +/** + * Loads a "notewidget" XMI element. + */ +bool NoteWidget::loadFromXMI(QDomElement & qElement) +{ + if (!UMLWidget::loadFromXMI(qElement)) + return false; + setZValue(20); //make sure always on top. + setDocumentation(qElement.attribute(QLatin1String("text"))); + QString diagramlink = qElement.attribute(QLatin1String("diagramlink")); + if (!diagramlink.isEmpty()) + m_diagramLink = Uml::ID::fromString(diagramlink); + QString type = qElement.attribute(QLatin1String("noteType")); + setNoteType((NoteType)type.toInt()); + return true; +} + +/** + * Saves to the "notewidget" XMI element. + */ +void NoteWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +{ + QDomElement noteElement = qDoc.createElement(QLatin1String("notewidget")); + UMLWidget::saveToXMI(qDoc, noteElement); + noteElement.setAttribute(QLatin1String("text"), documentation()); + if (m_diagramLink != Uml::ID::None) + noteElement.setAttribute(QLatin1String("diagramlink"), Uml::ID::toString(m_diagramLink)); + noteElement.setAttribute(QLatin1String("noteType"), m_noteType); + qElement.appendChild(noteElement); +} + +/** + * Show a properties dialog for a NoteWidget. + */ +void NoteWidget::showPropertiesDialog() +{ + NoteDialog * dlg = 0; + UMLApp::app()->docWindow()->updateDocumentation(false); + dlg = new NoteDialog(umlScene()->activeView(), this); + if (dlg->exec()) { + UMLApp::app()->docWindow()->showDocumentation(this, true); + UMLApp::app()->document()->setModified(true); + update(); + } + delete dlg; +} + +/** + * Will be called when a menu selection has been made from the popup + * menu. + * + * @param action The action that has been selected. + */ +void NoteWidget::slotMenuSelection(QAction* action) +{ + ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); + switch(sel) { + case ListPopupMenu::mt_Rename: + showPropertiesDialog(); + break; + + default: + UMLWidget::slotMenuSelection(action); + break; + } +} + +/** + * Overrides method from UMLWidget. + */ +QSizeF NoteWidget::minimumSize() const +{ + int width = 60; + int height = 30; + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int textWidth = fm.width(documentation()); + if (m_noteType == PreCondition) { + const int widthtemp = fm.width(QLatin1String("<< precondition >>")); + width = textWidth > widthtemp ? textWidth : widthtemp; + width += 10; + } + else if (m_noteType == PostCondition) { + const int widthtemp = fm.width(QLatin1String("<< postcondition >>")); + width = textWidth > widthtemp ? textWidth : widthtemp; + width += 10; + } + else if (m_noteType == Transformation) { + const int widthtemp = fm.width(QLatin1String("<< transformation >>")); + width = textWidth > widthtemp ? textWidth : widthtemp; + width += 10; + } + return QSizeF(width, height); +} + +/** + * Calculate content related size of widget. + * Overrides method from UMLWidget. + */ +QSizeF NoteWidget::calculateSize(bool withExtensions /* = true */) const +{ + Q_UNUSED(withExtensions) + int width = this->width(); + int height = this->height(); + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int margin = fm.width(QLatin1String("W")); + QSize size = fm.size (0, documentation()); + const int textWidth = size.width(); + if (m_noteType == PreCondition) { + const int widthtemp = fm.width(QLatin1String("<< precondition >>")); + width = textWidth > widthtemp ? textWidth : widthtemp; + width += 2 * margin; + } + else if (m_noteType == PostCondition) { + const int widthtemp = fm.width(QLatin1String("<< postcondition >>")); + width = textWidth > widthtemp ? textWidth : widthtemp; + width += 2 * margin; + } + else if (m_noteType == Transformation) { + const int widthtemp = fm.width(QLatin1String("<< transformation >>")); + width = textWidth > widthtemp ? textWidth : widthtemp; + width += 2 * margin; + } + return QSizeF(width, height); +} + +/** + * Paints the text. Auxiliary to paint(). + * Implemented without word wrap. + */ +void NoteWidget::paintText(QPainter *painter) +{ + if (painter == 0) { + return; + } + + QString text = documentation(); + if (text.length() == 0) { + return; + } + + painter->setPen(Qt::black); + QFont font = UMLWidget::font(); + painter->setFont(font); + + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + const int margin = fm.width(QLatin1String("W")); + const QSize textSize = fm.size(Qt::TextExpandTabs, text); + + const int width = this->width() - margin * 2; + const int height = this->height() - fontHeight; + int textY = fontHeight / 2; + int textX = margin; + + if ((textSize.width() < width) && (textSize.height() < height)) { + // the entire text is small enough - draw it + painter->drawText(textX, textY, + textSize.width(), textSize.height(), + Qt::AlignLeft, text); + } + else { + // not all text can be drawn + QStringList lines = text.split(QLatin1Char('\n')); + foreach(const QString& line, lines) { + int lineWidth = fm.width(line); + if (lineWidth < width) { + // line is small enough - draw it + painter->drawText(textX, textY, + textSize.width(), fontHeight, + Qt::AlignLeft, line); + } + else { + // draw a smaller line + for(int len = line.length(); len > 0; --len) { + QString smallerLine = line.left(len); + int smallerLineWidth = fm.width(smallerLine); + if (smallerLineWidth < width) { + // line is small enough - draw it + painter->drawText(textX, textY, + width, fontHeight, + Qt::AlignLeft, smallerLine); + } + } + } + textY += fontHeight; + if (textY > height) { + // skip the next lines - size is not enough + break; + } + } + } +} + +/** + * Paints the text. Auxiliary to paint(). + * Implemented with word wrap. + */ +void NoteWidget::paintTextWordWrap(QPainter *painter) +{ + if (painter == 0) { + return; + } + QString text = documentation(); + if (text.length() == 0) { + return; + } + // Implement word wrap for text as follows: + // wrap at width on whole words. + // if word is wider than width then clip word + // if reach height exit and don't print anymore + // start new line on \n character + painter->setPen(Qt::black); + QFont font = UMLWidget::font(); + painter->setFont(font); + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + QString word; + QString fullLine; + QString testCombineLine; + const int margin = fm.width(QLatin1String("W")); + int textY = fontHeight / 2; + int textX = margin; + const int width = this -> width() - margin * 2; + const int height = this -> height() - fontHeight; + QChar returnChar = QChar::fromLatin1('\n'); + QChar c; + + for (int i = 0; i <= text.length(); ++i) { + if (i < text.length()) { + c = text[i]; + } else { + // all chars of text have been handled already -> + // perform this last run to spool current content of "word" + c = returnChar; + } + if (c == returnChar || c.isSpace()) { + // new word delimiter found -> it is time to decide on word wrap + testCombineLine = fullLine + QLatin1Char(' ') + word; + int textWidth = fm.width(testCombineLine); + if (textX + textWidth > width) { + // combination of "fullLine" and "word" doesn't fit into one line -> + // print "fullLine" in current line, update write position to next line + // and decide then on following actions + painter->drawText(textX, textY, + textWidth, fontHeight, Qt::AlignLeft, fullLine); + fullLine = word; + word = QString(); + // update write position + textX = margin; + textY += fontHeight; + if (textY > height) + return; + // in case of c==newline -> + // print "word" and set write position one additional line lower + if (c == returnChar) { + // print "word" - which is now "fullLine" and set to next line + painter->drawText(textX, textY, + textWidth, fontHeight, Qt::AlignLeft, fullLine); + fullLine = QString(); + textX = margin; + textY += fontHeight; + if(textY > height) return; + } + } + else if (c == returnChar) { + // newline found and combination of "fullLine" and "word" fits + // in one line + painter->drawText(textX, textY, + textWidth, fontHeight, Qt::AlignLeft, testCombineLine); + fullLine = word = QString(); + textX = margin; + textY += fontHeight; + if (textY > height) + return; + } else { + // word delimiter found, and combination of "fullLine", space and "word" fits into one line + fullLine = testCombineLine; + word = QString(); + } + } else { + // no word delimiter found --> add current char to "word" + if (c != QLatin1Char('\0')) + word += c; + } + }//end for +} + +/** + * Event handler for moude double click events. + * + * @param event The QGraphicsSceneMouseEvent event. + */ +void NoteWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) { + if (m_diagramLink == Uml::ID::None) { + showPropertiesDialog(); + } else { + UMLDoc *umldoc = UMLApp::app()->document(); + umldoc->changeCurrentView(m_diagramLink); + } + event->accept(); + } +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/notewidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/notewidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/notewidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/notewidget.h 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,83 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef NOTEWIDGET_H +#define NOTEWIDGET_H + +//app includes +#include "umlwidget.h" + +// Qt forward declarations +class QPainter; + +/** + * Displays a note box to allow multiple lines of text to be displayed. + * These widgets are diagram specific. They will still need a unique id + * from the @ref UMLDoc class for deletion and other purpose-kf6s. + * + * @short Displays a note box. + * @author Paul Hensgen + * @see UMLWidget + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class NoteWidget : public UMLWidget +{ + Q_OBJECT +public: + + /// This enum type is used to specify the type of note. + enum NoteType + { + Normal, + PreCondition, + PostCondition, + Transformation + }; + + explicit NoteWidget(UMLScene * scene, NoteWidget::NoteType noteType = Normal, + Uml::ID::Type id = Uml::ID::None); + virtual ~NoteWidget(); + + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + + static NoteType stringToNoteType(const QString& noteType); + + NoteType noteType() const; + void setNoteType(NoteType noteType); + void setNoteType(const QString& noteType); + + Uml::ID::Type diagramLink() const; + void setDiagramLink(Uml::ID::Type viewID); + + void askForNoteType(UMLWidget* &targetWidget); + + virtual void showPropertiesDialog(); + + virtual bool loadFromXMI(QDomElement & qElement); + virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); + + static NoteWidget *s_pCurrentNote; + +public Q_SLOTS: + void slotMenuSelection(QAction* action); + +protected: + virtual QSizeF minimumSize() const; + virtual QSizeF calculateSize(bool withExtensions = true) const; + void paintText(QPainter *painter); + void paintTextWordWrap(QPainter *painter); + virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); + +private: + Uml::ID::Type m_diagramLink; ///< The diagram/scene this note links to. + NoteType m_noteType; ///< The type of note. @see NoteWidget::NoteType +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/objectnodewidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/objectnodewidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/objectnodewidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/objectnodewidget.cpp 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,377 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "objectnodewidget.h" + +// app includes +#include "debug_utils.h" +#include "docwindow.h" +#include "dialog_utils.h" +#include "listpopupmenu.h" +#include "objectnodedialog.h" +#include "uml.h" +#include "umldoc.h" +#include "umlscene.h" +#include "umlview.h" + +// kde includes +#include +#if QT_VERSION < 0x050000 +#include +#endif + +// qt includes +#if QT_VERSION >= 0x050000 +#include +#endif +#include +#include + +#define OBJECTNODE_MARGIN 5 +#define OBJECTNODE_WIDTH 30 +#define OBJECTNODE_HEIGHT 10 + +/** + * Creates a Object Node widget. + * + * @param scene The parent of the widget. + * @param objectNodeType The type of object node + * @param id The ID to assign (-1 will prompt a new ID.) + */ +ObjectNodeWidget::ObjectNodeWidget(UMLScene * scene, ObjectNodeType objectNodeType, Uml::ID::Type id) + : UMLWidget(scene, WidgetBase::wt_ObjectNode, id) +{ + setObjectNodeType(objectNodeType); + setState(QString()); +} + +/** + * Destructor. + */ +ObjectNodeWidget::~ObjectNodeWidget() +{ +} + +/** + * Overrides the standard paint event. + */ +void ObjectNodeWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + int w = width(); + int h = height(); + + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + int textStartY = (h / 2) - (fontHeight / 2); + + setPenFromSettings(painter); + + if (UMLWidget::useFillColor()) { + painter->setBrush(UMLWidget::fillColor()); + } + + painter->drawRect(0, 0, w, h); + painter->setFont(UMLWidget::font()); + + switch (m_objectNodeType) + { + case Normal : break; + case Buffer : + { + painter->setPen(textColor()); + painter->drawText(OBJECTNODE_MARGIN, (textStartY/2), w - OBJECTNODE_MARGIN * 2, fontHeight, Qt::AlignHCenter, QLatin1String("<< centralBuffer >>")); + painter->drawText(OBJECTNODE_MARGIN, (textStartY/2) + fontHeight + 5, w - OBJECTNODE_MARGIN * 2, fontHeight, Qt::AlignHCenter, name()); + } + break; + case Data : + { + painter->setPen(textColor()); + painter->drawText(OBJECTNODE_MARGIN, (textStartY/2), w - OBJECTNODE_MARGIN * 2, fontHeight, Qt::AlignHCenter, QLatin1String("<< datastore >>")); + painter->drawText(OBJECTNODE_MARGIN, (textStartY/2) + fontHeight + 5, w - OBJECTNODE_MARGIN * 2, fontHeight, Qt::AlignHCenter, name()); + } + break; + case Flow : + { + QString objectflow_value; + if (state() == QLatin1String("-") || state().isEmpty()) + { + objectflow_value = QLatin1Char(' '); + } + else + { + objectflow_value = QLatin1Char('[') + state() + QLatin1Char(']'); + } + + painter->drawLine(10, h/2, w-10, h/2); + painter->setPen(textColor()); + painter->setFont(UMLWidget::font()); + painter->drawText(OBJECTNODE_MARGIN, textStartY/2 - OBJECTNODE_MARGIN, w - OBJECTNODE_MARGIN * 2, fontHeight, Qt::AlignHCenter, name()); + painter->drawText(OBJECTNODE_MARGIN, textStartY/2 + textStartY + OBJECTNODE_MARGIN, w - OBJECTNODE_MARGIN * 2, fontHeight, Qt::AlignHCenter, objectflow_value); + } + break; + } + + UMLWidget::paint(painter, option, widget); +} + +/** + * Overrides method from UMLWidget. + */ +QSizeF ObjectNodeWidget::minimumSize() const +{ + int widthtmp = 10, height = 10, width=10; + if (m_objectNodeType == Buffer) { + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + const int textWidth = fm.width(QLatin1String("<< centralBuffer >>")); + const int namewidth = fm.width(name()); + height = fontHeight * 2; + widthtmp = textWidth > OBJECTNODE_WIDTH ? textWidth : OBJECTNODE_WIDTH; + width = namewidth > widthtmp ? namewidth : widthtmp; + height = height > OBJECTNODE_HEIGHT ? height : OBJECTNODE_HEIGHT; + width += OBJECTNODE_MARGIN * 2; + height += OBJECTNODE_MARGIN * 2 + 5; + } else if (m_objectNodeType == Data) { + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + const int textWidth = fm.width(QLatin1String("<< datastore >>")); + const int namewidth = fm.width(name()); + height = fontHeight * 2; + widthtmp = textWidth > OBJECTNODE_WIDTH ? textWidth : OBJECTNODE_WIDTH; + width = namewidth > widthtmp ? namewidth : widthtmp; + height = height > OBJECTNODE_HEIGHT ? height : OBJECTNODE_HEIGHT; + width += OBJECTNODE_MARGIN * 2; + height += OBJECTNODE_MARGIN * 2 + 5; + } else if (m_objectNodeType == Flow) { + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + const int textWidth = fm.width(QLatin1Char('[') + state() + QLatin1Char(']')); + const int namewidth = fm.width(name()); + height = fontHeight * 2; + widthtmp = textWidth > OBJECTNODE_WIDTH ? textWidth : OBJECTNODE_WIDTH; + width = namewidth > widthtmp ? namewidth : widthtmp; + height = height > OBJECTNODE_HEIGHT ? height : OBJECTNODE_HEIGHT; + width += OBJECTNODE_MARGIN * 2; + height += OBJECTNODE_MARGIN * 4; + } + + return QSizeF(width, height); +} + +/** + * Returns the type of object node. + */ +ObjectNodeWidget::ObjectNodeType ObjectNodeWidget::objectNodeType() const +{ + return m_objectNodeType; +} + +/** + * Returns the type of object node. + */ +ObjectNodeWidget::ObjectNodeType ObjectNodeWidget::toObjectNodeType(const QString& type) +{ + if (type == QLatin1String("Central buffer")) + return ObjectNodeWidget::Buffer; + if (type == QLatin1String("Data store")) + return ObjectNodeWidget::Data; + if (type == QLatin1String("Object Flow")) + return ObjectNodeWidget::Flow; + // Shouldn't happen + Q_ASSERT(0); + return ObjectNodeWidget::Flow; +} + +/** + * Sets the type of object node. + */ +void ObjectNodeWidget::setObjectNodeType(ObjectNodeType objectNodeType) +{ + m_objectNodeType = objectNodeType; + UMLWidget::m_resizable = true; +} + +/** + * Sets the type of object node. + */ +void ObjectNodeWidget::setObjectNodeType(const QString& type) +{ + setObjectNodeType(ObjectNodeWidget::toObjectNodeType(type)); +} + +/** + * Sets the state of an object node when it's an objectflow. + */ +void ObjectNodeWidget::setState(const QString& state) +{ + m_state = state; + updateGeometry(); +} + +/** + * Returns the state of object node. + */ +QString ObjectNodeWidget::state() const +{ + return m_state; +} + +/** + * Captures any popup menu signals for menus it created. + */ +void ObjectNodeWidget::slotMenuSelection(QAction* action) +{ + ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); + switch(sel) { + case ListPopupMenu::mt_Rename: + { + bool ok = false; + QString text = name(); +#if QT_VERSION >= 0x050000 + text = QInputDialog::getText(Q_NULLPTR, + i18n("Enter Object Node Name"), + i18n("Enter the name of the object node :"), + QLineEdit::Normal, + name(), &ok); +#else + text = KInputDialog::getText(i18n("Enter Object Node Name"), + i18n("Enter the name of the object node :"), + name(), &ok); +#endif + if (ok && !text.isEmpty()) { + setName(text); + } + } + break; + + case ListPopupMenu::mt_Properties: + showPropertiesDialog(); + break; + + default: + UMLWidget::slotMenuSelection(action); + } +} + +/** + * Show a properties dialog for an ObjectNodeWidget. + */ +void ObjectNodeWidget::showPropertiesDialog() +{ + UMLApp::app()->docWindow()->updateDocumentation(false); + + QPointer dialog = new ObjectNodeDialog(UMLApp::app()->currentView(), this); + if (dialog->exec() && dialog->getChangesMade()) { + UMLApp::app()->docWindow()->showDocumentation(this, true); + UMLApp::app()->document()->setModified(true); + } + delete dialog; +} + +/** + * Saves the widget to the "objectnodewidget" XMI element. + */ +void ObjectNodeWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +{ + QDomElement objectNodeElement = qDoc.createElement(QLatin1String("objectnodewidget")); + UMLWidget::saveToXMI(qDoc, objectNodeElement); + objectNodeElement.setAttribute(QLatin1String("objectnodename"), m_Text); + objectNodeElement.setAttribute(QLatin1String("documentation"), m_Doc); + objectNodeElement.setAttribute(QLatin1String("objectnodetype"), m_objectNodeType); + objectNodeElement.setAttribute(QLatin1String("objectnodestate"), m_state); + qElement.appendChild(objectNodeElement); +} + +/** + * Loads the widget from the "objectnodewidget" XMI element. + */ +bool ObjectNodeWidget::loadFromXMI(QDomElement& qElement) +{ + if(!UMLWidget::loadFromXMI(qElement) ) + return false; + m_Text = qElement.attribute(QLatin1String("objectnodename")); + m_Doc = qElement.attribute(QLatin1String("documentation")); + QString type = qElement.attribute(QLatin1String("objectnodetype"), QLatin1String("1")); + m_state = qElement.attribute(QLatin1String("objectnodestate")); + setObjectNodeType((ObjectNodeType)type.toInt()); + return true; +} + +/** + * Open a dialog box to select the objectNode type (Data, Buffer or Flow). + */ +void ObjectNodeWidget::askForObjectNodeType(UMLWidget* &targetWidget) +{ + bool pressedOK = false; + int current = 0; + const QStringList list = QStringList() + << QLatin1String("Central buffer") + << QLatin1String("Data store") + << QLatin1String("Object Flow"); + +#if QT_VERSION >= 0x050000 + QString type = QInputDialog::getItem (UMLApp::app(), + i18n("Select Object node type"), i18n("Select the object node type"), + list, current, false, &pressedOK); + +#else + QString type = KInputDialog::getItem (i18n("Select Object node type"), i18n("Select the object node type"), list, current, false, &pressedOK, UMLApp::app()); +#endif + + if (pressedOK) { + dynamic_cast(targetWidget)->setObjectNodeType(type); + if (type == QLatin1String("Data store")) + Dialog_Utils::askNameForWidget(targetWidget, i18n("Enter the name of the data store node"), i18n("Enter the name of the data store node"), i18n("data store name")); + if (type == QLatin1String("Central buffer")) + Dialog_Utils::askNameForWidget(targetWidget, i18n("Enter the name of the buffer node"), i18n("Enter the name of the buffer"), i18n("centralBuffer")); + if (type == QLatin1String("Object Flow")) { + Dialog_Utils::askNameForWidget(targetWidget, i18n("Enter the name of the object flow"), i18n("Enter the name of the object flow"), i18n("object flow")); + askStateForWidget(); + } + } else { + targetWidget->cleanup(); + delete targetWidget; + targetWidget = NULL; + } +} + +/** + * Open a dialog box to input the state of the widget. + * This box is shown only if m_objectNodeType = Flow. + */ +void ObjectNodeWidget::askStateForWidget() +{ + bool pressedOK = false; +#if QT_VERSION >= 0x050000 + QString state = QInputDialog::getText(UMLApp::app(), + i18n("Enter Object Flow State"), i18n("Enter State (keep '-' if there is no state for the object) "), + QLineEdit::Normal, + i18n("-"), &pressedOK); +#else + QString state = KInputDialog::getText(i18n("Enter Object Flow State"), i18n("Enter State (keep '-' if there is no state for the object) "), i18n("-"), &pressedOK, UMLApp::app()); +#endif + + if (pressedOK) { + setState(state); + } else { + cleanup(); + } +} + +void ObjectNodeWidget::slotOk() +{ + // kdialog-kf6::accept(); +} + + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/objectnodewidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/objectnodewidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/objectnodewidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/objectnodewidget.h 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,76 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef OBJECTNODEWIDGET_H +#define OBJECTNODEWIDGET_H + +#include "umlwidget.h" + +/** + * This class is the graphical version of a UML Object Node. A ObjectNodeWidget is created + * by a @ref UMLView. An ObjectNodeWidget belongs to only one @ref UMLView instance. + * When the @ref UMLView instance that this class belongs to, it will be automatically deleted. + * + * The ObjectNodeWidget class inherits from the @ref UMLWidget class which adds most of the functionality + * to this class. + * + * @short A graphical version of a UML Activity. + * @author Florence Mattler + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class ObjectNodeWidget : public UMLWidget +{ + Q_OBJECT + +public: + enum ObjectNodeType + { + Normal, + Data, + Buffer, + Flow + }; + + explicit ObjectNodeWidget(UMLScene * scene, ObjectNodeType objectNodeType = Normal, Uml::ID::Type id = Uml::ID::None); + virtual ~ObjectNodeWidget(); + + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + + ObjectNodeType objectNodeType() const; + static ObjectNodeType toObjectNodeType(const QString& type); + + void setObjectNodeType(ObjectNodeType objectNodeType); + void setObjectNodeType(const QString& type) ; + + void setState(const QString& state); + QString state() const; + + virtual void showPropertiesDialog(); + + void askStateForWidget(); + void askForObjectNodeType(UMLWidget* &targetWidget); + + virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); + virtual bool loadFromXMI(QDomElement& qElement); + +protected: + QSizeF minimumSize() const; + +public slots: + void slotMenuSelection(QAction* action); + void slotOk(); + +private: + ObjectNodeType m_objectNodeType; ///< type of object node + QString m_state; ///< state of object node when it's an objectFlow + +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/objectwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/objectwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/objectwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/objectwidget.cpp 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,710 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header file +#include "objectwidget.h" + +// local includes +#include "classpropertiesdialog.h" +#include "debug_utils.h" +#include "docwindow.h" +#include "listpopupmenu.h" +#include "messagewidget.h" +#include "seqlinewidget.h" +#include "uml.h" +#include "umldoc.h" +#include "umlobject.h" +#include "umlscene.h" +#include "umlview.h" + +// kde includes +#include +#if QT_VERSION < 0x050000 +#include +#endif + +// qt includes +#if QT_VERSION >= 0x050000 +#include +#endif +#include +#include +#include + +#define O_MARGIN 5 +#define O_WIDTH 40 +#define A_WIDTH 20 +#define A_HEIGHT 40 +#define A_MARGIN 5 + +DEBUG_REGISTER_DISABLED(ObjectWidget) + +/** + * The number of pixels margin between the lowest message + * and the bottom of the vertical line + */ +static const int sequenceLineMargin = 20; + +/** + * Creates an ObjectWidget. + * + * @param scene The parent to this object. + * @param o The object it will be representing. + */ +ObjectWidget::ObjectWidget(UMLScene * scene, UMLObject *o) + : UMLWidget(scene, WidgetBase::wt_Object, o), + m_multipleInstance(false), + m_drawAsActor(false), + m_showDestruction(false), + m_isOnDestructionBox(false) +{ + if (m_scene && (m_scene->type() == Uml::DiagramType::Sequence)) { + m_pLine = new SeqLineWidget( m_scene, this ); + m_pLine->setStartPoint(x() + width() / 2, y() + height()); + } else { + m_pLine = 0; + } +} + +/** + * Destructor. + */ +ObjectWidget::~ObjectWidget() +{ + cleanup(); +} + +/** + * Sets whether representing a multi-instance object. + * + * @param multiple Object state. true- multi, false - single. + */ +void ObjectWidget::setMultipleInstance(bool multiple) +{ + //make sure only calling this in relation to an object on a collab. diagram + if (m_scene && (m_scene->type() == Uml::DiagramType::Collaboration)) { + m_multipleInstance = multiple; + updateGeometry(); + update(); + } +} + +/** + * Returns whether object is representing a multi-object. + * + * @return True if object is representing a multi-object. + */ +bool ObjectWidget::multipleInstance() const +{ + return m_multipleInstance; +} + +/** + * Overridden from UMLWidget. + * Moves the widget to a new position using the difference between the + * current position and the new position. + * Y position is ignored, and widget is only moved along X axis. + * + * @param diffX The difference between current X position and new X position. + * @param diffY The difference between current Y position and new Y position + * (isn't used). + */ +void ObjectWidget::moveWidgetBy(qreal diffX, qreal diffY) +{ + setX(x() + diffX); + if (m_scene && (m_scene->type() != Uml::DiagramType::Sequence)) { + setY(y() + diffY); + } +} + +/** + * Overridden from UMLWidget. + * Modifies the value of the diffX and diffY variables used to move the widgets. + * All the widgets are constrained to be moved only in X axis (diffY is set to 0). + * + * @param diffX The difference between current X position and new X position. + * @param diffY The difference between current Y position and new Y position. + */ +void ObjectWidget::constrainMovementForAllWidgets(qreal &diffX, qreal &diffY) +{ + Q_UNUSED(diffX); + if (m_scene && (m_scene->type() == Uml::DiagramType::Sequence)) { + diffY = 0; + } +} + +/** + * Override default method. + */ +void ObjectWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + if (m_drawAsActor) + paintActor(painter); + else + paintObject(painter); + + setPenFromSettings(painter); + + UMLWidget::paint(painter, option, widget); +} + +/** + * Handles a popup menu selection. + */ +void ObjectWidget::slotMenuSelection(QAction* action) +{ + ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); + switch(sel) { + case ListPopupMenu::mt_Rename_Object: + { + bool ok; + QRegExpValidator* validator = new QRegExpValidator(QRegExp(QLatin1String(".*")), 0); +#if QT_VERSION >= 0x050000 + QString name = QInputDialog::getText(m_scene->activeView(), + i18n("Rename Object"), + i18n("Enter object name:"), + QLineEdit::Normal, + m_instanceName, + &ok); +#else + QString name = KInputDialog::getText + (i18n("Rename Object"), + i18n("Enter object name:"), + m_instanceName, + &ok, + m_scene->activeView(), + validator); +#endif + if (ok) { + m_instanceName = name; + updateGeometry(); + moveEvent(0); + update(); + UMLApp::app()->document()->setModified(true); + } + delete validator; + break; + } + case ListPopupMenu::mt_Properties: + showPropertiesDialog(); + updateGeometry(); + moveEvent(0); + update(); + break; + + case ListPopupMenu::mt_Up: + tabUp(); + break; + + case ListPopupMenu::mt_Down: + tabDown(); + break; + + default: + UMLWidget::slotMenuSelection(action); + break; + } +} + +/** + * Overrides method from UMLWidget + */ +QSizeF ObjectWidget::minimumSize() const +{ + int width, height; + const QFontMetrics &fm = getFontMetrics(FT_UNDERLINE); + const int fontHeight = fm.lineSpacing(); + const QString t = m_instanceName + QLatin1String(" : ") + name(); + const int textWidth = fm.width(t); + if (m_drawAsActor) { + width = textWidth > A_WIDTH?textWidth:A_WIDTH; + height = A_HEIGHT + fontHeight + A_MARGIN; + width += A_MARGIN * 2; + } else { + width = textWidth > O_WIDTH?textWidth:O_WIDTH; + height = fontHeight + O_MARGIN * 2; + width += O_MARGIN * 2; + if (m_multipleInstance) { + width += 10; + height += 10; + } + }//end else drawasactor + + return QSizeF(width, height); +} + +/** + * Sets whether to draw as an Actor. + * + * @param drawAsActor True if widget shall be drawn as an actor. + */ +void ObjectWidget::setDrawAsActor(bool drawAsActor) +{ + m_drawAsActor = drawAsActor; + updateGeometry(); +} + +/** + * Returns whether to draw as an Actor or not. + * + * @return True if widget is drawn as an actor. + */ +bool ObjectWidget::drawAsActor() const +{ + return m_drawAsActor; +} + +/** + * Activate the object after serializing it from a QDataStream + */ +bool ObjectWidget::activate(IDChangeLog* ChangeLog /*= 0*/) +{ + if (! UMLWidget::activate(ChangeLog)) + return false; + if (m_showDestruction && m_pLine) + m_pLine->setupDestructionBox(); + moveEvent(0); + return true; +} + +/** + * Sets the x-coordinate. + * Reimplements the method from UMLWidget. + * + * @param x The x-coordinate to be set. + */ +void ObjectWidget::setX(qreal x) +{ + UMLWidget::setX(x); + moveEvent(0); +} + +/** + * Sets the y-coordinate. + * Reimplements the method from UMLWidget. + * + * @param y The y-coordinate to be set. + */ +void ObjectWidget::setY(qreal y) +{ + UMLWidget::setY(y); + if (!UMLApp::app()->document()->loading()) + moveEvent(0); +} + +/** + * Return the x coordinate of the widgets center. + * @return The x-coordinate of the widget center. + */ +qreal ObjectWidget::centerX() +{ + return x() + width()/2; +} + +/** + * Overrides the standard operation. + */ +void ObjectWidget::moveEvent(QGraphicsSceneMouseEvent *event) +{ + Q_UNUSED(event) + emit sigWidgetMoved(m_nLocalID); + if (m_pLine) { + m_pLine->setStartPoint(x() + width() / 2, y() + height()); + } +} + +/** + * Overrides the standard operation. + */ +void ObjectWidget::mousePressEvent(QGraphicsSceneMouseEvent *me) +{ + UMLWidget::mousePressEvent(me); + m_isOnDestructionBox = false; + if (m_pLine && m_pLine->onDestructionBox(me->scenePos())) { + m_isOnDestructionBox = true; + qreal oldX = x() + width() / 2; + qreal oldY = getEndLineY() - 10; + m_oldPos = QPointF(oldX, oldY); + } +} + +/** + * Overrides the standard operation. + */ +void ObjectWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* me) +{ + if (m_inResizeArea) { + DEBUG(DBG_SRC) << "resizing..."; + resize(me); + moveEvent(0); + return; + } + + if (m_isOnDestructionBox) { + qreal diffY = me->scenePos().y() - m_oldPos.y(); + moveDestructionBy(diffY); + } + else { + UMLWidget::mouseMoveEvent(me); + } +} + +/** + * Moves the destruction Box to a new position using the difference between the + * current position and the new position. + * The destruction box is only moved along Y axis. + * + * @param diffY The difference between current Y position and new Y position + */ +void ObjectWidget::moveDestructionBy(qreal diffY) +{ + // endLine = length of the life line + diffY - 10 to center on the destruction box + qreal endLine = getEndLineY() + diffY - 10; + SeqLineWidget *pLine = sequentialLine(); + pLine->setEndOfLine(endLine); + m_oldPos.setY(endLine); +} + +/** + * Handles a color change signal. + */ +void ObjectWidget::slotFillColorChanged(Uml::ID::Type /*viewID*/) +{ + UMLWidget::setFillColor(m_scene->fillColor()); + UMLWidget::setLineColor(m_scene->lineColor()); + + if(m_pLine) + m_pLine->setPen(QPen(UMLWidget::lineColor(), UMLWidget::lineWidth(), Qt::DashLine)); +} + +/** + * Used to cleanup any other widget it may need to delete. + */ +void ObjectWidget::cleanup() +{ + UMLWidget::cleanup(); + if(m_pLine) { + m_pLine->cleanup(); + delete m_pLine; + m_pLine = 0; + } +} + +/** + * Show a properties dialog for an ObjectWidget. + */ +void ObjectWidget::showPropertiesDialog() +{ + UMLApp::app()->docWindow()->updateDocumentation(false); + QPointer dlg = new ClassPropertiesDialog((QWidget*)UMLApp::app(), this); + if (dlg->exec()) { + UMLApp::app()->docWindow()->showDocumentation(this, true); + UMLApp::app()->document()->setModified(true); + } + dlg->close(); + delete dlg; +} + +/** + * Draw the object as an object (default). + */ +void ObjectWidget::paintObject(QPainter *painter) +{ + QFont oldFont = painter->font(); + QFont font = UMLWidget::font(); + font.setUnderline(true); + painter->setFont(font); + + setPenFromSettings(painter); + if(UMLWidget::useFillColor()) + painter->setBrush(UMLWidget::fillColor()); + else + painter->setBrush(m_scene->backgroundColor()); + const int w = width(); + const int h = height(); + + const QString t = m_instanceName + QLatin1String(" : ") + name(); + int multiInstOfst = 0; + if (m_multipleInstance) { + painter->drawRect(10, 10, w - 10, h - 10); + painter->drawRect(5, 5, w - 10, h - 10); + multiInstOfst = 10; + } + painter->drawRect(0, 0, w - multiInstOfst, h - multiInstOfst); + painter->setPen(textColor()); + painter->drawText(O_MARGIN, O_MARGIN, + w - O_MARGIN * 2 - multiInstOfst, h - O_MARGIN * 2 - multiInstOfst, + Qt::AlignCenter, t); + + painter->setFont(oldFont); +} + +/** + * Draw the object as an actor. + */ +void ObjectWidget::paintActor(QPainter *painter) +{ + const QFontMetrics &fm = getFontMetrics(FT_UNDERLINE); + + setPenFromSettings(painter); + if (UMLWidget::useFillColor()) + painter->setBrush(UMLWidget::fillColor()); + const int w = width(); + const int textStartY = A_HEIGHT + A_MARGIN; + const int fontHeight = fm.lineSpacing(); + + const int middleX = w / 2; + const int thirdH = A_HEIGHT / 3; + + //draw actor + painter->drawEllipse(middleX - A_WIDTH / 2, 0, A_WIDTH, thirdH);//head + painter->drawLine(middleX, thirdH, middleX, thirdH * 2);//body + painter->drawLine(middleX, 2 * thirdH, + middleX - A_WIDTH / 2, A_HEIGHT);//left leg + painter->drawLine(middleX, 2 * thirdH, + middleX + A_WIDTH / 2, A_HEIGHT);//right leg + painter->drawLine(middleX - A_WIDTH / 2, thirdH + thirdH / 2, + middleX + A_WIDTH / 2, thirdH + thirdH / 2);//arms + //draw text + painter->setPen(textColor()); + QString t = m_instanceName + QLatin1String(" : ") + name(); + painter->drawText(A_MARGIN, textStartY, + w - A_MARGIN * 2, fontHeight, Qt::AlignCenter, t); +} + +/** + * Move the object up on a sequence diagram. + */ +void ObjectWidget::tabUp() +{ + int newY = y() - height(); + if (newY < topMargin()) + newY = topMargin(); + setY(newY); + adjustAssocs(x(), newY); +} + +/** + * Move the object down on a sequence diagram. + */ +void ObjectWidget::tabDown() +{ + int newY = y() + height(); + setY(newY); + adjustAssocs(x(), newY); +} + +/** + * Returns the top margin constant (Y axis value) + * + * @return Y coordinate of the space between the diagram top + * and the upper edge of the ObjectWidget. + */ +int ObjectWidget::topMargin() +{ + return 80 - height(); +} + +/** + * Returns whether or not the widget can be moved vertically up. + * + * @return True if widget can be moved upwards vertically. + */ +bool ObjectWidget::canTabUp() +{ + return (y() > topMargin()); +} + +/** + * Sets whether to show deconstruction on sequence line. + * + * @param bShow True if destruction on line shall be shown. + */ +void ObjectWidget::setShowDestruction(bool bShow) +{ + m_showDestruction = bShow; + if(m_pLine) + m_pLine->setupDestructionBox(); +} + +/** + * Returns whether to show deconstruction on sequence line. + * + * @return True if destruction on sequence line is shown. + */ +bool ObjectWidget::showDestruction() const +{ + return m_showDestruction; +} + +/** + * Sets the y position of the bottom of the vertical line. + * + * @param yPosition The y coordinate for the bottom of the line. + */ +void ObjectWidget::setEndLine(int yPosition) +{ + if (m_pLine) { + m_pLine->setEndOfLine(yPosition); + } +} + +/** + * Returns the end Y co-ord of the sequence line. + * + * @return Y coordinate of the endpoint of the sequence line. + */ +int ObjectWidget::getEndLineY() +{ + int y = this->y() + height(); + if(m_pLine) + y += m_pLine->getLineLength(); + if (m_showDestruction) + y += 10; + return y; +} + +/** + * Add a message widget to the list. + * + * @param message Pointer to the MessageWidget to add. + */ +void ObjectWidget::messageAdded(MessageWidget* message) +{ + if (m_messages.count(message)) { + uError() << message->name() << ": duplicate entry !"; + return ; + } + m_messages.append(message); +} + +/** + * Remove a message widget from the list. + * + * @param message Pointer to the MessageWidget to remove. + */ +void ObjectWidget::messageRemoved(MessageWidget* message) +{ + if (m_messages.removeAll(message) == false) { + uError() << message->name() << ": missing entry !"; + return ; + } +} + +/** + * Called when a message widget with an end on this object has + * moved up or down. + * Sets the bottom of the line to a nice position. + */ +void ObjectWidget::slotMessageMoved() +{ + if (m_pLine) { + int lowestMessage = 0; + foreach (MessageWidget* message, m_messages) { + int messageHeight = message->y() + message->height(); + if (lowestMessage < messageHeight) { + lowestMessage = messageHeight; + } + } + m_pLine->setEndOfLine(lowestMessage + sequenceLineMargin); + } +} + +/** + * Returns whether a message is overlapping with another message. + * Used by MessageWidget::paint() methods. + * + * @param y top of your message + * @param messageWidget pointer to your message so it doesn't check against itself + */ +bool ObjectWidget::messageOverlap(qreal y, MessageWidget* messageWidget) +{ + foreach (MessageWidget* message, m_messages) { + if (message == messageWidget) { + continue; + } + const qreal msgY = message->y(); + const qreal msgHeight = msgY + message->height(); + if (y >= msgY && y <= msgHeight) { + return true; + } + } + return false; +} + +/** + * Return the SeqLineWidget. + * Returns a non NULL pointer if this ObjectWidget is part of a + * sequence diagram. + */ +SeqLineWidget *ObjectWidget::sequentialLine() const +{ + return m_pLine; +} + +/** + * Overridden from UMLWidget. + * Returns the cursor to be shown when resizing the widget. + * The cursor shown is KCursor::sizeHorCursor(). + * + * @return The cursor to be shown when resizing the widget. + */ +QCursor ObjectWidget::resizeCursor() const +{ + return Qt::SizeHorCursor; +} + +/** + * Overridden from UMLWidget. + * Resizes the width of the object widget. + * Object widgets can only be resized horizontally, so height isn't modified. + * + * @param newW The new width for the widget. + * @param newH The new height for the widget (isn't used). + */ +void ObjectWidget::resizeWidget(qreal newW, qreal newH) +{ + Q_UNUSED(newH); + setSize(newW, height()); +} + +/** + * Saves to the "objectwidget" XMI element. + */ +void ObjectWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +{ + QDomElement objectElement = qDoc.createElement(QLatin1String("objectwidget")); + UMLWidget::saveToXMI(qDoc, objectElement); + objectElement.setAttribute(QLatin1String("drawasactor"), m_drawAsActor); + objectElement.setAttribute(QLatin1String("multipleinstance"), m_multipleInstance); + objectElement.setAttribute(QLatin1String("decon"), m_showDestruction); + qElement.appendChild(objectElement); +} + +/** + * Loads from a "objectwidget" XMI element. + */ +bool ObjectWidget::loadFromXMI(QDomElement& qElement) +{ + if(!UMLWidget::loadFromXMI(qElement)) + return false; + QString draw = qElement.attribute(QLatin1String("drawasactor"), QLatin1String("0")); + QString multi = qElement.attribute(QLatin1String("multipleinstance"), QLatin1String("0")); + QString decon = qElement.attribute(QLatin1String("decon"), QLatin1String("0")); + + m_drawAsActor = (bool)draw.toInt(); + m_multipleInstance = (bool)multi.toInt(); + m_showDestruction = (bool)decon.toInt(); + return true; +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/objectwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/objectwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/objectwidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/objectwidget.h 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,115 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef OBJECTWIDGET_H +#define OBJECTWIDGET_H + +#include "messagewidgetlist.h" +#include "umlwidget.h" + +class MessageWidget; +class SeqLineWidget; +class UMLScene; + +/** + * Displays an instance UMLObject of a concept. + * + * The local ID is needed as a it can represent a class + * that has many objects representing it. + * + * @short Displays an instance of a Concept. + * @author Paul Hensgen + * @see UMLWidget + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class ObjectWidget : public UMLWidget +{ + Q_OBJECT +public: + ObjectWidget(UMLScene *scene, UMLObject *o); + virtual ~ObjectWidget(); + + virtual void setX(qreal x); + virtual void setY(qreal y); + + qreal centerX(); + + void setMultipleInstance(bool multiple); + bool multipleInstance() const; + + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + + bool activate(IDChangeLog* ChangeLog = 0); + + void cleanup(); + + void showPropertiesDialog(); + + void setDrawAsActor(bool drawAsActor); + bool drawAsActor() const; + + void setShowDestruction(bool bShow); + bool showDestruction() const; + + int topMargin(); + + void setEndLine(int yPosition); + int getEndLineY(); + + void messageAdded(MessageWidget* message); + void messageRemoved(MessageWidget* message); + + bool canTabUp(); + + bool messageOverlap(qreal y, MessageWidget* messageWidget); + + SeqLineWidget *sequentialLine() const; + + virtual void resizeWidget(qreal newW, qreal newH); + + virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); + virtual bool loadFromXMI(QDomElement& qElement); + +public slots: + void slotMenuSelection(QAction* action); + virtual void slotFillColorChanged(Uml::ID::Type viewID); + void slotMessageMoved(); + +protected: + virtual void mousePressEvent(QGraphicsSceneMouseEvent *me); + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *me); + + QSizeF minimumSize() const; + + virtual void moveEvent(QGraphicsSceneMouseEvent *event); + virtual void moveWidgetBy(qreal diffX, qreal diffY); + virtual void constrainMovementForAllWidgets(qreal &diffX, qreal &diffY); + + virtual QCursor resizeCursor() const; + + void paintActor(QPainter *p); + void paintObject(QPainter *p); + +private: + void tabUp(); + void tabDown(); + + void moveDestructionBy(qreal diffY); + + SeqLineWidget* m_pLine; + bool m_multipleInstance; ///< draw an object as a multiple object + bool m_drawAsActor; ///< object should be drawn as an Actor or an Object + bool m_showDestruction; ///< show object destruction on sequence diagram line + bool m_isOnDestructionBox; ///< true when a click occurred on the destruction box + MessageWidgetList m_messages; ///< message widgets with an end on this widget + +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/packagewidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/packagewidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/packagewidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/packagewidget.cpp 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,149 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "packagewidget.h" + +// app includes +#include "debug_utils.h" +#include "package.h" +#include "uml.h" +#include "umldoc.h" +#include "umlobject.h" +#include "umlscene.h" +#include "umlview.h" + +// qt includes +#include + +/** + * Constructs a PackageWidget. + * + * @param scene The parent of this PackageWidget. + * @param o The UMLObject this will be representing. + */ +PackageWidget::PackageWidget(UMLScene * scene, UMLPackage *o) + : UMLWidget(scene, WidgetBase::wt_Package, o), + m_pMenu(0) +{ + setSize(100, 30); + setZValue(1); // above box but below UMLWidget because may embed widgets + //set defaults from m_scene + if (m_scene) { + //check to see if correct + const Settings::OptionState& ops = m_scene->optionState(); + m_showStereotype = ops.classState.showStereoType; + } +} + +/** + * Destructor. + */ +PackageWidget::~PackageWidget() +{ +} + +/** + * Overrides standard method. + */ +void PackageWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + setPenFromSettings(painter); + if (UMLWidget::useFillColor()) + painter->setBrush(UMLWidget::fillColor()); + else + painter->setBrush(m_scene->backgroundColor()); + + int w = width(); + int h = height(); + QFont font = UMLWidget::font(); + font.setBold(true); + //FIXME italic is true when a package is first created until you click elsewhere, not sure why + font.setItalic(false); + const QFontMetrics &fm = getFontMetrics(FT_BOLD); + const int fontHeight = fm.lineSpacing(); + + painter->drawRect(0, 0, 50, fontHeight); + if (m_umlObject != NULL + && m_umlObject->stereotype() == QLatin1String("subsystem")) { + + const int fHalf = fontHeight / 2; + const int symY = fHalf; + const int symX = 38; + painter->drawLine(symX, symY, symX, symY + fHalf - 2); // left leg + painter->drawLine(symX + 8, symY, symX + 8, symY + fHalf - 2); // right leg + painter->drawLine(symX, symY, symX + 8, symY); // waist + painter->drawLine(symX + 4, symY, symX + 4, symY - fHalf + 2); // head + } + painter->drawRect(0, fontHeight - 1, w, h - fontHeight); + + painter->setPen(textColor()); + painter->setFont(font); + + int lines = 1; + if (m_umlObject != NULL) { + QString stereotype = m_umlObject->stereotype(); + if (!stereotype.isEmpty()) { + painter->drawText(0, fontHeight + PACKAGE_MARGIN, + w, fontHeight, Qt::AlignCenter, m_umlObject->stereotype(true)); + lines = 2; + } + } + + painter->drawText(0, (fontHeight*lines) + PACKAGE_MARGIN, + w, fontHeight, Qt::AlignCenter, name()); + + UMLWidget::paint(painter, option, widget); +} + +/** + * Overrides method from UMLWidget + */ +QSizeF PackageWidget::minimumSize() const +{ + if (!m_umlObject) { + return UMLWidget::minimumSize(); + } + + const QFontMetrics &fm = getFontMetrics(FT_BOLD_ITALIC); + const int fontHeight = fm.lineSpacing(); + + int lines = 1; + + int width = fm.width(m_umlObject->name()); + + int tempWidth = 0; + if (!m_umlObject->stereotype().isEmpty()) { + tempWidth = fm.width(m_umlObject->stereotype(true)); + lines = 2; + } + if (tempWidth > width) + width = tempWidth; + width += PACKAGE_MARGIN * 2; + if (width < 70) + width = 70; // minumin width of 70 + + int height = (lines*fontHeight) + fontHeight + (PACKAGE_MARGIN * 2); + + return QSizeF(width, height); +} + +/** + * Saves to the "packagewidget" XMI element. + */ +void PackageWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +{ + QDomElement conceptElement = qDoc.createElement(QLatin1String("packagewidget")); + UMLWidget::saveToXMI(qDoc, conceptElement); + qElement.appendChild(conceptElement); +} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/packagewidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/packagewidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/packagewidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/packagewidget.h 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,47 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef PACKAGEWIDGET_H +#define PACKAGEWIDGET_H + +#include "umlwidget.h" + +class UMLPackage; +class ListPopupMenu; + +#define PACKAGE_MARGIN 5 + +/** + * Defines a graphical version of the Package. Most of the + * functionality will come from the @ref UMLPackage class. + * + * @short A graphical version of a Package. + * @author Jonathan Riddell + * @see UMLWidget + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class PackageWidget : public UMLWidget +{ +public: + explicit PackageWidget(UMLScene * scene, UMLPackage * o); + virtual ~PackageWidget(); + + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + + void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); + +protected: + QSizeF minimumSize() const; + +private: + ListPopupMenu* m_pMenu; ///< the right mouse button menu +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/pinportbase.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/pinportbase.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/pinportbase.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/pinportbase.cpp 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,378 @@ +/*************************************************************************** + * 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) 2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "pinportbase.h" + +// app includes +#include "port.h" +#include "package.h" +#include "debug_utils.h" +#include "umldoc.h" +#include "umlscene.h" +#include "umlview.h" +#include "floatingtextwidget.h" + +// qt includes +#include +#include + +// sys includes +#include + +PinPortBase::PinPortBase(UMLScene *scene, WidgetType type, UMLObject *o) + : UMLWidget(scene, type, o) +{ + init(); +} + +PinPortBase::PinPortBase(UMLScene *scene, WidgetType type, UMLWidget *a, Uml::ID::Type id) + : UMLWidget(scene, type, id) +{ + init(a); +} + +/** + * Standard destructor. + */ +PinPortBase::~PinPortBase() +{ +} + +/** + * Performs initializations which are common to PinWidget and PortWidget. + */ +void PinPortBase::init(UMLWidget *owner) +{ + m_ignoreSnapToGrid = true; + m_ignoreSnapComponentSizeToGrid = true; + m_resizable = false; + m_pOw = owner; + m_pName = NULL; + m_motionConnected = false; + const int edgeLength = 15; // old: (m_baseType == wt_Pin ? 10 : 15); + const QSizeF FixedSize(edgeLength, edgeLength); + setMinimumSize(FixedSize); + setMaximumSize(FixedSize); + setSize(FixedSize); +} + +UMLWidget* PinPortBase::ownerWidget() +{ + return m_pOw; +} + +/** + * Overrides method from UMLWidget in order to set a tooltip. + * The tooltip is set to the name(). + * The reason for using a tooltip for the name is that the size of this + * widget is not large enough to accommodate the average name. + */ +void PinPortBase::updateWidget() +{ + QString strName = name(); + uDebug() << " port name is " << strName; + if (m_pName) { + m_pName->setText(strName); + } else { + setToolTip(strName); + } +} + +/** + * Overrides method from UMLWidget to set the name. + */ +void PinPortBase::setName(const QString &strName) +{ + UMLWidget::setName(strName); + updateGeometry(); + if (m_pName) { + m_pName->setText(strName); + } +} + +/** + * Overridden from UMLWidget. + * Moves the widget to a new position using the difference between the + * current position and the new position. + * Movement is constrained such that the port is always attached to its + * owner widget. + * + * @param diffX The difference between current X position and new X position. + * @param diffY The difference between current Y position and new Y position. + */ +void PinPortBase::moveWidgetBy(qreal diffX, qreal diffY) +{ + UMLWidget* owner = ownerWidget(); + qreal newX = x() + diffX; + qreal newY = y() + diffY; + uDebug() << "PinPortBase::moveWidgetBy " << diffX << "," << diffY; + if (owner == NULL) { + uError() << "PinPortBase::moveWidgetBy: ownerWidget() returns NULL"; + setX(newX); + setY(newY); + return; + } + const qreal deltaTop = fabs(y() + height() - owner->y()); + const qreal deltaBottom = fabs(owner->y() + owner->height() - y()); + const qreal deltaLeft = fabs(x() + width() - owner->x()); + const qreal deltaRight = fabs(owner->x() + owner->width() - x()); + bool didAnyMovement = false; + if (deltaTop < 1.0 || deltaBottom < 1.0) { + if (newX < owner->x() - width()) + newX = owner->x() - width(); + else if (newX > owner->x() + owner->width()) + newX = owner->x() + owner->width(); + setX(newX); + didAnyMovement = true; + } + if (deltaLeft < 1.0 || deltaRight < 1.0) { + if (newY < owner->y() - height()) + newY = owner->y() - height(); + else if (newY > owner->y() + owner->height()) + newY = owner->y() + owner->height(); + setY(newY); + didAnyMovement = true; + } + if (!didAnyMovement) { + uDebug() << "constraint failed for (" << diffX << ", " << diffY << ")"; + setX(newX); + setY(newY); + } +} + +/** + * Align this widget's position such that it is attached at one of the + * sides of its owner's widget. + */ +void PinPortBase::attachToOwner() { + UMLWidget *owner = ownerWidget(); + const QPointF scenePos = m_scene->pos(); + if (owner == NULL) { + uError() << "PinPortBase::attachToOwner: ownerWidget() returns NULL"; + setX(scenePos.x()); + setY(scenePos.y()); + return; + } + bool xIsWithinOwner = false; + if (scenePos.x() < owner->x() - width()) { + setX(owner->x() - width()); + } else if (scenePos.x() <= owner->x() + owner->width()) { + setX(scenePos.x()); + xIsWithinOwner = true; + } else { + setX(owner->x() + owner->width()); + } + if (scenePos.y() < owner->y() - height()) { + setY(owner->y() - height()); + } else if (scenePos.y() <= owner->y() + owner->height()) { + if (xIsWithinOwner) { + if (scenePos.y() <= owner->y() + owner->height() / 2.0) + setY(owner->y() - height()); + else + setY(owner->y() + owner->height()); + } else { + setY(scenePos.y()); + } + } else { + setY(owner->y() + owner->height()); + } + + if (m_motionConnected) { + uDebug() << "connectOwnerMotion was already done"; + } else { + connectOwnerMotion(); + m_motionConnected = true; + } +} + +/** + * Overrides standard method. + */ +void PinPortBase::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + setPenFromSettings(painter); + if (UMLWidget::useFillColor()) { + painter->setBrush(UMLWidget::fillColor()); + } else { + painter->setBrush(m_scene->backgroundColor()); + } + + int w = width(); + int h = height(); + + painter->drawRect(0, 0, w, h); + + UMLWidget::paint(painter, option, widget); +} + +void PinPortBase::slotOwnerMoved(qreal diffX, qreal diffY) +{ + setX(x() + diffX); + setY(y() + diffY); +} + +/** + * Captures any popup menu signals for menus it created. + */ +void PinPortBase::slotMenuSelection(QAction* action) +{ + ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); + switch(sel) { + case ListPopupMenu::mt_NameAsTooltip: + if (m_pName) { + action->setChecked(true); + delete m_pName; + m_pName = NULL; + setToolTip(name()); + } else { + action->setChecked(false); + m_pName = new FloatingTextWidget(m_scene, Uml::TextRole::Floating, name()); + m_pName->setParentItem(this); + m_pName->setText(name()); // to get geometry update + m_pName->activate(); + UMLWidget* owner = ownerWidget(); + if (owner == NULL) { + uError() << "PinPortBase::slotMenuSelection: ownerWidget() returns NULL"; + setX(x()); + setY(y()); + } else { + const qreal w = width(); + const qreal h = height(); + if (x() < owner->x()) + m_pName->setX(-m_pName->width()); + else if (x() >= owner->x() + owner->width()) + m_pName->setX(w); + else + m_pName->setX(-m_pName->width() / 2.0 + w / 2.0); + if (y() < owner->y()) + m_pName->setY(-m_pName->height() - 2); + else if (y() >= owner->y() + owner->height()) + m_pName->setY(h); + else + m_pName->setY(-m_pName->height() / 2.0 + h / 2.0); + } + m_pName->update(); + setToolTip(QString()); + QToolTip::hideText(); + } + break; + + default: + UMLWidget::slotMenuSelection(action); + } +} + +FloatingTextWidget *PinPortBase::floatingTextWidget() { + return m_pName; +} + +void PinPortBase::setFloatingTextWidget(FloatingTextWidget *ft) { + m_pName = ft; + if (m_pName) + m_pName->setParentItem(this); +} + +/** + * Override method from UMLWidget in order to additionally check m_pName. + * + * @param p Point to be checked. + * + * @return 'this' if UMLWidget::onWidget(p) returns non NULL; + * m_pName if m_pName is non NULL and m_pName->onWidget(p) returns non NULL; + * else NULL. + */ +UMLWidget* PinPortBase::onWidget(const QPointF &p) +{ + if (UMLWidget::onWidget(p) != NULL) + return this; + if (m_pName) { + uDebug() << "floatingtext: " << m_pName->text(); + return m_pName->onWidget(p); + } + return NULL; +} + +/** + * Reimplement function from UMLWidget + */ +UMLWidget* PinPortBase::widgetWithID(Uml::ID::Type id) +{ + if (UMLWidget::widgetWithID(id)) + return this; + if (m_pName && m_pName->widgetWithID(id)) + return m_pName; + return NULL; +} + + +/** + * Saves the widget to the "pinwidget" or "portwidget" XMI element. + */ +void PinPortBase::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +{ + QDomElement element = qDoc.createElement(m_baseType == wt_Pin ? QLatin1String("pinwidget") + : QLatin1String("portwidget")); + element.setAttribute(QLatin1String("widgetaid"), Uml::ID::toString(ownerWidget()->id())); + UMLWidget::saveToXMI(qDoc, element); + if (m_pName && !m_pName->text().isEmpty()) { + m_pName->saveToXMI(qDoc, element); + } + qElement.appendChild(element); +} + +/** + * Loads from a "pinwidget" or from a "portwidget" XMI element. + */ +bool PinPortBase::loadFromXMI(QDomElement & qElement) +{ + if (!UMLWidget::loadFromXMI(qElement)) + return false; + + QString widgetaid = qElement.attribute(QLatin1String("widgetaid"), QLatin1String("-1")); + Uml::ID::Type aId = Uml::ID::fromString(widgetaid); + UMLWidget *owner = m_scene->findWidget(aId); + if (owner == NULL) { + DEBUG(DBG_SRC) << "owner object " << Uml::ID::toString(aId) << " not found"; + return false; + } + m_pOw = owner; + + // Optional child element: floatingtext + QDomNode node = qElement.firstChild(); + QDomElement element = node.toElement(); + if (!element.isNull()) { + QString tag = element.tagName(); + if (tag == QLatin1String("floatingtext")) { + m_pName = new FloatingTextWidget(m_scene, Uml::TextRole::Floating, + name(), Uml::ID::Reserved); + if (!m_pName->loadFromXMI(element)) { + // Most likely cause: The FloatingTextWidget is empty. + delete m_pName; + m_pName = NULL; + } else { + m_pName->setParentItem(this); + m_pName->activate(); + m_pName->update(); + } + } else { + uError() << "unknown tag " << tag; + } + } + + if (m_motionConnected) { + uDebug() << "connectOwnerMotion was already done"; + } else { + connectOwnerMotion(); + m_motionConnected = true; + } + return true; +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/pinportbase.h umbrello-kf6-15.08.1/umbrello/umlwidgets/pinportbase.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/pinportbase.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/pinportbase.h 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,63 @@ +/*************************************************************************** + * 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) 2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef PINPORTBASE_H +#define PINPORTBASE_H + +#include "umlwidget.h" + +class FloatingTextWidget; + +/** + * @short Abstract base class for PinWidget and PortWidget + * @author Oliver Kellogg + * @see UMLWidget + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class PinPortBase : public UMLWidget +{ + Q_OBJECT +public: + PinPortBase(UMLScene *scene, WidgetType type, UMLObject *o); + PinPortBase(UMLScene *scene, WidgetType type, UMLWidget *a, Uml::ID::Type id = Uml::ID::None); + virtual ~PinPortBase(); + + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + + virtual UMLWidget* ownerWidget(); + virtual void connectOwnerMotion() = 0; + + void setName(const QString &strName); + void updateWidget(); + void moveWidgetBy(qreal diffX, qreal diffY); + void attachToOwner(); + + UMLWidget* onWidget(const QPointF& p); + UMLWidget* widgetWithID(Uml::ID::Type id); + + FloatingTextWidget *floatingTextWidget(); + void setFloatingTextWidget(FloatingTextWidget *ft); + + void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); + bool loadFromXMI(QDomElement& qElement); + +public slots: + void slotOwnerMoved(qreal diffX, qreal diffY); + virtual void slotMenuSelection(QAction* action); + +protected: + void init(UMLWidget *owner = 0); + + UMLWidget* m_pOw; + FloatingTextWidget *m_pName; + bool m_motionConnected; +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/pinwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/pinwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/pinwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/pinwidget.cpp 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,103 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "pinwidget.h" + +// app includes +#include "debug_utils.h" +#include "floatingtextwidget.h" +#include "listpopupmenu.h" +#include "umlscene.h" +#include "activitywidget.h" + +// kde includes +#if QT_VERSION < 0x050000 +#include +#endif +#include + +// qt includes +#if QT_VERSION >= 0x050000 +#include +#endif +#include + +DEBUG_REGISTER_DISABLED(PinWidget) + +/** + * Creates a Pin widget. + * + * @param scene The parent of the widget. + * @param a The widget to which this pin is attached. + * @param id The ID to assign (-1 will prompt a new ID). + */ +PinWidget::PinWidget(UMLScene* scene, UMLWidget* a, Uml::ID::Type id) + : PinPortBase(scene, WidgetBase::wt_Pin, a, id) +{ + // setParent(a); + // m_nY = y() < getMinY() ? getMinY() : y(); + + m_pName = new FloatingTextWidget(m_scene, Uml::TextRole::Floating, name()); + m_pName->setParentItem(this); + m_pName->setText(name()); // to get geometry update + m_pName->activate(); + setVisible(true); +} + +/** + * Destructor. + */ +PinWidget::~PinWidget() +{ +} + +/** + * Implement abstract function from PinPortWidget. + */ +void PinWidget::connectOwnerMotion() +{ + ActivityWidget *owner = static_cast(ownerWidget()); + connect(owner, SIGNAL(sigActMoved(qreal,qreal)), this, SLOT(slotOwnerMoved(qreal,qreal))); +} + +/** + * Captures any popup menu signals for menus it created. + */ +void PinWidget::slotMenuSelection(QAction* action) +{ + ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); + switch(sel) { + case ListPopupMenu::mt_Rename: + { + bool ok = false; + QString name = m_Text; +#if QT_VERSION >= 0x050000 + name = QInputDialog::getText(Q_NULLPTR, + i18n("Enter Pin Name"), + i18n("Enter the pin name :"), + QLineEdit::Normal, + m_Text, &ok); +#else + name = KInputDialog::getText(i18n("Enter Pin Name"), + i18n("Enter the pin name :"), + m_Text, &ok); +#endif + if (ok) { + setName(name); + } + } + break; + + default: + PinPortBase::slotMenuSelection(action); + } +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/pinwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/pinwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/pinwidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/pinwidget.h 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,46 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef PINWIDGET_H +#define PINWIDGET_H + +#include "pinportbase.h" + +/** + * This class is the graphical version of a UML Pin. A pinWidget is created + * by a @ref UMLView. An pinWidget belongs to only one @ref UMLView instance. + * When the @ref UMLView instance that this class belongs to, it will be automatically deleted. + * + * The pinWidget class inherits from the @ref UMLWidget class which adds most of the functionality + * to this class. + * + * @short A graphical version of a UML pin. + * @author Hassan KOUCH + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class PinWidget : public PinPortBase +{ + Q_OBJECT +public: + + PinWidget(UMLScene* scene, UMLWidget* a, Uml::ID::Type id = Uml::ID::None); + virtual ~PinWidget(); + + void connectOwnerMotion(); + // int getMinY(); + +public slots: + void slotMenuSelection(QAction* action); + +// private: + // int m_nY; +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/portwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/portwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/portwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/portwidget.cpp 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,106 @@ +/*************************************************************************** + * 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) 2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "portwidget.h" + +// app includes +#include "port.h" +#include "package.h" +#include "debug_utils.h" +#include "umldoc.h" +#include "umlscene.h" +#include "componentwidget.h" +#include "floatingtextwidget.h" + +// kde includes +#if QT_VERSION < 0x050000 +#include +#endif +#include + +// qt includes +#if QT_VERSION >= 0x050000 +#include +#endif +#include +#include + +/** + * Constructs a PortWidget. + * + * @param scene The parent of this PortWidget. + * @param d The UMLPort this will be representing. + */ +PortWidget::PortWidget(UMLScene *scene, UMLPort *d) + : PinPortBase(scene, WidgetBase::wt_Port, d) +{ + setToolTip(d->name()); +} + +/** + * Standard deconstructor. + */ +PortWidget::~PortWidget() +{ +} + +/** + * Override function from PinPortWidget. + */ +UMLWidget* PortWidget::ownerWidget() +{ + if (m_pOw == NULL) { + const Uml::ID::Type compWidgetId = m_umlObject->umlPackage()->id(); + m_pOw = m_scene->widgetOnDiagram(compWidgetId); + } + return m_pOw; +} + +/** + * Implement abstract function from PinPortWidget. + */ +void PortWidget::connectOwnerMotion() +{ + ComponentWidget *owner = static_cast(ownerWidget()); + connect(owner, SIGNAL(sigCompMoved(qreal,qreal)), this, SLOT(slotOwnerMoved(qreal,qreal))); +} + +/** + * Captures any popup menu signals for menus it created. + */ +void PortWidget::slotMenuSelection(QAction* action) +{ + ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); + switch(sel) { + case ListPopupMenu::mt_Rename: + { + bool ok = false; + QString newName; +#if QT_VERSION >= 0x050000 + newName = QInputDialog::getText(Q_NULLPTR, + i18n("Enter Port Name"), i18n("Enter the port name :"), + QLineEdit::Normal, + name(), &ok); +#else + newName = KInputDialog::getText(i18n("Enter Port Name"), i18n("Enter the port name :"), + name(), &ok); +#endif + if (ok) { + setName(newName); + } + } + break; + + default: + PinPortBase::slotMenuSelection(action); + } +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/portwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/portwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/portwidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/portwidget.h 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,42 @@ +/*************************************************************************** + * 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) 2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef PORTWIDGET_H +#define PORTWIDGET_H + +#include "pinportbase.h" + +class UMLPort; + +/** + * Defines a graphical version of the UML2 port. Most of the functionality + * comes from the @ref PinPortBase class from which this class inherits. + * + * @short A graphical version of a port on a component. + * @author Oliver Kellogg + * @see PinPortBase, UMLWidget + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class PortWidget : public PinPortBase +{ + Q_OBJECT +public: + PortWidget(UMLScene *scene, UMLPort *d); + virtual ~PortWidget(); + + UMLWidget* ownerWidget(); + void connectOwnerMotion(); + +public slots: + void slotMenuSelection(QAction* action); + +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/preconditionwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/preconditionwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/preconditionwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/preconditionwidget.cpp 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,335 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "preconditionwidget.h" + +// app includes +#include "debug_utils.h" +#include "listpopupmenu.h" +#include "objectwidget.h" +#include "uml.h" +#include "umlscene.h" +#include "uniqueid.h" +#include "idchangelog.h" + +// kde includes +#if QT_VERSION < 0x050000 +#include +#endif +#include + +// qt includes +#if QT_VERSION >= 0x050000 +#include +#endif +#include + +DEBUG_REGISTER_DISABLED(PreconditionWidget) + +#define PRECONDITION_MARGIN 5 +#define PRECONDITION_WIDTH 30 +#define PRECONDITION_HEIGHT 10 + +/** + * Creates a Precondition widget. + * + * @param scene The parent of the widget. + * @param a The role A widget for this precondition. + * @param id The ID to assign (-1 will prompt a new ID). + */ +PreconditionWidget::PreconditionWidget(UMLScene* scene, ObjectWidget* a, Uml::ID::Type id) + : UMLWidget(scene, WidgetBase::wt_Precondition, id), + m_objectWidget(a) +{ + m_ignoreSnapToGrid = true; + m_ignoreSnapComponentSizeToGrid = true; + m_resizable = true ; + setVisible(true); + //updateResizability(); + // calculateWidget(); + if (y() < minY()) + m_nY = minY(); + else if (y() > maxY()) + m_nY = maxY(); + else + m_nY = y(); + + activate(); +} + +/** + * Destructor. + */ +PreconditionWidget::~PreconditionWidget() +{ +} + +/** + * Overrides the standard paint event. + */ +void PreconditionWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + int w = width(); + int h = height(); + + int x = m_objectWidget->x() + m_objectWidget->width() / 2; + x -= w/2; + setX(x); + int y = this->y(); + + //test if y isn't above the object + if (y <= m_objectWidget->y() + m_objectWidget->height()) { + y = m_objectWidget->y() + m_objectWidget->height() + 15; + } + if (y + h >= m_objectWidget->getEndLineY()) { + y = m_objectWidget->getEndLineY() - h; + } + setY(y); + setPenFromSettings(painter); + if (UMLWidget::useFillColor()) { + painter->setBrush(UMLWidget::fillColor()); + } + { + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + const QString precondition_value = QLatin1String("{ ") + name() + QLatin1String(" }"); + //int middleX = w / 2; + int textStartY = (h / 2) - (fontHeight / 2); + painter->drawRoundRect(0, 0, w, h, (h * 60) / w, 60); + painter->setPen(textColor()); + painter->setFont(UMLWidget::font()); + painter->drawText(PRECONDITION_MARGIN, textStartY, + w - PRECONDITION_MARGIN * 2, fontHeight, Qt::AlignCenter, precondition_value); + } + + UMLWidget::paint(painter, option, widget); +} + +/** + * Overrides method from UMLWidget. + */ +QSizeF PreconditionWidget::minimumSize() const +{ + int width = 10, height = 10; + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + const int textWidth = fm.width(name()) + 25; + height = fontHeight; + width = textWidth > PRECONDITION_WIDTH ? textWidth : PRECONDITION_WIDTH; + height = height > PRECONDITION_HEIGHT ? height : PRECONDITION_HEIGHT; + width += PRECONDITION_MARGIN * 2; + height += PRECONDITION_MARGIN * 2; + + return QSizeF(width, height); +} + +/** + * Calculate the geometry of the widget. + */ +void PreconditionWidget::calculateWidget() +{ + calculateDimensions(); + + setVisible(true); + + setX(m_nPosX); + setY(m_nY); +} + +/** + * Activates a PreconditionWidget. Connects the WidgetMoved signal from + * its m_objectWidget pointer so that PreconditionWidget can adjust to the move of + * the object widget. + */ +bool PreconditionWidget::activate(IDChangeLog * Log /*= 0*/) +{ + m_scene->resetPastep-kf6oint(); + UMLWidget::activate(Log); + + loadObjectWidget(); + + if (!m_objectWidget) { + DEBUG(DBG_SRC) << "role A widget " << Uml::ID::toString(m_widgetAId) + << " could not be found"; + return false; + } + + connect(m_objectWidget, SIGNAL(sigWidgetMoved(Uml::ID::Type)), this, SLOT(slotWidgetMoved(Uml::ID::Type))); + + calculateDimensions(); + return true; +} + +/** + * Resolve references of this precondition so it references the correct + * new object widget after paste. + */ +void PreconditionWidget::resolveObjectWidget(IDChangeLog* log) { + m_widgetAId = log->findNewID(m_widgetAId); +} + +/** + * Calculates the size of the widget. + */ +void PreconditionWidget::calculateDimensions() +{ + int x = 0; + int w = 0; + int h = 0; + int x1 = m_objectWidget->x(); + int w1 = m_objectWidget->width() / 2; + + x1 += w1; + + QSizeF q = minimumSize(); + w = q.width() > width() ? q.width() : width(); + h = q.height() > height() ? q.height() : height(); + + x = x1 - w/2; + + m_nPosX = x; + + setSize(w, h); +} + +/** + * Slot when widget is moved. + */ +void PreconditionWidget::slotWidgetMoved(Uml::ID::Type id) +{ + const Uml::ID::Type idA = m_objectWidget->localID(); + if (idA != id) { + DEBUG(DBG_SRC) << "id=" << Uml::ID::toString(id) << ": ignoring for idA=" << Uml::ID::toString(idA); + return; + } + m_nY = y(); + if (m_nY < minY()) + m_nY = minY(); + if (m_nY > maxY()) + m_nY = maxY(); + + calculateDimensions(); + if (m_scene->selectedCount(true) > 1) + return; +} + +/** + * Returns the minimum height this widget should be set at on + * a sequence diagrams. Takes into account the widget positions + * it is related to. + */ +int PreconditionWidget::minY() const +{ + if (m_objectWidget) { + return m_objectWidget->y() + m_objectWidget->height(); + } + return 0; +} + +/** + * Returns the maximum height this widget should be set at on + * a sequence diagrams. Takes into account the widget positions + * it is related to. + */ +int PreconditionWidget::maxY() const +{ + if (m_objectWidget) { + return ((int)m_objectWidget->getEndLineY() - height()); + } + return 0; +} + +/** + * Captures any popup menu signals for menus it created. + */ +void PreconditionWidget::slotMenuSelection(QAction* action) +{ + ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); + switch(sel) { + case ListPopupMenu::mt_Rename: + { + bool ok = false; + QString text = name(); +#if QT_VERSION >= 0x050000 + text = QInputDialog::getText(Q_NULLPTR, + i18n("Enter Precondition Name"), + i18n("Enter the precondition :"), + QLineEdit::Normal, + text, &ok); +#else + text = KInputDialog::getText(i18n("Enter Precondition Name"), + i18n("Enter the precondition :"), + text, &ok); +#endif + if (ok && !text.isEmpty()) { + setName(text); + } + calculateWidget(); + } + break; + + default: + UMLWidget::slotMenuSelection(action); + } +} + +/** + * Saves the widget to the "preconditionwidget" XMI element. + */ +void PreconditionWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +{ + QDomElement preconditionElement = qDoc.createElement(QLatin1String("preconditionwidget")); + UMLWidget::saveToXMI(qDoc, preconditionElement); + + preconditionElement.setAttribute(QLatin1String("widgetaid"), Uml::ID::toString(m_objectWidget->localID())); + preconditionElement.setAttribute(QLatin1String("preconditionname"), name()); + preconditionElement.setAttribute(QLatin1String("documentation"), documentation()); + qElement.appendChild(preconditionElement); +} + +/** + * Loads the widget from the "preconditionwidget" XMI element. + */ +bool PreconditionWidget::loadFromXMI(QDomElement& qElement) +{ + if(!UMLWidget::loadFromXMI(qElement)) + return false; + QString widgetaid = qElement.attribute(QLatin1String("widgetaid"), QLatin1String("-1")); + setName(qElement.attribute(QLatin1String("preconditionname"))); + setDocumentation(qElement.attribute(QLatin1String("documentation"))); + + m_widgetAId = Uml::ID::fromString(widgetaid); + + // Lookup the ObjectWidget, if it can't be found, assume it will be + // resolved later + loadObjectWidget(); + + return true; +} + +/** + * Load the object widget from m_widgetAId + * + * This method is called in loadFromXMI() when loading an XMI file, and called + * from activate() when activating a widget after pasting. + */ +void PreconditionWidget::loadObjectWidget() +{ + if (m_objectWidget == 0) { + m_objectWidget = dynamic_cast( + umlScene()->findWidget(m_widgetAId) + ); + } +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/preconditionwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/preconditionwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/preconditionwidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/preconditionwidget.h 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,70 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef PRECONDITIONWIDGET_H +#define PRECONDITIONWIDGET_H + +#include "umlwidget.h" + +class ObjectWidget; + +/** + * @short A graphical version of a UML Precondition (new in UML 2.0). + * + * This class is the graphical version of a UML Precondition. A PreconditionWidget is created + * by a @ref UMLView. An PreconditionWidget belongs to only one @ref UMLView instance. + * When the @ref UMLView instance that this class belongs to, it will be automatically deleted. + * + * The PreconditionWidget class inherits from the @ref UMLWidget class which adds most of the functionality + * to this class. + * + * @author Florence Mattler + * + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class PreconditionWidget : public UMLWidget +{ + Q_OBJECT +public: + PreconditionWidget(UMLScene* scene, ObjectWidget* a, Uml::ID::Type id = Uml::ID::None); + virtual ~PreconditionWidget(); + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + + int minY() const; + int maxY() const; + + bool activate(IDChangeLog* Log = 0); + void resolveObjectWidget(IDChangeLog* log); + + virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); + virtual bool loadFromXMI(QDomElement& qElement); + + void setObjectWidget(ObjectWidget* widget); + +public slots: + void slotMenuSelection(QAction* action); + void slotWidgetMoved(Uml::ID::Type id); + +protected: + QSizeF minimumSize() const; + +private: + void calculateWidget(); + void calculateDimensions(); + + ObjectWidget* m_objectWidget; + int m_nY; + + Uml::ID::Type m_widgetAId; + void loadObjectWidget(); +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/regionwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/regionwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/regionwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/regionwidget.cpp 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,108 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "regionwidget.h" + +// app includes +#include "basictypes.h" +#include "debug_utils.h" + +// kde includes +#include + +#define REGION_MARGIN 5 +#define REGION_WIDTH 90 +#define REGION_HEIGHT 45 + +/** + * Creates a Region widget. + * + * @param scene The parent of the widget. + * @param id The ID to assign (-1 will prompt a new ID.) + */ +RegionWidget::RegionWidget(UMLScene* scene, Uml::ID::Type id) + : UMLWidget(scene, WidgetBase::wt_Region, id) +{ +} + +/** + * Destructor. + */ +RegionWidget::~RegionWidget() +{ +} + +/** + * Overrides the standard paint event. + */ +void RegionWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + const int w = width(); + const int h = height(); + + setPenFromSettings(painter); + QPen pen = painter->pen(); + pen.setColor(Qt::red); + pen.setStyle(Qt::DashLine); + painter->setPen(pen); + painter->drawRoundRect(0, 0, w, h, (h * 60) / w, 60); + + UMLWidget::paint(painter, option, widget); +} + +/** + * Overrides method from UMLWidget + */ +QSizeF RegionWidget::minimumSize() const +{ + int width = 10, height = 10; + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + int textWidth = fm.width(name()); + + height = fontHeight; + width = textWidth > REGION_WIDTH?textWidth:REGION_WIDTH; + height = height > REGION_HEIGHT ? height : REGION_HEIGHT; + width += REGION_MARGIN * 2; + height += REGION_MARGIN * 2; + + return QSizeF(width, height); +} + +/** + * Saves region widget to XMI element. + */ +void RegionWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) +{ + QDomElement regionElement = qDoc.createElement(QLatin1String("regionwidget")); + UMLWidget::saveToXMI(qDoc, regionElement); + regionElement.setAttribute(QLatin1String("regionname"), name()); + regionElement.setAttribute(QLatin1String("documentation"), documentation()); + + qElement.appendChild(regionElement); +} + +/** + * Loads region widget from XMI element. + */ +bool RegionWidget::loadFromXMI(QDomElement& qElement) +{ + if (!UMLWidget::loadFromXMI(qElement)) { + return false; + } + setName(qElement.attribute(QLatin1String("regionname"))); + setDocumentation(qElement.attribute(QLatin1String("documentation"))); + return true; +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/regionwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/regionwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/regionwidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/regionwidget.h 2015-10-08 11:48:59.509089026 +0300 @@ -0,0 +1,36 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * +***************************************************************************/ + +#ifndef REGIONWIDGET_H +#define REGIONWIDGET_H + +#include "umlwidget.h" + +/** + * Represents a rectangular region on Activity diagram. + */ +class RegionWidget: public UMLWidget +{ + Q_OBJECT +public: + explicit RegionWidget(UMLScene* scene, Uml::ID::Type id = Uml::ID::None); + virtual ~RegionWidget(); + + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + + void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); + bool loadFromXMI(QDomElement& qElement); + +protected: + QSizeF minimumSize() const; + +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/seqlinewidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/seqlinewidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/seqlinewidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/seqlinewidget.cpp 2015-10-08 11:48:59.553089025 +0300 @@ -0,0 +1,197 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "seqlinewidget.h" + +//app includes +#include "messagewidget.h" +#include "objectwidget.h" +#include "umlscene.h" +#include "umlview.h" + +//qt includes +#include + +// class members +int const SeqLineWidget::m_nMouseDownEpsilonX = 20; + +/** + * Constructor. + */ +SeqLineWidget::SeqLineWidget(UMLScene *scene, ObjectWidget * pObject) + : QGraphicsLineItem(), + m_scene(scene) +{ + scene->addItem(this); + m_pObject = pObject; + setPen(QPen(m_pObject->lineColor(), 0, Qt::DashLine)); + setZValue(0); + setVisible(true); + m_DestructionBox.line1 = 0; + m_nLengthY = 250; + setupDestructionBox(); +} + +/** + * Destructor. + */ +SeqLineWidget::~SeqLineWidget() +{ +} + +/** + * Return whether point is on sequence line. + * Takes into account destruction box if shown. + * + * @param p The point to investigate. + * @return True if point is on this sequence line. + */ +bool SeqLineWidget::onWidget(const QPointF & p) +{ + bool isOnWidget = false; + QPointF sp = line().p1(); + QPointF ep = line().p2(); + //see if on widget (for message creation) + if (sp.x() - m_nMouseDownEpsilonX < p.x() + && ep.x() + m_nMouseDownEpsilonX > p.x() + && sp.y() < p.y() && ep.y() + 3 > p.y()) + { + isOnWidget = true; + } + return isOnWidget; +} + +/** + * Return whether point is on the destruction box. + * + * @param p The point to investigate. + * @return True if point is on the destruction box of this sequence line. + */ +bool SeqLineWidget::onDestructionBox(const QPointF & p) +{ + bool isOnDestructionBox = false; + int x = m_pObject->x() + m_pObject->width() / 2; + int y = m_pObject->y() + m_pObject->height() + m_nLengthY; + + //see if on destruction box + if (!m_pObject->showDestruction()) { + return false; + } + if (x - 10 < p.x() && x + 10 > p.x() + && y - 10 < p.y() && y + 10 > p.y()) + { + isOnDestructionBox = true; + } + return isOnDestructionBox; +} + +/** + * Clean up anything before deletion. + */ +void SeqLineWidget::cleanup() +{ + cleanupDestructionBox(); +} + +/** + * Set the start point of the line. + * + * @param startX X coordinate of the start point. + * @param startY Y coordinate of the start point. + */ +void SeqLineWidget::setStartPoint(int startX, int startY) +{ + int endX = startX; + int endY = startY + m_nLengthY; + QGraphicsLineItem::setLine(startX, startY, endX, endY); + moveDestructionBox(); +} + +/** + * Clean up destruction box. + */ +void SeqLineWidget::cleanupDestructionBox() +{ + if (m_DestructionBox.line1) { + delete m_DestructionBox.line1; + m_DestructionBox.line1 = 0; + delete m_DestructionBox.line2; + m_DestructionBox.line2 = 0; + } +} + +/** + * Set up destruction box. + */ +void SeqLineWidget::setupDestructionBox() +{ + cleanupDestructionBox(); + if(!m_pObject->showDestruction()) { + return; + } + QRect rect; + rect.setX(m_pObject->x() + m_pObject->width() / 2 - 10); + rect.setY(m_pObject->y() + m_pObject->height() + m_nLengthY); + rect.setWidth(14); + rect.setHeight(14); + + m_DestructionBox.line1 = new QGraphicsLineItem; + m_scene->addItem(m_DestructionBox.line1); + m_DestructionBox.setLine1Points(rect); + m_DestructionBox.line1->setVisible(true); + m_DestructionBox.line1->setPen(QPen(m_pObject->lineColor(), 2)); + m_DestructionBox.line1->setZValue(3); + + m_DestructionBox.line2 = new QGraphicsLineItem; + m_scene->addItem(m_DestructionBox.line2); + m_DestructionBox.setLine2Points(rect); + m_DestructionBox.line2->setVisible(true); + m_DestructionBox.line2->setPen(QPen(m_pObject->lineColor(), 2)); + m_DestructionBox.line2->setZValue(3); +} + +/** + * Move destruction box. + */ +void SeqLineWidget::moveDestructionBox() +{ + if(!m_DestructionBox.line1) { + return; + } + QRect rect; + rect.setX(m_pObject->x() + m_pObject->width() / 2 - 7); + rect.setY(m_pObject->y() + m_pObject->height() + m_nLengthY - 7); + rect.setWidth(14); + rect.setHeight(14); + m_DestructionBox.setLine1Points(rect); + m_DestructionBox.setLine2Points(rect); +} + +/** + * Sets the y position of the bottom of the vertical line. + * + * @param yPosition The y coordinate for the bottom of the line. + */ +void SeqLineWidget::setEndOfLine(int yPosition) +{ + QPointF sp = line().p1(); + int newY = yPosition; + m_nLengthY = yPosition - m_pObject->y() - m_pObject->height(); + // normally the managing Objectwidget is responsible for the call of this function + // but to be sure - make a double check _against current position_ + if (m_nLengthY < 0) { + m_nLengthY = 0; + newY = m_pObject->y() + m_pObject->height(); + } + setLine(sp.x(), sp.y(), sp.x(), newY); + moveDestructionBox(); + m_scene->resizeSceneToItems(); +} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/seqlinewidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/seqlinewidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/seqlinewidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/seqlinewidget.h 2015-10-08 11:48:59.553089025 +0300 @@ -0,0 +1,86 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef SEQLINEWIDGET_H +#define SEQLINEWIDGET_H + +#include + +class ObjectWidget; +class UMLScene; + +/** + * @short Widget class for graphical representation of sequence lines + * @author Paul Hensgen + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class SeqLineWidget : public QGraphicsLineItem +{ +public: + SeqLineWidget(UMLScene *scene, ObjectWidget * pObject); + virtual ~SeqLineWidget(); + + bool onWidget(const QPointF& p); + + bool onDestructionBox(const QPointF& p); + + void cleanup(); + + void setupDestructionBox(); + + void setStartPoint(int startX, int startY); + + /** + * Gets the length of the line. + * + * @return Length of the line. + */ + int getLineLength() { + return m_nLengthY; + } + + /** + * Returns the @ref ObjectWidget associated with this sequence line. + * + * @return Pointer to the associated ObjectWidget. + */ + ObjectWidget * getObjectWidget() { + return m_pObject; + } + + void setEndOfLine(int yPosition); + +protected: + void cleanupDestructionBox(); + + void moveDestructionBox(); + + ObjectWidget* m_pObject; ///< ObjectWidget associated with this sequence line + UMLScene* m_scene; ///< scene displayed on + + struct DestructionBox { + QGraphicsLineItem * line1; + QGraphicsLineItem * line2; + void setLine1Points(QRect rect) { + line1->setLine(rect.x(), rect.y(), + rect.x() + rect.width(), rect.y() + rect.height()); + } + void setLine2Points(QRect rect) { + line2->setLine(rect.x(), rect.y() + rect.height(), + rect.x() + rect.width(), rect.y()); + } + } m_DestructionBox; ///< the destruction box + + int m_nLengthY; ///< the length of the line + + static int const m_nMouseDownEpsilonX; ///< margin used for mouse clicks +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/signalwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/signalwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/signalwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/signalwidget.cpp 2015-10-08 11:48:59.553089025 +0300 @@ -0,0 +1,386 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "signalwidget.h" + +// app includes +#include "basictypes.h" +#include "debug_utils.h" +#include "floatingtextwidget.h" +#include "linkwidget.h" +#include "listpopupmenu.h" +#include "uml.h" +#include "umldoc.h" +#include "uniqueid.h" +#include "umlview.h" +#include "umlwidget.h" + +// kde includes +#include +#if QT_VERSION < 0x050000 +#include +#endif + +// qt includes +#include +#if QT_VERSION >= 0x050000 +#include +#endif +#include + +/** + * Creates a Signal widget. + * + * @param scene The parent of the widget. + * @param signalType The type of Signal. + * @param id The ID to assign (-1 will prompt a new ID.) + */ +SignalWidget::SignalWidget(UMLScene *scene, SignalType signalType, Uml::ID::Type id) + : UMLWidget(scene, WidgetBase::wt_Signal, id), + m_oldX(0), + m_oldY(0) +{ + m_signalType = signalType; + m_pName = NULL; + if (signalType == SignalWidget::Time) { + m_pName = new FloatingTextWidget(scene, Uml::TextRole::Floating, QString()); + scene->setupNewWidget(m_pName); + m_pName->setX(0); + m_pName->setY(0); + connect(m_pName, SIGNAL(destroyed()), this, SLOT(slotTextDestroyed())); + } +} + +/** + * Destructor. + */ +SignalWidget::~SignalWidget() +{ +} + +/** + * Overrides the standard paint event. + */ +void SignalWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + setPenFromSettings(painter); + const int w = width(); + const int h = height(); + QPolygon a; + switch (m_signalType) + { + case Send : + if(UMLWidget::useFillColor()) + painter->setBrush(UMLWidget::fillColor()); + { + a.setPoints(5, 0, 0, + (w*2)/3, 0, + w, h/2, + (w*2)/3, h, + 0, h); + painter->drawPolygon(a); + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + int textStartY = (h / 2) - (fontHeight / 2); + + painter->setPen(textColor()); + QFont font = UMLWidget::font(); + font.setBold(false); + painter->setFont(font); + painter->drawText(SIGNAL_MARGIN, textStartY, + w - SIGNAL_MARGIN * 2, fontHeight, + Qt::AlignCenter, name()); + setPenFromSettings(painter); + } + break; + case Accept : + if(UMLWidget::useFillColor()) + painter->setBrush(UMLWidget::fillColor()); + { + a.setPoints(5, 0, 0, + w/3, h/2, + 0, h, + w, h, + w, 0); + + painter->drawPolygon(a); + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + int textStartY = (h / 2) - (fontHeight / 2); + + painter->setPen(textColor()); + QFont font = UMLWidget::font(); + font.setBold(false); + painter->setFont(font); + painter->drawText(SIGNAL_MARGIN, textStartY, + w - SIGNAL_MARGIN * 2 + (w/3), fontHeight, + Qt::AlignCenter, name()); + setPenFromSettings(painter); + } + break; + case Time : + if(UMLWidget::useFillColor()) + painter->setBrush(UMLWidget::fillColor()); + { + a.setPoints(4, 0, 0, + w, h, + 0, h, + w, 0); + + painter->drawPolygon(a); + //const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + //const int fontHeight = fm.lineSpacing(); + //int textStartY = (h / 2) - (fontHeight / 2); + painter->setPen(textColor()); + QFont font = UMLWidget::font(); + font.setBold(false); + painter->setFont(font); + + setPenFromSettings(painter); + } + if (m_pName) { + if (m_pName->x() == 0 && m_pName->y() == 0) { + //the floating text has not been linked with the signal + m_pName->setX(w/2 - m_pName->width()/2); + m_pName->setY(h); + } + m_pName->setVisible((m_pName->text().length() > 0)); + m_pName->updateGeometry(); + } + + break; + default: + uWarning() << "Unknown signal type:" << m_signalType; + break; + } + + UMLWidget::paint(painter, option, widget); +} + +/** + * Overrides the UMLWidget method. + */ +void SignalWidget::setX(qreal newX) +{ + m_oldX = x(); + UMLWidget::setX(newX); +} + +/** + * Overrides the UMLWidget method. + */ +void SignalWidget::setY(qreal newY) +{ + m_oldY = y(); + UMLWidget::setY(newY); +} + +/** + * Sets the name of the signal. + */ +void SignalWidget::setName(const QString &strName) +{ + UMLWidget::setName(strName); + updateGeometry(); + if (signalType() == SignalWidget::Time) { + if (!m_pName) { + m_pName = new FloatingTextWidget(umlScene(), Uml::TextRole::Floating, m_Text); + umlScene()->setupNewWidget(m_pName); + m_pName->setX(0); + m_pName->setY(0); + connect(m_pName, SIGNAL(destroyed()), this, SLOT(slotTextDestroyed())); + } + else + m_pName->setText(m_Text); + } +} + +/** + * Returns the type of Signal. + */ +SignalWidget::SignalType SignalWidget::signalType() const +{ + return m_signalType; +} + +/** + * Returns the type string of Signal. + */ +QString SignalWidget::signalTypeStr() const +{ + return QLatin1String(ENUM_NAME(SignalWidget, SignalType, m_signalType)); +} + +/** + * Sets the type of Signal. + */ +void SignalWidget::setSignalType(SignalType signalType) +{ + m_signalType = signalType; +} + +/** + * Show a properties dialog for a UMLWidget. + */ +void SignalWidget::showPropertiesDialog() +{ +} + +/** + * Overrides mouseMoveEvent. + */ +void SignalWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* me) +{ + UMLWidget::mouseMoveEvent(me); + int diffX = m_oldX - x(); + int diffY = m_oldY - y(); + if (m_pName!=NULL) { + m_pName->setX(m_pName->x() - diffX); + m_pName->setY(m_pName->y() - diffY); + } +} + +/** + * Loads a "signalwidget" XMI element. + */ +bool SignalWidget::loadFromXMI(QDomElement & qElement) +{ + if(!UMLWidget::loadFromXMI(qElement)) + return false; + m_Text = qElement.attribute(QLatin1String("signalname")); + m_Doc = qElement.attribute(QLatin1String("documentation")); + QString type = qElement.attribute(QLatin1String("signaltype")); + QString textid = qElement.attribute(QLatin1String("textid"), QLatin1String("-1")); + Uml::ID::Type textId = Uml::ID::fromString(textid); + + setSignalType((SignalType)type.toInt()); + if (signalType() == Time) { + + if (textId != Uml::ID::None) { + UMLWidget *flotext = m_scene -> findWidget(textId); + if (flotext != NULL) { + // This only happens when loading files produced by + // umbrello-kf6-1.3-beta2. + m_pName = static_cast(flotext); + return true; + } + } else { + // no textid stored -> get unique new one + textId = UniqueID::gen(); + } + } + //now load child elements + QDomNode node = qElement.firstChild(); + QDomElement element = node.toElement(); + if (!element.isNull()) { + QString tag = element.tagName(); + if (tag == QLatin1String("floatingtext") || tag == QLatin1String("UML::FloatingTextWidget")) { + m_pName = new FloatingTextWidget(m_scene, Uml::TextRole::Floating, m_Text, textId); + if(! m_pName->loadFromXMI(element)) { + // Most likely cause: The FloatingTextWidget is empty. + delete m_pName; + m_pName = NULL; + } + else + connect(m_pName, SIGNAL(destroyed()), this, SLOT(slotTextDestroyed())); + } else { + uError() << "unknown tag " << tag; + } + } + return true; +} + +/** + * Creates the "signalwidget" XMI element. + */ +void SignalWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +{ + QDomElement signalElement = qDoc.createElement(QLatin1String("signalwidget")); + UMLWidget::saveToXMI(qDoc, signalElement); + signalElement.setAttribute(QLatin1String("signalname"), m_Text); + signalElement.setAttribute(QLatin1String("documentation"), m_Doc); + signalElement.setAttribute(QLatin1String("signaltype"), m_signalType); + if (m_pName && !m_pName->text().isEmpty()) { + signalElement.setAttribute(QLatin1String("textid"), Uml::ID::toString(m_pName->id())); + m_pName -> saveToXMI(qDoc, signalElement); + } + qElement.appendChild(signalElement); +} + +/** + * Show a properties dialog for a SignalWidget. + * + */ +void SignalWidget::slotMenuSelection(QAction* action) +{ + ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); + switch(sel) { + case ListPopupMenu::mt_Rename: + { + bool ok = false; + QString name = m_Text; +#if QT_VERSION >= 0x050000 + name = QInputDialog::getText(Q_NULLPTR, + i18n("Enter signal name"), + i18n("Enter the signal name :"), + QLineEdit::Normal, + m_Text, &ok); +#else + name = KInputDialog::getText(i18n("Enter signal name"), + i18n("Enter the signal name :"), + m_Text, &ok); +#endif + if (ok && name.length() > 0) { + setName(name); + } + } + break; + + default: + UMLWidget::slotMenuSelection(action); + } +} + +/** + * Overrides method from UMLWidget + */ +QSizeF SignalWidget::minimumSize() const +{ + int width = SIGNAL_WIDTH, height = SIGNAL_HEIGHT; + const QFontMetrics &fm = getFontMetrics(FT_BOLD); + const int fontHeight = fm.lineSpacing(); + int textWidth = fm.width(name()); + + if (m_signalType == Accept) + textWidth = int((float)textWidth * 1.3f); + height = fontHeight; + if (m_signalType != Time) + { + width = textWidth > SIGNAL_WIDTH?textWidth:SIGNAL_WIDTH; + height = height > SIGNAL_HEIGHT?height:SIGNAL_HEIGHT; + } + width += SIGNAL_MARGIN * 2; + height += SIGNAL_MARGIN * 2; + + return QSizeF(width, height); +} + +/** + * Called if user deletes text widget + */ +void SignalWidget::slotTextDestroyed() +{ + m_pName = 0; +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/signalwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/signalwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/signalwidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/signalwidget.h 2015-10-08 11:48:59.553089025 +0300 @@ -0,0 +1,86 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * +***************************************************************************/ + +#ifndef SIGNALWIDGET_H +#define SIGNALWIDGET_H + +#include "floatingtextwidget.h" +#include "linkwidget.h" +#include "umlwidget.h" +#include "worktoolbar.h" + +#define SIGNAL_MARGIN 5 +#define SIGNAL_WIDTH 45 +#define SIGNAL_HEIGHT 15 + +/** + * Represents a Send signal, Accept signal or Time event on an + * Activity diagram. + */ +class SignalWidget : public UMLWidget +{ + Q_OBJECT + Q_ENUMS(SignalType) +public: + /// Enumeration that codes the different types of signal. + enum SignalType + { + Send = 0, + Accept, + Time + }; + + explicit SignalWidget(UMLScene * scene, SignalType signalType = Send, Uml::ID::Type id = Uml::ID::None); + virtual ~SignalWidget(); + + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + + void setX(qreal newX); + void setY(qreal newY); + + virtual void setName(const QString &strName); + + SignalType signalType() const; + QString signalTypeStr() const; + void setSignalType(SignalType signalType); + + virtual void showPropertiesDialog(); + + void mouseMoveEvent(QGraphicsSceneMouseEvent *me); + + virtual bool loadFromXMI(QDomElement & qElement); + virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); + +public Q_SLOTS: + virtual void slotMenuSelection(QAction* action); + +protected: + QSizeF minimumSize() const; + + /** + * Save the value of the widget to know how to move the floatingtext + */ + int m_oldX; + int m_oldY; + + // Only for the time event + /** + * This is a pointer to the Floating Text widget which displays the + * name of the signal widget. + */ + FloatingTextWidget* m_pName; + + SignalType m_signalType; ///< Type of signal + +protected Q_SLOTS: + void slotTextDestroyed(); +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/statewidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/statewidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/statewidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/statewidget.cpp 2015-10-08 11:48:59.553089025 +0300 @@ -0,0 +1,534 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "statewidget.h" + +// app includes +#include "debug_utils.h" +#include "docwindow.h" +#include "listpopupmenu.h" +#include "statedialog.h" +#include "uml.h" +#include "umldoc.h" +#include "umlscene.h" +#include "umlview.h" +#include "umlwidget.h" + +// kde includes +#include +#if QT_VERSION < 0x050000 +#include +#endif + +// qt includes +#if QT_VERSION >= 0x050000 +#include +#endif +#include + +/** + * Creates a State widget. + * + * @param scene The parent of the widget. + * @param stateType The type of state. + * @param id The ID to assign (-1 will prompt a new ID.) + */ +StateWidget::StateWidget(UMLScene * scene, StateType stateType, Uml::ID::Type id) + : UMLWidget(scene, WidgetBase::wt_State, id) +{ + m_stateType = stateType; + m_drawVertical = true; + setAspectRatioMode(); + m_Text = QLatin1String("State"); + QSizeF size = minimumSize(); + setSize(size.width(), size.height()); +} + +/** + * Destructor. + */ +StateWidget::~StateWidget() +{ +} + +/** + * Overrides the standard paint event. + */ +void StateWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + const qreal w = width(); + const qreal h = height(); + if (w == 0 || h == 0) + return; + + setPenFromSettings(painter); + switch (m_stateType) { + case StateWidget::Normal: + { + if (UMLWidget::useFillColor()) { + painter->setBrush(UMLWidget::fillColor()); + } + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + int textStartY = (h / 2) - (fontHeight / 2); + const int count = m_Activities.count(); + if (count == 0) { + painter->drawRoundRect(0, 0, w, h, (h*40)/w, (w*40)/h); + painter->setPen(textColor()); + QFont font = UMLWidget::font(); + font.setBold(false); + painter->setFont(font); + painter->drawText(STATE_MARGIN, textStartY, + w - STATE_MARGIN * 2, fontHeight, + Qt::AlignCenter, name()); + setPenFromSettings(painter); + } else { + painter->drawRoundRect(0, 0, w, h, (h*40)/w, (w*40)/h); + textStartY = STATE_MARGIN; + painter->setPen(textColor()); + QFont font = UMLWidget::font(); + font.setBold(true); + painter->setFont(font); + painter->drawText(STATE_MARGIN, textStartY, w - STATE_MARGIN * 2, + fontHeight, Qt::AlignCenter, name()); + font.setBold(false); + painter->setFont(font); + setPenFromSettings(painter); + int linePosY = textStartY + fontHeight; + + QStringList::Iterator end(m_Activities.end()); + for(QStringList::Iterator it(m_Activities.begin()); it != end; ++it) { + textStartY += fontHeight; + painter->drawLine(0, linePosY, w, linePosY); + painter->setPen(textColor()); + painter->drawText(STATE_MARGIN, textStartY, w - STATE_MARGIN * 2, + fontHeight, Qt::AlignCenter, *it); + setPenFromSettings(painter); + linePosY += fontHeight; + }//end for + }//end else + } + break; + case StateWidget::Initial : + painter->setBrush(WidgetBase::lineColor()); + painter->drawEllipse(0, 0, w, h); + break; + case StateWidget::End : + painter->setBrush(WidgetBase::lineColor()); + painter->drawEllipse(0, 0, w, h); + painter->setBrush(Qt::white); + painter->drawEllipse(1, 1, w - 2, h - 2); + painter->setBrush(WidgetBase::lineColor()); + painter->drawEllipse(3, 3, w - 6, h - 6); + break; + case StateWidget::Fork: + case StateWidget::Join: + { + painter->setPen(Qt::black); + painter->setBrush(Qt::black); + painter->drawRect(rect()); + } + break; + case StateWidget::Junction: + { + painter->setPen(Qt::black); + painter->setBrush(Qt::black); + painter->drawEllipse(rect()); + } + break; + case StateWidget::DeepHistory: + { + painter->setBrush(Qt::white); + painter->drawEllipse(rect()); + painter->setPen(Qt::black); + painter->setFont(UMLWidget::font()); + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing() / 2; + const int xStar = fm.boundingRect(QLatin1String("H")).width(); + const int yStar = fontHeight / 4; + painter->drawText((w / 6), + (h / 4) + fontHeight, QLatin1String("H")); + painter->drawText((w / 6) + xStar, + (h / 4) + fontHeight - yStar, QLatin1String("*")); + } + break; + case StateWidget::ShallowHistory: + { + painter->setBrush(Qt::white); + painter->drawEllipse(rect()); + painter->setPen(Qt::black); + painter->setFont(UMLWidget::font()); + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing() / 2; + painter->drawText((w / 6), + (h / 4) + fontHeight, QLatin1String("H")); + } + break; + case StateWidget::Choice: + { + const qreal x = w / 2; + const qreal y = h / 2; + QPolygonF polygon; + polygon << QPointF(x, 0) << QPointF(w, y) + << QPointF(x, h) << QPointF(0, y); + painter->setBrush(UMLWidget::fillColor()); + painter->drawPolygon(polygon); + } + break; + default: + uWarning() << "Unknown state type: " << stateTypeStr(); + break; + } + + UMLWidget::paint(painter, option, widget); +} + +/** + * Overrides method from UMLWidget + */ +QSizeF StateWidget::minimumSize() const +{ + int width = 10, height = 10; + switch (m_stateType) { + case StateWidget::Normal: + { + const QFontMetrics &fm = getFontMetrics(FT_BOLD); + const int fontHeight = fm.lineSpacing(); + int textWidth = fm.width(name()); + const int count = m_Activities.count(); + height = fontHeight; + if(count > 0) { + height = fontHeight * (count + 1); + + QStringList::ConstIterator end(m_Activities.end()); + for(QStringList::ConstIterator it(m_Activities.begin()); it != end; ++it) { + int w = fm.width(*it); + if(w > textWidth) + textWidth = w; + }//end for + }//end if + width = textWidth > STATE_WIDTH?textWidth:STATE_WIDTH; + height = height > STATE_HEIGHT?height:STATE_HEIGHT; + width += STATE_MARGIN * 2; + height += STATE_MARGIN * 2; + break; + } + case StateWidget::Fork: + case StateWidget::Join: + if (m_drawVertical) { + width = 8; + height = 60; + } else { + width = 60; + height = 8; + } + break; + case StateWidget::Junction: + width = 18; + height = 18; + break; + case StateWidget::DeepHistory: + case StateWidget::ShallowHistory: + { + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + width = height = fm.lineSpacing(); + } + break; + case StateWidget::Choice: + width = 25; + height = 25; + break; + default: + break; + } + + return QSizeF(width, height); +} + +/** + * Overrides method from UMLWidget + */ +QSizeF StateWidget::maximumSize() +{ + switch (m_stateType) { + case StateWidget::Initial: + case StateWidget::End: + case StateWidget::Junction: + case StateWidget::Choice: + return QSizeF(35, 35); + break; + case StateWidget::DeepHistory: + case StateWidget::ShallowHistory: + { + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + return QSizeF(fontHeight + 10, fontHeight + 10); + } + break; + default: + break; + } + return UMLWidget::maximumSize(); +} + +/** + * Set the aspect ratio mode. + * Some state types have a fixed aspect ratio + */ +void StateWidget::setAspectRatioMode() +{ + switch (m_stateType) { + case StateWidget::Initial: + case StateWidget::End: + case StateWidget::Choice: + case StateWidget::DeepHistory: + case StateWidget::ShallowHistory: + case StateWidget::Fork: + case StateWidget::Join: + case StateWidget::Junction: + setFixedAspectRatio(true); + break; + default: + setFixedAspectRatio(false); + break; + } +} + +/** + * Returns the type of state. + * @return StateType + */ +StateWidget::StateType StateWidget::stateType() const +{ + return m_stateType; +} + +/** + * Returns the type string of state. + */ +QString StateWidget::stateTypeStr() const +{ + return QLatin1String(ENUM_NAME(StateWidget, StateType, m_stateType)); +} + +/** + * Sets the type of state. + */ +void StateWidget::setStateType(StateType stateType) +{ + m_stateType = stateType; + setAspectRatioMode(); +} + +/** + * Adds an activity to this widget. + * @return true on success + */ +bool StateWidget::addActivity(const QString &activity) +{ + m_Activities.append(activity); + updateGeometry(); + return true; +} + +/** + * Removes the given activity from the state. + */ +bool StateWidget::removeActivity(const QString &activity) +{ + if(m_Activities.removeAll(activity) == 0) + return false; + updateGeometry(); + return true; +} + +/** + * Renames the given activity. + */ +bool StateWidget::renameActivity(const QString &activity, const QString &newName) +{ + int index = - 1; + if((index = m_Activities.indexOf(activity)) == -1) + return false; + m_Activities[ index ] = newName; + return true; +} + +/** + * Sets the states activities to the ones given. + */ +void StateWidget::setActivities(const QStringList &list) +{ + m_Activities = list; + updateGeometry(); +} + +/** + * Returns the list of activities. + */ +QStringList StateWidget::activities() const +{ + return m_Activities; +} + +/** + * Get whether to draw a fork or join vertically. + */ +bool StateWidget::drawVertical() const +{ + return m_drawVertical; +} + +/** + * Set whether to draw a fork or join vertically. + */ +void StateWidget::setDrawVertical(bool to) +{ + m_drawVertical = to; + setSize(height(), width()); + updateGeometry(); + UMLWidget::adjustAssocs(x(), y()); +} + +/** + * Show a properties dialog for a StateWidget. + */ +void StateWidget::showPropertiesDialog() +{ + UMLApp::app()->docWindow()->updateDocumentation(false); + + QPointer dialog = new StateDialog(m_scene->activeView(), this); + if (dialog->exec() && dialog->getChangesMade()) { + UMLApp::app()->docWindow()->showDocumentation(this, true); + UMLApp::app()->document()->setModified(true); + } + delete dialog; +} + +/** + * Creates the "statewidget" XMI element. + */ +void StateWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +{ + QDomElement stateElement = qDoc.createElement(QLatin1String("statewidget")); + UMLWidget::saveToXMI(qDoc, stateElement); + stateElement.setAttribute(QLatin1String("statename"), m_Text); + stateElement.setAttribute(QLatin1String("documentation"), m_Doc); + stateElement.setAttribute(QLatin1String("statetype"), m_stateType); + if (m_stateType == Fork || m_stateType == Join) + stateElement.setAttribute(QLatin1String("drawvertical"), m_drawVertical); + //save states activities + QDomElement activitiesElement = qDoc.createElement(QLatin1String("Activities")); + + QStringList::Iterator end(m_Activities.end()); + for(QStringList::Iterator it(m_Activities.begin()); it != end; ++it) { + QDomElement tempElement = qDoc.createElement(QLatin1String("Activity")); + tempElement.setAttribute(QLatin1String("name"), *it); + activitiesElement.appendChild(tempElement); + }//end for + stateElement.appendChild(activitiesElement); + qElement.appendChild(stateElement); +} + +/** + * Loads a "statewidget" XMI element. + */ +bool StateWidget::loadFromXMI(QDomElement & qElement) +{ + if(!UMLWidget::loadFromXMI(qElement)) + return false; + m_Text = qElement.attribute(QLatin1String("statename")); + m_Doc = qElement.attribute(QLatin1String("documentation")); + QString type = qElement.attribute(QLatin1String("statetype"), QLatin1String("1")); + m_stateType = (StateType)type.toInt(); + setAspectRatioMode(); + QString drawVertical = qElement.attribute(QLatin1String("drawvertical"), QLatin1String("1")); + m_drawVertical = (bool)drawVertical.toInt(); + //load states activities + QDomNode node = qElement.firstChild(); + QDomElement tempElement = node.toElement(); + if(!tempElement.isNull() && tempElement.tagName() == QLatin1String("Activities")) { + QDomNode node = tempElement.firstChild(); + QDomElement activityElement = node.toElement(); + while(!activityElement.isNull()) { + if(activityElement.tagName() == QLatin1String("Activity")) { + QString name = activityElement.attribute(QLatin1String("name")); + if(!name.isEmpty()) + m_Activities.append(name); + }//end if + node = node.nextSibling(); + activityElement = node.toElement(); + }//end while + }//end if + return true; +} + +/** + * Captures any popup menu signals for menus it created. + */ +void StateWidget::slotMenuSelection(QAction* action) +{ + bool ok = false; + QString nameNew = name(); + + ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); + switch(sel) { + case ListPopupMenu::mt_Rename: +#if QT_VERSION >= 0x050000 + nameNew = QInputDialog::getText(Q_NULLPTR, + i18n("Enter State Name"), + i18n("Enter the name of the new state:"), + QLineEdit::Normal, + name(), &ok); +#else + nameNew = KInputDialog::getText(i18n("Enter State Name"), + i18n("Enter the name of the new state:"), + name(), &ok); +#endif + if (ok && nameNew.length() > 0) { + setName(nameNew); + } + break; + + case ListPopupMenu::mt_Properties: + showPropertiesDialog(); + break; + + case ListPopupMenu::mt_New_Activity: +#if QT_VERSION >= 0x050000 + nameNew = QInputDialog::getText(Q_NULLPTR, + i18n("Enter Activity"), + i18n("Enter the name of the new activity:"), + QLineEdit::Normal, + i18n("new activity"), &ok); +#else + nameNew = KInputDialog::getText(i18n("Enter Activity"), + i18n("Enter the name of the new activity:"), + i18n("new activity"), &ok); +#endif + if (ok && nameNew.length() > 0) { + addActivity(nameNew); + } + break; + + case ListPopupMenu::mt_Flip: + setDrawVertical(!m_drawVertical); + break; + + default: + UMLWidget::slotMenuSelection(action); + break; + } +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/statewidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/statewidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/statewidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/statewidget.h 2015-10-08 11:48:59.553089025 +0300 @@ -0,0 +1,99 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * +***************************************************************************/ + +#ifndef STATEWIDGET_H +#define STATEWIDGET_H + +#include "umlwidget.h" + +#include +#include + +#define STATE_MARGIN 5 +#define STATE_WIDTH 30 +#define STATE_HEIGHT 10 + +/** + * This class is the graphical version of a UML State. + * + * A StateWidget is created by a @ref UMLView. A StateWidget belongs to + * only one @ref UMLView instance. + * When the @ref UMLView instance that this class belongs to is destroyed, + * it will be automatically deleted. + * + * The StateWidget class inherits from the @ref UMLWidget class + * which adds most of the functionality to this class. + * + * @short A graphical version of a UML State. + * @author Paul Hensgen + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class StateWidget : public UMLWidget +{ + Q_OBJECT + Q_ENUMS(StateType) +public: + /// Enumeration that codes the different types of state. + enum StateType + { + Initial = 0, // Pseudostate + Normal, + End, + Fork, // Pseudostate + Join, // Pseudostate + Junction, // Pseudostate + DeepHistory, // Pseudostate + ShallowHistory, // Pseudostate + Choice // Pseudostate + //Terminate // Pseudostate + //EntryPoint // Pseudostate + //ExitPoint // Pseudostate + }; + + explicit StateWidget(UMLScene * scene, StateType stateType = Normal, Uml::ID::Type id = Uml::ID::None); + virtual ~StateWidget(); + + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + + StateType stateType() const; + QString stateTypeStr() const; + void setStateType(StateType stateType); + + bool addActivity(const QString &activity); + bool removeActivity(const QString &activity); + bool renameActivity(const QString &activity, const QString &newName); + + QStringList activities() const; + void setActivities(const QStringList &list); + + bool drawVertical() const; + void setDrawVertical(bool to = true); + + virtual void showPropertiesDialog(); + + virtual bool loadFromXMI(QDomElement & qElement); + virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); + +protected: + QSizeF minimumSize() const; + QSizeF maximumSize(); + void setAspectRatioMode(); + +public Q_SLOTS: + virtual void slotMenuSelection(QAction* action); + +private: + StateType m_stateType; ///< Type of state. + bool m_drawVertical; ///< whether to draw the fork/join horizontally or vertically + QStringList m_Activities; ///< List of activities for the state. + +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/statusbartoolbutton.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/statusbartoolbutton.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/statusbartoolbutton.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/statusbartoolbutton.cpp 2015-10-08 11:48:59.553089025 +0300 @@ -0,0 +1,122 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +/* +Widget taken from gwenview-kf6 +Copyright 2007 Aurélien Gâteau + +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. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR purpose-kf6. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ +// Self +#include "statusbartoolbutton.h" + +// Qt +#include +#include +#include +#include + +// KDE +#include + +StatusBarToolButton::StatusBarToolButton(QWidget* parent) + : QToolButton(parent), + mGroupPosition(NotGrouped) +{ + setToolButtonStyle(Qt::ToolButtonTextOnly); + setFocusPolicy(Qt::NoFocus); + setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); +} + + +QSize StatusBarToolButton::minimumSizeHint() const +{ + return sizeHint(); +} + + +QSize StatusBarToolButton::sizeHint() const +{ + QSize sh = QToolButton::sizeHint(); + sh.setHeight(fontMetrics().height()); + return sh; +} + + +void StatusBarToolButton::setGroupPosition(StatusBarToolButton::GroupPosition groupPosition) +{ + mGroupPosition = groupPosition; +} + + +void StatusBarToolButton::paintEvent(QPaintEvent* event) +{ + if (mGroupPosition == NotGrouped) { + QToolButton::paintEvent(event); + return; + } + QStylePainter painter(this); + QStyleOptionToolButton opt; + initStyleOption(&opt); + QStyleOptionToolButton panelOpt = opt; + + // Panel + QRect& panelRect = panelOpt.rect; + switch (mGroupPosition) { + case GroupLeft: + panelRect.setWidth(panelRect.width() * 2); + break; + case GroupCenter: + panelRect.setLeft(panelRect.left() - panelRect.width()); + panelRect.setWidth(panelRect.width() * 3); + break; + case GroupRight: + panelRect.setLeft(panelRect.left() - panelRect.width()); + break; + case NotGrouped: + Q_ASSERT(0); + } + painter.drawPrimitive(QStyle::PE_PanelButtonTool, panelOpt); + + // Separator + const int y1 = opt.rect.top() + 6; + const int y2 = opt.rect.bottom() - 6; + if (mGroupPosition & GroupRight) { + const int x = opt.rect.left(); + painter.setPen(opt.palette.color(QPalette::Light)); + painter.drawLine(x, y1, x, y2); + } + if (mGroupPosition & GroupLeft) { + const int x = opt.rect.right(); + painter.setPen(opt.palette.color(QPalette::Mid)); + painter.drawLine(x, y1, x, y2); + } + + // Text + painter.drawControl(QStyle::CE_ToolButtonLabel, opt); + + // Filtering message on tooltip text for CJK to remove accelerators. + // Quoting ktoolbar.cpp: + // """ + // CJK languages use more verbose accelerator marker: they add a Latin + // letter in parenthesis, and put accelerator on that. Hence, the default + // removal of ampersand only may not be enough there, instead the whole + // parenthesis construct should be removed. Provide these filtering i18n + // messages so that translators can use Transcript for custom removal. + // """ + if (!actions().isEmpty()) { + QAction* action = actions().first(); + setToolTip(i18nc("@info:tooltip of custom toolbar button", "%1", action->toolTip())); + } +} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/statusbartoolbutton.h umbrello-kf6-15.08.1/umbrello/umlwidgets/statusbartoolbutton.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/statusbartoolbutton.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/statusbartoolbutton.h 2015-10-08 11:48:59.553089025 +0300 @@ -0,0 +1,58 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab: +/* +gwenview-kf6: an image viewer +Copyright 2007 Aurélien Gâteau + +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. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR purpose-kf6. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ +#ifndef STATUSBARTOOLBUTTON_H +#define STATUSBARTOOLBUTTON_H + +// Qt +#include + +/** + * A thin tool button which can be grouped with another and look like one solid-kf6 + * bar: + * + * (button1 | button2) + */ +class StatusBarToolButton : public QToolButton +{ + Q_OBJECT +public: + enum GroupPosition { + NotGrouped = 0, + GroupLeft = 1, + GroupRight = 2, + GroupCenter = 3 + }; + + explicit StatusBarToolButton(QWidget* parent = 0); + + virtual QSize minimumSizeHint() const; + virtual QSize sizeHint() const; + + void setGroupPosition(StatusBarToolButton::GroupPosition groupPosition); + +protected: + virtual void paintEvent(QPaintEvent* event); + +private: + GroupPosition mGroupPosition; +}; + +#endif /* STATUSBARTOOLBUTTON_H */ diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/toolbarstateonewidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/toolbarstateonewidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/toolbarstateonewidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/toolbarstateonewidget.cpp 2015-10-08 11:48:59.553089025 +0300 @@ -0,0 +1,249 @@ +/*************************************************************************** + * 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) 2004-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "toolbarstateonewidget.h" + +// app includes +#include "activitywidget.h" +#include "dialog_utils.h" +#include "floatingtextwidget.h" +#include "messagewidget.h" +#include "objectwidget.h" +#include "pinwidget.h" +#include "portwidget.h" +#include "preconditionwidget.h" +#include "regionwidget.h" +#include "uml.h" +#include "umldoc.h" +#include "umlscene.h" +#include "umlwidget.h" +#include "object_factory.h" +#include "package.h" +#include "widget_factory.h" + +// kde includes +#include +#include +#if QT_VERSION < 0x050000 +#include +#endif + +// qt includes +#if QT_VERSION >= 0x050000 +#include +#endif + +// using namespace Uml; + +/** + * Creates a new ToolBarStateOneWidget. + * + * @param umlScene The UMLScene to use. + */ +ToolBarStateOneWidget::ToolBarStateOneWidget(UMLScene *umlScene) + : ToolBarStatePool(umlScene), + m_firstObject(0), + m_isObjectWidgetLine(false) +{ +} + +/** + * Destroys this ToolBarStateOneWidget. + */ +ToolBarStateOneWidget::~ToolBarStateOneWidget() +{ +} + +/** + * Called when the current tool is changed to use another tool. + * Executes base method and cleans the message. + */ +void ToolBarStateOneWidget::cleanBeforeChange() +{ + ToolBarStatePool::cleanBeforeChange(); +} + +/** + * Called when a mouse event happened. + * It executes the base method and then updates the position of the + * message line, if any. + */ +void ToolBarStateOneWidget::mouseMove(QGraphicsSceneMouseEvent* ome) +{ + ToolBarStatePool::mouseMove(ome); +} + +/** + * A widget was removed from the UMLView. + * If the widget removed was the current widget, the current widget is set + * to 0. + * Also, if it was the first object, the message is cleaned. + */ +void ToolBarStateOneWidget::slotWidgetRemoved(UMLWidget* widget) +{ + ToolBarState::slotWidgetRemoved(widget); +} + +/** + * Selects only widgets, but no associations. + * Overrides base class method. + * If the press event happened on the line of an object, the object is set + * as current widget. If the press event happened on a widget, the widget is + * set as current widget. + */ +void ToolBarStateOneWidget::setCurrentElement() +{ + m_isObjectWidgetLine = false; + ObjectWidget* objectWidgetLine = m_pUMLScene->onWidgetLine(m_pMouseEvent->scenePos()); + if (objectWidgetLine) { + setCurrentWidget(objectWidgetLine); + m_isObjectWidgetLine = true; + return; + } + + UMLWidget *widget = m_pUMLScene->widgetAt(m_pMouseEvent->scenePos()); + if (widget) { + setCurrentWidget(widget); + return; + } +} + +/** + * Called when the release event happened on a widget. + * If the button pressed isn't left button or the widget isn't an object + * widget, the message is cleaned. + * If the release event didn't happen on the line of an object and the first + * object wasn't selected, nothing is done. If the first object was already + * selected, a creation message is made. + * If the event happened on the line of an object, the first object or the + * second are set, depending on whether the first object was already set or + * not. + */ +void ToolBarStateOneWidget::mouseReleaseWidget() +{ + WidgetBase::WidgetType type = widgetType(); + + if (type == WidgetBase::wt_Precondition) { + m_firstObject = 0; + } + if (type == WidgetBase::wt_Pin) { + m_firstObject = 0; + } + + if (m_pMouseEvent->button() != Qt::LeftButton || + (currentWidget()->baseType() != WidgetBase::wt_Object && + currentWidget()->baseType() != WidgetBase::wt_Activity && + currentWidget()->baseType() != WidgetBase::wt_Component && + currentWidget()->baseType() != WidgetBase::wt_Region)) { + return; + } + + if (!m_firstObject && type == WidgetBase::wt_Pin) { + setWidget(currentWidget()); + return ; + } + + if (!m_isObjectWidgetLine && !m_firstObject) { + return; + } + + if (!m_firstObject) { + setWidget(currentWidget()); + } + +} + +/** + * Called when the release event happened on an empty space. + * Cleans the message. + * Empty spaces are not only actual empty spaces, but also associations. + */ +void ToolBarStateOneWidget::mouseReleaseEmpty() +{ +} + +/** + * Sets the first object of the message using the specified object. + * The temporal visual message is created and mouse tracking enabled, so + * mouse events will be delivered. + * + * @param firstObject The first object of the message. + */ +void ToolBarStateOneWidget::setWidget(UMLWidget* firstObject) +{ + m_firstObject = firstObject; + + UMLWidget * umlwidget = 0; + //m_pUMLScene->viewport()->setMouseTracking(true); + if (widgetType() == WidgetBase::wt_Precondition) { + umlwidget = new PreconditionWidget(m_pUMLScene, static_cast(m_firstObject)); + + Dialog_Utils::askNameForWidget(umlwidget, i18n("Enter Precondition Name"), i18n("Enter the precondition"), i18n("new precondition")); + // Create the widget. Some setup functions can remove the widget. + } + + if (widgetType() == WidgetBase::wt_Pin) { + if (m_firstObject->baseType() == WidgetBase::wt_Activity) { + umlwidget = new PinWidget(m_pUMLScene, m_firstObject); + // Create the widget. Some setup functions can remove the widget. + } else if (m_firstObject->baseType() == WidgetBase::wt_Component) { + bool pressedOK = false; +#if QT_VERSION >= 0x050000 + QString name = QInputDialog::getText(UMLApp::app(), + i18n("Enter Port Name"), i18n("Enter the port"), + QLineEdit::Normal, + i18n("new port"), + &pressedOK); +#else + QString name = KInputDialog::getText(i18n("Enter Port Name"), i18n("Enter the port"), i18n("new port"), + &pressedOK, UMLApp::app()); +#endif + if (pressedOK) { + UMLPackage* component = static_cast(m_firstObject->umlObject()); + UMLObject *port = Object_Factory::createUMLObject(UMLObject::ot_Port, name, component); + umlwidget = Widget_Factory::createWidget(m_pUMLScene, port); + } + } + } + + if (umlwidget) { + m_pUMLScene->setupNewWidget(umlwidget); + } + +} + +/** + * Returns the widget type of this tool. + * + * @return The widget type of this tool. + */ +WidgetBase::WidgetType ToolBarStateOneWidget::widgetType() +{ + if (getButton() == WorkToolBar::tbb_Seq_Precondition) { + return WidgetBase::wt_Precondition; + } + + if (getButton() == WorkToolBar::tbb_Pin) { + return WidgetBase::wt_Pin; + } + // Shouldn't happen + Q_ASSERT(0); + return WidgetBase::wt_Pin; +} + +/** + * Goes back to the initial state. + */ +void ToolBarStateOneWidget::init() +{ + ToolBarStatePool::init(); +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/toolbarstateonewidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/toolbarstateonewidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/toolbarstateonewidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/toolbarstateonewidget.h 2015-10-08 11:48:59.553089025 +0300 @@ -0,0 +1,59 @@ +/*************************************************************************** + * 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) 2004-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef TOOLBARSTATEONEWIDGET_H +#define TOOLBARSTATEONEWIDGET_H + +#include "toolbarstatepool.h" +#include "widgetbase.h" + +/** + * Sequence tool to create components linked with one object in sequence diagram + * like precondition. + * With sequence tool, one objects is selected clicking with left button on + * it + */ +class ToolBarStateOneWidget : public ToolBarStatePool +{ + Q_OBJECT +public: + explicit ToolBarStateOneWidget(UMLScene *umlScene); + virtual ~ToolBarStateOneWidget(); + + virtual void cleanBeforeChange(); + + // FIXME: obsolete + virtual void mouseMove(QGraphicsSceneMouseEvent* ome); + +public Q_SLOTS: + virtual void slotWidgetRemoved(UMLWidget* widget); + +protected: + virtual void setCurrentElement(); + + virtual void mouseReleaseWidget(); + virtual void mouseReleaseEmpty(); + + void setWidget(UMLWidget* firstObject); + WidgetBase::WidgetType widgetType(); + + UMLWidget* m_firstObject; ///< The first object in the message. + + /** + * If there is a current widget, it is true if the press event happened on + * the line of an object, or false if it happened on a normal UMLWidget. + */ + bool m_isObjectWidgetLine; + +private: + virtual void init(); +}; + +#endif //TOOLBARSTATEONEWIDGET_H diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/umlwidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/umlwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/umlwidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/umlwidget.cpp 2015-10-08 11:48:59.553089025 +0300 @@ -0,0 +1,1859 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#include "umlwidget.h" + +// local includes +#include "associationwidget.h" +#include "classifier.h" +#include "classpropertiesdialog.h" +#include "cmds.h" +#include "debug_utils.h" +#include "docwindow.h" +#include "floatingtextwidget.h" +#include "idchangelog.h" +#include "listpopupmenu.h" +#include "settingsdialog.h" +#include "uml.h" +#include "umldoc.h" +#include "umllistview.h" +#include "umlobject.h" +#include "umlscene.h" +#include "umlview.h" +#include "uniqueid.h" + +// kde includes +#include +#include + +// qt includes +#include +#include +#include +#include + +using namespace Uml; + +DEBUG_REGISTER_DISABLED(UMLWidget) + +const QSizeF UMLWidget::DefaultMinimumSize(50, 20); +const QSizeF UMLWidget::DefaultMaximumSize(1000, 5000); +const qreal UMLWidget::defaultMargin = 5; + +/** + * Creates a UMLWidget object. + * + * @param scene The view to be displayed on. + * @param type The WidgetType to construct. + * This must be set to the appropriate value by the constructors of inheriting classes. + * @param o The UMLObject to represent. + */ +UMLWidget::UMLWidget(UMLScene * scene, WidgetType type, UMLObject * o) + : WidgetBase(scene, type) +{ + init(); + m_umlObject = o; + if (m_umlObject) { + connect(m_umlObject, SIGNAL(modified()), this, SLOT(updateWidget())); + m_nId = m_umlObject->id(); + } +} + +/** + * Creates a UMLWidget object. + * + * @param scene The view to be displayed on. + * @param type The WidgetType to construct. + * This must be set to the appropriate value by the constructors of inheriting classes. + * @param id The id of the widget. + * The default value (id_None) will prompt generation of a new ID. + */ +UMLWidget::UMLWidget(UMLScene *scene, WidgetType type, Uml::ID::Type id) + : WidgetBase(scene, type) +{ + init(); + if (id == Uml::ID::None) + m_nId = UniqueID::gen(); + else + m_nId = id; +} + +/** + * Destructor. + */ +UMLWidget::~UMLWidget() +{ + cleanup(); +} + +/** + * Assignment operator + */ +UMLWidget& UMLWidget::operator=(const UMLWidget & other) +{ + if (this == &other) + return *this; + + WidgetBase::operator=(other); + + // assign members loaded/saved + m_useFillColor = other.m_useFillColor; + m_usesDiagramFillColor = other.m_usesDiagramFillColor; + m_usesDiagramUseFillColor = other.m_usesDiagramUseFillColor; + m_fillColor = other.m_fillColor; + m_Assocs = other.m_Assocs; + m_isInstance = other.m_isInstance; + m_instanceName = other.m_instanceName; + m_instanceName = other.m_instanceName; + m_showStereotype = other.m_showStereotype; + setX(other.x()); + setY(other.y()); + setRect(rect().x(), rect().y(), other.width(), other.height()); + + // assign volatile (non-saved) members + m_startMove = other.m_startMove; + m_nPosX = other.m_nPosX; + m_doc = other.m_doc; //new + m_resizable = other.m_resizable; + for (unsigned i = 0; i < FT_INVALID; ++i) + m_pFontMetrics[i] = other.m_pFontMetrics[i]; + m_activated = other.m_activated; + m_ignoreSnapToGrid = other.m_ignoreSnapToGrid; + m_ignoreSnapComponentSizeToGrid = other.m_ignoreSnapComponentSizeToGrid; + return *this; +} + +/** + * Overload '==' operator + */ +bool UMLWidget::operator==(const UMLWidget& other) const +{ + if (this == &other) + return true; + + if (m_baseType != other.m_baseType) { + return false; + } + + if (id() != other.id()) + return false; + + /* Testing the associations is already an exaggeration, no? + The type and ID should uniquely identify an UMLWidget. + */ + if (m_Assocs.count() != other.m_Assocs.count()) { + return false; + } + + // if(getBaseType() != wt_Text) // DON'T do this for floatingtext widgets, an infinite loop will result + // { + AssociationWidgetListIt assoc_it(m_Assocs); + AssociationWidgetListIt assoc_it2(other.m_Assocs); + AssociationWidget * assoc = 0, *assoc2 = 0; + while (assoc_it.hasNext() && assoc_it2.hasNext()) { + assoc = assoc_it.next(); + assoc2 = assoc_it2.next(); + + if (!(*assoc == *assoc2)) { + return false; + } + } + // } + return true; + // NOTE: In the comparison tests we are going to do, we don't need these values. + // They will actually stop things functioning correctly so if you change these, be aware of that. + /* + if(m_useFillColor != other.m_useFillColor) + return false; + if(m_nId != other.m_nId) + return false; + if(m_nX != other.m_nX) + return false; + if(m_nY != other.m_nY) + return false; + */ +} + +/** + * Sets the local id of the object. + * + * @param id The local id of the object. + */ +void UMLWidget::setLocalID(Uml::ID::Type id) +{ + m_nLocalID = id; +} + +/** + * Returns the local ID for this object. This ID is used so that + * many objects of the same @ref UMLObject instance can be on the + * same diagram. + * + * @return The local ID. + */ +Uml::ID::Type UMLWidget::localID() const +{ + return m_nLocalID; +} + +/** + * Returns the widget with the given ID. + * The default implementation tests the following IDs: + * - m_nLocalID + * - if m_umlObject is non NULL: m_umlObject->id() + * - m_nID + * Composite widgets override this function to test further owned widgets. + * + * @param id The ID to test this widget against. + * @return 'this' if id is either of m_nLocalID, m_umlObject->id(), or m_nId; + * else NULL. + */ +UMLWidget* UMLWidget::widgetWithID(Uml::ID::Type id) +{ + if (id == m_nLocalID || + (m_umlObject != NULL && id == m_umlObject->id()) || + id == m_nId) + return this; + return NULL; +} + +/** + * Compute the minimum possible width and height. + * + * @return QSizeF(mininum_width, minimum_height) + */ +QSizeF UMLWidget::minimumSize() const +{ + return m_minimumSize; +} + +/** + * This method is used to set the minimum size variable for this + * widget. + * + * @param newSize The size being set as minimum. + */ +void UMLWidget::setMinimumSize(const QSizeF& newSize) +{ + m_minimumSize = newSize; +} + +/** + * Compute the maximum possible width and height. + * + * @return maximum size + */ +QSizeF UMLWidget::maximumSize() +{ + return m_maximumSize; +} + +/** + * This method is used to set the maximum size variable for this + * widget. + * + * @param newSize The size being set as maximum. + */ +void UMLWidget::setMaximumSize(const QSizeF& newSize) +{ + m_maximumSize = newSize; +} + +/** + * Event handler for context menu events. + */ +void UMLWidget::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) +{ + WidgetBase::contextMenuEvent(event); +} + +/** + * Moves the widget to a new position using the difference between the + * current position and the new position. + * This method doesn't adjust associations. It only moves the widget. + * + * It can be overridden to constrain movement only in one axis even when + * the user isn't constraining the movement with shift or control buttons, for example. + * The movement policy set here is applied whenever the widget is moved, being it + * moving it explicitly, or as a part of a selection but not receiving directly the + * mouse events. + * + * Default behaviour is move the widget to the new position using the diffs. + * @see constrainMovementForAllWidgets + * + * @param diffX The difference between current X position and new X position. + * @param diffY The difference between current Y position and new Y position. + */ +void UMLWidget::moveWidgetBy(qreal diffX, qreal diffY) +{ + setX(x() + diffX); + setY(y() + diffY); +} + +/** + * Modifies the value of the diffX and diffY variables used to move the widgets. + * + * It can be overridden to constrain movement of all the selected widgets only in one + * axis even when the user isn't constraining the movement with shift or control + * buttons, for example. + * The difference with moveWidgetBy is that the diff positions used here are + * applied to all the selected widgets instead of only to m_widget, and that + * moveWidgetBy, in fact, moves the widget, and here simply the diff positions + * are modified. + * + * Default behaviour is do nothing. + * @see moveWidgetBy + * + * @param diffX The difference between current X position and new X position. + * @param diffY The difference between current Y position and new Y position. + */ +void UMLWidget::constrainMovementForAllWidgets(qreal &diffX, qreal &diffY) +{ + Q_UNUSED(diffX) Q_UNUSED(diffY) +} + +/** + * Bring the widget at the pressed position to the foreground. + */ +void UMLWidget::toForeground() +{ + QRectF rect = QRectF(scenePos(), QSizeF(width(), height())); + QList items = scene()->items(rect, Qt::IntersectsItemShape, Qt::DescendingOrder); + DEBUG(DBG_SRC) << "items at " << rect << " = " << items.count(); + if (items.count() > 1) { + foreach(QGraphicsItem* i, items) { + UMLWidget* w = dynamic_cast(i); + if (w) { + DEBUG(DBG_SRC) << "item=" << w->name() << " with zValue=" << w->zValue(); + if (w->name() != name()) { + if (w->zValue() >= zValue()) { + setZValue(w->zValue() + 1.0); + DEBUG(DBG_SRC) << "bring to foreground with zValue: " << zValue(); + } + } + } + } + } + else { + setZValue(0.0); + } + DEBUG(DBG_SRC) << "zValue is " << zValue(); +} + +/** + * Handles a mouse press event. + * It'll select the widget (or mark it to be deselected) and prepare it to + * be moved or resized. Go on reading for more info about this. + * + * Widget values and message bar status are saved. + * + * If shift or control buttons are pressed, we're in move area no matter + * where the button was pressed in the widget. Moreover, if the widget + * wasn't already selected, it's added to the selection. If already selected, + * it's marked to be deselected when releasing the button (provided it isn't + * moved). + * Also, if the widget is already selected with other widgets but shift nor + * control buttons are pressed, we're in move area. If finally we don't move + * the widget, it's selected and the other widgets deselected when releasing + * the left button. + * + * If shift nor control buttons are pressed, we're facing a single selection. + * Depending on the position of the cursor, we're in move or in resize area. + * If the widget wasn't selected (both when there are no widgets selected, or + * when there're other widgets selected but not the one receiving the press + * event) it's selected and the others deselected, if any. If already selected, + * it's marked to be deselected when releasing the button (provided it wasn't + * moved or resized). + * + * @param event The QGraphicsSceneMouseEvent event. + */ +void UMLWidget::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + if (event->button() != Qt::LeftButton) { + event->ignore(); + return; + } + event->accept(); + DEBUG(DBG_SRC) << "widget = " << name() << " / type = " << baseTypeStr(); + + toForeground(); + + m_startMovePostion = pos(); + m_startResizeSize = QSizeF(width(), height()); + + // saving the values of the widget + m_pressOffset = event->scenePos() - pos(); + DEBUG(DBG_SRC) << "press offset=" << m_pressOffset; + + m_oldStatusBarMsg = UMLApp::app()->statusBarMsg(); + + if (event->modifiers() == Qt::ShiftModifier || event->modifiers() == Qt::ControlModifier) { + m_shiftPressed = true; + + if (event->button() == Qt::LeftButton) { + m_inMoveArea = true; + } + + if (!isSelected()) { + selectMultiple(event); + } + return; + } + + m_shiftPressed = false; + + int count = m_scene->selectedCount(true); + if (event->button() == Qt::LeftButton) { + if (isSelected() && count > 1) { + // single selection is made in release event if the widget wasn't moved + m_inMoveArea = true; + m_oldPos = pos(); + return; + } + + if (isInResizeArea(event)) { + m_inResizeArea = true; + m_oldW = width(); + m_oldH = height(); + } else { + m_inMoveArea = true; + } + } + + // if widget wasn't selected, or it was selected but with other widgets also selected + if (!isSelected() || count > 1) { + selectSingle(event); + } +} + +/** + * Handles a mouse move event. + * It resizes or moves the widget, depending on where the cursor is pressed + * on the widget. Go on reading for more info about this. + * + * If resizing, the widget is resized using UMLWidget::resizeWidget (where specific + * widget resize constraint can be applied), and then the associations are + * adjusted. + * The resizing can be constrained also to a specific axis using control + * and shift buttons. If on or another is pressed, it's constrained to X axis. + * If both are pressed, it's constrained to Y axis. + * + * If not resizing, the widget is being moved. If the move is being started, + * the selection bounds are set (which includes updating the list of selected + * widgets). + * The difference between the previous position of the selection and the new + * one is got (taking in account the selection bounds so widgets don't go + * beyond the scene limits). Then, it's constrained to X or Y axis depending + * on shift and control buttons. + * A further constraint is made using constrainMovementForAllWidgets (for example, + * if the widget that receives the event can only be moved in Y axis, with this + * method the movement of all the widgets in the selection can be constrained to + * be moved only in Y axis). + * Then, all the selected widgets are moved using moveWidgetBy (where specific + * widget movement constraint can be applied) and, if a certain amount of time + * passed from the last move event, the associations are also updated (they're + * not updated always to be easy on the CPU). Finally, the scene is resized, + * and selection bounds updated. + * + * @param event The QGraphicsSceneMouseEvent event. + */ +void UMLWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* event) +{ + if (m_inResizeArea) { + resize(event); + return; + } + + if (!m_moved) { + UMLApp::app()->document()->writeToStatusBar(i18n("Hold shift or ctrl to move in X axis. Hold shift and control to move in Y axis. Right button click to cancel move.")); + + m_moved = true; + //Maybe needed by AssociationWidget + m_startMove = true; + + setSelectionBounds(); + } + + QPointF position = event->scenePos() - m_pressOffset; + qreal diffX = position.x() - x(); + qreal diffY = position.y() - y(); + + if ((event->modifiers() & Qt::ShiftModifier) && (event->modifiers() & Qt::ControlModifier)) { + // move only in Y axis + diffX = 0; + } else if ((event->modifiers() & Qt::ShiftModifier) || (event->modifiers() & Qt::ControlModifier)) { + // move only in X axis + diffY = 0; + } + + constrainMovementForAllWidgets(diffX, diffY); + + // nothing to move + if (diffX == 0 && diffY == 0) { + return; + } + + QPointF delta = event->scenePos() - event->lastScenePos(); + adjustUnselectedAssocs(delta.x(), delta.y()); + + DEBUG(DBG_SRC) << "diffX=" << diffX << " / diffY=" << diffY; + foreach(UMLWidget* widget, umlScene()->selectedWidgets()) { + widget->moveWidgetBy(diffX, diffY); + widget->slotSnapToGrid(); + } + + // Move any selected associations. + foreach(AssociationWidget* aw, m_scene->selectedAssocs()) { + if (aw->isSelected()) { + aw->moveEntireAssoc(diffX, diffY); + } + } + + umlScene()->resizeSceneToItems(); +} + +/** + * Handles a mouse release event. + * It selects or deselects the widget and cancels or confirms the move or + * resize. Go on reading for more info about this. + * No matter which tool is selected, Z position of widget is updated. + * + * Middle button release resets the selection. + * Left button release, if it wasn't moved nor resized, selects the widget + * and deselect the others if it wasn't selected and there were other widgets + * selected. If the widget was marked to be deselected, deselects it. + * If it was moved or resized, the document is set to modified if position + * or size changed. Also, if moved, all the associations are adjusted because + * the timer could have prevented the adjustment in the last move event before + * the release. + * If mouse was pressed in resize area, cursor is set again to normal cursor + * Right button release if right button was pressed shows the pop up menu for + * the widget. + * If left button was pressed, it cancels the move or resize with a mouse move + * event at the same position than the cursor was when pressed. Another left + * button release is also sent. + * + * @param event The QGraphicsSceneMouseEvent event. + */ +void UMLWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + if (!m_moved && !m_resized) { + if (!m_shiftPressed && (m_scene->selectedCount(true) > 1)) { + selectSingle(event); + } else if (!isSelected()) { + deselect(event); + } + } else { + // Commands + if (m_moved) { + int selectionCount = umlScene()->selectedWidgets().count(); + if (selectionCount > 1) { + UMLApp::app()->beginMacro(i18n("Move widgets")); + } + foreach(UMLWidget* widget, umlScene()->selectedWidgets()) { + UMLApp::app()->executeCommand(new Uml::CmdMoveWidget(widget)); + } + if (selectionCount > 1) { + UMLApp::app()->endMacro(); + } + m_moved = false; + } else { + UMLApp::app()->executeCommand(new Uml::CmdResizeWidget(this)); + m_resized = false; + } + + if ((m_inMoveArea && wasPositionChanged()) || + (m_inResizeArea && wasSizeChanged())) { + umlDoc()->setModified(true); + } + + UMLApp::app()->document()->writeToStatusBar(m_oldStatusBarMsg); + } + + if (m_inResizeArea) { + m_inResizeArea = false; + m_scene->activeView()->setCursor(Qt::ArrowCursor); + } else { + m_inMoveArea = false; + } +} + +/** + * Event handler for mouse double click events. + * @param event the QGraphicsSceneMouseEvent event. + */ +void UMLWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) { + DEBUG(DBG_SRC) << "widget = " << name() << " / type = " << baseTypeStr(); + switch(baseType()) { + case WidgetBase::wt_Message: // will be handled in its class + QGraphicsItem::mouseDoubleClickEvent(event); + break; + default: + showPropertiesDialog(); + event->accept(); + break; + } + } +} + +/** + * Return the start position of the move action. + * @return point where the move began + */ +QPointF UMLWidget::startMovePosition() const +{ + return m_startMovePostion; +} + +/** + * Set the start position of the move action. + * @param position point where the move began + */ +void UMLWidget::setStartMovePosition(const QPointF &position) +{ + m_startMovePostion = position; +} + +/** + * Return the start size of the resize action. + * @return size where the resize began + */ +QSizeF UMLWidget::startResizeSize() const +{ + return m_startResizeSize; +} + +/** + * Resizes the widget. + * It's called from resize, after the values are constrained and before + * the associations are adjusted. + * + * Default behaviour is resize the widget using the new size values. + * @see resize + * + * @param newW The new width for the widget. + * @param newH The new height for the widget. + */ +void UMLWidget::resizeWidget(qreal newW, qreal newH) +{ + setSize(newW, newH); +} + +/** + * When a widget changes this slot captures that signal. + */ +void UMLWidget::updateWidget() +{ + updateGeometry(); + switch (m_baseType) { + case WidgetBase::wt_Class: + m_scene->createAutoAttributeAssociations(this); + break; + case WidgetBase::wt_Entity: + m_scene->createAutoConstraintAssociations(this); + break; + default: + break; + } + + if (isVisible()) + update(); +} + +/** + * Apply possible constraints to the given candidate width and height. + * The default implementation limits input values to the bounds returned + * by minimumSize()/maximumSize(). + * + * @param width input value, may be modified by the constraint + * @param height input value, may be modified by the constraint + */ +void UMLWidget::constrain(qreal& width, qreal& height) +{ + QSizeF minSize = minimumSize(); + if (width < minSize.width()) + width = minSize.width(); + if (height < minSize.height()) + height = minSize.height(); + QSizeF maxSize = maximumSize(); + if (width > maxSize.width()) + width = maxSize.width(); + if (height > maxSize.height()) + height = maxSize.height(); + + if (fixedAspectRatio()) { + QSizeF size = rect().size(); + float aspectRatio = size.width() > 0 ? (float)size.height()/size.width() : 1; + height = width * aspectRatio; + } +} + +/** + * Initializes key attributes of the class. + */ +void UMLWidget::init() +{ + m_nId = Uml::ID::None; + m_nLocalID = UniqueID::gen(); + m_isInstance = false; + setMinimumSize(DefaultMinimumSize); + setMaximumSize(DefaultMaximumSize); + + m_font = QApplication::font(); + for (int i = (int)FT_INVALID - 1; i >= 0; --i) { + FontType fontType = (FontType)i; + setupFontType(m_font, fontType); + m_pFontMetrics[fontType] = new QFontMetrics(m_font); + } + + if (m_scene) { + m_useFillColor = true; + m_usesDiagramFillColor = true; + m_usesDiagramUseFillColor = true; + const Settings::OptionState& optionState = m_scene->optionState(); + m_fillColor = optionState.uiState.fillColor; + m_showStereotype = optionState.classState.showStereoType; + } else { + uError() << "SERIOUS PROBLEM - m_scene is NULL"; + m_useFillColor = false; + m_usesDiagramFillColor = false; + m_usesDiagramUseFillColor = false; + m_showStereotype = false; + } + + m_resizable = true; + m_fixedAspectRatio = false; + + m_startMove = false; + m_activated = false; + m_ignoreSnapToGrid = false; + m_ignoreSnapComponentSizeToGrid = false; + m_doc = UMLApp::app()->document(); + m_nPosX = 0; + connect(m_scene, SIGNAL(sigFillColorChanged(Uml::ID::Type)), this, SLOT(slotFillColorChanged(Uml::ID::Type))); + connect(m_scene, SIGNAL(sigLineColorChanged(Uml::ID::Type)), this, SLOT(slotLineColorChanged(Uml::ID::Type))); + connect(m_scene, SIGNAL(sigTextColorChanged(Uml::ID::Type)), this, SLOT(slotTextColorChanged(Uml::ID::Type))); + connect(m_scene, SIGNAL(sigLineWidthChanged(Uml::ID::Type)), this, SLOT(slotLineWidthChanged(Uml::ID::Type))); + + m_umlObject = 0; + + m_oldPos = QPointF(); + m_pressOffset = QPointF(); + m_oldW = 0; + m_oldH = 0; + + m_shiftPressed = false; + m_inMoveArea = false; + m_inResizeArea = false; + m_moved = false; + m_resized = false; + + setZValue(2.0); // default for most widgets +} + +/** + * This is usually called synchronously after menu.exec() and \a + * trigger's parent is always the ListPopupMenu which can be used to + * get the type of action of \a trigger. + * + * @note Subclasses can reimplement to handle specific actions and + * leave the rest to WidgetBase::slotMenuSelection. + */ +void UMLWidget::slotMenuSelection(QAction *trigger) +{ + if (!trigger) { + return; + } + + ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(trigger); + switch (sel) { + case ListPopupMenu::mt_Resize: + umlScene()->resizeSelection(); + break; + + default: + WidgetBase::slotMenuSelection(trigger); + break; + } +} + +/** + * Captures when another widget moves if this widget is linked to it. + * @see sigWidgetMoved + * + * @param id The id of object behind the widget. + */ +void UMLWidget::slotWidgetMoved(Uml::ID::Type /*id*/) +{ +} + +/** + * Captures a color change signal. + * + * @param viewID The id of the UMLScene behind the widget. + */ +void UMLWidget::slotFillColorChanged(Uml::ID::Type viewID) +{ + //only change if on the diagram concerned + if (m_scene->ID() != viewID) { + return; + } + if (m_usesDiagramFillColor) { + WidgetBase::setFillColor(m_scene->fillColor()); + } + if (m_usesDiagramUseFillColor) { + WidgetBase::setUseFillColor(m_scene->useFillColor()); + } + update(); +} + +/** + * Captures a text color change signal. + * + * @param viewID The id of the UMLScene behind the widget. + */ +void UMLWidget::slotTextColorChanged(Uml::ID::Type viewID) +{ + //only change if on the diagram concerned + if (m_scene->ID() != viewID) + return; + WidgetBase::setTextColor(m_scene->textColor()); + update(); +} + + +/** + * Captures a line color change signal. + * + * @param viewID The id of the UMLScene behind the widget. + */ +void UMLWidget::slotLineColorChanged(Uml::ID::Type viewID) +{ + //only change if on the diagram concerned + if (m_scene->ID() != viewID) + return; + + if (m_usesDiagramLineColor) { + WidgetBase::setLineColor(m_scene->lineColor()); + } + update(); +} + +/** + * Captures a linewidth change signal. + * + * @param viewID The id of the UMLScene behind the widget. + */ +void UMLWidget::slotLineWidthChanged(Uml::ID::Type viewID) +{ + //only change if on the diagram concerned + if (m_scene->ID() != viewID) { + return; + } + if (m_usesDiagramLineWidth) { + WidgetBase::setLineWidth(m_scene->lineWidth()); + } + update(); +} + +/** + * Set the status of using fill color (undo action) + * + * @param fc the status of using fill color. + */ +void UMLWidget::setUseFillColor(bool fc) +{ + if (useFillColor() != fc) { + UMLApp::app()->executeCommand(new CmdChangeUseFillColor(this, fc)); + } +} + +/** + * Set the status of using fill color. + * + * @param fc the status of using fill color. + */ +void UMLWidget::setUseFillColorCmd(bool fc) +{ + WidgetBase::setUseFillColor(fc); + update(); +} + +/** + * Overrides the method from WidgetBase. + */ +void UMLWidget::setTextColorCmd(const QColor &color) +{ + WidgetBase::setTextColor(color); + update(); +} + +/** + * Overrides the method from WidgetBase. + */ +void UMLWidget::setTextColor(const QColor &color) +{ + if (textColor() != color) { + UMLApp::app()->executeCommand(new CmdChangeTextColor(this, color)); + update(); + } +} + +/** + * Overrides the method from WidgetBase. + */ +void UMLWidget::setLineColorCmd(const QColor &color) +{ + WidgetBase::setLineColor(color); + update(); +} + +/** + * Overrides the method from WidgetBase. + */ +void UMLWidget::setLineColor(const QColor &color) +{ + if (lineColor() != color) { + UMLApp::app()->executeCommand(new CmdChangeLineColor(this, color)); + } +} + +/** + * Overrides the method from WidgetBase, execute CmdChangeLineWidth + */ +void UMLWidget::setLineWidth(uint width) +{ + if (lineWidth() != width) { + UMLApp::app()->executeCommand(new CmdChangeLineWidth(this, width)); + } +} + +/** + * Overrides the method from WidgetBase. + */ +void UMLWidget::setLineWidthCmd(uint width) +{ + WidgetBase::setLineWidth(width); + update(); +} + +/** + * Sets the background fill color + * + * @param color the new fill color + */ +void UMLWidget::setFillColor(const QColor &color) +{ + if (fillColor() != color) { + UMLApp::app()->executeCommand(new CmdChangeFillColor(this, color)); + } +} + +/** + * Sets the background fill color + * + * @param color the new fill color + */ +void UMLWidget::setFillColorCmd(const QColor &color) +{ + WidgetBase::setFillColor(color); + update(); +} + +/** + * Activate the object after serializing it from a QDataStream + * + * @param ChangeLog + * @return true for success + */ +bool UMLWidget::activate(IDChangeLog* /*ChangeLog = 0 */) +{ + if (widgetHasUMLObject(m_baseType) && m_umlObject == NULL) { + m_umlObject = m_doc->findObjectById(m_nId); + if (m_umlObject == NULL) { + uError() << "cannot find UMLObject with id=" << Uml::ID::toString(m_nId); + return false; + } + } + setFontCmd(m_font); + setSize(width(), height()); + m_activated = true; + updateGeometry(); + if (m_scene->getPaste()) { + FloatingTextWidget * ft = 0; + QPointF point = m_scene->getPastep-kf6oint(); + int x = point.x() + this->x(); + int y = point.y() + this->y(); + if (m_scene->type() == Uml::DiagramType::Sequence) { + switch (baseType()) { + case WidgetBase::wt_Object: + case WidgetBase::wt_Precondition : + setY(this->y()); + setX(x); + break; + + case WidgetBase::wt_Message: + setY(this->y()); + setX(x); + break; + + case WidgetBase::wt_Text: + ft = static_cast(this); + if (ft->textRole() == Uml::TextRole::Seq_Message) { + setX(x); + setY(this->y()); + } else { + setX(this->x()); + setY(this->y()); + } + break; + + default: + setY(y); + break; + }//end switch base type + }//end if sequence + else { + setX(x); + setY(y); + } + }//end if pastep-kf6oint + else { + setX(this->x()); + setY(this->y()); + } + if (m_scene->getPaste()) + m_scene->createAutoAssociations(this); + updateGeometry(); + return true; +} + +/** + * Returns true if the Activate method has been called for this instance + * + * @return The activate status. + */ +bool UMLWidget::isActivated() const +{ + return m_activated; +} + +/** + * Set the m_activated flag of a widget but does not perform the Activate method + * + * @param active Status of activation is to be set. + */ +void UMLWidget::setActivated(bool active /*=true*/) +{ + m_activated = active; +} + +/** + * Adds an already created association to the list of + * associations that include this UMLWidget + */ +void UMLWidget::addAssoc(AssociationWidget* pAssoc) +{ + if (pAssoc && !m_Assocs.contains(pAssoc)) { + m_Assocs.append(pAssoc); + } +} + +/** + * Removes an already created association from the list of + * associations that include this UMLWidget + */ +void UMLWidget::removeAssoc(AssociationWidget* pAssoc) +{ + if (pAssoc) { + m_Assocs.removeAll(pAssoc); + } +} + +/** + * Adjusts associations with the given co-ordinates + * + * @param dx The amount by which the widget moved in X direction. + * @param dy The amount by which the widget moved in Y direction. + */ +void UMLWidget::adjustAssocs(qreal dx, qreal dy) +{ + // don't adjust Assocs on file load, as + // the original positions, which are stored in XMI + // should be reproduced exactly + // (don't try to reposition assocs as long + // as file is only partly loaded -> reposition + // could be misguided) + /// @todo avoid trigger of this event during load + if (m_doc->loading()) { + // don't recalculate the assocs during load of XMI + // -> return immediately without action + return; + } + + foreach(AssociationWidget* assocwidget, m_Assocs) { + assocwidget->saveIdealTextPositions(); + } + + foreach(AssociationWidget* assocwidget, m_Assocs) { + assocwidget->widgetMoved(this, dx, dy); + } +} + +/** + * Adjusts all unselected associations with the given co-ordinates + * + * @param dx The amount by which the widget moved in X direction. + * @param dy The amount by which the widget moved in Y direction. + */ +void UMLWidget::adjustUnselectedAssocs(qreal dx, qreal dy) +{ + foreach(AssociationWidget* assocwidget, m_Assocs) { + if (!assocwidget->isSelected()) + assocwidget->saveIdealTextPositions(); + } + + foreach(AssociationWidget* assocwidget, m_Assocs) { + if (!assocwidget->isSelected()) { + assocwidget->widgetMoved(this, dx, dy); + } + } +} + +/** + * Show a properties dialog for a UMLWidget. + */ +void UMLWidget::showPropertiesDialog() +{ + // will already be selected so make sure docWindow updates the doc + // back it the widget + UMLApp::app()->docWindow()->updateDocumentation(false); + QPointer dlg = new ClassPropertiesDialog((QWidget*)UMLApp::app(), this); + + if (dlg->exec()) { + UMLApp::app()->docWindow()->showDocumentation(umlObject(), true); + m_doc->setModified(true); + } + dlg->close(); //wipe from memory + delete dlg; +} + +/** + * Move the widget by an X and Y offset relative to + * the current position. + */ +void UMLWidget::moveByLocal(qreal dx, qreal dy) +{ + qreal newX = x() + dx; + qreal newY = y() + dy; + setX(newX); + setY(newY); + adjustAssocs(dx, dy); +} + +/** + * Set the pen. + */ +void UMLWidget::setPenFromSettings(QPainter & p) +{ + p.setPen(QPen(m_lineColor, m_lineWidth)); +} + +/** + * Set the pen. + */ +void UMLWidget::setPenFromSettings(QPainter *p) +{ + p->setPen(QPen(m_lineColor, m_lineWidth)); +} + +/** + * Returns the cursor to be shown when resizing the widget. + * Default cursor is KCursor::sizeFDiagCursor(). + * + * @return The cursor to be shown when resizing the widget. + */ +QCursor UMLWidget::resizeCursor() const +{ + return Qt::SizeFDiagCursor; +} + +/** + * Checks if the mouse is in resize area (right bottom corner), and sets + * the cursor depending on that. + * The cursor used when resizing is gotten from resizeCursor(). + * + * @param me The QMouseEVent to check. + * @return true if the mouse is in resize area, false otherwise. + */ +bool UMLWidget::isInResizeArea(QGraphicsSceneMouseEvent *me) +{ + qreal m = 10.0; + const qreal w = width(); + const qreal h = height(); + + // If the widget itself is very small then make the resize area small, too. + // Reason: Else it becomes impossible to do a move instead of resize. + if (w - m < m || h - m < m) { + m = 2.0; + } + + if (m_resizable && + me->scenePos().x() >= (x() + w - m) && + me->scenePos().y() >= (y() + h - m)) { + m_scene->activeView()->setCursor(resizeCursor()); + return true; + } else { + m_scene->activeView()->setCursor(Qt::ArrowCursor); + return false; + } +} + +/** + * calculate content related size of widget. + * + * @return calculated widget size + */ +QSizeF UMLWidget::calculateSize(bool withExtensions /* = true */) const +{ + Q_UNUSED(withExtensions) + return QSizeF(width(), height()); +} + +/** + * Resize widget to minimum size. + */ +void UMLWidget::resize() +{ + qreal oldW = width(); + qreal oldH = height(); + // @TODO minimumSize() do not work in all cases, we need a dedicated autoResize() method + QSizeF size = minimumSize(); + setSize(size.width(), size.height()); + DEBUG(DBG_SRC) << "size=" << size; + adjustAssocs(size.width()-oldW, size.height()-oldH); +} + +/** + * Resizes the widget and adjusts the associations. + * It's called when a mouse move event happens and the cursor was + * in resize area when pressed. + * Resizing can be constrained to an specific axis using control and shift buttons. + * + * @param me The QGraphicsSceneMouseEvent to get the values from. + */ +void UMLWidget::resize(QGraphicsSceneMouseEvent *me) +{ + // TODO the status message lies for at least MessageWidget which could only be resized vertical + UMLApp::app()->document()->writeToStatusBar(i18n("Hold shift or ctrl to move in X axis. Hold shift and control to move in Y axis. Right button click to cancel resize.")); + + m_resized = true; + + qreal newW = m_oldW + me->scenePos().x() - x() - m_pressOffset.x(); + qreal newH = m_oldH + me->scenePos().y() - y() - m_pressOffset.y(); + + if ((me->modifiers() & Qt::ShiftModifier) && (me->modifiers() & Qt::ControlModifier)) { + //Move in Y axis + newW = m_oldW; + } else if ((me->modifiers() & Qt::ShiftModifier) || (me->modifiers() & Qt::ControlModifier)) { + //Move in X axis + newH = m_oldH; + } + + constrain(newW, newH); + resizeWidget(newW, newH); + DEBUG(DBG_SRC) << "event=" << me->scenePos() << "/ pos=" << pos() << " / newW=" << newW << " / newH=" << newH; + QPointF delta = me->scenePos() - me->lastScenePos(); + adjustAssocs(delta.x(), delta.y()); + + m_scene->resizeSceneToItems(); +} + +/** + * Checks if the size of the widget changed respect to the size that + * it had when press event was fired. + * + * @return true if was resized, false otherwise. + */ +bool UMLWidget::wasSizeChanged() +{ + return m_oldW != width() || m_oldH != height(); +} + +/** + * Checks if the position of the widget changed respect to the position that + * it had when press event was fired. + * + * @return true if was moved, false otherwise. + */ +bool UMLWidget::wasPositionChanged() +{ + return m_oldPos != pos(); +} + +/** + * Fills m_selectedWidgetsList and sets the selection bounds ((m_min/m_max)X/Y attributes). + */ +void UMLWidget::setSelectionBounds() +{ +} + +void UMLWidget::setSelectedFlag(bool _select) +{ + WidgetBase::setSelected(_select); +} + +/** + * Sets the state of whether the widget is selected. + * + * @param _select The state of whether the widget is selected. + */ +void UMLWidget::setSelected(bool _select) +{ + WidgetBase::setSelected(_select); + const WidgetBase::WidgetType wt = m_baseType; + if (_select) { + if (m_scene->selectedCount() == 0) { + if (widgetHasUMLObject(wt)) { + UMLApp::app()->docWindow()->showDocumentation(m_umlObject, false); + } else { + UMLApp::app()->docWindow()->showDocumentation(this, false); + } + }//end if + /* if (wt != wt_Text && wt != wt_Box) { + setZ(9);//keep text on top and boxes behind so don't touch Z value + } */ + } else { + /* if (wt != wt_Text && wt != wt_Box) { + setZ(m_origZ); + } */ + if (isSelected()) + UMLApp::app()->docWindow()->updateDocumentation(true); + } + + // TODO: isn't this handled by toForeground() ? + const QPoint pos(x(), y()); + UMLWidget *bkgnd = m_scene->widgetAt(pos); + if (bkgnd && bkgnd != this && _select) { + DEBUG(DBG_SRC) << "setting Z to " << bkgnd->zValue() + 1.0 << ", SelectState: " << _select; + setZValue(bkgnd->zValue() + 1.0); + } + + update(); + + // selection changed, we have to make sure the copy and paste items + // are correctly enabled/disabled + UMLApp::app()->slotCopyChanged(); + + // select in tree view as done for diagrams + if (_select) { + UMLListViewItem * item = UMLApp::app()->listView()->findItem(id()); + if (item) + UMLApp::app()->listView()->setCurrentItem(item); + else + UMLApp::app()->listView()->clearSelection(); + } +} + +/** + * Selects the widget and clears the other selected widgets, if any. + * + * @param me The QGraphicsSceneMouseEvent which made the selection. + */ +void UMLWidget::selectSingle(QGraphicsSceneMouseEvent *me) +{ + m_scene->clearSelected(); + + // Adds the widget to the selected widgets list, but as it has been cleared + // only the current widget is selected. + selectMultiple(me); +} + +/** + * Selects the widget and adds it to the list of selected widgets. + * + * @param me The QGraphicsSceneMouseEvent which made the selection. + */ +void UMLWidget::selectMultiple(QGraphicsSceneMouseEvent *me) +{ + Q_UNUSED(me); + + setSelected(true); +} + +/** + * Deselects the widget and removes it from the list of selected widgets. + * + * @param me The QGraphicsSceneMouseEvent which made the selection. + */ +void UMLWidget::deselect(QGraphicsSceneMouseEvent *me) +{ + Q_UNUSED(me); + + setSelected(false); +} + +/** + * Clears the selection, resets the toolbar and deselects the widget. + */ +//void UMLWidget::resetSelection() +//{ +// m_scene->clearSelected(); +// m_scene->resetToolbar(); +// setSelected(false); +//} + +/** + * Sets the view the widget is on. + * + * @param scene The UMLScene the widget is on. + */ +void UMLWidget::setScene(UMLScene *scene) +{ + //remove signals from old view - was probably 0 anyway + disconnect(m_scene, SIGNAL(sigFillColorChanged(Uml::ID::Type)), this, SLOT(slotFillColorChanged(Uml::ID::Type))); + disconnect(m_scene, SIGNAL(sigTextColorChanged(Uml::ID::Type)), this, SLOT(slotTextColorChanged(Uml::ID::Type))); + disconnect(m_scene, SIGNAL(sigLineWidthChanged(Uml::ID::Type)), this, SLOT(slotLineWidthChanged(Uml::ID::Type))); + m_scene = scene; + connect(m_scene, SIGNAL(sigFillColorChanged(Uml::ID::Type)), this, SLOT(slotFillColorChanged(Uml::ID::Type))); + connect(m_scene, SIGNAL(sigTextColorChanged(Uml::ID::Type)), this, SLOT(slotTextColorChanged(Uml::ID::Type))); + connect(m_scene, SIGNAL(sigLineWidthChanged(Uml::ID::Type)), this, SLOT(slotLineWidthChanged(Uml::ID::Type))); +} + +/** + * Sets the x-coordinate. + * Currently, the only class that reimplements this method is + * ObjectWidget. + * + * @param x The x-coordinate to be set. + */ +void UMLWidget::setX(qreal x) +{ + QGraphicsObject::setX(x); +} + +/** + * Sets the y-coordinate. + * Currently, the only class that reimplements this method is + * ObjectWidget. + * + * @param y The y-coordinate to be set. + */ +void UMLWidget::setY(qreal y) +{ + QGraphicsObject::setY(y); +} + +/** + * Used to cleanup any other widget it may need to delete. + * Used by child classes. This should be called before deleting a widget of a diagram. + */ +void UMLWidget::cleanup() +{ +} + +/** + * Tells the widget to snap to grid. + * Will use the grid settings of the @ref UMLView it belongs to. + */ +void UMLWidget::slotSnapToGrid() +{ + if (!m_ignoreSnapToGrid) { + qreal newX = m_scene->snappedX(x()); + setX(newX); + qreal newY = m_scene->snappedY(y()); + setY(newY); + } +} + +/** + * Returns whether the widget type has an associated UMLObject + */ +bool UMLWidget::widgetHasUMLObject(WidgetBase::WidgetType type) +{ + if (type == WidgetBase::wt_Actor || + type == WidgetBase::wt_UseCase || + type == WidgetBase::wt_Class || + type == WidgetBase::wt_Interface || + type == WidgetBase::wt_Enum || + type == WidgetBase::wt_Datatype || + type == WidgetBase::wt_Package || + type == WidgetBase::wt_Component || + type == WidgetBase::wt_Port || + type == WidgetBase::wt_Node || + type == WidgetBase::wt_Artifact || + type == WidgetBase::wt_Object) { + return true; + } else { + return false; + } +} + +/** + * Set m_ignoreSnapToGrid. + */ +void UMLWidget::setIgnoreSnapToGrid(bool to) +{ + m_ignoreSnapToGrid = to; +} + +/** + * Return the value of m_ignoreSnapToGrid. + */ +bool UMLWidget::getIgnoreSnapToGrid() const +{ + return m_ignoreSnapToGrid; +} + +/** + * Sets the size. + * If m_scene->snapComponentSizeToGrid() is true, then + * set the next larger size that snaps to the grid. + */ +void UMLWidget::setSize(qreal width, qreal height) +{ + // snap to the next larger size that is a multiple of the grid + if (!m_ignoreSnapComponentSizeToGrid + && m_scene->snapComponentSizeToGrid()) { + // integer divisions + int numX = width / m_scene->snapX(); + int numY = height / m_scene->snapY(); + // snap to the next larger valid value + if (width > numX * m_scene->snapX()) + width = (numX + 1) * m_scene->snapX(); + if (height > numY * m_scene->snapY()) + height = (numY + 1) * m_scene->snapY(); + } + + setRect(rect().x(), rect().y(), width, height); +} + +/** + * Sets the size with another size. + */ +void UMLWidget::setSize(const QSizeF& size) +{ + setSize(size.width(), size.height()); +} + +/** + * Update the size of this widget. + */ +void UMLWidget::updateGeometry() +{ + if (m_doc->loading()) { + return; + } + qreal oldW = width(); + qreal oldH = height(); + QSizeF size = calculateSize(); + qreal clipWidth = size.width(); + qreal clipHeight = size.height(); + constrain(clipWidth, clipHeight); + setSize(clipWidth, clipHeight); + slotSnapToGrid(); + adjustAssocs(size.width()-oldW, size.height()-oldH); +} + +/** + * clip the size of this widget against the + * minimal and maximal limits. + */ +void UMLWidget::clipSize() +{ + qreal clipWidth = width(); + qreal clipHeight = height(); + constrain(clipWidth, clipHeight); + setSize(clipWidth, clipHeight); +} + +/** + * Template Method, override this to set the default font metric. + */ +void UMLWidget::setDefaultFontMetrics(QFont &font, UMLWidget::FontType fontType) +{ + setupFontType(font, fontType); + setFontMetrics(fontType, QFontMetrics(font)); +} + +void UMLWidget::setupFontType(QFont &font, UMLWidget::FontType fontType) +{ + switch (fontType) { + case FT_NORMAL: + font.setBold(false); + font.setItalic(false); + font.setUnderline(false); + break; + case FT_BOLD: + font.setBold(true); + font.setItalic(false); + font.setUnderline(false); + break; + case FT_ITALIC: + font.setBold(false); + font.setItalic(true); + font.setUnderline(false); + break; + case FT_UNDERLINE: + font.setBold(false); + font.setItalic(false); + font.setUnderline(true); + break; + case FT_BOLD_ITALIC: + font.setBold(true); + font.setItalic(true); + font.setUnderline(false); + break; + case FT_BOLD_UNDERLINE: + font.setBold(true); + font.setItalic(false); + font.setUnderline(true); + break; + case FT_ITALIC_UNDERLINE: + font.setBold(false); + font.setItalic(true); + font.setUnderline(true); + break; + case FT_BOLD_ITALIC_UNDERLINE: + font.setBold(true); + font.setItalic(true); + font.setUnderline(true); + break; + default: return; + } +} + +void UMLWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + if (option->state & QStyle::State_Selected) { + const qreal w = width(); + const qreal h = height(); + const qreal s = 4; + QBrush brush(Qt::blue); + painter->fillRect(0, 0, s, s, brush); + painter->fillRect(0, 0 + h - s, s, s, brush); + painter->fillRect(0 + w - s, 0, s, s, brush); + + // Draw the resize anchor in the lower right corner. + // Don't draw it if the widget is so small that the + // resize anchor would cover up most of the widget. + if (m_resizable && w >= s+8 && h >= s+8) { + brush.setColor(Qt::red); + const int right = 0 + w; + const int bottom = 0 + h; + painter->drawLine(right - s, 0 + h - 1, 0 + w - 1, 0 + h - s); + painter->drawLine(right - (s*2), bottom - 1, right - 1, bottom - (s*2)); + painter->drawLine(right - (s*3), bottom - 1, right - 1, bottom - (s*3)); + } else { + painter->fillRect(0 + w - s, 0 + h - s, s, s, brush); + } + // debug info + if (Tracer::instance()->isEnabled(QLatin1String(metaObject()->className()))) { + painter->setPen(Qt::green); + painter->setBrush(Qt::NoBrush); + painter->drawPath(shape()); + painter->setPen(Qt::red); + painter->drawRect(boundingRect()); + // origin + painter->drawLine(-10, 0, 10, 0); + painter->drawLine(0, -10, 0, 10); + } + } + + if (umlScene()->isShowDocumentationIndicator() && hasDocumentation()) { + const qreal h = height(); + const qreal d = 8; + QPolygonF p; + p << QPointF(0, h - d) << QPointF(d, h) << QPointF(0, h); + painter->setPen(Qt::blue); + painter->setBrush(Qt::red); + painter->drawPolygon(p); + } +} + +/** + * Template Method, override this to set the default font metric. + */ +void UMLWidget::setDefaultFontMetrics(QFont &font, UMLWidget::FontType fontType, QPainter &painter) +{ + setupFontType(font, fontType); + painter.setFont(font); + setFontMetrics(fontType, painter.fontMetrics()); +} + +/** + * Returns the font metric used by this object for Text + * which uses bold/italic fonts. + */ +QFontMetrics &UMLWidget::getFontMetrics(UMLWidget::FontType fontType) const +{ + return *m_pFontMetrics[fontType]; +} + +/** + * Set the font metric to use. + */ +void UMLWidget::setFontMetrics(UMLWidget::FontType fontType, QFontMetrics fm) +{ + delete m_pFontMetrics[fontType]; + m_pFontMetrics[fontType] = new QFontMetrics(fm); +} + +/** + * Sets the font the widget is to use. + * + * @param font Font to be set. + */ +void UMLWidget::setFont(const QFont &font) +{ + QFont newFont = font; + forceUpdateFontMetrics(newFont, 0); + + if (m_font != newFont) { + UMLApp::app()->executeCommand(new CmdChangeFont(this, font)); + } +} + +/** + * Sets the font the widget is to use. + * + * @param font Font to be set. + */ +void UMLWidget::setFontCmd(const QFont &font) +{ + WidgetBase::setFont(font); + forceUpdateFontMetrics(0); + if (m_doc->loading()) + return; + update(); +} + +/** + * Updates font metrics for widgets current m_font + */ +void UMLWidget::forceUpdateFontMetrics(QPainter *painter) +{ + forceUpdateFontMetrics(m_font, painter); +} + +/** + * @note For performance Reasons, only FontMetrics for already used + * font types are updated. Not yet used font types will not get a font metric + * and will get the same font metric as if painter was zero. + * This behaviour is acceptable, because diagrams will always be shown on Display + * first before a special painter like a printer device is used. + */ +void UMLWidget::forceUpdateFontMetrics(QFont& font, QPainter *painter) +{ + if (painter == 0) { + for (int i = (int)FT_INVALID - 1; i >= 0; --i) { + if (m_pFontMetrics[(UMLWidget::FontType)i] != 0) + setDefaultFontMetrics(font, (UMLWidget::FontType)i); + } + } else { + for (int i2 = (int)FT_INVALID - 1; i2 >= 0; --i2) { + if (m_pFontMetrics[(UMLWidget::FontType)i2] != 0) + setDefaultFontMetrics(font, (UMLWidget::FontType)i2, *painter); + } + } + if (m_doc->loading()) + return; + // calculate the size, based on the new font metric + updateGeometry(); +} + +/** + * Set the status of whether to show Stereotype. + * + * @param flag True if stereotype shall be shown. + */ +void UMLWidget::setShowStereotype(bool flag) +{ + m_showStereotype = flag; + updateGeometry(); + update(); +} + +/** + * Returns the status of whether to show Stereotype. + * + * @return True if stereotype is shown. + */ +bool UMLWidget::showStereotype() const +{ + return m_showStereotype; +} + +/** + * Overrides the standard operation. + * + * @param me The move event. + */ +void UMLWidget::moveEvent(QGraphicsSceneMouseEvent* me) +{ + Q_UNUSED(me) +} + +void UMLWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +{ + /* + Call after required actions in child class. + Type must be set in the child class. + */ + WidgetBase::saveToXMI(qDoc, qElement); + qElement.setAttribute(QLatin1String("xmi.id"), Uml::ID::toString(id())); + qElement.setAttribute(QLatin1String("x"), x()); + qElement.setAttribute(QLatin1String("y"), y()); + qElement.setAttribute(QLatin1String("width"), width()); + qElement.setAttribute(QLatin1String("height"), height()); + qElement.setAttribute(QLatin1String("isinstance"), m_isInstance); + if (!m_instanceName.isEmpty()) + qElement.setAttribute(QLatin1String("instancename"), m_instanceName); + if (m_showStereotype) + qElement.setAttribute(QLatin1String("showstereotype"), m_showStereotype); + + // Unique identifier for widget (todo: id() should be unique, new attribute + // should indicate the UMLObject's ID it belongs to) + qElement.setAttribute(QLatin1String("localid"), Uml::ID::toString(m_nLocalID)); +} + +bool UMLWidget::loadFromXMI(QDomElement & qElement) +{ + QString id = qElement.attribute(QLatin1String("xmi.id"), QLatin1String("-1")); + m_nId = Uml::ID::fromString(id); + + WidgetBase::loadFromXMI(qElement); + QString x = qElement.attribute(QLatin1String("x"), QLatin1String("0")); + QString y = qElement.attribute(QLatin1String("y"), QLatin1String("0")); + QString h = qElement.attribute(QLatin1String("height"), QLatin1String("0")); + QString w = qElement.attribute(QLatin1String("width"), QLatin1String("0")); + + setSize(w.toFloat(), h.toFloat()); + setX(x.toFloat()); + setY(y.toFloat()); + QString isinstance = qElement.attribute(QLatin1String("isinstance"), QLatin1String("0")); + m_isInstance = (bool)isinstance.toInt(); + m_instanceName = qElement.attribute(QLatin1String("instancename")); + QString showstereo = qElement.attribute(QLatin1String("showstereotype"), QLatin1String("0")); + m_showStereotype = (bool)showstereo.toInt(); + + QString localid = qElement.attribute(QLatin1String("localid"), QLatin1String("0")); + if (localid != QLatin1String("0")) { + m_nLocalID = Uml::ID::fromString(localid); + } + + return true; +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/umlwidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/umlwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/umlwidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/umlwidget.h 2015-10-08 11:48:59.553089025 +0300 @@ -0,0 +1,347 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef UMLWIDGET_H +#define UMLWIDGET_H + +#include "associationwidgetlist.h" +#include "basictypes.h" +#include "optionstate.h" +#include "umlwidgetlist.h" +#include "widgetbase.h" + +#include +#include + +class IDChangeLog; +class UMLDoc; +class UMLObject; +class UMLScene; + +class QPainter; +class QFontMetrics; + +/** + * This is the base class for nearly all graphical widgets. + * + * @short The base class for graphical UML objects. + * @author Paul Hensgen + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class UMLWidget : public WidgetBase +{ + Q_OBJECT +public: + + friend class ToolBarStateArrow; // for calling the mouse*Event handlers + + static const QSizeF DefaultMinimumSize; + static const QSizeF DefaultMaximumSize; + static const qreal defaultMargin; + + explicit UMLWidget(UMLScene *scene, WidgetType type = wt_UMLWidget, UMLObject *o = 0); + explicit UMLWidget(UMLScene *scene, WidgetType type = wt_UMLWidget, Uml::ID::Type id = Uml::ID::None); + virtual ~UMLWidget(); + + // Copy constructor - not implemented. + // UMLWidget(const UMLWidget& other); + + UMLWidget& operator=(const UMLWidget& other); + + bool operator==(const UMLWidget& other) const; + + void setLocalID(Uml::ID::Type id); + Uml::ID::Type localID() const; + + virtual UMLWidget* widgetWithID(Uml::ID::Type id); + + virtual QSizeF minimumSize() const; + void setMinimumSize(const QSizeF &size); + + virtual QSizeF maximumSize(); + void setMaximumSize(const QSizeF &size); + + virtual void setUseFillColor(bool fc); + void setUseFillColorCmd(bool fc); + + virtual void setTextColor(const QColor &color); + void setTextColorCmd(const QColor &color); + + virtual void setLineColor(const QColor &color); + void setLineColorCmd(const QColor &color); + + virtual void setLineWidth(uint width); + void setLineWidthCmd(uint width); + + virtual void setFillColor(const QColor &color); + void setFillColorCmd(const QColor &color); + + void setSelectedFlag(bool _select); + virtual void setSelected(bool _select); + + void setScene(UMLScene *scene); + + virtual bool activate(IDChangeLog* ChangeLog = 0); + + void setPenFromSettings(QPainter &p); + void setPenFromSettings(QPainter *p); + + virtual void setFont(const QFont &font); + void setFontCmd(const QFont &font); + + /** + * Returns whether we triggered the update of position movement. + * If so, you probably don't want to move it. + * + * @return The moving state. + */ + bool getStartMove() const { + return m_startMove; + } + + virtual void setX(qreal x); + virtual void setY(qreal y); + + /** + * Returns the height of widget. + */ + qreal height() const { + return rect().height(); + } + + /** + * Returns the width of the widget. + */ + qreal width() const { + return rect().width(); + } + + void setSize(qreal width, qreal height); + void setSize(const QSizeF& size); + + virtual void resizeWidget(qreal newW, qreal newH); + + bool getIgnoreSnapToGrid() const; + void setIgnoreSnapToGrid(bool to); + + void moveByLocal(qreal dx, qreal dy); + + void removeAssoc(AssociationWidget* pAssoc); + void addAssoc(AssociationWidget* pAssoc); + + /** + * Returns the list of associations connected to this widget. + */ + AssociationWidgetList & associationWidgetList() { + return m_Assocs; + } + + /** + * Read property of bool m_isInstance + */ + bool isInstance() const { + return m_isInstance; + } + + /** + * Write property of bool m_isInstance + */ + void setIsInstance(bool isInstance) { + m_isInstance = isInstance; + } + + /** + * Write property of m_instanceName + */ + void setInstanceName(const QString &instanceName) { + m_instanceName = instanceName; + } + + /** + * Read property of m_instanceName + */ + QString instanceName() const { + return m_instanceName; + } + + bool showStereotype() const; + virtual void setShowStereotype(bool flag); + + virtual void showPropertiesDialog(); + + virtual void adjustAssocs(qreal dx, qreal dy); + void adjustUnselectedAssocs(qreal dx, qreal dy); + + bool isActivated() const; + void setActivated(bool active = true); + + virtual void cleanup(); + + static bool widgetHasUMLObject(WidgetBase::WidgetType type); + + void updateGeometry(); + + void clipSize(); + + void forceUpdateFontMetrics(QPainter *painter); + void forceUpdateFontMetrics(QFont &font, QPainter *painter); + + virtual bool loadFromXMI(QDomElement &qElement); + virtual void saveToXMI(QDomDocument &qDoc, QDomElement &qElement); + + QPointF startMovePosition() const; + void setStartMovePosition(const QPointF &position); + + QSizeF startResizeSize() const; + + virtual QSizeF calculateSize(bool withExtensions = true) const; + void resize(); + + bool fixedAspectRatio() const { + return m_fixedAspectRatio; + } + + void setFixedAspectRatio(bool state) { + m_fixedAspectRatio = state; + } + + typedef enum { + FT_NORMAL = 0, + FT_BOLD = 1, + FT_ITALIC = 2, + FT_UNDERLINE = 3, + FT_BOLD_ITALIC = 4, + FT_BOLD_UNDERLINE = 5, + FT_ITALIC_UNDERLINE = 6, + FT_BOLD_ITALIC_UNDERLINE = 7, + FT_INVALID = 8 + } FontType; + + virtual void setDefaultFontMetrics(QFont &font, UMLWidget::FontType fontType); + virtual void setDefaultFontMetrics(QFont &font, UMLWidget::FontType fontType, QPainter &painter); + + QFontMetrics &getFontMetrics(UMLWidget::FontType fontType) const; + void setFontMetrics(UMLWidget::FontType fontType, QFontMetrics fm); + void setupFontType(QFont &font, UMLWidget::FontType fontType); + + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + +public Q_SLOTS: + virtual void updateWidget(); + virtual void slotMenuSelection(QAction* action); + virtual void slotWidgetMoved(Uml::ID::Type id); + virtual void slotFillColorChanged(Uml::ID::Type viewID); + virtual void slotLineColorChanged(Uml::ID::Type viewID); + virtual void slotTextColorChanged(Uml::ID::Type viewID); + virtual void slotLineWidthChanged(Uml::ID::Type viewID); + + void slotSnapToGrid(); + +signals: + /** + * Emit when the widget moves its' position. + * @param id The id of the object behind the widget. + */ + void sigWidgetMoved(Uml::ID::Type id); + +protected: + virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent* event); + virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); + virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event); + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + + virtual void moveEvent(QGraphicsSceneMouseEvent *event); + virtual void moveWidgetBy(qreal diffX, qreal diffY); + virtual void constrainMovementForAllWidgets(qreal &diffX, qreal &diffY); + virtual void constrain(qreal& width, qreal& height); + + virtual bool isInResizeArea(QGraphicsSceneMouseEvent *me); + virtual QCursor resizeCursor() const; + + void selectSingle(QGraphicsSceneMouseEvent *me); + void selectMultiple(QGraphicsSceneMouseEvent *me); + void deselect(QGraphicsSceneMouseEvent *me); + // void resetSelection(); + + void setSelectionBounds(); + + void resize(QGraphicsSceneMouseEvent *me); + + bool wasSizeChanged(); + bool wasPositionChanged(); + + ///////////////// Data Loaded/Saved ///////////////////////////////// + + /// A list of AssociationWidgets between the UMLWidget and other UMLWidgets in the diagram + AssociationWidgetList m_Assocs; + + QString m_instanceName; ///< instance name (used if on a deployment diagram) + bool m_isInstance; ///< holds whether this widget is a component instance (i.e. on a deployment diagram) + bool m_showStereotype; ///< should the stereotype be displayed + + ///////////////// End of Data Loaded/Saved ////////////////////////// + + Uml::ID::Type m_nLocalID; + bool m_startMove; + QPointF m_startMovePostion; + QSizeF m_startResizeSize; + int m_nPosX; + UMLDoc *m_doc; ///< shortcut for UMLApp::app()->getDocument() + bool m_resizable; + QFontMetrics *m_pFontMetrics[FT_INVALID]; + QSizeF m_minimumSize; + QSizeF m_maximumSize; + + /// true if the activate function has been called for this class instance + bool m_activated; + + /** + * Change Widget Behaviour + */ + bool m_ignoreSnapToGrid; + bool m_ignoreSnapComponentSizeToGrid; + bool m_fixedAspectRatio; + + /// The text in the status bar when the cursor was pressed. + QString m_oldStatusBarMsg; + + /// The X/Y offset from the position of the cursor when it was pressed to the + /// upper left corner of the widget. + QPointF m_pressOffset; + + /// The X/Y position the widget had when the movement started. + QPointF m_oldPos; + + /// The width/height the widget had when the resize started. + qreal m_oldW, m_oldH; + + /// If shift or control button were pressed in mouse press event. + bool m_shiftPressed; + + /** + * If cursor was in move/resize area when left button was pressed (and no + * other widgets were selected). + */ + bool m_inMoveArea, m_inResizeArea; + + /** + * If the widget was selected/moved/resized in the press and release cycle. + * Moved/resized is true if the widget was moved/resized even if the final + * position/size is the same as the starting one. + */ + bool m_moved, m_resized; + +private: + void init(); + void toForeground(); + +}; +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/usecasewidget.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/usecasewidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/usecasewidget.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/usecasewidget.cpp 2015-10-08 11:48:59.553089025 +0300 @@ -0,0 +1,96 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header file +#include "usecasewidget.h" + +// app includes +#include "usecase.h" +#include "umlview.h" + +/** + * Creates a UseCase widget. + * @param scene The parent of the widget. + * @param o The UMLUseCase to represent. + */ +UseCaseWidget::UseCaseWidget(UMLScene * scene, UMLUseCase *o) + : UMLWidget(scene, WidgetBase::wt_UseCase, o) +{ +} + +/** + * Destructor. + */ +UseCaseWidget::~UseCaseWidget() +{ +} + +/** + * Overrides the standard paint event. + */ +void UseCaseWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + setPenFromSettings(painter); + if (UMLWidget::useFillColor()) + painter->setBrush(UMLWidget::fillColor()); + QFont font = UMLWidget::font(); + font.setUnderline(false); + font.setBold(false); + font.setItalic(m_umlObject->isAbstract()); + painter->setFont(font); + const QFontMetrics &fm = getFontMetrics(FT_NORMAL); + const int fontHeight = fm.lineSpacing(); + const int w = width(); + const int h = height(); + //int middleX = w / 2; + bool drawStereotype = umlObject() && !umlObject()->stereotype().isEmpty(); + const int textStartY = (h / 2) - (drawStereotype ? fontHeight / 4 : fontHeight / 2); + + painter->drawEllipse(0, 0, w, h); + painter->setPen(textColor()); + if (drawStereotype) + painter->drawText(UC_MARGIN, textStartY-fontHeight, w - UC_MARGIN * 2, fontHeight, Qt::AlignCenter, umlObject()->stereotype(true)); + + painter->drawText(UC_MARGIN, textStartY, w - UC_MARGIN * 2, fontHeight, Qt::AlignCenter, name()); + setPenFromSettings(painter); + + UMLWidget::paint(painter, option, widget); +} + +/** + * Saves this UseCase to file. + */ +void UseCaseWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) +{ + QDomElement usecaseElement = qDoc.createElement(QLatin1String("usecasewidget")); + UMLWidget::saveToXMI(qDoc, usecaseElement); + qElement.appendChild(usecaseElement); +} + +/** + * Overrides method from UMLWidget + */ +QSizeF UseCaseWidget::minimumSize() const +{ + const UMLWidget::FontType ft = (m_umlObject->isAbstract() ? FT_BOLD_ITALIC : FT_BOLD); + const QFontMetrics &fm = UMLWidget::getFontMetrics(ft); + const int fontHeight = fm.lineSpacing(); + const int textWidth = fm.width(name()); + bool drawStereotype = umlObject() && !umlObject()->stereotype().isEmpty(); + int width = textWidth > UC_WIDTH?textWidth:UC_WIDTH; + int height = UC_HEIGHT + (drawStereotype ? 2 * fontHeight : fontHeight) + UC_MARGIN; + + width += UC_MARGIN * 2; + + return QSizeF(width, height); +} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/usecasewidget.h umbrello-kf6-15.08.1/umbrello/umlwidgets/usecasewidget.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/usecasewidget.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/usecasewidget.h 2015-10-08 11:48:59.553089025 +0300 @@ -0,0 +1,58 @@ +/*************************************************************************** + * 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-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef USECASEWIDGET_H +#define USECASEWIDGET_H + +#include "umlwidget.h" + +class UMLUseCase; + +#define UC_MARGIN 5 +#define UC_WIDTH 60 +#define UC_HEIGHT 30 + + +/** + * This class is the graphical version of a UMLUseCase. The + * UseCaseWidget class inherits from the @ref UMLWidget class + * which adds most of the functionality to this class. + + * A UseCaseWidget is created by a @ref UMLView. An UseCaseWidget belongs to only one + * @ref UMLView instance. When the @ref UMLView instance that this class belongs to, + * it will be automatically deleted. + * + * If the @ref UMLUseCase class that this UseCaseWidget is displaying is deleted, the @ref UMLView will + * make sure that this instance is also deleted. + * + * The UseCaseWidget class inherits from the @ref UMLWidget class which adds most of the functionality + * to this class. + * + * @short A graphical version of a UMLUseCase. + * @author Paul Hensgen + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class UseCaseWidget : public UMLWidget +{ +public: + UseCaseWidget(UMLScene * scene, UMLUseCase *o); + virtual ~UseCaseWidget(); + + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + + // For loading we can use the loadFromXMI() inherited from + // UMLWidget. + virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); + +protected: + QSizeF minimumSize() const; +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widgetbase.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/widgetbase.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widgetbase.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/widgetbase.cpp 2015-10-08 11:48:59.553089025 +0300 @@ -0,0 +1,1119 @@ +/*************************************************************************** + * 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) 2004-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#include "widgetbase.h" + +#include "classifier.h" +#include "debug_utils.h" +#include "floatingtextwidget.h" +#include "optionstate.h" +#include "uml.h" +#include "umldoc.h" +#include "umlobject.h" +#include "umlscene.h" + +#if QT_VERSION < 0x050000 +#include +#include +#endif +#include + +#include +#if QT_VERSION >= 0x050000 +#include +#include +#endif +#include + +/** + * Creates a WidgetBase object. + * + * @param scene The view to be displayed on. + * @param type The WidgetType to construct. This must be set to the appropriate + * value by the constructors of inheriting classes. + */ +WidgetBase::WidgetBase(UMLScene *scene, WidgetType type) + : QGraphicsObject(), + m_baseType(type), + m_scene(scene), + m_umlObject(0), + m_textColor(QColor("black")), + m_lineColor(QColor("black")), + m_fillColor(QColor("yellow")), + m_brush(m_fillColor), + m_lineWidth(0), // initialize with 0 to have valid start condition + m_useFillColor(true), + m_usesDiagramTextColor(true), + m_usesDiagramLineColor(true), + m_usesDiagramLineWidth(true) +{ + setSelected(false); + scene->addItem(this); + + // TODO 310283 + setFlags(ItemIsSelectable); + //setFlags(ItemIsSelectable | ItemIsMovable |ItemSendsGeometryChanges); + if (m_scene) { + m_usesDiagramLineColor = true; + m_usesDiagramLineWidth = true; + m_usesDiagramTextColor = true; + const Settings::OptionState& optionState = m_scene->optionState(); + m_textColor = optionState.uiState.textColor; + m_lineColor = optionState.uiState.lineColor; + m_lineWidth = optionState.uiState.lineWidth; + m_font = optionState.uiState.font; + } else { + uError() << "WidgetBase constructor: SERIOUS PROBLEM - m_scene is NULL"; + } +} + +/** + * Destructor. + */ +WidgetBase::~WidgetBase() +{ +} + +/** + * Read property of m_baseType. + */ +WidgetBase::WidgetType WidgetBase::baseType() const +{ + return m_baseType; +} + +/** + * @return The type used for rtti as string. + */ +QLatin1String WidgetBase::baseTypeStr() const +{ + return QLatin1String(ENUM_NAME(WidgetBase, WidgetType, m_baseType)); +} + +/* + * Sets the state of whether the widget is selected. + * + * @param select The state of whether the widget is selected. + */ +void WidgetBase::setSelected(bool select) +{ + QGraphicsObject::setSelected(select); +} + +/** + * Deliver a pointer to the connected UMLView + * (needed esp. by event handling of AssociationLine). + */ +UMLScene* WidgetBase::umlScene() const +{ + return m_scene; +} + +/** + * This is shortcut method for UMLApp::app()->document(). + * + * @return Pointer to the UMLDoc object. + */ +UMLDoc* WidgetBase::umlDoc() const +{ + return UMLApp::app()->document(); +} + +/** + * Returns the @ref UMLObject set to represent. + * + * @return the UMLObject to represent. + */ +UMLObject* WidgetBase::umlObject() const +{ + return m_umlObject; +} + +/** + * Sets the @ref UMLObject to represent. + * + * @param obj The object to represent. + */ +void WidgetBase::setUMLObject(UMLObject *obj) +{ + m_umlObject = obj; +} + +/** + * Write property of m_nId. + */ +void WidgetBase::setID(Uml::ID::Type id) +{ + if (m_umlObject) { + if (m_umlObject->id() != Uml::ID::None) + uWarning() << "changing old UMLObject " << Uml::ID::toString(m_umlObject->id()) + << " to " << Uml::ID::toString(id); + m_umlObject->setID(id); + } + m_nId = id; +} + +/** + * Read property of m_nId. + */ +Uml::ID::Type WidgetBase::id() const +{ + if (m_umlObject) + return m_umlObject->id(); + return m_nId; +} + +/** + * Used by some child classes to get documentation. + * + * @return The documentation from the UMLObject (if m_umlObject is set.) + */ +QString WidgetBase::documentation() const +{ + if (m_umlObject) + return m_umlObject->doc(); + return m_Doc; +} + +/** + * Returns state of documentation for the widget. + * + * @return false if documentation is empty + */ +bool WidgetBase::hasDocumentation() +{ + if (m_umlObject) + return m_umlObject->hasDoc(); + return !m_Doc.isEmpty(); +} + +/** + * Used by some child classes to set documentation. + * + * @param doc The documentation to be set in the UMLObject + * (if m_umlObject is set.) + */ +void WidgetBase::setDocumentation(const QString& doc) +{ + if (m_umlObject) + m_umlObject->setDoc(doc); + else + m_Doc = doc; +} + +/** + * Gets the name from the corresponding UMLObject if this widget has an + * underlying UMLObject; if it does not, then it returns the local + * m_Text (notably the case for FloatingTextWidget.) + * + * @return the currently set name + */ +QString WidgetBase::name() const +{ + if (m_umlObject) + return m_umlObject->name(); + return m_Text; +} + +/** + * Sets the name in the corresponding UMLObject. + * Sets the local m_Text if m_umlObject is NULL. + * + * @param strName The name to be set. + */ +void WidgetBase::setName(const QString &strName) +{ + if (m_umlObject) + m_umlObject->setName(strName); + else + m_Text = strName; +} + +/** + * Returns text color + * + * @return currently used text color + */ +QColor WidgetBase::textColor() const +{ + return m_textColor; +} + +/** + * Sets the text color + * + * @param color the new text color + */ +void WidgetBase::setTextColor(const QColor &color) +{ + m_textColor = color; + m_usesDiagramTextColor = false; +} + +/** + * Returns line color + * + * @return currently used line color + */ +QColor WidgetBase::lineColor() const +{ + return m_lineColor; +} + +/** + * Sets the line color + * + * @param color The new line color + */ +void WidgetBase::setLineColor(const QColor &color) +{ + m_lineColor = color; + m_usesDiagramLineColor = false; +} + +/** + * Returns fill color + * + * @return currently used fill color + */ +QColor WidgetBase::fillColor() const +{ + return m_fillColor; +} + +/** + * Sets the fill color + * + * @param color The new fill color + */ +void WidgetBase::setFillColor(const QColor &color) +{ + m_fillColor = color; + m_usesDiagramFillColor = false; +} + +/** + * Returns line width + * + * @return currently used line with + */ +uint WidgetBase::lineWidth() const +{ + return m_lineWidth; +} + +/** + * Sets the line width + * + * @param width The new line width + */ +void WidgetBase::setLineWidth(uint width) +{ + m_lineWidth = width; + m_usesDiagramLineWidth = false; +} + +/** + * Return state of fill color usage + * + * @return True if fill color is used + */ +bool WidgetBase::useFillColor() +{ + return m_useFillColor; +} + +/** + * Set state if fill color is used + * + * @param state The state to set + */ +void WidgetBase::setUseFillColor(bool state) +{ + m_useFillColor = state; + m_usesDiagramUseFillColor = false; +} + +/** + * Returns state if diagram text color is used + * + * @return True means diagram text color is used + */ +bool WidgetBase::usesDiagramTextColor() const +{ + return m_usesDiagramTextColor; +} + +/** + * Set state if diagram text color is used + * + * @param state The state to set + */ +void WidgetBase::setUsesDiagramTextColor(bool state) +{ + if (m_usesDiagramTextColor == state) { + return; + } + m_usesDiagramTextColor = state; + setTextColor(m_textColor); +} + +/** + * Returns state of diagram line color is used + * + * @return True means diagrams line color is used +*/ +bool WidgetBase::usesDiagramLineColor() const +{ + return m_usesDiagramLineColor; +} + +/** + * Set state of diagram line color is used + * + * @param state The state to set + */ +void WidgetBase::setUsesDiagramLineColor(bool state) +{ + m_usesDiagramLineColor = state; +} + +/** + * Returns state of diagram fill color is used + * + * @return True means diagrams fill color is used +*/ +bool WidgetBase::usesDiagramFillColor() const +{ + return m_usesDiagramFillColor; +} + +/** + * Set state if diagram fill color is used + * + * @param state The state to set + */ +void WidgetBase::setUsesDiagramFillColor(bool state) +{ + m_usesDiagramFillColor = state; +} + +/** + * Returns state of diagram use fill color is used + * + * @return True means diagrams fill color is used +*/ +bool WidgetBase::usesDiagramUseFillColor() const +{ + return m_usesDiagramUseFillColor; +} + +/** + * Set state of diagram use fill color is used + * + * @param state The state to set + */ +void WidgetBase::setUsesDiagramUseFillColor(bool state) +{ + m_usesDiagramUseFillColor = state; +} + +/** + * Returns state of diagram line width is used + * + * @return True means diagrams line width is used + */ +bool WidgetBase::usesDiagramLineWidth() const +{ + return m_usesDiagramLineWidth; +} + +/** + * Set state of diagram line width is used + * + * @param state The state to set + */ +void WidgetBase::setUsesDiagramLineWidth(bool state) +{ + m_usesDiagramLineWidth = state; +} + +/** + * Returns the font used for diaplaying any text. + * @return the font + */ +QFont WidgetBase::font() const +{ + return m_font; +} + +/** + * Set the font used to display text inside this widget. + */ +void WidgetBase::setFont(const QFont& font) +{ + m_font = font; +} + +/** + * A virtual method for the widget to display a property dialog box. + * Subclasses should reimplment this appropriately. + */ +void WidgetBase::showPropertiesDialog() +{ +} + +/** + * A virtual method to save the properties of this widget into a + * QDomElement i.e xml. + * + * Subclasses should first create a new dedicated element as the child + * of \a qElement parameter passed. Then this base method should be + * called to save basic widget properties. + * + * @param qDoc A QDomDocument object representing the xml document. + * @param qElement A QDomElement representing xml element data. + */ +void WidgetBase::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) + { + Q_UNUSED(qDoc) + + qElement.setAttribute(QLatin1String("textcolor"), m_usesDiagramTextColor ? QLatin1String("none") + : m_textColor.name()); + if (m_usesDiagramLineColor) { + qElement.setAttribute(QLatin1String("linecolor"), QLatin1String("none")); + } else { + qElement.setAttribute(QLatin1String("linecolor"), m_lineColor.name()); + } + if (m_usesDiagramLineWidth) { + qElement.setAttribute(QLatin1String("linewidth"), QLatin1String("none")); + } else { + qElement.setAttribute(QLatin1String("linewidth"), m_lineWidth); + } + qElement.setAttribute(QLatin1String("usefillcolor"), m_useFillColor); + // for consistency the following attributes now use american spelling for "color" + qElement.setAttribute(QLatin1String("usesdiagramfillcolor"), m_usesDiagramFillColor); + qElement.setAttribute(QLatin1String("usesdiagramusefillcolor"), m_usesDiagramUseFillColor); + if (m_usesDiagramFillColor) { + qElement.setAttribute(QLatin1String("fillcolor"), QLatin1String("none")); + } else { + qElement.setAttribute(QLatin1String("fillcolor"), m_fillColor.name()); + } + qElement.setAttribute(QLatin1String("font"), m_font.toString()); +} + +/** + * A virtual method to load the properties of this widget from a + * QDomElement into this widget. + * + * Subclasses should reimplement this to load addtional properties + * required, calling this base method to load the basic properties of + * the widget. + * + * @param qElement A QDomElement which contains xml info for this widget. + * + * @todo Add support to load older version. + */ +bool WidgetBase::loadFromXMI(QDomElement& qElement) +{ + // first load from "linecolour" and then overwrite with the "linecolor" + // attribute if that one is present. The "linecolour" name was a "typo" in + // earlier versions of umbrello-kf6 + QString lineColor = qElement.attribute(QLatin1String("linecolour"), QLatin1String("none")); + lineColor = qElement.attribute(QLatin1String("linecolor"), lineColor); + if (lineColor != QLatin1String("none")) { + m_lineColor = QColor(lineColor); + m_usesDiagramLineColor = false; + } else if (m_baseType != WidgetBase::wt_Box && m_scene != NULL) { + m_lineColor = m_scene->lineColor(); + m_usesDiagramLineColor = true; + } + QString lineWidth = qElement.attribute(QLatin1String("linewidth"), QLatin1String("none")); + if (lineWidth != QLatin1String("none")) { + m_lineWidth = lineWidth.toInt(); + m_usesDiagramLineWidth = false; + } else if (m_scene) { + m_lineWidth = m_scene->lineWidth(); + m_usesDiagramLineWidth = true; + } + QString textColor = qElement.attribute(QLatin1String("textcolor"), QLatin1String("none")); + if (textColor != QLatin1String("none")) { + m_textColor = QColor(textColor); + m_usesDiagramTextColor = false; + } else if (m_scene) { + m_textColor = m_scene->textColor(); + m_usesDiagramTextColor = true; + } + QString usefillcolor = qElement.attribute(QLatin1String("usefillcolor"), QLatin1String("1")); + m_useFillColor = (bool)usefillcolor.toInt(); + /* + For the next three *color attributes, there was a mixup of american and english spelling for "color". + So first we need to keep backward compatibility and try to retrieve the *colour attribute. + Next we overwrite this value if we find a *color, otherwise the former *colour is kept. + */ + QString fillColor = qElement.attribute(QLatin1String("fillcolour"), QLatin1String("none")); + fillColor = qElement.attribute(QLatin1String("fillcolor"), fillColor); + if (fillColor != QLatin1String("none")) { + m_fillColor = QColor(fillColor); + } + + QString usesDiagramFillColor = qElement.attribute(QLatin1String("usesdiagramfillcolour"), QLatin1String("1")); + usesDiagramFillColor = qElement.attribute(QLatin1String("usesdiagramfillcolor"), usesDiagramFillColor); + m_usesDiagramFillColor = (bool)usesDiagramFillColor.toInt(); + + QString usesDiagramUseFillColor = qElement.attribute(QLatin1String("usesdiagramusefillcolour"), QLatin1String("1")); + usesDiagramUseFillColor = qElement.attribute(QLatin1String("usesdiagramusefillcolor"), usesDiagramUseFillColor); + m_usesDiagramUseFillColor = (bool)usesDiagramUseFillColor.toInt(); + + QString font = qElement.attribute(QLatin1String("font")); + if (!font.isEmpty()) { + QFont newFont; + newFont.fromString(font); + m_font = newFont; + } else { + uWarning() << "Using default font " << m_font.toString() + << " for widget with xmi.id " << Uml::ID::toString(m_nId); + } + + return true; +} + +/** + * Assignment operator + */ +WidgetBase& WidgetBase::operator=(const WidgetBase& other) +{ + m_baseType = other.m_baseType; + m_scene = other.m_scene; + m_umlObject = other.m_umlObject; + m_Doc = other.m_Doc; + m_Text = other.m_Text; + m_nId = other.m_nId; + m_textColor = other.m_textColor; + m_lineColor = other.m_lineColor; + m_fillColor = other.m_fillColor; + m_brush = other.m_brush; + m_font = other.m_font; + m_lineWidth = other.m_lineWidth; + m_useFillColor = other.m_useFillColor; + m_usesDiagramTextColor = other.m_usesDiagramTextColor; + m_usesDiagramLineColor = other.m_usesDiagramLineColor; + m_usesDiagramFillColor = other.m_usesDiagramFillColor; + m_usesDiagramLineWidth = other.m_usesDiagramLineWidth; + setSelected(other.isSelected()); + + return *this; +} + +/** + * return drawing rectangle of widget in local coordinates + */ +QRectF WidgetBase::rect() const +{ + return m_rect; +} + +/** + * set widget rectangle in item coordinates + */ +void WidgetBase::setRect(const QRectF& rect) +{ + if (m_rect == rect) + return; + prepareGeometryChange(); + m_rect = rect; + update(); +} + +/** + * set widget rectangle in item coordinates + */ +void WidgetBase::setRect(qreal x, qreal y, qreal width, qreal height) +{ + setRect(QRectF(x, y, width, height)); +} + +/** + * @return The bounding rectangle for this widget. + * @see setRect + */ +QRectF WidgetBase::boundingRect() const +{ + int halfWidth = lineWidth()/2; + return m_rect.adjusted(-halfWidth, -halfWidth, halfWidth, halfWidth); +} + +/** + * Test if point is inside the bounding rectangle of the widget. + * Inheriting classes may reimplement this to test possible child widgets. + * + * @param p Point to be checked. + * + * @return 'this' if the given point is in the boundaries of the widget; + * else NULL. + */ +UMLWidget* WidgetBase::onWidget(const QPointF &p) +{ + UMLWidget *uw = dynamic_cast(this); + if (uw == NULL) + return NULL; + const qreal w = m_rect.width(); + const qreal h = m_rect.height(); + const qreal left = x(); // don't use m_rect.x() for this, it is always 0 + const qreal right = left + w; + const qreal top = y(); // don't use m_rect.y() for this, it is always 0 + const qreal bottom = top + h; + // uDebug() << "p=(" << p.x() << "," << p.y() + // << "), x=" << left << ", y=" << top << ", w=" << w << ", h=" << h + // << "; right=" << right << ", bottom=" << bottom; + if (p.x() < left || p.x() > right || + p.y() < top || p.y() > bottom) { // Qt coord.sys. origin in top left corner + // uDebug() << "returning NULL"; + return NULL; + } + // uDebug() << "returning this"; + return uw; +} + +/** + * Draws the UMLWidget on the given paint device + * + * @param painter The painter for the drawing device + * @param option Painting related options + * @param widget Background widget on which to paint (optional) + * + */ +void WidgetBase::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(painter); Q_UNUSED(option); Q_UNUSED(widget); +} + +/** + * Reimplemented to show appropriate context menu. + */ +void WidgetBase::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) +{ + event->accept(); + uDebug() << "widget = " << name() << " / type = " << baseTypeStr(); + + UMLScene *scene = umlScene(); + + // If right-click was done on a widget that was not selected, clear the + // current selection and select the new widget. The context menu is shown + // with actions for that single widget. + // If a keyboard modifier was used, add the widget to the current selection + // and show the menu with actions for the whole selection. + if (!isSelected()) { + Qt::KeyboardModifiers forSelection = (Qt::ControlModifier | Qt::ShiftModifier); + if ((event->modifiers() & forSelection) == 0) { + scene->clearSelected(); + } + + if (umlObject() != 0) { + scene->selectWidget(dynamic_cast(this)); + } else { + setSelected(true); + } + } + + int count = scene->selectedCount(true); + + // Determine multi state + bool multi = (isSelected() && count > 1); + + ListPopupMenu popup(0, this, multi, scene->getUniqueSelectionType()); + + // Disable the "view code" menu for simple code generators + if (UMLApp::app()->isSimpleCodeGeneratorActive()) { + popup.setActionEnabled(ListPopupMenu::mt_ViewCode, false); + } + + QAction *triggered = popup.exec(event->screenPos()); + ListPopupMenu *parentMenu = ListPopupMenu::menuFromAction(triggered); + + if (!parentMenu) { + uDebug() << "Action's data field does not contain ListPopupMenu pointer"; + return; + } + + WidgetBase *ownerWidget = parentMenu->ownerWidget(); + // assert because logic is based on only WidgetBase being the owner of + // ListPopupMenu actions executed in this context menu. + Q_ASSERT_X(ownerWidget != 0, "WidgetBase::contextMenuEvent", + "ownerWidget is null which means action belonging to UMLView, UMLScene" + " or UMLObject is the one triggered in ListPopupMenu"); + + ownerWidget->slotMenuSelection(triggered); +} + +/** + * This is usually called synchronously after menu.exec() and \a + * trigger's parent is always the ListPopupMenu which can be used to + * get the type of action of \a trigger. + * + * @note Subclasses can reimplement to handle specific actions and + * leave the rest to WidgetBase::slotMenuSelection. + */ +void WidgetBase::slotMenuSelection(QAction *trigger) +{ + if (!trigger) { + return; + } + QColor newColor; + + const WidgetType wt = m_baseType; // short hand name + + ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(trigger); + switch (sel) { + case ListPopupMenu::mt_Rename: + umlDoc()->renameUMLObject(umlObject()); + break; + + case ListPopupMenu::mt_Properties: + if (wt == WidgetBase::wt_Actor || wt == WidgetBase::wt_UseCase || + wt == WidgetBase::wt_Package || wt == WidgetBase::wt_Interface || + wt == WidgetBase::wt_Datatype || wt == WidgetBase::wt_Node || + wt == WidgetBase::wt_Component || wt == WidgetBase::wt_Artifact || + wt == WidgetBase::wt_Enum || wt == WidgetBase::wt_Entity || + wt == WidgetBase::wt_Port || + (wt == WidgetBase::wt_Class && umlScene()->type() == Uml::DiagramType::Class)) { + + showPropertiesDialog(); + + } else if (wt == WidgetBase::wt_Object) { + m_umlObject->showPropertiesDialog(); + } else { + uWarning() << "making properties dialog for unknown widget type"; + } + break; + + case ListPopupMenu::mt_Line_Color: + case ListPopupMenu::mt_Line_Color_Selection: +#if QT_VERSION >= 0x050000 + newColor = QColorDialog::getColor(lineColor()); + if (newColor != lineColor()) { +#else + newColor = lineColor(); + if (KColorDialog::getColor(newColor)) { +#endif + if (sel == ListPopupMenu::mt_Line_Color_Selection) { + umlScene()->selectionSetLineColor(newColor); + } else { + setLineColor(newColor); + } + setUsesDiagramLineColor(false); + umlDoc()->setModified(true); + } + break; + + case ListPopupMenu::mt_Fill_Color: + case ListPopupMenu::mt_Fill_Color_Selection: +#if QT_VERSION >= 0x050000 + newColor = QColorDialog::getColor(fillColor()); + if (newColor != fillColor()) { +#else + newColor = fillColor(); + if (KColorDialog::getColor(newColor)) { +#endif + if (sel == ListPopupMenu::mt_Fill_Color_Selection) { + umlScene()->selectionSetFillColor(newColor); + } else { + setFillColor(newColor); + } + umlDoc()->setModified(true); + } + break; + + case ListPopupMenu::mt_Use_Fill_Color: + setUseFillColor(!m_useFillColor); + break; + + case ListPopupMenu::mt_Set_Use_Fill_Color_Selection: + umlScene()->selectionUseFillColor(true); + break; + + case ListPopupMenu::mt_Unset_Use_Fill_Color_Selection: + umlScene()->selectionUseFillColor(false); + break; + + case ListPopupMenu::mt_Show_Attributes_Selection: + case ListPopupMenu::mt_Hide_Attributes_Selection: + umlScene()->selectionSetVisualProperty( + ClassifierWidget::ShowAttributes, sel != ListPopupMenu::mt_Hide_Attributes_Selection + ); + break; + + case ListPopupMenu::mt_Show_Operations_Selection: + case ListPopupMenu::mt_Hide_Operations_Selection: + umlScene()->selectionSetVisualProperty( + ClassifierWidget::ShowOperations, sel != ListPopupMenu::mt_Hide_Operations_Selection + ); + break; + + case ListPopupMenu::mt_Show_Visibility_Selection: + case ListPopupMenu::mt_Hide_Visibility_Selection: + umlScene()->selectionSetVisualProperty( + ClassifierWidget::ShowVisibility, sel != ListPopupMenu::mt_Hide_Visibility_Selection + ); + break; + + case ListPopupMenu::mt_Show_Operation_Signature_Selection: + case ListPopupMenu::mt_Hide_Operation_Signature_Selection: + umlScene()->selectionSetVisualProperty( + ClassifierWidget::ShowOperationSignature, sel != ListPopupMenu::mt_Hide_Operation_Signature_Selection + ); + break; + + case ListPopupMenu::mt_Show_Attribute_Signature_Selection: + case ListPopupMenu::mt_Hide_Attribute_Signature_Selection: + umlScene()->selectionSetVisualProperty( + ClassifierWidget::ShowAttributeSignature, sel != ListPopupMenu::mt_Hide_Attribute_Signature_Selection + ); + break; + + case ListPopupMenu::mt_Show_Packages_Selection: + case ListPopupMenu::mt_Hide_Packages_Selection: + umlScene()->selectionSetVisualProperty( + ClassifierWidget::ShowPackage, sel != ListPopupMenu::mt_Hide_Packages_Selection + ); + break; + + case ListPopupMenu::mt_Show_Stereotypes_Selection: + case ListPopupMenu::mt_Hide_Stereotypes_Selection: + umlScene()->selectionSetVisualProperty( + ClassifierWidget::ShowStereotype, sel != ListPopupMenu::mt_Hide_Stereotypes_Selection + ); + break; + + case ListPopupMenu::mt_Hide_NonPublic_Selection: + case ListPopupMenu::mt_Show_NonPublic_Selection: + umlScene()->selectionSetVisualProperty( + ClassifierWidget::ShowPublicOnly, sel != ListPopupMenu::mt_Show_NonPublic_Selection + ); + break; + + + case ListPopupMenu::mt_ViewCode: { + UMLClassifier *c = dynamic_cast(umlObject()); + if (c) { + UMLApp::app()->viewCodeDocument(c); + } + break; + } + + case ListPopupMenu::mt_Delete: + umlScene()->deleteSelection(); + break; + + case ListPopupMenu::mt_Change_Font: + case ListPopupMenu::mt_Change_Font_Selection: { +#if QT_VERSION >= 0x050000 + bool ok = false; + QFont newFont = QFontDialog::getFont(&ok, font()); + if (ok) { +#else + QFont newFont = font(); + if (KFontDialog::getFont(newFont, KFontChooser::NoDisplayFlags, 0) == KFontDialog::Accepted) { +#endif + if (sel == ListPopupMenu::mt_Change_Font_Selection) { + m_scene->selectionSetFont(newFont); + } else { + setFont(newFont); + } + } + } + break; + + case ListPopupMenu::mt_Cut: + umlScene()->setStartedCut(); + UMLApp::app()->slotEditCut(); + break; + + case ListPopupMenu::mt_Copy: + UMLApp::app()->slotEditCopy(); + break; + + case ListPopupMenu::mt_Paste: + UMLApp::app()->slotEditPaste(); + break; + + case ListPopupMenu::mt_Refactoring: + //check if we are operating on a classifier, or some other kind of UMLObject + if (dynamic_cast(umlObject())) { + UMLApp::app()->refactor(static_cast(umlObject())); + } + break; + + case ListPopupMenu::mt_Clone: + { + foreach (UMLWidget* widget, umlScene()->selectedWidgets()) { + if (Model_Utils::isCloneable(widget->baseType())) { + UMLObject *clone = widget->umlObject()->clone(); + umlScene()->addObject(clone); + } + } + } + break; + + case ListPopupMenu::mt_Rename_MultiA: + case ListPopupMenu::mt_Rename_MultiB: + case ListPopupMenu::mt_Rename_Name: + case ListPopupMenu::mt_Rename_RoleAName: + case ListPopupMenu::mt_Rename_RoleBName: { + FloatingTextWidget *ft = static_cast(this); + ft->handleRename(); + break; + } + case ListPopupMenu::mt_Align_Right: + umlScene()->alignRight(); + break; + case ListPopupMenu::mt_Align_Left: + umlScene()->alignLeft(); + break; + case ListPopupMenu::mt_Align_Top: + umlScene()->alignTop(); + break; + case ListPopupMenu::mt_Align_Bottom: + umlScene()->alignBottom(); + break; + case ListPopupMenu::mt_Align_VerticalMiddle: + umlScene()->alignVerticalMiddle(); + break; + case ListPopupMenu::mt_Align_HorizontalMiddle: + umlScene()->alignHorizontalMiddle(); + break; + case ListPopupMenu::mt_Align_VerticalDistribute: + umlScene()->alignVerticalDistribute(); + break; + case ListPopupMenu::mt_Align_HorizontalDistribute: + umlScene()->alignHorizontalDistribute(); + break; + default: + uDebug() << "MenuType " << ListPopupMenu::toString(sel) << " not implemented"; + break; + } +} + +/** + * Helper function for debug output. + * Returns the given enum value as string. + * @param wt WidgetType of which a string representation is wanted + * @return the WidgetType as string + */ +QString WidgetBase::toString(WidgetType wt) +{ + return QLatin1String(ENUM_NAME(WidgetBase, WidgetType, wt)); +} + +/** + * Returns the given enum value as localized string. + * @param wt WidgetType of which a string representation is wanted + * @return the WidgetType as localized string + */ +QString WidgetBase::toI18nString(WidgetType wt) +{ + QString name; + + switch (wt) { + case wt_Activity: + name = i18n("Activity"); + break; + case wt_Actor: + name = i18n("Actor"); + break; + case wt_Artifact: + name = i18n("Artifact"); + break; + case wt_Association: + name = i18n("Association"); + break; + case wt_Box: + name = i18n("Box"); + break; + case wt_Category: + name = i18n("Category"); + break; + case wt_CombinedFragment: + name = i18n("CombinedFragment"); + break; + case wt_Component: + name = i18n("Component"); + break; + case wt_Class: + name = i18n("Class"); + break; + case wt_Datatype: + name = i18n("Datatype"); + break; + case wt_Entity: + name = i18n("Entity"); + break; + case wt_Enum: + name = i18n("Enum"); + break; + case wt_FloatingDashLine: + name = i18n("FloatingDashLine"); + break; + case wt_ForkJoin: + name = i18n("ForkJoin"); + break; + case wt_Interface: + name = i18n("Interface"); + break; + case wt_Message: + name = i18n("Message"); + break; + case wt_Node: + name = i18n("Node"); + break; + case wt_Note: + name = i18n("Note"); + break; + case wt_Object: + name = i18n("Object"); + break; + case wt_ObjectNode: + name = i18n("ObjectNode"); + break; + case wt_Package: + name = i18n("Package"); + break; + case wt_Pin: + name = i18n("Pin"); + break; + case wt_Port: + name = i18n("Port"); + break; + case wt_Precondition: + name = i18n("Precondition"); + break; + case wt_Region: + name = i18n("Region"); + break; + case wt_Signal: + name = i18n("Signal"); + break; + case wt_State: + name = i18n("State"); + break; + case wt_Text: + name = i18n("Text"); + break; + case wt_UseCase: + name = i18n("UseCase"); + break; + default: + name = QLatin1String(" &name:"); + uWarning() << "unknown widget type"; + break; + } + return name; +} + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widgetbase.h umbrello-kf6-15.08.1/umbrello/umlwidgets/widgetbase.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widgetbase.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/widgetbase.h 2015-10-08 11:48:59.553089025 +0300 @@ -0,0 +1,192 @@ +/*************************************************************************** + * 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) 2004-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef WIDGETBASE_H +#define WIDGETBASE_H + +#include "basictypes.h" + +#include +#include +#include +#include +#include +#include + +// forward declarations +class QAction; +class UMLDoc; +class UMLObject; +class UMLScene; +class UMLWidget; // required by function onWidget() + +/** + * @short Common base class for UMLWidget and AssociationWidget + * @author Oliver Kellogg + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +class WidgetBase : public QGraphicsObject +{ + Q_OBJECT + Q_ENUMS(WidgetType) + +public: + enum WidgetType + { + wt_UMLWidget = 300, // does not have UMLObject representation + wt_Actor, // has UMLObject representation + wt_UseCase, // has UMLObject representation + wt_Class, // has UMLObject representation + wt_Interface, // has UMLObject representation + wt_Datatype, // has UMLObject representation + wt_Enum, // has UMLObject representation + wt_Entity, // has UMLObject representation + wt_Package, // has UMLObject representation + wt_Object, // has UMLObject representation + wt_Note, // does not have UMLObject representation + wt_Box, // does not have UMLObject representation + wt_Message, // does not have UMLObject representation + wt_Text, // does not have UMLObject representation + wt_State, // does not have UMLObject representation + wt_Activity, // does not have UMLObject representation + wt_Component, // has UMLObject representation + wt_Artifact, // has UMLObject representation + wt_Node, // has UMLObject representation + wt_Association, // has UMLObject representation + wt_ForkJoin, // does not have UMLObject representation + wt_Precondition, // does not have UMLObject representation + wt_CombinedFragment, // does not have UMLObject representation + wt_FloatingDashLine, // does not have UMLObject representation + wt_Signal, // does not have UMLObject representation + wt_Pin, + wt_ObjectNode, + wt_Region, + wt_Category, // has UMLObject representation + wt_Port // has UMLObject representation + }; + + static QString toString(WidgetType wt); + static QString toI18nString(WidgetType wt); + + explicit WidgetBase(UMLScene * scene, WidgetType type= wt_UMLWidget); + virtual ~WidgetBase(); + + UMLObject* umlObject() const; + virtual void setUMLObject(UMLObject *obj); + + Uml::ID::Type id() const; + void setID(Uml::ID::Type id); + + WidgetType baseType() const; + QLatin1String baseTypeStr() const; + + virtual void setSelected(bool select); + + UMLScene* umlScene() const; + UMLDoc* umlDoc() const; + + QString documentation() const; + bool hasDocumentation(); + virtual void setDocumentation(const QString& doc); + + QString name() const; + virtual void setName(const QString &strName); + + QColor lineColor() const; + virtual void setLineColor(const QColor& color); + + uint lineWidth() const; + virtual void setLineWidth(uint width); + + QColor textColor() const; + virtual void setTextColor(const QColor& color); + + QColor fillColor() const; + virtual void setFillColor(const QColor& color); + + bool usesDiagramLineColor() const; + void setUsesDiagramLineColor(bool state); + + bool usesDiagramLineWidth() const; + void setUsesDiagramLineWidth(bool state); + + bool useFillColor(); + virtual void setUseFillColor(bool state); + + bool usesDiagramTextColor() const; + void setUsesDiagramTextColor(bool state); + + bool usesDiagramFillColor() const; + void setUsesDiagramFillColor(bool state); + + bool usesDiagramUseFillColor() const; + void setUsesDiagramUseFillColor(bool state); + + virtual QFont font() const; + virtual void setFont(const QFont& font); + + virtual void showPropertiesDialog(); + + virtual bool loadFromXMI(QDomElement &qElement); + virtual void saveToXMI(QDomDocument &qDoc, QDomElement &qElement); + + WidgetBase& operator=(const WidgetBase& other); + + QRectF rect() const; + void setRect(const QRectF& rect); + void setRect(qreal x, qreal y, qreal width, qreal height); + + virtual QRectF boundingRect() const; + + virtual UMLWidget* onWidget(const QPointF &p); + + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + +public Q_SLOTS: + virtual void slotMenuSelection(QAction *trigger); + +protected: + virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *event); + + WidgetType m_baseType; ///< Type of widget. + UMLScene *m_scene; + UMLObject *m_umlObject; + QString m_Doc; ///< Only used if m_umlObject is not set. + QString m_Text; + QRectF m_rect; ///< widget size + + /** + * This ID is only used when the widget does not have a + * corresponding UMLObject (i.e. the m_umlObject pointer is NULL.) + * For UMLObjects, the ID from the UMLObject is used. + */ + Uml::ID::Type m_nId; + + QColor m_textColor; ///< Color of the text of the widget. Is saved to XMI. + QColor m_lineColor; ///< Color of the lines of the widget. Is saved to XMI. + QColor m_fillColor; ///< color of the background of the widget + QBrush m_brush; + QFont m_font; + uint m_lineWidth; ///< Width of the lines of the widget. Is saved to XMI. + bool m_useFillColor; ///< flag indicates if the UMLWidget uses the Diagram FillColour + + /** + * true by default, false if the colors have + * been explicitly set for this widget. + * These are saved to XMI. + */ + bool m_usesDiagramTextColor; + bool m_usesDiagramLineColor; + bool m_usesDiagramFillColor; + bool m_usesDiagramUseFillColor; + bool m_usesDiagramLineWidth; +}; + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widget_factory.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/widget_factory.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widget_factory.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/widget_factory.cpp 2015-10-08 11:48:59.553089025 +0300 @@ -0,0 +1,298 @@ +/*************************************************************************** + * 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) 2006-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "widget_factory.h" + +// app includes +#include "activitywidget.h" +#include "actor.h" +#include "actorwidget.h" +#include "artifact.h" +#include "artifactwidget.h" +#include "associationwidget.h" +#include "boxwidget.h" +#include "category.h" +#include "categorywidget.h" +#include "classifier.h" +#include "classifierwidget.h" +#include "cmds.h" +#include "combinedfragmentwidget.h" +#include "component.h" +#include "componentwidget.h" +#include "datatypewidget.h" +#include "debug_utils.h" +#include "entity.h" +#include "entitywidget.h" +#include "enum.h" +#include "enumwidget.h" +#include "floatingdashlinewidget.h" +#include "floatingtextwidget.h" +#include "folder.h" +#include "forkjoinwidget.h" +#include "messagewidget.h" +#include "node.h" +#include "nodewidget.h" +#include "notewidget.h" +#include "object_factory.h" +#include "objectnodewidget.h" +#include "objectwidget.h" +#include "package.h" +#include "packagewidget.h" +#include "pinwidget.h" +#include "port.h" +#include "portwidget.h" +#include "preconditionwidget.h" +#include "regionwidget.h" +#include "signalwidget.h" +#include "statewidget.h" +#include "uml.h" +#include "umldoc.h" +#include "umlscene.h" +#include "umlview.h" +#include "usecase.h" +#include "usecasewidget.h" + +namespace Widget_Factory { + +/** + * Create a UMLWidget in the given view and representing the given document object. + */ +UMLWidget *createWidget(UMLScene *scene, UMLObject *o) +{ + QPointF pos = scene->pos(); + int y = pos.y(); + Uml::DiagramType::Enum diagramType = scene->type(); + UMLObject::ObjectType type = o->baseType(); + UMLWidget *newWidget = NULL; + switch (type) { + case UMLObject::ot_Actor: + if (diagramType == Uml::DiagramType::Sequence) { + ObjectWidget *ow = new ObjectWidget(scene, o); + ow->setDrawAsActor(true); + y = ow->topMargin(); + newWidget = ow; + } else + newWidget = new ActorWidget(scene, static_cast(o)); + break; + case UMLObject::ot_UseCase: + newWidget = new UseCaseWidget(scene, static_cast(o)); + break; + case UMLObject::ot_Folder: + newWidget = new PackageWidget(scene, static_cast(o)); + break; + case UMLObject::ot_Package: + newWidget = new ClassifierWidget(scene, static_cast(o)); + break; + case UMLObject::ot_Component: + newWidget = new ComponentWidget(scene, static_cast(o)); + if (diagramType == Uml::DiagramType::Deployment) { + newWidget->setIsInstance(true); + } + break; + case UMLObject::ot_Port: + { + PinPortBase *pw = new PortWidget(scene, static_cast(o)); + pw->attachToOwner(); + newWidget = pw; + } + break; + case UMLObject::ot_Node: + newWidget = new NodeWidget(scene, static_cast(o)); + break; + case UMLObject::ot_Artifact: + newWidget = new ArtifactWidget(scene, static_cast(o)); + break; + case UMLObject::ot_Datatype: + newWidget = new DatatypeWidget(scene, static_cast(o)); + break; + case UMLObject::ot_Enum: + newWidget = new EnumWidget(scene, static_cast(o)); + break; + case UMLObject::ot_Entity: + newWidget = new EntityWidget(scene, static_cast(o)); + break; + case UMLObject::ot_Interface: + if (diagramType == Uml::DiagramType::Sequence || diagramType == Uml::DiagramType::Collaboration) { + ObjectWidget *ow = new ObjectWidget(scene, o); + if (diagramType == Uml::DiagramType::Sequence) { + y = ow->topMargin(); + } + newWidget = ow; + } else { + UMLClassifier *c = static_cast(o); + ClassifierWidget* interfaceWidget = new ClassifierWidget(scene, c); + if (diagramType == Uml::DiagramType::Component || diagramType == Uml::DiagramType::Deployment) { + interfaceWidget->setDrawAsCircle(true); + } + newWidget = interfaceWidget; + } + break; + case UMLObject::ot_Class: + //see if we really want an object widget or class widget + if (diagramType == Uml::DiagramType::Class || diagramType == Uml::DiagramType::Component) { + UMLClassifier *c = static_cast(o); + ClassifierWidget *cw = new ClassifierWidget(scene, c); + if (diagramType == Uml::DiagramType::Component) + cw->setDrawAsCircle(true); + newWidget = cw; + } else { + ObjectWidget *ow = new ObjectWidget(scene, o); + if (diagramType == Uml::DiagramType::Sequence) { + y = ow->topMargin(); + } + newWidget = ow; + } + break; + case UMLObject::ot_Category: + newWidget = new CategoryWidget(scene, static_cast(o)); + break; + default: + uWarning() << "trying to create an invalid widget (" << UMLObject::toString(type) << ")"; + } + + if (newWidget) { + newWidget->setX(pos.x()); + newWidget->setY(y); + } + + return newWidget; +} + +bool validateObjType(UMLObject::ObjectType expected, UMLObject* &o, Uml::ID::Type id) +{ + if (o == NULL) { + uDebug() << "Widget_Factory::validateObjType: creating new object of type " + << expected; + QString artificialName = QLatin1String("LOST_") + Uml::ID::toString(id); + o = Object_Factory::createUMLObject(expected, artificialName, NULL, false); + if (o == NULL) + return false; + o->setID(id); + UMLPackage *parentPkg = o->umlPackage(); + parentPkg->addObject(o); + return true; + } + UMLObject::ObjectType actual = o->baseType(); + if (actual == expected) + return true; + uError() << "validateObjType(" << o->name() + << "): expected type " << UMLObject::toString(expected) << ", actual type " + << UMLObject::toString(actual); + return false; +} + +/** + * Create a UMLWidget according to the given XMI tag. + */ +UMLWidget* makeWidgetFromXMI(const QString& tag, + const QString& idStr, UMLScene *scene) +{ + UMLWidget *widget = NULL; + + // Loading of widgets which do NOT represent any UMLObject, + // just graphic stuff with no real model information + //FIXME while boxes and texts are just diagram objects, activities and + // states should be UMLObjects + if (tag == QLatin1String("statewidget") || tag == QLatin1String("UML:StateWidget")) { + widget = new StateWidget(scene, StateWidget::Normal, Uml::ID::Reserved); + } else if (tag == QLatin1String("notewidget") || tag == QLatin1String("UML:NoteWidget")) { + widget = new NoteWidget(scene, NoteWidget::Normal, Uml::ID::Reserved); + } else if (tag == QLatin1String("boxwidget")) { + widget = new BoxWidget(scene, Uml::ID::Reserved); + } else if (tag == QLatin1String("floatingtext") || tag == QLatin1String("UML:FloatingTextWidget")) { + widget = new FloatingTextWidget(scene, Uml::TextRole::Floating, QString(), Uml::ID::Reserved); + } else if (tag == QLatin1String("activitywidget") || tag == QLatin1String("UML:ActivityWidget")) { + widget = new ActivityWidget(scene, ActivityWidget::Initial, Uml::ID::Reserved); + } else if (tag == QLatin1String("messagewidget")) { + widget = new MessageWidget(scene, Uml::SequenceMessage::Asynchronous, Uml::ID::Reserved); + } else if (tag == QLatin1String("forkjoin")) { + widget = new ForkJoinWidget(scene, Qt::Vertical, Uml::ID::Reserved); + } else if (tag == QLatin1String("preconditionwidget")) { + widget = new PreconditionWidget(scene, NULL, Uml::ID::Reserved); + } else if (tag == QLatin1String("combinedFragmentwidget")) { + widget = new CombinedFragmentWidget(scene, CombinedFragmentWidget::Ref, Uml::ID::Reserved); + } else if (tag == QLatin1String("signalwidget")) { + widget = new SignalWidget(scene, SignalWidget::Send, Uml::ID::Reserved); + } else if (tag == QLatin1String("floatingdashlinewidget")) { + widget = new FloatingDashLineWidget(scene, Uml::ID::Reserved); + } else if (tag == QLatin1String("objectnodewidget")) { + widget = new ObjectNodeWidget(scene, ObjectNodeWidget::Normal, Uml::ID::Reserved); + } else if (tag == QLatin1String("regionwidget")) { + widget = new RegionWidget(scene, Uml::ID::Reserved); + } else if (tag == QLatin1String("pinwidget")) { + PinPortBase *pw = new PinWidget(scene, NULL, Uml::ID::Reserved); + pw->attachToOwner(); + widget = pw; + } + else + { + // Loading of widgets which represent an UMLObject + + // Find the UMLObject and create the Widget to represent it + Uml::ID::Type id = Uml::ID::fromString(idStr); + UMLDoc *umldoc = UMLApp::app()->document(); + UMLObject *o = umldoc->findObjectById(id); + if (o == NULL) { + uDebug() << "makeWidgetFromXMI: cannot find object with id " + << Uml::ID::toString(id); + } + + if (tag == QLatin1String("actorwidget") || tag == QLatin1String("UML:ActorWidget")) { + if (validateObjType(UMLObject::ot_Actor, o, id)) + widget = new ActorWidget(scene, static_cast(o)); + } else if (tag == QLatin1String("usecasewidget") || tag == QLatin1String("UML:UseCaseWidget")) { + if (validateObjType(UMLObject::ot_UseCase, o, id)) + widget = new UseCaseWidget(scene, static_cast(o)); + } else if (tag == QLatin1String("classwidget") || + tag == QLatin1String("UML:ClassWidget") || tag == QLatin1String("UML:ConceptWidget")) { + if (validateObjType(UMLObject::ot_Class, o, id) || validateObjType(UMLObject::ot_Package, o, id)) + widget = new ClassifierWidget(scene, static_cast(o)); + } else if (tag == QLatin1String("packagewidget")) { + if (validateObjType(UMLObject::ot_Package, o, id)) + widget = new ClassifierWidget(scene, static_cast(o)); + } else if (tag == QLatin1String("componentwidget")) { + if (validateObjType(UMLObject::ot_Component, o, id)) + widget = new ComponentWidget(scene, static_cast(o)); + } else if (tag == QLatin1String("portwidget")) { + if (validateObjType(UMLObject::ot_Port, o, id)) + widget = new PortWidget(scene, static_cast(o)); + } else if (tag == QLatin1String("nodewidget")) { + if (validateObjType(UMLObject::ot_Node, o, id)) + widget = new NodeWidget(scene, static_cast(o)); + } else if (tag == QLatin1String("artifactwidget")) { + if (validateObjType(UMLObject::ot_Artifact, o, id)) + widget = new ArtifactWidget(scene, static_cast(o)); + } else if (tag == QLatin1String("interfacewidget")) { + if (validateObjType(UMLObject::ot_Interface, o, id)) + widget = new ClassifierWidget(scene, static_cast(o)); + } else if (tag == QLatin1String("datatypewidget")) { + if (validateObjType(UMLObject::ot_Datatype, o, id)) + widget = new DatatypeWidget(scene, static_cast(o)); + } else if (tag == QLatin1String("enumwidget")) { + if (validateObjType(UMLObject::ot_Enum, o, id)) + widget = new EnumWidget(scene, static_cast(o)); + } else if (tag == QLatin1String("entitywidget")) { + if (validateObjType(UMLObject::ot_Entity, o, id)) + widget = new EntityWidget(scene, static_cast(o)); + } else if (tag == QLatin1String("categorywidget")) { + if (validateObjType(UMLObject::ot_Category, o, id)) + widget = new CategoryWidget(scene, static_cast(o)); + } else if (tag == QLatin1String("objectwidget") || tag == QLatin1String("UML:ObjectWidget")) { + widget = new ObjectWidget(scene, o); + } else { + uWarning() << "Trying to create an unknown widget:" << tag; + } + } + return widget; +} + +} // end namespace Widget_Factory + diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widget_factory.h umbrello-kf6-15.08.1/umbrello/umlwidgets/widget_factory.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widget_factory.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/widget_factory.h 2015-10-08 11:48:59.553089025 +0300 @@ -0,0 +1,34 @@ +/*************************************************************************** + * 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) 2006-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef WIDGET_FACTORY_H +#define WIDGET_FACTORY_H + +#include + +// forward declarations +class UMLObject; +class UMLScene; +class UMLWidget; + +/** + * Widget factory methods. + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +namespace Widget_Factory { + + UMLWidget *createWidget(UMLScene *scene, UMLObject *docObj); + + UMLWidget* makeWidgetFromXMI(const QString& tag, + const QString& idStr, UMLScene *scene); + +} // end namespace Widget_Factory + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widgetlist_utils.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/widgetlist_utils.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widgetlist_utils.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/widgetlist_utils.cpp 2015-10-08 11:48:59.553089025 +0300 @@ -0,0 +1,157 @@ +/*************************************************************************** + * 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) 2009-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "widgetlist_utils.h" + +// app includes +#include "debug_utils.h" +#include "umlwidget.h" + +// qt/kde includes +#include + +namespace WidgetList_Utils +{ + +/** + * Looks for the smallest x-value of the given UMLWidgets. + * @param widgetList A list with UMLWidgets. + * @return The smallest X position. + */ +qreal getSmallestX(const UMLWidgetList &widgetList) +{ + qreal smallestX = 0; + + int i = 1; + foreach(UMLWidget *widget, widgetList) { + if (i == 1) { + smallestX = widget->x(); + } else { + if (smallestX > widget->x()) + smallestX = widget->x(); + } + i++; + } + + return smallestX; +} + +/** + * Looks for the smallest y-value of the given UMLWidgets. + * @param widgetList A list with UMLWidgets. + * @return The smallest Y position. + */ +qreal getSmallestY(const UMLWidgetList &widgetList) +{ + if (widgetList.isEmpty()) + return -1; + + qreal smallestY = 0; + + int i = 1; + foreach(UMLWidget *widget, widgetList) { + if (i == 1) { + smallestY = widget->y(); + } else { + if (smallestY > widget->y()) + smallestY = widget->y(); + } + i++; + } + + return smallestY; +} + +/** + * Looks for the biggest x-value of the given UMLWidgets. + * @param widgetList A list with UMLWidgets. + * @return The biggest X position. + */ +qreal getBiggestX(const UMLWidgetList &widgetList) +{ + if (widgetList.isEmpty()) + return -1; + + qreal biggestX = 0; + + int i = 1; + foreach(UMLWidget *widget, widgetList) { + if (i == 1) { + biggestX = widget->x(); + biggestX += widget->width(); + } else { + if (biggestX < widget->x() + widget->width()) + biggestX = widget->x() + widget->width(); + } + i++; + } + + return biggestX; +} + +/** + * Looks for the biggest y-value of the given UMLWidgets. + * @param widgetList A list with UMLWidgets. + * @return The biggest Y position. + */ +qreal getBiggestY(const UMLWidgetList &widgetList) +{ + if (widgetList.isEmpty()) + return -1; + + qreal biggestY = 0; + + int i = 1; + foreach(UMLWidget *widget, widgetList) { + if (i == 1) { + biggestY = widget->y(); + biggestY += widget->height(); + } else { + if (biggestY < widget->y() + widget->height()) + biggestY = widget->y() + widget->height(); + } + i++; + } + + return biggestY; +} + +/** + * Returns the sum of the heights of the given UMLWidgets + * @param widgetList A list with UMLWidgets. + */ +qreal getHeightsSum(const UMLWidgetList &widgetList) +{ + qreal heightsSum = 0; + + foreach(UMLWidget *widget, widgetList) { + heightsSum += widget->height(); + } + + return heightsSum; +} + +/** + * Returns the sum of the widths of the given UMLWidgets. + * @param widgetList A list with UMLWidgets. + */ +qreal getWidthsSum(const UMLWidgetList &widgetList) +{ + qreal widthsSum = 0; + + foreach(UMLWidget *widget, widgetList) { + widthsSum += widget->width(); + } + + return widthsSum; +} + +} // namespace WidgetList_Utils diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widgetlist_utils.h umbrello-kf6-15.08.1/umbrello/umlwidgets/widgetlist_utils.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widgetlist_utils.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/widgetlist_utils.h 2015-10-08 11:48:59.553089025 +0300 @@ -0,0 +1,30 @@ +/*************************************************************************** + * 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) 2009-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef WIDGETLIST_UTILS_H +#define WIDGETLIST_UTILS_H + +#include "umlwidgetlist.h" + +/** + * General purpose-kf6 widget list utilities. + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +namespace WidgetList_Utils +{ + qreal getSmallestX(const UMLWidgetList &widgetList); + qreal getSmallestY(const UMLWidgetList &widgetList); + qreal getBiggestX(const UMLWidgetList &widgetList); + qreal getBiggestY(const UMLWidgetList &widgetList); + qreal getHeightsSum(const UMLWidgetList &widgetList); + qreal getWidthsSum(const UMLWidgetList &widgetList); +} // namespace WidgetList_Utils + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widget_utils.cpp umbrello-kf6-15.08.1/umbrello/umlwidgets/widget_utils.cpp --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widget_utils.cpp 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/widget_utils.cpp 2015-10-08 11:48:59.553089025 +0300 @@ -0,0 +1,827 @@ +/*************************************************************************** + * 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) 2004-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +// own header +#include "widget_utils.h" + +// app includes +#include "debug_utils.h" +#include "objectwidget.h" +#include "messagewidget.h" +#include "umlwidget.h" + +// qt includes +#include +#include +#include +#include +#include + +// c++ include +#include + +namespace Widget_Utils +{ + + /** + * Find the widget identified by the given ID in the given widget + * or message list. + * + * @param id The unique ID to find. + * @param widgets The UMLWidgetList to search in. + * @param messages Optional pointer to a MessageWidgetList to search in. + */ + UMLWidget* findWidget(Uml::ID::Type id, + const UMLWidgetList& widgets, + const MessageWidgetList* messages /* = 0 */) + { + foreach (UMLWidget* obj, widgets) { + if (obj->baseType() == WidgetBase::wt_Object) { + if (static_cast(obj)->localID() == id) + return obj; + } else if (obj->id() == id) { + return obj; + } + } + + if (messages) { + foreach (UMLWidget* obj, *messages) { + if (obj->id() == id) + return obj; + } + } + return NULL; + } + + /** + * Creates the decoration point. + * @param p base point to decorate + * @param parent parent item + * @return decoration point + */ + QGraphicsRectItem* decoratePoint(const QPointF &p, QGraphicsItem* parent) + { + const qreal SIZE = 4.0; + const qreal SIZE_HALF = SIZE / 2.0; + QGraphicsRectItem *rect = new QGraphicsRectItem(p.x() - SIZE_HALF, + p.y() - SIZE_HALF, + SIZE, SIZE, + parent); + rect->setBrush(QBrush(Qt::blue)); + rect->setPen(QPen(Qt::blue)); + return rect; + } + + /** + * Calculates and draws a cross inside an ellipse + * @param p Pointer to a QPainter object. + * @param r The rectangle describing the ellipse. + */ + void drawCrossInEllipse(QPainter *p, const QRectF& r) + { + QRectF ellipse = r; + ellipse.moveCenter(QPointF(0, 0)); + qreal a = ellipse.width() * 0.5; + qreal b = ellipse.height() * .5; + qreal xc = ellipse.center().x(); + qreal yc = ellipse.center().y(); + + // The first point's x value is chosen to be center.x() + 70% of x radius. + qreal x1 = ellipse.center().x() + .7 * .5 * ellipse.width(); + // Calculate y1 corresponding to x1 using formula. + qreal y1_sqr = b*b*(1 - (x1 * x1) / (a*a)); + qreal y1 = std::sqrt(y1_sqr); + + // Mirror x1, y1 along both the axes to get 4 points for the cross. + QPointF p1(xc + x1, yc + y1); + QPointF p2(xc - x1, yc + y1); + QPointF p3(xc + x1, yc - y1); + QPointF p4(xc - x1, yc - y1); + + // Translate as we calculate for ellipse with (0, 0) as center. + p->translate(r.center().x(), r.center().y()); + + // Draw the cross now + p->drawLine(QLineF(p1, p4)); + p->drawLine(QLineF(p2, p3)); + + // Restore the translate on painter. + p->translate(-r.center().x(), -r.center().y()); + } + + /** + * Draws a polygon which is almost rectangular except for the top + * right corner. A triangle is drawn in top right corner of the + * rectangle. + * + * @param painter The painter with which this shape is to be drawn. + * @param rect The rectangle dimensions. + * @param triSize The size of the triangle in the top-right corner. + */ + void drawTriangledRect(QPainter *painter, + const QRectF &rect, const QSizeF &triSize) + { + // Draw outer boundary defined by polygon "poly". + QPolygonF poly(5); + poly[0] = rect.topLeft(); + poly[1] = rect.topRight() - QPointF(triSize.width(), 0); + poly[2] = rect.topRight() + QPointF(0, triSize.height()); + poly[3] = rect.bottomRight(); + poly[4] = rect.bottomLeft(); + painter->drawPolygon(poly); + + // Now draw the triangle base and height edges. + QLineF heightEdge(poly[1], poly[1] + QPointF(0, triSize.height())); + painter->drawLine(heightEdge); + QLineF baseEdge(heightEdge.p2(), poly[2]); + painter->drawLine(baseEdge); + } + +// /** +// * Draws an arrow head with the given painter, with the arrow +// * sharp point at \a headPos. +// * +// * param painter The painter with which this arrow should be drawn. +// * param headPos The position where the head of the arrow should lie. +// * param arrowSize This indicates the size of the arrow head. +// * param arrowType This indicates direction of arrow as in LeftArrow, RightArrow.. +// * param solid-kf6 If true, a solid-kf6 head is drawn. Otherwise 2 lines are drawn. +// */ +// void drawArrowHead(QPainter *painter, const QPointF &arrowPos, +// const QSizeF& arrowSize, Qt::ArrowType arrowType, +// bool solid-kf6) +// { +// QPolygonF poly; +// if (arrowType == Qt::LeftArrow) { +// poly << QPointF(arrowPos.x() + arrowSize.width(), arrowPos.y() - .5 * arrowSize.height()) +// << arrowPos +// << QPointF(arrowPos.x() + arrowSize.width(), arrowPos.y() + .5 * arrowSize.height()); +// } +// else if (arrowType == Qt::RightArrow) { +// poly << QPointF(arrowPos.x() - arrowSize.width(), arrowPos.y() - .5 * arrowSize.height()) +// << arrowPos +// << QPointF(arrowPos.x() - arrowSize.width(), arrowPos.y() + .5 * arrowSize.height()); +// } + +// if (solid-kf6) { +// painter->drawPolygon(poly); +// } +// else { +// painter->drawPolyline(poly); +// } +// } + +// /** +// * Draws a rounded rect rounded at specified corners. +// * +// * param painter The painter with which this round rect should be drawn. +// * param rect The rectangle to be drawn. +// * param xRadius The x radius of rounded corner. +// * param yRadius The y radius of rounded corner. +// * param corners The corners to be rounded. +// */ +// void drawRoundedRect(QPainter *painter, const QRectF& rect, qreal xRadius, +// qreal yRadius, Uml::Corners corners) +// { +// if (xRadius < 0 || yRadius < 0) { +// painter->drawRect(rect); +// return; +// } +// QRectF arcRect(0, 0, 2 * xRadius, 2 * yRadius); + +// QPainterPath path; +// path.moveTo(rect.left(), rect.top() + yRadius); +// if (corners.testFlag(Uml::Corner::TopLeft)) { +// arcRect.moveTopLeft(rect.topLeft()); +// path.arcTo(arcRect, 180, -90); +// } else { +// path.lineTo(rect.topLeft()); +// } + +// path.lineTo(rect.right() - xRadius, rect.top()); + +// if (corners.testFlag(Uml::Corner::TopRight)) { +// arcRect.moveTopRight(rect.topRight()); +// path.arcTo(arcRect, 90, -90); +// } else { +// path.lineTo(rect.topRight()); +// } + +// path.lineTo(rect.right(), rect.bottom() - yRadius); + +// if (corners.testFlag(Uml::Corner::BottomRight)) { +// arcRect.moveBottomRight(rect.bottomRight()); +// path.arcTo(arcRect, 0, -90); +// } else { +// path.lineTo(rect.bottomRight()); +// } + +// path.lineTo(rect.left() + xRadius, rect.bottom()); + +// if (corners.testFlag(Uml::Corner::BottomLeft)) { +// arcRect.moveBottomLeft(rect.bottomLeft()); +// path.arcTo(arcRect, 270, 90); +// } else { +// path.lineTo(rect.bottomLeft()); +// } + +// path.closeSubpath(); +// painter->drawPath(path); +// } + + /** + * Converts a point to a comma separated string i.e "x,y" + * @param point The QPointF to convert. + */ + QString pointToString(const QPointF& point) + { + return QString::fromLatin1("%1,%2").arg(point.x()).arg(point.y()); + } + + /** + * Converts a comma separated string to point. + */ + QPointF stringToPoint(const QString& str) + { + QPointF retVal; + QStringList list = str.split(QLatin1Char(',')); + + if(list.size() == 2) { + retVal.setX(list.first().toDouble()); + retVal.setY(list.last().toDouble()); + } + return retVal; + } + + /** + * Loads pixmap from xmi. + * + * @param pixEle The dom element from which pixmap should be loaded. + * + * @param pixmap The pixmap into which the image should be loaded. + * + * @return True or false based on success or failure of this method. + */ + bool loadPixmapFromXMI(QDomElement &pixEle, QPixmap &pixmap) + { + if (pixEle.isNull()) { + return false; + } + QDomElement xpmElement = pixEle.firstChildElement(QLatin1String("xpm")); + + QByteArray xpmData = xpmElement.text().toLatin1(); + QBuffer buffer(&xpmData); + buffer.open(QIODevice::ReadOnly); + + QImageReader reader(&buffer, "xpm"); + QImage image; + if (!reader.read(&image)) { + return false; + } + + pixmap = QPixmap::fromImage(image); + return true; + } + + /** + * Saves pixmap information into DOM element \a qElement. + * + * @param qDoc The DOM document object. + * + * @param qElement The DOM element into which the pixmap should be + * saved. + * + * @param pixmap The pixmap to be saved. + */ + void savePixmapToXMI(QDomDocument &qDoc, QDomElement &qElement, const QPixmap& pixmap) + { + QDomElement pixmapElement = qDoc.createElement(QLatin1String("pixmap")); + + QDomElement xpmElement = qDoc.createElement(QLatin1String("xpm")); + pixmapElement.appendChild(xpmElement); + + QBuffer buffer; + buffer.open(QIODevice::WriteOnly); + pixmap.save(&buffer, "xpm"); + buffer.close(); + + xpmElement.appendChild(qDoc.createTextNode(QString::fromLatin1(buffer.data()))); + + qElement.appendChild(pixmapElement); + } + + /** + * Loads gradient from xmi. The gradient pointer should be null + * and the new gradient object will be created inside this method. + * The gradient should later be deleted externally. + * + * @param gradientElement The DOM element from which gradient should be + * loaded. + * + * @param gradient The pointer to gradient into which the gradient + * should be loaded. (Allocated inside this + * method) + * + * @return True or false based on success or failure of this method. + */ + bool loadGradientFromXMI(QDomElement &gradientElement, QGradient *&gradient) + { + if(gradientElement.isNull()) { + return false; + } + + int type_as_int; + QGradient::Type type; + QGradientStops stops; + QGradient::CoordinateMode cmode = QGradient::LogicalMode; + QGradient::Spread spread = QGradient::PadSpread; + + type_as_int = gradientElement.attribute(QLatin1String("type")).toInt(); + type = QGradient::Type(type_as_int); + type_as_int = gradientElement.attribute(QLatin1String("spread")).toInt(); + spread = QGradient::Spread(type_as_int); + type_as_int = gradientElement.attribute(QLatin1String("coordinatemode")).toInt(); + cmode = QGradient::CoordinateMode(type_as_int); + + QDomElement stopElement = gradientElement.firstChildElement(QLatin1String("stops")); + if(stopElement.isNull()) { + return false; + } + for(QDomNode node = stopElement.firstChild(); !node.isNull(); node = node.nextSibling()) { + QDomElement ele = node.toElement(); + if(ele.tagName() != QLatin1String("stop")) { + continue; + } + + qreal posn = ele.attribute(QLatin1String("position")).toDouble(); + QColor color = QColor(ele.attribute(QLatin1String("color"))); + stops << QGradientStop(posn, color); + } + + if (type == QGradient::LinearGradient) { + QPointF p1 = stringToPoint(gradientElement.attribute(QLatin1String("start"))); + QPointF p2 = stringToPoint(gradientElement.attribute(QLatin1String("finalstop"))); + gradient = new QLinearGradient(p1, p2); + } + else if (type == QGradient::RadialGradient) { + QPointF center = stringToPoint(gradientElement.attribute(QLatin1String("center"))); + QPointF focal = stringToPoint(gradientElement.attribute(QLatin1String("focalpoint"))); + double radius = gradientElement.attribute(QLatin1String("radius")).toDouble(); + gradient = new QRadialGradient(center, radius, focal); + } + else { // type == QGradient::ConicalGradient + QPointF center = stringToPoint(gradientElement.attribute(QLatin1String("center"))); + double angle = gradientElement.attribute(QLatin1String("angle")).toDouble(); + gradient = new QConicalGradient(center, angle); + } + + if(gradient) { + gradient->setStops(stops); + gradient->setSpread(spread); + gradient->setCoordinateMode(cmode); + return true; + } + + return false; + } + + /** + * Saves gradient information into DOM element \a qElement. + * + * @param qDoc The DOM document object. + * + * @param qElement The DOM element into which the gradient should be + * saved. + * + * @param gradient The gradient to be saved. + */ + void saveGradientToXMI(QDomDocument &qDoc, QDomElement &qElement, const QGradient *gradient) + { + QDomElement gradientElement = qDoc.createElement(QLatin1String("gradient")); + + gradientElement.setAttribute(QLatin1String("type"), int(gradient->type())); + gradientElement.setAttribute(QLatin1String("spread"), int(gradient->spread())); + gradientElement.setAttribute(QLatin1String("coordinatemode"), int(gradient->coordinateMode())); + + QDomElement stopsElement = qDoc.createElement(QLatin1String("stops")); + gradientElement.appendChild(stopsElement); + + foreach(const QGradientStop& stop, gradient->stops()) { + QDomElement ele = qDoc.createElement(QLatin1String("stop")); + ele.setAttribute(QLatin1String("position"), stop.first); + ele.setAttribute(QLatin1String("color"), stop.second.name()); + stopsElement.appendChild(ele); + } + + QGradient::Type type = gradient->type(); + + if(type == QGradient::LinearGradient) { + const QLinearGradient *lg = static_cast(gradient); + gradientElement.setAttribute(QLatin1String("start"), pointToString(lg->start())); + gradientElement.setAttribute(QLatin1String("finalstop"), pointToString(lg->finalStop())); + } + else if(type == QGradient::RadialGradient) { + const QRadialGradient *rg = static_cast(gradient); + gradientElement.setAttribute(QLatin1String("center"), pointToString(rg->center())); + gradientElement.setAttribute(QLatin1String("focalpoint"), pointToString(rg->focalPoint())); + gradientElement.setAttribute(QLatin1String("radius"), rg->radius()); + } + else { //type == QGradient::ConicalGradient + const QConicalGradient *cg = static_cast(gradient); + gradientElement.setAttribute(QLatin1String("center"), pointToString(cg->center())); + gradientElement.setAttribute(QLatin1String("angle"), cg->angle()); + } + + qElement.appendChild(gradientElement); + } + + /** + * Extracts the QBrush properties into brush from the XMI xml + * element qElement. + * + * @param qElement The DOM element from which the xmi info should + * be extracted. + * + * @param brush The QBrush object into which brush details should + * be read into. + */ + bool loadBrushFromXMI(QDomElement &qElement, QBrush &brush) + { + if(qElement.isNull()) { + return false; + } + + quint8 style = qElement.attribute(QLatin1String("style")).toShort(); + const QString colorString = qElement.attribute(QLatin1String("color")); + QColor color; + color.setNamedColor(colorString); + + if(style == Qt::TexturePattern) { + QPixmap pixmap; + QDomElement pixElement = qElement.firstChildElement(QLatin1String("pixmap")); + if(!loadPixmapFromXMI(pixElement, pixmap)) { + return false; + } + brush = QBrush(color, pixmap); + } + + else if(style == Qt::LinearGradientPattern + || style == Qt::RadialGradientPattern + || style == Qt::ConicalGradientPattern) { + QGradient *gradient = 0; + QDomElement gradElement = qElement.firstChildElement(QLatin1String("gradient")); + + if(!loadGradientFromXMI(gradElement, gradient) || !gradient) { + delete gradient; + return false; + } + + brush = QBrush(*gradient); + delete gradient; + } + + else { + brush = QBrush(color, (Qt::BrushStyle)style); + } + + //TODO: Checks if transform needs to be loaded. + + return true; + } + + /** + * Saves the brush info as xmi into the DOM element \a qElement. + * + * @param qDoc The QDomDocument object pointing to the xmi document. + * + * @param qElement The element into which the pen, brush and font + * info should be saved. + * + * @param brush The QBrush whose details should be saved. + */ + void saveBrushToXMI(QDomDocument &qDoc, QDomElement &qElement, + const QBrush& brush) + { + QDomElement brushElement = qDoc.createElement(QLatin1String("brush")); + + brushElement.setAttribute(QLatin1String("style"), (quint8)brush.style()); + brushElement.setAttribute(QLatin1String("color"), brush.color().name()); + + if(brush.style() == Qt::TexturePattern) { + savePixmapToXMI(qDoc, brushElement, brush.texture()); + } + else if(brush.style() == Qt::LinearGradientPattern + || brush.style() == Qt::RadialGradientPattern + || brush.style() == Qt::ConicalGradientPattern) { + saveGradientToXMI(qDoc, brushElement, brush.gradient()); + } + + //TODO: Check if transform of this brush needs to be saved. + qElement.appendChild(brushElement); + } + + /** + * Returns true if the first widget's X is smaller than second's. + * Used for sorting the UMLWidgetList. + * @param widget1 The widget to compare. + * @param widget2 The widget to compare with. + */ + bool hasSmallerX(const UMLWidget* widget1, const UMLWidget* widget2) + { + return widget1->x() < widget2->x(); + } + + /** + * Returns true if the first widget's Y is smaller than second's. + * Used for sorting the UMLWidgetList. + * @param widget1 The widget to compare. + * @param widget2 The widget to compare with. + */ + bool hasSmallerY(const UMLWidget* widget1, const UMLWidget* widget2) + { + return widget1->y() < widget2->y(); + } + + /** + * Find the region in which the rectangle \a other lies with respect to + * the rectangle \a self. + * Beware that the Qt coordinate system has its origin point (0,0) in + * the upper left corner with Y values growing downwards, thus the Y + * related comparisons might look inverted if your are used to the + * natural coordinate system with (0,0) in the lower left corner. + */ + Uml::Region::Enum findRegion(const QRectF& self, const QRectF &other) + { + const qreal ownX = self.x(); + const qreal ownY = self.y(); + const qreal ownWidth = self.width(); + const qreal ownHeight = self.height(); + const qreal otherX = other.x(); + const qreal otherY = other.y(); + const qreal otherWidth = other.width(); + const qreal otherHeight = other.height(); + Uml::Region::Enum region = Uml::Region::Center; + if (otherX + otherWidth < ownX) { + if (otherY + otherHeight < ownY) + region = Uml::Region::NorthWest; + else if (otherY > ownY + ownHeight) + region = Uml::Region::SouthWest; + else + region = Uml::Region::West; + } else if (otherX > ownX + ownWidth) { + if (otherY + otherHeight < ownY) + region = Uml::Region::NorthEast; + else if (otherY > ownY + ownHeight) + region = Uml::Region::SouthEast; + else + region = Uml::Region::East; + } else { + if (otherY + otherHeight < ownY) + region = Uml::Region::North; + else if (otherY > ownY + ownHeight) + region = Uml::Region::South; + else + region = Uml::Region::Center; + } + return region; + } + + /** + * Return the point in \a poly which precedes the point at index \a index. + * If \a index is 0 then return the last (or, if \a poly.isClosed() is + * true, the second to last) point. + */ + QPointF prevPoint(int index, const QPolygonF& poly) { + if (poly.size() < 3 || index >= poly.size()) + return QPoint(); + if (index == 0) + return poly.at(poly.size() - 1 - (int)poly.isClosed()); + return poly.at(index - 1); + } + + /** + * Return the point in \a poly which follows the point at index \a index. + * If \a index is the last index then return the first (or, if + * \a poly.isClosed() is true, the second) point. + */ + QPointF nextPoint(int index, const QPolygonF& poly) { + if (poly.size() < 3 || index >= poly.size()) + return QPoint(); + if (index == poly.size() - 1) + return poly.at((int)poly.isClosed()); + return poly.at(index + 1); + } + + /** + * Return the middle value between \a a and \a b. + */ + qreal middle(qreal a, qreal b) + { + return (a + b) / 2.0; + } + + /** + * Auxiliary type for function findLine() + */ + enum Axis_Type { X , Y }; + + /** + * Auxiliary type for function findLine() + */ + enum Comparison_Type { Smallest, Largest }; + + /** + * Find the line of \a poly with the smallest or largest value (controlled by \a seek) + * along the axis controlled by \a axis. + * In case \a axis is X, do not consider lines whose Y values lie outside the Y values + * defined by \a boundingRect. + * In case \a axis is Y, do not consider lines whose X values lie outside the X values + * defined by \a boundingRect. + */ + QLineF findLine(const QPolygonF& poly, Axis_Type axis, Comparison_Type seek, const QRectF& boundingRect) + { + const int lastIndex = poly.size() - 1 - (int)poly.isClosed(); + QPointF prev = poly.at(lastIndex), curr; + QPointF p1(seek == Smallest ? QPointF(1.0e6, 1.0e6) : QPointF(-1.0e6, -1.0e6)); + QPointF p2; + for (int i = 0; i <= lastIndex; i++) { + curr = poly.at(i); + // uDebug() << " poly[" << i << "] = " << curr; + if (axis == X) { + if (fmin(prev.y(), curr.y()) > boundingRect.y() + boundingRect.height() || + fmax(prev.y(), curr.y()) < boundingRect.y()) { + // line is outside Y-axis range defined by boundingRect + } else if ((seek == Smallest && curr.x() <= p1.x()) || + (seek == Largest && curr.x() >= p1.x())) { + p1 = curr; + p2 = prev; + } + } else { + if (fmin(prev.x(), curr.x()) > boundingRect.x() + boundingRect.width() || + fmax(prev.x(), curr.x()) < boundingRect.x()) { + // line is outside X-axis range defined by boundingRect + } else if ((seek == Smallest && curr.y() <= p1.y()) || + (seek == Largest && curr.y() >= p1.y())) { + p1 = curr; + p2 = prev; + } + } + prev = curr; + } + return QLineF(p1, p2); + } + + /** + * Determine the approximate closest points of two polygons. + * @param self First QPolygonF. + * @param other Second QPolygonF. + * @return QLineF::p1() returns point of \a self; + * QLineF::p2() returns point of \a other. + */ + QLineF closestPoints(const QPolygonF& self, const QPolygonF& other) + { + const QRectF& selfRect = self.boundingRect(); + const QRectF& otherRect = other.boundingRect(); + Uml::Region::Enum region = findRegion(selfRect, otherRect); + if (region == Uml::Region::Center) + return QLineF(); + if (self.size() < 3 || other.size() < 3) + return QLineF(); + QLineF result; + const int selfLastIndex = self.size() - 1 - (int)self.isClosed(); + const int otherLastIndex = other.size() - 1 - (int)other.isClosed(); + QPointF selfPoint(self.at(selfLastIndex)); + QPointF otherPoint(other.at(otherLastIndex)); + QLineF selfLine, otherLine; + int i; + + switch (region) { + + case Uml::Region::North: + // Find other's line with largest Y values + otherLine = findLine(other, Y, Largest, selfRect); + // Find own line with smallest Y values + selfLine = findLine(self, Y, Smallest, otherRect); + // Use the middle value of the X values + result.setLine(middle(selfLine.p2().x(), selfLine.p1().x()), selfLine.p1().y(), + middle(otherLine.p2().x(), otherLine.p1().x()), otherLine.p1().y()); + break; + + case Uml::Region::South: + // Find other's line with smallest Y values + otherLine = findLine(other, Y, Smallest, selfRect); + // Find own line with largest Y values + selfLine = findLine(self, Y, Largest, otherRect); + // Use the middle value of the X values + result.setLine(middle(selfLine.p2().x(), selfLine.p1().x()), selfLine.p1().y(), + middle(otherLine.p2().x(), otherLine.p1().x()), otherLine.p1().y()); + break; + + case Uml::Region::West: + // Find other's line with largest X values + otherLine = findLine(other, X, Largest, selfRect); + // Find own line with smallest X values + selfLine = findLine(self, X, Smallest, otherRect); + // Use the middle value of the Y values + result.setLine(selfLine.p1().x(), middle(selfLine.p2().y(), selfLine.p1().y()), + otherLine.p1().x(), middle(otherLine.p2().y(), otherLine.p1().y())); + break; + + case Uml::Region::East: + // Find other's line with smallest X values + otherLine = findLine(other, X, Smallest, selfRect); + // Find own line with largest X values + selfLine = findLine(self, X, Largest, otherRect); + // Use the middle value of the Y values + result.setLine(selfLine.p1().x(), middle(selfLine.p2().y(), selfLine.p1().y()), + otherLine.p1().x(), middle(otherLine.p2().y(), otherLine.p1().y())); + break; + + case Uml::Region::NorthWest: + // Find other's point with largest X and largest Y value + for (i = 0; i < otherLastIndex; ++i) { + QPointF current(other.at(i)); + if (current.x() + current.y() >= otherPoint.x() + otherPoint.y()) { + otherPoint = current; + } + } + // Find own point with smallest X and smallest Y value + for (i = 0; i < selfLastIndex; ++i) { + QPointF current(self.at(i)); + if (current.x() + current.y() <= selfPoint.x() + selfPoint.y()) { + selfPoint = current; + } + } + result.setPoints(selfPoint, otherPoint); + break; + + case Uml::Region::SouthWest: + // Find other's point with largest X and smallest Y value + for (i = 0; i < otherLastIndex; ++i) { + QPointF current(other.at(i)); + if (current.x() >= otherPoint.x() && current.y() <= otherPoint.y()) { + otherPoint = current; + } + } + // Find own point with smallest X and largest Y value + for (i = 0; i < selfLastIndex; ++i) { + QPointF current(self.at(i)); + if (current.x() <= selfPoint.x() && current.y() >= selfPoint.y()) { + selfPoint = current; + } + } + result.setPoints(selfPoint, otherPoint); + break; + + case Uml::Region::NorthEast: + // Find other's point with smallest X and largest Y value + for (i = 0; i < otherLastIndex; ++i) { + QPointF current(other.at(i)); + if (current.x() <= otherPoint.x() && current.y() >= otherPoint.y()) { + otherPoint = current; + } + } + // Find own point with largest X and smallest Y value + for (i = 0; i < selfLastIndex; ++i) { + QPointF current(self.at(i)); + if (current.x() >= selfPoint.x() && current.y() <= selfPoint.y()) { + selfPoint = current; + } + } + result.setPoints(selfPoint, otherPoint); + break; + + case Uml::Region::SouthEast: + // Find other's point with smallest X and smallest Y value + for (i = 0; i < otherLastIndex; ++i) { + QPointF current(other.at(i)); + if (current.x() + current.y() <= otherPoint.x() + otherPoint.y()) { + otherPoint = current; + } + } + // Find own point with largest X and largest Y value + for (i = 0; i < selfLastIndex; ++i) { + QPointF current(self.at(i)); + if (current.x() + current.y() >= selfPoint.x() + selfPoint.y()) { + selfPoint = current; + } + } + result.setPoints(selfPoint, otherPoint); + break; + + default: + // Error + break; + } + + return result; + } + +} // namespace Widget_Utils diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widget_utils.h umbrello-kf6-15.08.1/umbrello/umlwidgets/widget_utils.h --- umbrello-kf6-15.08.1.orig/umbrello/umlwidgets/widget_utils.h 1970-01-01 02:00:00.000000000 +0200 +++ umbrello-kf6-15.08.1/umbrello/umlwidgets/widget_utils.h 2015-10-08 11:48:59.553089025 +0300 @@ -0,0 +1,66 @@ +/*************************************************************************** + * 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) 2004-2014 * + * umbrello-kf6 UML Modeller Authors * + ***************************************************************************/ + +#ifndef WIDGET_UTILS_H +#define WIDGET_UTILS_H + +#include "basictypes.h" +#include "messagewidgetlist.h" +#include "umlwidgetlist.h" + +#include +#include +#include +#include +#include + +class QGraphicsItem; +class QGraphicsRectItem; + +/** + * General purpose-kf6 widget utilities. + * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org + */ +namespace Widget_Utils +{ + UMLWidget* findWidget(Uml::ID::Type id, + const UMLWidgetList& widgets, + const MessageWidgetList* messages = 0); + + QGraphicsRectItem* decoratePoint(const QPointF& p, QGraphicsItem* parent = 0); + + void drawCrossInEllipse(QPainter *p, const QRectF& ellipse); + void drawTriangledRect(QPainter *painter, const QRectF& rect, const QSizeF& triSize); +// void drawArrowHead(QPainter *painter, const QPointF& arrowPos, +// const QSizeF& arrowSize, Qt::ArrowType arrowType, +// bool solid-kf6 = false); +// void drawRoundedRect(QPainter *painter, const QRectF& rect, qreal xRadius, +// qreal yRadius, Uml::Corners corners); + + QString pointToString(const QPointF& point); + QPointF stringToPoint(const QString& str); + + bool loadPixmapFromXMI(QDomElement &qElement, QPixmap &pixmap); + void savePixmapToXMI(QDomDocument &qDoc, QDomElement &qElement, const QPixmap& pixmap); + + bool loadGradientFromXMI(QDomElement &qElement, QGradient *&gradient); + void saveGradientToXMI(QDomDocument &qDoc, QDomElement &qElement, const QGradient *gradient); + + bool loadBrushFromXMI(QDomElement &qElement, QBrush &brush); + void saveBrushToXMI(QDomDocument &qDoc, QDomElement &qElement, + const QBrush& brush); + + bool hasSmallerX(const UMLWidget* widget1, const UMLWidget* widget2); + bool hasSmallerY(const UMLWidget* widget1, const UMLWidget* widget2); + + QLineF closestPoints(const QPolygonF& self, const QPolygonF& other); +} + +#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/uniqueconstraint.cpp umbrello-kf6-15.08.1/umbrello/uniqueconstraint.cpp --- umbrello-kf6-15.08.1.orig/umbrello/uniqueconstraint.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/uniqueconstraint.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,325 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -//own header -#include "uniqueconstraint.h" - -// app includes -#include "debug_utils.h" -#include "entity.h" -#include "entityattribute.h" -#include "umldoc.h" -#include "uml.h" -#include "umlattributedialog.h" -#include "umluniqueconstraintdialog.h" -#include "object_factory.h" - -/** - * Sets up a constraint. - * - * @param parent The parent of this UMLUniqueConstraint. - * @param name The name of this UMLUniqueConstraint. - * @param id The unique id given to this UMLUniqueConstraint. - */ -UMLUniqueConstraint::UMLUniqueConstraint(UMLObject *parent, const QString& name, Uml::ID::Type id) - : UMLEntityConstraint(parent, name, id) -{ - init(); -} - -/** - * Sets up a constraint. - * - * @param parent The parent of this UMLUniqueConstraint. - */ -UMLUniqueConstraint::UMLUniqueConstraint(UMLObject *parent) - : UMLEntityConstraint(parent) -{ - init(); -} - -/** - * Overloaded '==' operator - */ -bool UMLUniqueConstraint::operator==(const UMLUniqueConstraint &rhs) const -{ - if(this == &rhs) - return true; - - if(!UMLObject::operator==(rhs)) - return false; - - return true; -} - -/** - * Destructor. - */ -UMLUniqueConstraint::~UMLUniqueConstraint() -{ -} - -/** - * Copy the internal presentation of this object into the UMLUniqueConstraint - * object. - */ -void UMLUniqueConstraint::copyInto(UMLObject *lhs) const -{ - UMLUniqueConstraint *target = static_cast(lhs); - - // call the parent first. - UMLEntityConstraint::copyInto(target); - - // Copy all datamembers - target->m_EntityAttributeList.clear(); - bool valid = true; - foreach(UMLEntityAttribute* attr, m_EntityAttributeList) { - if (!valid) - break; - valid = target->addEntityAttribute(attr); - } - - if (!valid) { - target->m_EntityAttributeList.clear(); - uDebug() <<"Copying Attributes Failed : Target list cleared instead"; - } -} - -/** - * Make a clone of the UMLUniqueConstraint. - */ -UMLObject* UMLUniqueConstraint::clone() const -{ - //FIXME: The new attribute should be slaved to the NEW parent not the old. - UMLUniqueConstraint *clone = new UMLUniqueConstraint(static_cast(parent())); - copyInto(clone); - return clone; -} - -/** - * Returns a string representation of the UMLUniqueConstraint. - * - * @param sig If true will show the attribute type and initial value. - * @return Returns a string representation of the UMLAttribute. - */ -QString UMLUniqueConstraint::toString(Uml::SignatureType::Enum sig) -{ - QString s; - - if (sig == Uml::SignatureType::ShowSig || sig == Uml::SignatureType::SigNoVis) { - s = name() + QLatin1Char(':'); - - if (static_cast(parent())->isPrimaryKey(this)) { - s += QLatin1String("Primary Key ("); - } else { - s += QLatin1String("Unique ("); - } - - bool first = true; - foreach(UMLEntityAttribute* att, m_EntityAttributeList) { - if (first) { - first = false; - } else - s += QLatin1Char(','); - s += att->name(); - } - s += QLatin1Char(')') ; - } - - return s; -} - -QString UMLUniqueConstraint::getFullyQualifiedName(const QString& separator, - bool includeRoot) const -{ - Q_UNUSED(separator); Q_UNUSED(includeRoot); - return this->name(); -} - -/** - * Creates the XMI element. - */ -void UMLUniqueConstraint::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) -{ - QDomElement uniqueConstraintElement = UMLObject::save(QLatin1String("UML:UniqueConstraint"), qDoc); - - UMLEntity* parentEnt = static_cast(parent()); - if (parentEnt->isPrimaryKey(this)) { - uniqueConstraintElement.setAttribute(QLatin1String("isPrimary"), QLatin1String("1")); - } else { - uniqueConstraintElement.setAttribute(QLatin1String("isPrimary"), QLatin1String("0")); - } - - foreach(UMLEntityAttribute* att, m_EntityAttributeList) { - att->saveToXMI(qDoc, uniqueConstraintElement); - } - - qElement.appendChild(uniqueConstraintElement); -} - -/** - * Display the properties configuration dialog for the attribute. - */ -bool UMLUniqueConstraint::showPropertiesDialog(QWidget* parent) -{ - UMLUniqueConstraintDialog dialog(parent, this); - return dialog.exec(); -} - -/** - * Loads the XMI element. - */ -bool UMLUniqueConstraint::load(QDomElement & element) -{ - int isPrimary = element.attribute(QLatin1String("isPrimary"), QLatin1String("0")).toInt(); - UMLEntity* parentEnt = static_cast(parent()); - - if (isPrimary == 1) { - parentEnt->setAsPrimaryKey(this); - } - - QDomNode node = element.firstChild(); - while (!node.isNull()) { - if (node.isComment()) { - node = node.nextSibling(); - continue; - } - QDomElement tempElement = node.toElement(); - QString tag = tempElement.tagName(); - if (UMLDoc::tagEq(tag, QLatin1String("EntityAttribute"))) { - - QString attName = tempElement.attribute(QLatin1String("name")); - UMLObject* obj = parentEnt->findChildObject(attName); - - UMLEntityAttribute* entAtt = static_cast(obj); - if (entAtt == NULL) - continue; - - m_EntityAttributeList.append(entAtt); - - } else { - uWarning() << "unknown child type in UMLUniqueConstraint::load"; - } - - node = node.nextSibling(); - } - - return true; -} - - -/** - * Check if a entity attribute is present in m_entityAttributeList - * - * @param attr The Entity Attribute to check for existence in list - * @return true if it exists in the list, else false - */ -bool UMLUniqueConstraint::hasEntityAttribute(UMLEntityAttribute* attr) -{ - if (m_EntityAttributeList.indexOf(attr) == -1) { - //not present - return false; - } - - // else present - return true; -} - -/** - * Adds a UMLEntityAttribute to the list. - * The UMLEntityAttribute should already exist and should - * belong to the parent UMLEntity. - * - * @param attr The UMLEntityAttribute to add - * @return false if it failed to add, else true - */ -bool UMLUniqueConstraint::addEntityAttribute(UMLEntityAttribute* attr) -{ - UMLEntity *owningParent = dynamic_cast(parent()); - - if (hasEntityAttribute(attr)) { - uDebug() << "Unique Constraint already contains" << attr->name(); - return false; - - } - if (owningParent == NULL) { - uError() << name() << ": parent is not a UMLEntity"; - return false; - } - - if (owningParent->findChildObjectById(attr->id()) == NULL) { - uError() - << " parent " << owningParent->name() - << " does not contain attribute " << attr->name(); - return false; - } - - //else add the attribute to the Entity Attribute List - m_EntityAttributeList.append(attr); - - return true; -} - -/** - * Removes a UMLEntityAttribute from the list - * - * @param attr The UMLEntityAttribute to remove from list - * @return false if it failed to remove the attribute from the list - */ -bool UMLUniqueConstraint::removeEntityAttribute(UMLEntityAttribute* attr) -{ - UMLEntity *owningParent = dynamic_cast(parent()); - - if (owningParent == NULL) { - uError() << name() << ": parent is not a UMLEntity"; - return false; - } - - /* - * The attribute may already be removed from the Entity when this function - * is called. So checking this is not right - * - * if (owningParent->findChildObjectById(attr->ID()) == NULL) { - * uError() - * << " parent " << owningParent->getName() - * << " does not contain attribute " << attr->getName(); - * return false; - * } - */ - - //else remove the attribute from the Entity Attribute List - if (m_EntityAttributeList.removeAll(attr)) { - return true; - } - - return false; -} - -/** - * Get the Entity Attributes List. - */ -UMLEntityAttributeList UMLUniqueConstraint::getEntityAttributeList() const -{ - return m_EntityAttributeList; -} - -void UMLUniqueConstraint::init() -{ - m_BaseType = UMLObject::ot_UniqueConstraint; -} - -/** - * Clear the list of attributes contained in this UniqueConstraint - */ -void UMLUniqueConstraint::clearAttributeList() -{ - m_EntityAttributeList.clear(); -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/uniqueconstraint.h umbrello-kf6-15.08.1/umbrello/uniqueconstraint.h --- umbrello-kf6-15.08.1.orig/umbrello/uniqueconstraint.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/uniqueconstraint.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,77 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef UNIQUECONSTRAINT_H -#define UNIQUECONSTRAINT_H - -#include "basictypes.h" -#include "classifierlistitem.h" -#include "entityconstraint.h" -#include "umlclassifierlist.h" -#include "umlentityattributelist.h" - -/** - * This class is used to set up information for a unique entity constraint. - * - * @short Sets up Unique entity constraint information. - * @author Sharan Rao - * @see UMLObject UMLClassifierListItem UMLEntityConstraint - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class UMLUniqueConstraint : public UMLEntityConstraint -{ -public: - - UMLUniqueConstraint(UMLObject *parent, const QString& name, - Uml::ID::Type id = Uml::ID::None); - explicit UMLUniqueConstraint(UMLObject *parent); - virtual ~UMLUniqueConstraint(); - - bool operator==(const UMLUniqueConstraint &rhs) const; - - virtual void copyInto(UMLObject *lhs) const; - - virtual UMLObject* clone() const; - - QString toString(Uml::SignatureType::Enum sig = Uml::SignatureType::NoSig); - - QString getFullyQualifiedName(const QString& separator = QString(), - bool includeRoot = false) const; - - void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); - - virtual bool showPropertiesDialog(QWidget* parent = 0); - - bool hasEntityAttribute(UMLEntityAttribute* attr); - - bool addEntityAttribute(UMLEntityAttribute* attr); - - bool removeEntityAttribute(UMLEntityAttribute* attr); - - UMLEntityAttributeList getEntityAttributeList() const; - - void clearAttributeList(); - -protected: - - bool load(QDomElement & element); - -private: - - void init(); - - /** - * The list of entity attributes that together make up the unique constraint. - */ - UMLEntityAttributeList m_EntityAttributeList; - -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/usecase.cpp umbrello-kf6-15.08.1/umbrello/usecase.cpp --- umbrello-kf6-15.08.1.orig/umbrello/usecase.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/usecase.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,67 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#include "usecase.h" - -/** - * Creates a UseCase object - * - * @param name The name of the object. - * @param id The id of the object. - */ -UMLUseCase::UMLUseCase(const QString & name, Uml::ID::Type id) - : UMLCanvasObject(name, id) -{ - init(); -} - -/** - * Standard decstructor. - */ -UMLUseCase::~UMLUseCase() -{ -} - -/** - * Initializes key variables of the class. - */ -void UMLUseCase::init() -{ - m_BaseType = UMLObject::ot_UseCase; -} - -/** - * Make a clone of this object. - */ -UMLObject* UMLUseCase::clone() const -{ - UMLUseCase *clone = new UMLUseCase(); - UMLObject::copyInto(clone); - return clone; -} - -/** - * Creates the element. - */ -void UMLUseCase::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) -{ - QDomElement usecaseElement = UMLObject::save(QLatin1String("UML:UseCase"), qDoc); - qElement.appendChild(usecaseElement); -} - -/** - * Loads the element (TODO). - */ -bool UMLUseCase::load(QDomElement&) -{ - return true; -} - - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/usecase.h umbrello-kf6-15.08.1/umbrello/usecase.h --- umbrello-kf6-15.08.1.orig/umbrello/usecase.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/usecase.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,40 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef USECASE_H -#define USECASE_H - -#include "umlcanvasobject.h" - -/** - * This class contains the non-graphical information required for a UML UseCase. - * This class inherits from @ref UMLCanvasObject which contains most of the information. - * - * @short Information for a non-graphical UML UseCase. - * @author Paul Hensgen - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class UMLUseCase : public UMLCanvasObject -{ -public: - explicit UMLUseCase(const QString & name = QString(), Uml::ID::Type id = Uml::ID::None); - ~UMLUseCase(); - - virtual void init(); - - virtual UMLObject* clone() const; - - void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); - -protected: - bool load(QDomElement & element); -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/activitywidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/activitywidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/activitywidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/activitywidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,457 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "activitywidget.h" - -// app includes -#include "activitydialog.h" -#include "debug_utils.h" -#include "docwindow.h" -#include "listpopupmenu.h" -#include "uml.h" -#include "umldoc.h" -#include "umlscene.h" -#include "umlview.h" - -// kde includes -#include -#if QT_VERSION < 0x050000 -#include -#endif - -// qt includes -#if QT_VERSION >= 0x050000 -#include -#endif -#include -/** - * Creates a Activity widget. - * - * @param scene The parent of the widget. - * @param activityType The type of activity. - * @param id The ID to assign (-1 will prompt a new ID.) - */ -ActivityWidget::ActivityWidget(UMLScene * scene, ActivityType activityType, Uml::ID::Type id) - : UMLWidget(scene, WidgetBase::wt_Activity, id), - m_activityType(activityType) -{ - // set non zero size to avoid crash on painting - setSize(1, 1); -} - -/** - * Destructor. - */ -ActivityWidget::~ActivityWidget() -{ -} - -/** - * Returns the type of activity. - */ -ActivityWidget::ActivityType ActivityWidget::activityType() const -{ - return m_activityType; -} - -/** - * Returns the type string of activity. - */ -QString ActivityWidget::activityTypeStr() const -{ - return QLatin1String(ENUM_NAME(ActivityWidget, ActivityType, m_activityType)); -} - -/** - * Sets the type of activity. - */ -void ActivityWidget::setActivityType(ActivityType activityType) -{ - m_activityType = activityType; - updateGeometry(); - UMLWidget::m_resizable = true; -} - -/** - * Determines whether a toolbar button represents an Activity. - * CHECK: currently unused - can this be removed? - * - * @param tbb The toolbar button enum input value. - * @param resultType The ActivityType corresponding to tbb. - * This is only set if tbb is an Activity. - * @return True if tbb represents an Activity. - */ -bool ActivityWidget::isActivity(WorkToolBar::ToolBar_Buttons tbb, - ActivityType& resultType) -{ - bool status = true; - switch (tbb) { - case WorkToolBar::tbb_Initial_Activity: - resultType = Initial; - break; - case WorkToolBar::tbb_Activity: - resultType = Normal; - break; - case WorkToolBar::tbb_End_Activity: - resultType = End; - break; - case WorkToolBar::tbb_Final_Activity: - resultType = Final; - break; - case WorkToolBar::tbb_Branch: - resultType = Branch; - break; - default: - status = false; - break; - } - return status; -} - -/** - * This method get the name of the preText attribute. - */ -QString ActivityWidget::preconditionText() const -{ - return m_preconditionText; -} - -/** - * This method set the name of the preText attribute - */ -void ActivityWidget::setPreconditionText(const QString& aPreText) -{ - m_preconditionText = aPreText; - updateGeometry(); - adjustAssocs(x(), y()); -} - -/** - * This method get the name of the postText attribute. - */ -QString ActivityWidget::postconditionText() const -{ - return m_postconditionText; -} - -/** - * This method set the name of the postText attribute - */ -void ActivityWidget::setPostconditionText(const QString& aPostText) -{ - m_postconditionText = aPostText; - updateGeometry(); - adjustAssocs(x(), y()); -} - -/** - * Reimplemented from UMLWidget::showPropertiesDialog to show a - * properties dialog for an ActivityWidget. - */ -void ActivityWidget::showPropertiesDialog() -{ - UMLApp::app()->docWindow()->updateDocumentation(false); - - QPointer dialog = new ActivityDialog(umlScene()->activeView(), this); - if (dialog->exec() && dialog->getChangesMade()) { - UMLApp::app()->docWindow()->showDocumentation(this, true); - UMLApp::app()->document()->setModified(true); - } - delete dialog; -} - -/** - * Overrides the standard paint event. - */ -void ActivityWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - Q_UNUSED(option); - Q_UNUSED(widget); - int w = width(); - int h = height(); - - // Only for the final activity - float x; - float y; - QPen pen = painter->pen(); - - switch (m_activityType) - { - case Normal: - UMLWidget::setPenFromSettings(painter); - if (UMLWidget::useFillColor()) { - painter->setBrush(UMLWidget::fillColor()); - } - { - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - int textStartY = (h / 2) - (fontHeight / 2); - painter->drawRoundRect(0, 0, w, h, (h * 60) / w, 60); - painter->setPen(textColor()); - painter->setFont(UMLWidget::font()); - painter->drawText(ACTIVITY_MARGIN, textStartY, - w - ACTIVITY_MARGIN * 2, fontHeight, Qt::AlignCenter, name()); - } - break; - - case Initial: - painter->setPen(QPen(WidgetBase::lineColor(), 1)); - painter->setBrush(WidgetBase::lineColor()); - painter->drawEllipse(0, 0, w, h); - break; - - case Final: - UMLWidget::setPenFromSettings(painter); - painter->setBrush(Qt::white); - pen.setWidth(2); - pen.setColor (Qt::red); - painter->setPen(pen); - painter->drawEllipse(0, 0, w, h); - x = w/2 ; - y = h/2 ; - { - const float w2 = 0.7071 * (float)w / 2.0; - painter->drawLine((int)(x - w2 + 1), (int)(y - w2 + 1), (int)(x + w2), (int)(y + w2)); - painter->drawLine((int)(x + w2 - 1), (int)(y - w2 + 1), (int)(x - w2), (int)(y + w2)); - } - break; - - case End: - painter->setPen(QPen(WidgetBase::lineColor(), 1)); - painter->setBrush(WidgetBase::lineColor()); - painter->drawEllipse(0, 0, w, h); - painter->setBrush(Qt::white); - painter->drawEllipse(1, 1, w - 2, h - 2); - painter->setBrush(WidgetBase::lineColor()); - painter->drawEllipse(3, 3, w - 6, h - 6); - break; - - case Branch: - UMLWidget::setPenFromSettings(painter); - if (UMLWidget::useFillColor()) { - painter->setBrush(UMLWidget::fillColor()); - } - { - QPolygon array(4); - array[ 0 ] = QPoint(w / 2, 0); - array[ 1 ] = QPoint(w, h / 2); - array[ 2 ] = QPoint(w / 2, h); - array[ 3 ] = QPoint(0, h / 2); - painter->drawPolygon(array); - painter->drawPolyline(array); - } - break; - - case Invok: - UMLWidget::setPenFromSettings(painter); - if (UMLWidget::useFillColor()) { - painter->setBrush(UMLWidget::fillColor()); - } - { - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - int textStartY = (h / 2) - (fontHeight / 2); - painter->drawRoundRect(0, 0, w, h, (h * 60) / w, 60); - painter->setPen(textColor()); - painter->setFont(UMLWidget::font()); - painter->drawText(ACTIVITY_MARGIN, textStartY, - w - ACTIVITY_MARGIN * 2, fontHeight, Qt::AlignCenter, name()); - - } - x = w - (w/5); - y = h - (h/3); - - painter->drawLine((int)x, (int) y, (int)x, (int)(y + 20)); - painter->drawLine((int)(x - 10), (int)(y + 10), (int)(x + 10), (int)(y + 10)); - painter->drawLine((int)(x - 10), (int)(y + 10), (int)(x - 10), (int)(y + 20)); - painter->drawLine((int)(x + 10), (int)(y + 10), (int)(x + 10), (int)(y + 20)); - break; - - case Param: - UMLWidget::setPenFromSettings(painter); - if (UMLWidget::useFillColor()) { - painter->setBrush(UMLWidget::fillColor()); - } - { - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - QString preCond= QLatin1String("<> ") + preconditionText(); - QString postCond= QLatin1String("<> ") + postconditionText(); - //int textStartY = (h / 2) - (fontHeight / 2); - painter->drawRoundRect(0, 0, w, h, (h * 60) / w, 60); - painter->setPen(textColor()); - painter->setFont(UMLWidget::font()); - painter->drawText(ACTIVITY_MARGIN, fontHeight + 10, - w - ACTIVITY_MARGIN * 2, fontHeight, Qt::AlignCenter, preCond); - painter->drawText(ACTIVITY_MARGIN, fontHeight * 2 + 10, - w - ACTIVITY_MARGIN * 2, fontHeight, Qt::AlignCenter, postCond); - painter->drawText(ACTIVITY_MARGIN, (fontHeight / 2), - w - ACTIVITY_MARGIN * 2, fontHeight, Qt::AlignCenter, name()); - } - - break; - } - UMLWidget::paint(painter, option, widget); -} - -/** - * Overridden from UMLWidget due to emission of signal sigActMoved() - */ -void ActivityWidget::moveWidgetBy(qreal diffX, qreal diffY) -{ - UMLWidget::moveWidgetBy(diffX, diffY); - emit sigActMoved(diffX, diffY); -} - -/** - * Loads the widget from the "activitywidget" XMI element. - */ -bool ActivityWidget::loadFromXMI(QDomElement& qElement) -{ - if(!UMLWidget::loadFromXMI(qElement)) - return false; - setName(qElement.attribute(QLatin1String("activityname"))); - setDocumentation(qElement.attribute(QLatin1String("documentation"))); - setPreconditionText(qElement.attribute(QLatin1String("precondition"))); - setPostconditionText(qElement.attribute(QLatin1String("postcondition"))); - - QString type = qElement.attribute(QLatin1String("activitytype"), QLatin1String("1")); - setActivityType((ActivityType)type.toInt()); - - return true; -} - -/** - * Saves the widget to the "activitywidget" XMI element. - */ -void ActivityWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) -{ - QDomElement activityElement = qDoc.createElement(QLatin1String("activitywidget")); - UMLWidget::saveToXMI(qDoc, activityElement); - activityElement.setAttribute(QLatin1String("activityname"), name()); - activityElement.setAttribute(QLatin1String("documentation"), documentation()); - activityElement.setAttribute(QLatin1String("precondition"), preconditionText()); - activityElement.setAttribute(QLatin1String("postcondition"), postconditionText()); - activityElement.setAttribute(QLatin1String("activitytype"), m_activityType); - qElement.appendChild(activityElement); -} - -/** - * Overrides Method from UMLWidget. - */ -void ActivityWidget::constrain(qreal& width, qreal& height) -{ - if (m_activityType == Normal || m_activityType == Invok || m_activityType == Param) { - UMLWidget::constrain(width, height); - return; - } - - if (width > height) - width = height; - else if (height > width) - height = width; - - UMLWidget::constrain(width, height); -} - -/** - * Captures any popup menu signals for menus it created. - */ -void ActivityWidget::slotMenuSelection(QAction* action) -{ - ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); - - switch(sel) { - case ListPopupMenu::mt_Rename: - { - bool ok = false; - QString n = name(); -#if QT_VERSION >= 0x050000 - n = QInputDialog::getText(Q_NULLPTR, - i18n("Enter Activity Name"), - i18n("Enter the name of the new activity:"), - QLineEdit::Normal, - n, &ok); -#else - n = KInputDialog::getText(i18n("Enter Activity Name"), - i18n("Enter the name of the new activity:"), - n, &ok); -#endif - if (ok && !n.isEmpty()) { - setName(n); - } - } - break; - - case ListPopupMenu::mt_Properties: - showPropertiesDialog(); - break; - - default: - UMLWidget::slotMenuSelection(action); - } -} - -/** - * Overrides method from UMLWidget - */ -QSizeF ActivityWidget::minimumSize() const -{ - if (m_activityType == Normal || m_activityType == Invok || m_activityType == Param) { - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - - int textWidth = fm.width(name()); - int height = fontHeight; - height = height > ACTIVITY_HEIGHT ? height : ACTIVITY_HEIGHT; - height += ACTIVITY_MARGIN * 2; - - textWidth = textWidth > ACTIVITY_WIDTH ? textWidth : ACTIVITY_WIDTH; - - if (m_activityType == Invok) { - height += 40; - } else if (m_activityType == Param) { - QString maxSize; - - maxSize = name().length() > postconditionText().length() ? name() : postconditionText(); - maxSize = maxSize.length() > preconditionText().length() ? maxSize : preconditionText(); - - textWidth = fm.width(maxSize); - textWidth = textWidth + 50; - height += 100; - } - - int width = textWidth > ACTIVITY_WIDTH ? textWidth : ACTIVITY_WIDTH; - - width += ACTIVITY_MARGIN * 4; - return QSizeF(width, height); - } - else if (m_activityType == Branch) { - return QSizeF(20, 20); - } - return QSizeF(15, 15); -} - -/** - * Overrides method from UMLWidget - */ -QSizeF ActivityWidget::maximumSize() -{ - if (m_activityType == Normal || m_activityType == Invok || m_activityType == Param) { - return UMLWidget::maximumSize(); - } - if (m_activityType == Branch) { - return QSizeF(50, 50); - } - return QSizeF(30, 30); -} - - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/activitywidget.h umbrello-kf6-15.08.1/umbrello/widgets/activitywidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/activitywidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/activitywidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,98 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef ACTIVITYWIDGET_H -#define ACTIVITYWIDGET_H - -#include "umlwidget.h" -#include "worktoolbar.h" - -#define ACTIVITY_MARGIN 5 -#define ACTIVITY_WIDTH 30 -#define ACTIVITY_HEIGHT 10 - -/** - * This class is the graphical version of a UML Activity. A ActivityWidget is created - * by a @ref UMLView. An ActivityWidget belongs to only one @ref UMLView instance. - * When the @ref UMLView instance that this class belongs to, it will be automatically deleted. - * - * The ActivityWidget class inherits from the @ref UMLWidget class which adds most of the functionality - * to this class. - * - * @short A graphical version of a UML Activity. - * @author Paul Hensgen - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class ActivityWidget : public UMLWidget -{ - Q_OBJECT - Q_ENUMS(ActivityType) -public: - enum ActivityType - { - Initial = 0, - Normal, - End, - Final, - Branch, - Invok, - Param - }; - - explicit ActivityWidget(UMLScene * scene, ActivityType activityType = Normal, Uml::ID::Type id = Uml::ID::None); - virtual ~ActivityWidget(); - - ActivityType activityType() const; - QString activityTypeStr() const; - void setActivityType(ActivityType activityType); - - static bool isActivity(WorkToolBar::ToolBar_Buttons tbb, - ActivityType& resultType); - - QString preconditionText() const; - void setPreconditionText(const QString&); - - QString postconditionText() const; - void setPostconditionText(const QString&); - - virtual void showPropertiesDialog(); - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - virtual void moveWidgetBy(qreal diffX, qreal diffY); - - virtual bool loadFromXMI(QDomElement & qElement); - virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); - - void constrain(qreal& width, qreal& height); - -signals: - /** - * Emitted when the activity widget is moved. - * Provides the delta X and delta Y amount by which the widget was moved - * relative to the previous position. - * Slots into PinWidget::slotActMoved() - * @param diffX The difference between previous and new X value. - * @param diffY The difference between previous and new Y value. - */ - void sigActMoved(qreal diffX, qreal diffY); - -public Q_SLOTS: - virtual void slotMenuSelection(QAction* action); - -protected: - virtual QSizeF minimumSize() const; - virtual QSizeF maximumSize(); - - ActivityType m_activityType; ///< Type of activity. - - QString m_preconditionText; - QString m_postconditionText; -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/actorwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/actorwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/actorwidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/actorwidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,104 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header file -#include "actorwidget.h" - -// local includes -#include "actor.h" -#include "umlview.h" - -/** - * Constructs an ActorWidget. - * - * @param scene The parent of this ActorWidget. - * @param a The Actor class this ActorWidget will display. - */ -ActorWidget::ActorWidget(UMLScene * scene, UMLActor *a) - : UMLWidget(scene, WidgetBase::wt_Actor, a) -{ - setFixedAspectRatio(true); -} - -/** - * Destructor. - */ -ActorWidget::~ActorWidget() -{ -} - -/** - * Overrides the standard paint event. - */ -void ActorWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - Q_UNUSED(option); - Q_UNUSED(widget); - UMLWidget::setPenFromSettings(painter); - if(UMLWidget::useFillColor()) - painter->setBrush(UMLWidget::fillColor()); - const int w = width(); - const int h = height(); - painter->setFont(UMLWidget::font()); - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - bool drawStereotype = umlObject() && !umlObject()->stereotype().isEmpty(); - const int a_height = h - (drawStereotype ? 2 * fontHeight : fontHeight) - A_MARGIN; - const int h2 = a_height / 2; - const int a_width = (h2); - const int middleX = w / 2; - const int thirdY = a_height / 3; - - //draw actor - painter->drawEllipse(middleX - a_width / 2, 0, a_width, thirdY); //head - painter->drawLine(middleX, thirdY, - middleX, thirdY * 2); //body - painter->drawLine(middleX, 2 * thirdY, - middleX - a_width / 2, a_height); //left leg - painter->drawLine(middleX, 2 * thirdY, - middleX + a_width / 2, a_height); //right leg - painter->drawLine(middleX - a_width / 2, thirdY + thirdY / 2, - middleX + a_width / 2, thirdY + thirdY / 2); //arms - //draw text - painter->setPen(textColor()); - if (drawStereotype) - painter->drawText(A_MARGIN, h - 2 * fontHeight, w - A_MARGIN * 2, fontHeight, Qt::AlignCenter, umlObject()->stereotype(true)); - painter->drawText(A_MARGIN, h - fontHeight, - w - A_MARGIN * 2, fontHeight, Qt::AlignCenter, name()); - UMLWidget::paint(painter, option, widget); -} - -/** - * Saves the widget to the "actorwidget" XMI element. - * Note: For loading from XMI, the inherited parent method is used. - */ -void ActorWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) -{ - QDomElement actorElement = qDoc.createElement(QLatin1String("actorwidget")); - UMLWidget::saveToXMI(qDoc, actorElement); - qElement.appendChild(actorElement); -} - -/** - * Overrides method from UMLWidget. - */ -QSizeF ActorWidget::minimumSize() const -{ - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - const int textWidth = fm.width(name()); - bool drawStereotype = umlObject() && !umlObject()->stereotype().isEmpty(); - int width = textWidth > A_WIDTH ? textWidth : A_WIDTH; - int height = A_HEIGHT + (drawStereotype ? 2 * fontHeight : fontHeight) + A_MARGIN; - width += A_MARGIN * 2; - return QSizeF(width, height); -} - - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/actorwidget.h umbrello-kf6-15.08.1/umbrello/widgets/actorwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/actorwidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/actorwidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,55 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef ACTORWIDGET_H -#define ACTORWIDGET_H - -#include "umlwidget.h" - -#define A_WIDTH 20 -#define A_HEIGHT 40 -#define A_MARGIN 5 - -class UMLActor; - -/** - * This class is the graphical version of a UML Actor. - * An ActorWidget is created by a @ref UMLView. An ActorWidget belongs to only - * one @ref UMLView instance. - * When the @ref UMLView instance that this class belongs to is destroyed, the - * ActorWidget will be automatically deleted. - * - * If the UMLActor class that this ActorWidget is displaying is deleted, the - * @ref UMLView will make sure that this instance is also deleted. - * - * The ActorWidget class inherits from the @ref UMLWidget class - * which adds most of the functionality to this class. - * - * @short A graphical version of a UML Actor. - * @author Paul Hensgen - * @see UMLWidget - * @see UMLView - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class ActorWidget : public UMLWidget -{ -public: - ActorWidget(UMLScene * scene, UMLActor *o); - virtual ~ActorWidget(); - - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - - virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); - -protected: - QSizeF minimumSize() const; -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/artifactwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/artifactwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/artifactwidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/artifactwidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,293 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "artifactwidget.h" - -// app includes -#include "artifact.h" -#include "debug_utils.h" -#include "umlscene.h" -#include "umlview.h" - -/** - * Constructs a ArtifactWidget. - * - * @param scene The parent of this ArtifactWidget. - * @param a The Artifact this widget will be representing. - */ -ArtifactWidget::ArtifactWidget(UMLScene *scene, UMLArtifact *a) - : UMLWidget(scene, WidgetBase::wt_Artifact, a) -{ - setSize(100, 30); -} - -/** - * Destructor. - */ -ArtifactWidget::~ArtifactWidget() -{ -} - -/** - * Reimplemented to paint the articraft widget. Some part of specific - * drawing is delegeted to private method like drawAsFile.. - */ -void ArtifactWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - Q_UNUSED(option); - Q_UNUSED(widget); - - UMLWidget::setPenFromSettings(painter); - if (UMLWidget::useFillColor()) { - painter->setBrush(UMLWidget::fillColor()); - } else { - painter->setBrush(m_scene->backgroundColor()); - } - - if (umlObject()) { - UMLArtifact *umlart = static_cast(m_umlObject); - UMLArtifact::Draw_Type drawType = umlart->getDrawAsType(); - switch (drawType) { - case UMLArtifact::defaultDraw: - paintAsNormal(painter, option); - break; - case UMLArtifact::file: - paintAsFile(painter, option); - break; - case UMLArtifact::library: - paintAsLibrary(painter, option); - break; - case UMLArtifact::table: - paintAsTable(painter, option); - break; - default: - uWarning() << "Artifact drawn as unknown type"; - break; - } - } - else { - uWarning() << "Cannot draw as there is no UMLArtifact for this widget."; - } -} - -/** - * Reimplemented from WidgetBase::saveToXMI to save the widget to - * the "artifactwidget" XMI element. - */ -void ArtifactWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) -{ - QDomElement conceptElement = qDoc.createElement(QLatin1String("artifactwidget")); - UMLWidget::saveToXMI(qDoc, conceptElement); - qElement.appendChild(conceptElement); -} - -/** - * Overrides method from UMLWidget. - */ -QSizeF ArtifactWidget::minimumSize() const -{ - if (!m_umlObject) { - return UMLWidget::minimumSize(); - } - UMLArtifact *umlart = static_cast(m_umlObject); - if (umlart->getDrawAsType() == UMLArtifact::defaultDraw) { - return calculateNormalSize(); - } else { - return calculateIconSize(); - } -} - -/** - * calculates the size when drawing as an icon (it's the same size for all icons) - */ -QSize ArtifactWidget::calculateIconSize() const -{ - const QFontMetrics &fm = getFontMetrics(FT_BOLD_ITALIC); - const int fontHeight = fm.lineSpacing(); - - int width = fm.width(m_umlObject->name()); - - width = width<50 ? 50 : width; - - int height = 50 + fontHeight; - - return QSize(width, height); -} - -/** - * calculates the size for drawing as a box - */ -QSize ArtifactWidget::calculateNormalSize() const -{ - const QFontMetrics &fm = getFontMetrics(FT_BOLD_ITALIC); - const int fontHeight = fm.lineSpacing(); - - int width = fm.width(m_umlObject->name()); - - int tempWidth = 0; - if(!m_umlObject->stereotype().isEmpty()) { - tempWidth = fm.width(m_umlObject->stereotype(true)); - } - width = tempWidth>width ? tempWidth : width; - width += ARTIFACT_MARGIN * 2; - - int height = (2*fontHeight) + (ARTIFACT_MARGIN * 2); - - return QSize(width, height); -} - -/** - * draw as a file icon - */ -void ArtifactWidget::paintAsFile(QPainter *painter, const QStyleOptionGraphicsItem *option) -{ - const int w = width(); - const int h = height(); - QFont font = UMLWidget::font(); - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - - int startX = (w/2) - 25; - int iconHeight = h - fontHeight; - QPolygon pointArray(5); - pointArray.setPoint(0, startX, 0); - pointArray.setPoint(1, startX + 40, 0); - pointArray.setPoint(2, startX + 50, 10); - pointArray.setPoint(3, startX + 50, iconHeight); - pointArray.setPoint(4, startX, iconHeight); - painter->drawPolygon(pointArray); - - painter->drawLine(startX + 40, 0, startX + 40, 10); - painter->drawLine(startX + 40, 10, startX + 50, 10); - painter->drawLine(startX + 40, 0, startX + 50, 10); - - painter->setPen(textColor()); - painter->setFont(font); - - painter->drawText(0, h - fontHeight, - w, fontHeight, Qt::AlignCenter, name()); - - UMLWidget::paint(painter, option); -} - -/** - * draw as a library file icon - */ -void ArtifactWidget::paintAsLibrary(QPainter *painter, const QStyleOptionGraphicsItem *option) -{ - //FIXME this should have gears on it - const int w = width(); - const int h = height(); - const QFont font = UMLWidget::font(); - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - - const int startX = (w/2) - 25; - const int iconHeight = h - fontHeight; - QPolygon pointArray(5); - pointArray.setPoint(0, startX, 0); - pointArray.setPoint(1, startX + 40, 0); - pointArray.setPoint(2, startX + 50, 10); - pointArray.setPoint(3, startX + 50, iconHeight); - pointArray.setPoint(4, startX, iconHeight); - painter->drawPolygon(pointArray); - - painter->drawLine(startX + 40, 0, startX + 40, 10); - painter->drawLine(startX + 40, 10, startX + 50, 10); - painter->drawLine(startX + 40, 0, startX + 50, 10); - - painter->setPen(textColor()); - painter->setFont(font); - - painter->drawText(0, h - fontHeight, - w, fontHeight, Qt::AlignCenter, name()); - - UMLWidget::paint(painter, option); -} - -/** - * draw as a database table icon - */ -void ArtifactWidget::paintAsTable(QPainter *painter, const QStyleOptionGraphicsItem *option) -{ - const int w = width(); - const int h = height(); - const QFont font = UMLWidget::font(); - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - - const int startX = (w/2) - 25; - const int iconHeight = h - fontHeight; - - painter->drawRect(startX, 0, 50, h - fontHeight + 1); - painter->drawLine(startX + 20, 0, startX + 20, iconHeight); - painter->drawLine(startX + 30, 0, startX + 30, iconHeight); - painter->drawLine(startX + 40, 0, startX + 40, iconHeight); - painter->drawLine(startX, (iconHeight/2), startX + 49, (iconHeight/2)); - painter->drawLine(startX, (iconHeight/2) + (iconHeight/4), - startX + 49, (iconHeight/2) + (iconHeight/4)); - - QPen thickerPen = painter->pen(); - thickerPen.setWidth(2); - painter->setPen(thickerPen); - painter->drawLine(startX + 10, 0, startX + 10, iconHeight); - painter->drawLine(startX, (iconHeight/4), startX + 50, (iconHeight/4)); - - painter->setPen(textColor()); - painter->setFont(font); - - painter->drawText(0, h - fontHeight, - w, fontHeight, Qt::AlignCenter, name()); - - UMLWidget::paint(painter, option); -} - -/** - * draw as a box - */ -void ArtifactWidget::paintAsNormal(QPainter *painter, const QStyleOptionGraphicsItem *option) -{ - int w = width(); - int h = height(); - QFont font = UMLWidget::font(); - font.setBold(true); - const QFontMetrics &fm = getFontMetrics(FT_BOLD); - const int fontHeight = fm.lineSpacing(); - QString stereotype = m_umlObject->stereotype(); - - painter->drawRect(0, 0, w, h); - - painter->setPen(textColor()); - painter->setFont(font); - - if (!stereotype.isEmpty()) { - painter->drawText(ARTIFACT_MARGIN, (h/2) - fontHeight, - w, fontHeight, Qt::AlignCenter, m_umlObject->stereotype(true)); - } - - int lines; - if (!stereotype.isEmpty()) { - lines = 2; - } else { - lines = 1; - } - - if (lines == 1) { - painter->drawText(0, (h/2) - (fontHeight/2), - w, fontHeight, Qt::AlignCenter, name()); - } else { - painter->drawText(0, (h/2), - w, fontHeight, Qt::AlignCenter, name()); - } - - UMLWidget::paint(painter, option); -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/artifactwidget.h umbrello-kf6-15.08.1/umbrello/widgets/artifactwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/artifactwidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/artifactwidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,55 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef ARTIFACTWIDGET_H -#define ARTIFACTWIDGET_H - -#include "umlwidget.h" - -class UMLScene; -class UMLArtifact; - -#define ARTIFACT_MARGIN 5 - -/** - * Defines a graphical version of the @ref UMLArtifact. - * Most of the functionality will come from the @ref UMLWidget class. - * - * @short A graphical version of a Artifact. - * @author Jonathan Riddell - * @see UMLWidget - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class ArtifactWidget : public UMLWidget -{ -public: - ArtifactWidget(UMLScene *scene, UMLArtifact *a); - virtual ~ArtifactWidget(); - - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - - // Note: For loading from XMI, the inherited parent method is used. - virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); - -protected: - QSizeF minimumSize() const; - -private: - void paintAsFile(QPainter *painter, const QStyleOptionGraphicsItem *option); - void paintAsLibrary(QPainter *painter, const QStyleOptionGraphicsItem *option); - void paintAsTable(QPainter *painter, const QStyleOptionGraphicsItem *option); - void paintAsNormal(QPainter *painter, const QStyleOptionGraphicsItem *option); - - QSize calculateIconSize() const; - QSize calculateNormalSize() const; - -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/associationline.cpp umbrello-kf6-15.08.1/umbrello/widgets/associationline.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/associationline.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/associationline.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,1404 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "associationline.h" - -// application includes -#include "associationwidget.h" -#include "debug_utils.h" -#include "umlwidget.h" - -// qt includes -#include -#include - -// system includes -#include -#include - -DEBUG_REGISTER_DISABLED(AssociationLine) - -// Initialize static variables. -const qreal AssociationLine::Delta = 5; -const qreal AssociationLine::SelectedPointDiameter = 4; -const qreal AssociationLine::SelfAssociationMinimumHeight = 30; - -/** - * Constructor. - * Constructs an AssociationLine item with its parent being \a parent. - */ -AssociationLine::AssociationLine(AssociationWidget *association) - : QGraphicsObject(association), - m_associationWidget(association), - m_activePointIndex(-1), - m_activeSegmentIndex(-1), - m_startSymbol(0), - m_endSymbol(0), - m_subsetSymbol(0), - m_collaborationLineItem(0), - m_collaborationLineHead(0), - m_layout(Polyline) -{ - Q_ASSERT(association); - setFlag(QGraphicsLineItem::ItemIsSelectable); - setAcceptHoverEvents(true); - setZValue(3); -} - -/** - * Destructor. - */ -AssociationLine::~AssociationLine() -{ -} - -/** - * Returns the point at the point index. - * @return point at given index - */ -QPointF AssociationLine::point(int index) const -{ - if ((index < 0) | (index >= m_points.size())) { - uWarning() << "Index " << index << " out of range [0.." << m_points.size() - 1 << "]."; - return QPointF(-1.0, -1.0); - } - return m_points.at(index); -} - -/** - * Sets the point value at given index to \a point. - */ -bool AssociationLine::setPoint(int index, const QPointF &point) -{ - if ((index < 0) | (index >= m_points.size())) { - uWarning() << "Index " << index << " out of range [0.." << m_points.size() - 1 << "]."; - return false; - } - if (m_points.at(index) == point) { - return false; // nothing to change - } - prepareGeometryChange(); - m_points[index] = point; - alignSymbols(); - return true; -} - -/** - * Shortcut for point(0). - */ -QPointF AssociationLine::startPoint() const -{ - return m_points.at(0); -} - -/** - * Shortcut for end point. - */ -QPointF AssociationLine::endPoint() const -{ - return m_points.at(m_points.size()-1); -} - -/** - * Inserts the passed in \a point at the \a index passed in and - * recalculates the bounding rect. - */ -void AssociationLine::insertPoint(int index, const QPointF &point) -{ - prepareGeometryChange(); - m_points.insert(index, point); - alignSymbols(); -} - -/** - * Removes the point at \a index passed in. - * @see removeNonEndPoint - */ -void AssociationLine::removePoint(int index) -{ - prepareGeometryChange(); - m_points.remove(index); - alignSymbols(); -} - -/** - * Returns the amount of POINTS on the line. - * Includes start and end points. - * @return number of points in the AssociationLine - */ -int AssociationLine::count() const -{ - return m_points.size(); -} - -/** - * Removes all the points and signals a geometry update. - */ -void AssociationLine::cleanup() -{ - if (!m_points.isEmpty()) { - prepareGeometryChange(); - m_points.clear(); - alignSymbols(); - } -} - -/** - * This method optimizes the number of points in the - * AssociationLine. This can be used to reduce the clutter caused - * due to too many points. - * TODO: Use delta comparison 'closestPointIndex' instead of exact comparison. - * TODO: Not used anywhere. - */ -void AssociationLine::optimizeLinePoints() -{ - int i = 1; - prepareGeometryChange(); - while (i < m_points.size()) { - if (m_points.at(i) == m_points.at(i-1)) { - m_points.remove(i); - } - else { - ++i; - } - } - alignSymbols(); -} - -/** - * Return index of point closer a given delta. - * - * @param point The point which is to be tested for closeness. - * @param delta The distance the point should be closer to. - * - * @retval "Index" of the first line point closer to the \a point passed. - * @retval -1 If no line point is closer to passed in \a point. - */ -int AssociationLine::closestPointIndex(const QPointF &point, qreal delta) const -{ - for(int i = 0; i < m_points.size(); ++i) { - const QPointF& linePoint = m_points.at(i); - // Apply distance formula to see point closeness. - qreal deltaXSquare = (point.x() - linePoint.x()) * (point.x() - linePoint.x()); - qreal deltaYSquare = (point.y() - linePoint.y()) * (point.y() - linePoint.y()); - - qreal lhs = deltaXSquare + deltaYSquare; - qreal rhs = delta * delta; - - if (lhs <= rhs) { - return i; - } - } - return -1; -} - -/** - * Return index of closest segment. - * - * @param point The point which is to be tested for closeness. - * - * @return Index of the line segment closest to the \a point passed; - * -1 if no line segment is closer to passed in \a point. - */ -int AssociationLine::closestSegmentIndex(const QPointF &point, qreal delta) const -{ - QPainterPathStroker stroker; - stroker.setWidth(delta); - - for(int i = 1; i < m_points.size(); ++i) { - QLineF segment(m_points[i-1], m_points[i]); - - QPainterPath path; - path.moveTo(segment.p1()); - path.lineTo(segment.p2()); - - path = stroker.createStroke(path); - - if (path.contains(point)) { - return i-1; - } - } - return -1; -} - -/** - * Retval True If point at \a index is start or end. - */ -bool AssociationLine::isEndPointIndex(int index) const -{ - const int size = m_points.size(); - Q_ASSERT(index >= 0 && index < size); - - return (index == 0 || index == (size - 1)); -} - -/** - * Retval True If segment at \a index is start or end. - */ -bool AssociationLine::isEndSegmentIndex(int index) const -{ - // num of seg = num of points - 1 - const int size = m_points.size() - 1; - Q_ASSERT(index >= 0 && index < size); - - return (index == 0 || index == (size - 1)); -} - -/** - * Sets the start and end points. - */ -bool AssociationLine::setEndPoints(const QPointF &start, const QPointF &end) -{ - const int size = m_points.size(); - - prepareGeometryChange(); - - if (size == 0) { - m_points.insert(0, start); - m_points.insert(1, end); - } - else if (size == 1) { - m_points[0] = start; - m_points.insert(1, end); - } - else { - m_points[0] = start; - m_points[size-1] = end; - } - - alignSymbols(); - return true; -} - -/** - * Debug helper method to write out the points. - */ -void AssociationLine::dumpPoints() -{ - for (int i = 1; i < m_points.size(); ++i) { - QPointF p = m_points.at(i); - DEBUG(DBG_SRC) << i << ". point x:" << p.x() << " / y:" << p.y(); - } -} - -/** - * Loads AssociationLine information saved in \a qElement XMI element. - */ -bool AssociationLine::loadFromXMI(QDomElement &qElement) -{ - QString layout = qElement.attribute(QLatin1String("layout"), QLatin1String("polyline")); - m_layout = fromString(layout); - - QDomNode node = qElement.firstChild(); - - m_points.clear(); - - QDomElement startElement = node.toElement(); - if(startElement.isNull() || startElement.tagName() != QLatin1String("startpoint")) { - return false; - } - QString x = startElement.attribute(QLatin1String("startx"), QLatin1String("0")); - qreal nX = x.toFloat(); - QString y = startElement.attribute(QLatin1String("starty"), QLatin1String("0")); - qreal nY = y.toFloat(); - QPointF startPoint(nX, nY); - - node = startElement.nextSibling(); - QDomElement endElement = node.toElement(); - if(endElement.isNull() || endElement.tagName() != QLatin1String("endpoint")) { - return false; - } - x = endElement.attribute(QLatin1String("endx"), QLatin1String("0")); - nX = x.toFloat(); - y = endElement.attribute(QLatin1String("endy"), QLatin1String("0")); - nY = y.toFloat(); - QPointF endPoint(nX, nY); - setEndPoints(startPoint, endPoint); - QPointF point; - node = endElement.nextSibling(); - QDomElement element = node.toElement(); - int i = 1; - while(!element.isNull()) { - if(element.tagName() == QLatin1String("point")) { - x = element.attribute(QLatin1String("x"), QLatin1String("0")); - y = element.attribute(QLatin1String("y"), QLatin1String("0")); - point.setX(x.toFloat()); - point.setY(y.toFloat()); - insertPoint(i++, point); - } - node = element.nextSibling(); - element = node.toElement(); - } - - return true; -} - -/** - * Saves association line information into XMI element named "linepath". - * @note Stored as linepath for backwared compatibility - */ -void AssociationLine::saveToXMI(QDomDocument &qDoc, QDomElement &qElement) -{ - QPointF point = m_associationWidget->mapToScene(startPoint()); - QDomElement lineElement = qDoc.createElement(QLatin1String("linepath")); - lineElement.setAttribute(QLatin1String("layout"), toString(m_layout)); - QDomElement startElement = qDoc.createElement(QLatin1String("startpoint")); - startElement.setAttribute(QLatin1String("startx"), point.x()); - startElement.setAttribute(QLatin1String("starty"), point.y()); - lineElement.appendChild(startElement); - QDomElement endElement = qDoc.createElement(QLatin1String("endpoint")); - point = m_associationWidget->mapToScene(endPoint()); - endElement.setAttribute(QLatin1String("endx"), point.x()); - endElement.setAttribute(QLatin1String("endy"), point.y()); - lineElement.appendChild(endElement); - for(int i = 1; i < count()-1; ++i) { - QDomElement pointElement = qDoc.createElement(QLatin1String("point")); - point = m_associationWidget->mapToScene(this->point(i)); - pointElement.setAttribute(QLatin1String("x"), point.x()); - pointElement.setAttribute(QLatin1String("y"), point.y()); - lineElement.appendChild(pointElement); - } - qElement.appendChild(lineElement); -} - -/** - * Returns the type of brush to use depending on the type of Association. - */ -QBrush AssociationLine::brush() const -{ - QBrush brush(Qt::solid-kf6Pattern); - Uml::AssociationType::Enum type = m_associationWidget->associationType(); - if (type == Uml::AssociationType::Aggregation || - type == Uml::AssociationType::Generalization || - type == Uml::AssociationType::Realization) { - brush.setColor(Qt::white); - } - if (type == Uml::AssociationType::Composition) { - brush.setColor(m_associationWidget->lineColor()); - } - return brush; -} - -/** - * Returns the type of pen to use depending on the type of Association. - */ -QPen AssociationLine::pen() const -{ - QPen pen(m_associationWidget->lineColor(), - m_associationWidget->lineWidth(), - Qt::solid-kf6Line, - Qt::RoundCap, - Qt::RoundJoin); - Uml::AssociationType::Enum type = m_associationWidget->associationType(); - if (type == Uml::AssociationType::Dependency || - type == Uml::AssociationType::Realization || - type == Uml::AssociationType::Anchor) { - pen.setStyle(Qt::DashLine); - } - return pen; -} - -/** - * This method simply ensures presence of two points and - * adds the needed points for self associations. - */ -void AssociationLine::calculateInitialEndPoints() -{ - if (m_associationWidget->isSelf() && count() < 4) { - for (int i = count(); i < 4; ++i) { - insertPoint(i, QPointF()); - } - UMLWidget *wid = m_associationWidget->widgetForRole(Uml::RoleType::B); - if (!wid) { - uError() << "AssociationWidget is partially constructed." - "UMLWidget for role B is null."; - return; - } - const QRectF rect = m_associationWidget->mapFromScene( - mapToScene(wid->rect()).boundingRect()).boundingRect(); - - qreal l = rect.left() + .25 * rect.width(); - qreal r = rect.left() + .75 * rect.width(); - bool drawAbove = rect.top() >= SelfAssociationMinimumHeight; - qreal y = drawAbove ? rect.top() : rect.bottom(); - qreal yOffset = SelfAssociationMinimumHeight; - if (drawAbove) { - yOffset *= -1.0; - } - - setPoint(0, QPointF(l, y)); - setPoint(1, QPointF(l, y + yOffset)); - setPoint(2, QPointF(r, y + yOffset)); - setPoint(3, QPointF(r, y)); - } else if (!m_associationWidget->isSelf() && count() < 2) { - setEndPoints(QPointF(), QPointF()); - } -} - -/** - * This method creates, deletes symbols and collaboration lines based on - * m_associationWidget->associationType(). - * - * Call this method when associationType of m_associationWidget changes. - */ -void AssociationLine::reconstructSymbols() -{ - switch( m_associationWidget->associationType() ) { - case Uml::AssociationType::State: - case Uml::AssociationType::Activity: - case Uml::AssociationType::Exception: - case Uml::AssociationType::UniAssociation: - case Uml::AssociationType::Dependency: - setStartSymbol(Symbol::None); - setEndSymbol(Symbol::OpenArrow); - removeSubsetSymbol(); - removeCollaborationLine(); - break; - - case Uml::AssociationType::Relationship: - setStartSymbol(Symbol::None); - setEndSymbol(Symbol::CrowFeet); - removeSubsetSymbol(); - removeCollaborationLine(); - break; - - case Uml::AssociationType::Generalization: - case Uml::AssociationType::Realization: - setStartSymbol(Symbol::None); - setEndSymbol(Symbol::ClosedArrow); - removeSubsetSymbol(); - removeCollaborationLine(); - break; - - case Uml::AssociationType::Composition: - case Uml::AssociationType::Aggregation: - setStartSymbol(Symbol::Diamond); - setEndSymbol(Symbol::None); - removeSubsetSymbol(); - removeCollaborationLine(); - break; - - case Uml::AssociationType::Containment: - setStartSymbol(Symbol::Circle); - setEndSymbol(Symbol::None); - removeSubsetSymbol(); - removeCollaborationLine(); - break; - - case Uml::AssociationType::Child2Category: - setStartSymbol(Symbol::None); - setEndSymbol(Symbol::None); - createSubsetSymbol(); - removeCollaborationLine(); - break; - - case Uml::AssociationType::Coll_Message_Synchronous: - case Uml::AssociationType::Coll_Message_Asynchronous: - case Uml::AssociationType::Coll_Message_Self: - setStartSymbol(Symbol::None); - setEndSymbol(Symbol::None); - removeSubsetSymbol(); - createCollaborationLine(); - break; - - default: - break; - } - alignSymbols(); -} - -/** - * Sets the Symbol to appear at the first line segment to \a symbol. - * - * If symbol == Symbol::None , then it deletes the symbol item. - */ -void AssociationLine::setStartSymbol(Symbol::SymbolType symbolType) -{ - Q_ASSERT(symbolType != Symbol::Count); - if (symbolType == Symbol::None) { - delete m_startSymbol; - m_startSymbol = 0; - return; - } - - if (m_startSymbol) { - m_startSymbol->setSymbolType(symbolType); - } - else { - m_startSymbol = new Symbol(symbolType, m_associationWidget); - } - m_startSymbol->setPen(pen()); - m_startSymbol->setBrush(brush()); -} - -/** - * Sets the Symbol to appear at the last line segment to \a symbol. - * - * If symbol == Symbol::None , then it deletes the symbol item. - */ -void AssociationLine::setEndSymbol(Symbol::SymbolType symbolType) -{ - Q_ASSERT(symbolType != Symbol::Count); - if (symbolType == Symbol::None) { - delete m_endSymbol; - m_endSymbol = 0; - return; - } - - if (m_endSymbol) { - m_endSymbol->setSymbolType(symbolType); - } - else { - m_endSymbol = new Symbol(symbolType, m_associationWidget); - } - m_endSymbol->setPen(pen()); - m_endSymbol->setBrush(brush()); -} - -/** - * Constructs a new subset symbol. - */ -void AssociationLine::createSubsetSymbol() -{ - delete m_subsetSymbol; // recreate - m_subsetSymbol = new Symbol(Symbol::Subset, m_associationWidget); - m_subsetSymbol->setPen(pen()); - m_subsetSymbol->setBrush(brush()); -} - -/** - * Removes the subset symbol if it existed by deleting appropriate items. - */ -void AssociationLine::removeSubsetSymbol() -{ - delete m_subsetSymbol; - m_subsetSymbol = 0; -} - -/** - * Constructs the open arrow symbol and arrow line, that would represent Collaboration line. - */ -void AssociationLine::createCollaborationLine() -{ - const QPen p = pen(); - - // recreate - delete m_collaborationLineItem; - delete m_collaborationLineHead; - - m_collaborationLineItem = new QGraphicsLineItem(m_associationWidget); - m_collaborationLineItem->setPen(p); - - if (m_associationWidget->associationType() == Uml::AssociationType::Coll_Message_Synchronous) { - m_collaborationLineHead = new Symbol(Symbol::ClosedArrow, m_associationWidget); - m_collaborationLineHead->setBrush(p.color()); - } - else - m_collaborationLineHead = new Symbol(Symbol::OpenArrow, m_associationWidget); - m_collaborationLineHead->setPen(p); -} - -/** - * Removes collaboration line by deleting the head and line item. - */ -void AssociationLine::removeCollaborationLine() -{ - delete m_collaborationLineItem; - m_collaborationLineItem = 0; - - delete m_collaborationLineHead; - m_collaborationLineHead = 0; -} - -/** - * This method aligns both the \b "start" and \b "end" symbols to - * the current angles of the \b "first" and the \b "last" line - * segment respectively. - */ -void AssociationLine::alignSymbols() -{ - const int sz = m_points.size(); - if (sz < 2) { - // cannot align if there is no line (one line = 2 points) - return; - } - - QList polygons = path().toSubpathPolygons(); - - if (m_startSymbol) { - QPolygonF firstLine = polygons.first(); - QLineF segment(firstLine.at(1), firstLine.at(0)); - m_startSymbol->alignTo(segment); - } - - if (m_endSymbol) { - QPolygonF lastLine = polygons.last(); - int maxIndex = lastLine.size(); - QLineF segment(lastLine.at(maxIndex-2), lastLine.at(maxIndex-1)); - m_endSymbol->alignTo(segment); - } - - if (m_subsetSymbol) { - QPointF p1 = path().pointAtPercent(0.4); - QPointF p2 = path().pointAtPercent(0.5); - QLineF segment(p1, p2); - m_subsetSymbol->alignTo(segment); - } - - if (m_collaborationLineItem) { - const qreal distance = 10; - const int midSegmentIndex = (sz - 1) / 2; - - const QPointF a = m_points.at(midSegmentIndex); - const QPointF b = m_points.at(midSegmentIndex + 1); - - if (a == b) - return; - - const QPointF p1 = (a + b) / 2.0; - const QPointF p2 = (p1 + b) / 2.0; - - // Reversed line as we want normal in opposite direction. - QLineF segment(p2, p1); - QLineF normal = segment.normalVector().unitVector(); - normal.setLength(distance); - - QLineF actualLine; - actualLine.setP2(normal.p2()); - - normal.translate(p1 - p2); - actualLine.setP1(normal.p2()); - - m_collaborationLineItem->setLine(actualLine); - m_collaborationLineHead->alignTo(actualLine); - } -} - -/** - * @return The path of the AssociationLine. - */ -QPainterPath AssociationLine::path() const -{ - if (m_points.count() > 0) { - QPainterPath path; - switch (m_layout) { - case Direct: - path.moveTo(m_points.first()); - path.lineTo(m_points.last()); - break; - - case Spline: - path = createBezierCurve(m_points); - break; - - case Orthogonal: - path = createOrthogonalPath(m_points); - break; - - case Polyline: - default: - QPolygonF polygon(m_points); - path.addPolygon(polygon); - break; - } - return path; - } - else { - return QPainterPath(); - } -} - -/** - * The points are used for the bounding rect. The reason is, - * that for splines the control points are further away from the path. - * @return The bounding rectangle for the AssociationLine. - */ -QRectF AssociationLine::boundingRect() const -{ - QPolygonF polygon(m_points); - QRectF rect = polygon.boundingRect(); - const qreal margin(5.0); - rect.adjust(-margin, -margin, margin, margin); - return rect; -} - -/** - * @return The shape of the AssociationLine. - */ -QPainterPath AssociationLine::shape() const -{ - QPainterPathStroker stroker; - stroker.setWidth(qMax(2*SelectedPointDiameter, pen().widthF()) + 2.0); // allow delta region - stroker.setCapStyle(Qt::FlatCap); - return stroker.createStroke(path()); -} - -/** - * Convert enum LayoutType to string. - */ -QString AssociationLine::toString(LayoutType layout) -{ - return QLatin1String(ENUM_NAME(AssociationLine, LayoutType, layout)); -} - -/** - * Convert string to enum LayoutType. - */ -AssociationLine::LayoutType AssociationLine::fromString(const QString &layout) -{ - if (layout == QLatin1String("Direct")) - return Direct; - if (layout == QLatin1String("Spline")) - return Spline; - if (layout == QLatin1String("Orthogonal")) - return Orthogonal; - return Polyline; -} - -/** - * Return the layout type of the association line. - * @return the currently used layout - */ -AssociationLine::LayoutType AssociationLine::layout() const -{ - return m_layout; -} - -/** - * Set the layout type of the association line. - * @param layout the desired layout to set - */ -void AssociationLine::setLayout(LayoutType layout) -{ - prepareGeometryChange(); - m_layout = layout; - DEBUG(DBG_SRC) << "new layout = " << toString(m_layout); - if (m_layout == Spline) { - createSplinePoints(); - } - alignSymbols(); -} - -/** - * For a cubic Bezier curve at least four points are needed. - * If there are less, the missing points will be created. - * Note: Implementation is only for two points. - */ -void AssociationLine::createSplinePoints() -{ - if (m_points.size() == 2) { // create two points - QPointF p1 = m_points.first(); // start point - QPointF p2 = m_points.last(); // end point - qreal dx = p2.x() - p1.x(); - qreal dy = p2.y() - p1.y(); - qreal oneThirdX = 0.33 * dx; - qreal oneThirdY = 0.33 * dy; - QPointF c1(p1.x() + oneThirdX, // control point 1 - p1.y() - oneThirdY); - QPointF c2(p2.x() - oneThirdX, // control point 2 - p2.y() + oneThirdY); - insertPoint(1, c1); - insertPoint(2, c2); - } - if (m_points.size() == 3) { // create one point - // insertPoint(1 or 2, ); - // Note: For now we use a quadratic Bezier curve in createBezierCurve(...). - } -} - -/** - * Returns a Bézier path from given points. - * @param points points which define the Bézier curve - * @return cubic Bézier spline - */ -QPainterPath AssociationLine::createBezierCurve(QVector points) -{ - QPainterPath path; - if (points.size() > 3) { // cubic Bezier curve(s) - path.moveTo(points.at(0)); - int i = 1; - while (i + 2 < points.size()) { - path.cubicTo(points.at(i), points.at(i+1), points.at(i+2)); - i += 3; - } - while (i < points.size()) { // draw a line if points are not modulo 3 - path.lineTo(points.at(i)); - ++i; - } - } - else { - if (points.size() == 3) { // quadratic Bezier curve - path.moveTo(points.at(0)); - path.quadTo(points.at(1), points.at(2)); - } - else { // should not be reached - QPolygonF polygon(points); - path.addPolygon(polygon); - } - } - return path; -} - -/** - * Returns an orthogonal path constructed of vertical and horizontal segments - * through the given points. - * @param points base points for the path - * @return orthogonal path - */ -QPainterPath AssociationLine::createOrthogonalPath(QVector points) -{ - QPainterPath path; - if (points.size() > 1) { - QPointF start = points.first(); - QPointF end = points.last(); - qreal deltaX = fabs(start.x() - end.x()); - qreal deltaY = fabs(start.y() - end.y()); - // DEBUG("AssociationLine") << "start=" << start << " / end=" << end - // << " / deltaX=" << deltaX << " / deltaY=" << deltaY; - QVector vector; - for (int i = 0; i < points.size() - 1; ++i) { - QPointF curr = points.at(i); - QPointF next = points.at(i+1); - QPointF center = (next + curr)/2.0; - - vector.append(curr); - if (deltaX < deltaY) { - // go vertical first - vector.append(QPointF(curr.x(), center.y())); - vector.append(QPointF(next.x(), center.y())); - } - else { - // go horizontal first - vector.append(QPointF(center.x(), curr.y())); - vector.append(QPointF(center.x(), next.y())); - } - vector.append(next); - } - - QPolygonF rectLine(vector); - path.addPolygon(rectLine); - } - else { - QPolygonF polygon(points); - path.addPolygon(polygon); - } - return path; -} - -/** - * Reimplemented from QGraphicsItem::paint. - * Draws the AssociationLine and also takes care of highlighting active point or line. - */ -void AssociationLine::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) -{ - Q_UNUSED(widget) - QPen _pen = pen(); - const QColor orig = _pen.color().lighter(); - QColor invertedColor(orig.green(), orig.blue(), orig.red()); - if (invertedColor == _pen.color()) { - // Ensure different color. - invertedColor.setRed((invertedColor.red() + 50) % 256); - } - invertedColor.setAlpha(150); - - int sz = m_points.size(); - if (sz < 1) { - // not enough points - do nothing - return; - } - - QPointF savedStart = m_points.first(); - QPointF savedEnd = m_points.last(); - - // modify the m_points array not to include the Symbol, the value depends on Symbol - if (m_startSymbol) { - QPointF newStart = m_startSymbol->mapToParent(m_startSymbol->symbolEndPoints().first); - m_points[0] = newStart; - } - - if (m_endSymbol) { - QPointF newEnd = m_endSymbol->mapToParent(m_endSymbol->symbolEndPoints().first); - m_points[sz - 1] = newEnd; - } - - painter->setPen(_pen); - painter->setBrush(Qt::NoBrush); - painter->drawPath(path()); - - if (option->state & QStyle::State_Selected) { - // make the association broader in the selected state - QPainterPathStroker stroker; - stroker.setWidth(3.0); - QPainterPath outline = stroker.createStroke(path()); - QColor shadowColor(Qt::lightGray); - shadowColor.setAlpha(80); - QBrush shadowBrush(shadowColor); - painter->setBrush(shadowBrush); - painter->setPen(Qt::NoPen); - painter->drawPath(outline); - - // set color for selected painting - _pen.setColor(Qt::blue); - QRectF circle(0, 0, SelectedPointDiameter, SelectedPointDiameter); - painter->setBrush(_pen.color()); - painter->setPen(Qt::NoPen); - - // draw points - circle.moveCenter(savedStart); - painter->drawRect(circle); - for (int i = 1; i < sz-1; ++i) { - if (i != m_activePointIndex) { - circle.moveCenter(m_points.at(i)); - painter->drawRect(circle); - } - } - circle.moveCenter(savedEnd); - painter->drawRect(circle); - - if (m_activePointIndex != -1) { - painter->setBrush(invertedColor); - painter->setPen(Qt::NoPen); - circle.setWidth(1.5*SelectedPointDiameter); - circle.setHeight(1.5*SelectedPointDiameter); - circle.moveCenter(m_points.at(m_activePointIndex)); - painter->drawEllipse(circle); - } - else if (m_activeSegmentIndex != -1) { - if (m_layout == Polyline) { - painter->setPen(QPen(invertedColor, _pen.widthF() + 1)); - painter->setBrush(Qt::NoBrush); - - QLineF segmentLine(m_points[m_activeSegmentIndex], m_points[m_activeSegmentIndex + 1]); - painter->drawLine(segmentLine); - } - } - // debug info - if (Tracer::instance()->isEnabled(QString::fromLatin1(metaObject()->className()))) { - painter->setPen(Qt::green); - painter->setBrush(Qt::NoBrush); - painter->drawPath(shape()); - painter->setPen(Qt::red); - painter->drawRect(boundingRect()); - // origin - painter->drawLine(-10, 0, 10, 0); - painter->drawLine(0, -10, 0, 10); - } - - } - - // now restore the points array - m_points[0] = savedStart; - m_points[sz - 1] = savedEnd; -} - -/** - * Determines the active point or segment, the latter being given more priority. - */ -void AssociationLine::mousePressEvent(QGraphicsSceneMouseEvent *event) -{ - DEBUG(DBG_SRC) << "at " << event->scenePos(); - if (event->buttons() & Qt::LeftButton) { - m_activePointIndex = closestPointIndex(event->scenePos()); - if (m_activePointIndex != -1 && isEndPointIndex(m_activePointIndex)) { - // end points are not drawn and hence not active - m_activePointIndex = -1; - } - // calculate only if active point index is -1 - m_activeSegmentIndex = (m_activePointIndex != -1) ? -1 : closestSegmentIndex(event->scenePos()); - } - else if (event->buttons() & Qt::RightButton) { - DEBUG(DBG_SRC) << "call context menu of association widget at " << event->scenePos(); - } - else { - m_activePointIndex = -1; - m_activeSegmentIndex = -1; - } -} - -/** - * Moves the point or line if active. - */ -void AssociationLine::mouseMoveEvent(QGraphicsSceneMouseEvent *event) -{ - UMLScene* scene = m_associationWidget->umlScene(); - - QPointF oldPos = event->scenePos(); - QPointF newPos( - scene->snappedX(oldPos.x()), - scene->snappedY(oldPos.y()) - ); - - // Prevent the moving vertex from disappearing underneath a widget - // (else there's no way to get it back.) - UMLWidget *onW = scene->widgetAt(newPos); - if (onW && onW->baseType() != WidgetBase::wt_Box) { // boxes are transparent - const qreal pX = newPos.x(); - const qreal pY = newPos.y(); - const qreal wX = onW->x(); - const qreal wY = onW->y(); - const qreal wWidth = onW->width(); - const qreal wHeight = onW->height(); - if (pX > wX && pX < wX + wWidth) { - const qreal midX = wX + wWidth / 2.0; - if (pX <= midX) - newPos.setX(wX); - else - newPos.setX(wX + wWidth); - } - if (pY > wY && pY < wY + wHeight) { - const qreal midY = wY + wHeight / 2.0; - if (pY <= midY) - newPos.setY(wY); - else - newPos.setY(wY + wHeight); - } - } - - if (m_activePointIndex != -1) { - // Move a single point (snap behaviour) - setPoint(m_activePointIndex, newPos); - } - else if (m_activeSegmentIndex != -1 && !isEndSegmentIndex(m_activeSegmentIndex)) { - // Move a segment (between two points, snap behaviour not implemented) - QPointF delta = event->scenePos() - event->lastScenePos(); - setPoint(m_activeSegmentIndex, m_points[m_activeSegmentIndex] + delta); - setPoint(m_activeSegmentIndex + 1, m_points[m_activeSegmentIndex + 1] + delta); - } -} - -/** - * Reset active indices and also push undo command. - */ -void AssociationLine::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) -{ - if (event->buttons() & Qt::LeftButton) { - m_activeSegmentIndex = -1; - m_activePointIndex = -1; - } -} - -/** - * Calculates the "to be highlighted" point and segment indicies - * and updates if necessary. - */ -void AssociationLine::hoverEnterEvent(QGraphicsSceneHoverEvent *event) -{ - DEBUG(DBG_SRC) << "at " << event->scenePos(); - int oldPointIndex = m_activePointIndex; - int oldSegmentIndex = m_activeSegmentIndex; - - m_activePointIndex = closestPointIndex(event->scenePos()); - // End points are not drawn and hence not active. - if (m_activePointIndex != -1 && isEndPointIndex(m_activePointIndex)) { - m_activePointIndex = -1; - } - // Activate segment index only if point index is -1 - m_activeSegmentIndex = (m_activePointIndex != -1) ? -1 : closestSegmentIndex(event->scenePos()); - - bool isChanged = (oldSegmentIndex != m_activeSegmentIndex || oldPointIndex != m_activePointIndex); - if (isChanged) { - m_associationWidget->update(); - } -} - -/** - * Calculates the "to be highlighted" point and segment indicies - * and updates if necessary. - */ -void AssociationLine::hoverMoveEvent(QGraphicsSceneHoverEvent *event) -{ - int oldPointIndex = m_activePointIndex; - int oldSegmentIndex = m_activeSegmentIndex; - - m_activePointIndex = closestPointIndex(event->scenePos()); - // End points are not drawn and hence not active. - if (m_activePointIndex != -1 && isEndPointIndex(m_activePointIndex)) { - m_activePointIndex = -1; - } - // Activate segment index only if point index is -1 - m_activeSegmentIndex = (m_activePointIndex != -1) ? -1 : closestSegmentIndex(event->scenePos()); - - bool isChanged = (oldSegmentIndex != m_activeSegmentIndex || oldPointIndex != m_activePointIndex); - if (isChanged) { - m_associationWidget->update(); - } -} - -/** - * Reset active indicies and updates. - */ -void AssociationLine::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) -{ - DEBUG(DBG_SRC) << "at " << event->scenePos(); - //Q_UNUSED(event) - m_activePointIndex = -1; - m_activeSegmentIndex = -1; - m_associationWidget->update(); -} - -//----------------------------------------------------------------------------- - -/** - * SymbolEndPoints: - * The first point is where the AssociationLine's visible line is - * supposed to end. - * The second points is where the actual symbol part is to appear. - */ -Symbol::SymbolProperty Symbol::symbolTable[Count] = -{ - { - QRectF(-6, 0, 12, 10), QPainterPath(), QLineF(0, 0, 0, 10), - SymbolEndPoints(QPointF(0, 10), QPointF(0, 10)) - }, - { - QRectF(-6, 0, 12, 10), QPainterPath(), QLineF(0, 0, 0, 10), - SymbolEndPoints(QPointF(0, 0), QPointF(0, 10)) - }, - { - QRectF(-6, 0, 12, 10), QPainterPath(), QLineF(0, 0, 0, 10), - SymbolEndPoints(QPointF(0, 10), QPointF(0, 10)) - }, - { - QRectF(-5, -10, 10, 20), QPainterPath(), QLineF(0, -10, 0, 10), - SymbolEndPoints(QPointF(0, -10), QPointF(0, 10)) - }, - { - QRectF(-15, -10, 30, 20), QPainterPath(), QLineF(-10, 0, 0, 0), - SymbolEndPoints(QPointF(0, 0), QPointF(0, 0)) - }, - { - QRectF(-8, -8, 16, 16), QPainterPath(), QLineF(0, -8, 0, 8), - SymbolEndPoints(QPointF(0, -8), QPointF(0, 8)) - } - -}; - -/** - * @internal A convenience method to setup shapes of all symbols. - */ -void Symbol::setupSymbolTable() -{ - SymbolProperty &openArrow = symbolTable[OpenArrow]; - if (openArrow.shape.isEmpty()) { - QRectF rect = openArrow.boundRect; - // Defines a 'V' shape arrow fitting in the bound rect. - openArrow.shape.moveTo(rect.topLeft()); - openArrow.shape.lineTo(rect.center().x(), rect.bottom()); - openArrow.shape.lineTo(rect.topRight()); - } - - SymbolProperty &closedArrow = symbolTable[ClosedArrow]; - if (closedArrow.shape.isEmpty()) { - QRectF rect = closedArrow.boundRect; - // Defines a 'V' shape arrow fitting in the bound rect. - closedArrow.shape.moveTo(rect.topLeft()); - closedArrow.shape.lineTo(rect.center().x(), rect.bottom()); - closedArrow.shape.lineTo(rect.topRight()); - closedArrow.shape.lineTo(rect.topLeft()); - } - - SymbolProperty &crowFeet = symbolTable[CrowFeet]; - if (crowFeet.shape.isEmpty()) { - QRectF rect = crowFeet.boundRect; - // Defines a crowFeet fitting in the bound rect. - QPointF topMid(rect.center().x(), rect.top()); - - // left leg - crowFeet.shape.moveTo(rect.bottomLeft()); - crowFeet.shape.lineTo(topMid); - - // middle leg - crowFeet.shape.moveTo(rect.center().x(), rect.bottom()); - crowFeet.shape.lineTo(topMid); - - // right leg - crowFeet.shape.moveTo(rect.bottomRight()); - crowFeet.shape.lineTo(topMid); - } - - SymbolProperty &diamond = symbolTable[Diamond]; - if (diamond.shape.isEmpty()) { - QRectF rect = diamond.boundRect; - // Defines a 'diamond' shape fitting in the bound rect. - diamond.shape.moveTo(rect.center().x(), rect.top()); - diamond.shape.lineTo(rect.left(), rect.center().y()); - diamond.shape.lineTo(rect.center().x(), rect.bottom()); - diamond.shape.lineTo(rect.right(), rect.center().y()); - diamond.shape.lineTo(rect.center().x(), rect.top()); - } - - SymbolProperty &subset = symbolTable[Subset]; - if (subset.shape.isEmpty()) { - QRectF rect = subset.boundRect; - // Defines an arc fitting in bound rect. - qreal start = 90, span = 180; - subset.shape.arcMoveTo(rect, start); - subset.shape.arcTo(rect, start, span); - } - - SymbolProperty &circle = symbolTable[Circle]; - if (circle.shape.isEmpty()) { - QRectF rect = circle.boundRect; - // Defines a circle with a horizontal-vertical cross lines. - circle.shape.addEllipse(rect); - - circle.shape.moveTo(rect.center().x(), rect.top()); - circle.shape.lineTo(rect.center().x(), rect.bottom()); - - circle.shape.moveTo(rect.left(), rect.center().y()); - circle.shape.lineTo(rect.right(), rect.center().y()); - } - -} - -/** - * Constructs a Symbol with current symbol being \a symbol and - * parented to \a parent. - */ -Symbol::Symbol(SymbolType symbolType, QGraphicsItem *parent) - : QGraphicsItem(parent), - m_symbolType(symbolType) -{ - // ensure SymbolTable is validly initialized - setupSymbolTable(); -} - -/** - * Destructor. - */ -Symbol::~Symbol() -{ -} - -/** - * @return The current symbol being represented. - */ -Symbol::SymbolType Symbol::symbolType() const -{ - return m_symbolType; -} - -/** - * Sets the current symbol type to \a symbol and updates the geometry. - */ -void Symbol::setSymbolType(SymbolType symbolType) -{ - prepareGeometryChange(); // calls update implicitly - m_symbolType = symbolType; -} - -/** - * Draws the current symbol using the QPainterPath stored for the current - * symbol. - */ -void Symbol::paint(QPainter *painter, const QStyleOptionGraphicsItem * option, QWidget * widget) -{ - Q_UNUSED(option) Q_UNUSED(widget) - painter->setPen(m_pen); - switch (m_symbolType) { - case ClosedArrow: - case CrowFeet: - case Diamond: - painter->setBrush(m_brush); - break; - default: - break; - } - painter->drawPath(Symbol::symbolTable[m_symbolType].shape); -} - -/** - * @return The bound rectangle for this based on current symbol. - */ -QRectF Symbol::boundingRect() const -{ - const qreal adj = .5 * m_pen.widthF(); - return Symbol::symbolTable[m_symbolType].boundRect. - adjusted(-adj, -adj, adj, adj); -} - -/** - * @return The path for this based on current symbol. - */ -QPainterPath Symbol::shape() const -{ - QPainterPath path; - path.addRect(boundingRect()); - return path; -} - -/** - * This method aligns *this* Symbol to the line being - * passed. That is, it ensures that the axis of this symbol aligns - * exactly with the \a "to" line passed. - * - * Also this item is moved such that the second end point of the - * SymbolEndPoints for the current symbol *collides* with the second end - * point of \a "to" line. - */ -void Symbol::alignTo(const QLineF& to) -{ - QLineF toMapped(mapFromParent(to.p1()), mapFromParent(to.p2())); - - QLineF origAxis = Symbol::symbolTable[m_symbolType].axisLine; - QLineF translatedAxis = origAxis.translated(toMapped.p2() - origAxis.p2()); - - qreal angle = translatedAxis.angleTo(toMapped); - setRotation(rotation() - angle); - - QPointF delta = to.p2() - mapToParent(symbolEndPoints().second); - moveBy(delta.x(), delta.y()); -} - -/** - * @return The end points for the symbol. - */ -Symbol::SymbolEndPoints Symbol::symbolEndPoints() const -{ - return Symbol::symbolTable[m_symbolType].endPoints; -} - -/** - * @return The pen used to draw symbol. - */ -QPen Symbol::pen() const -{ - return m_pen; -} - -/** - * Sets the pen used to draw the symbol. - */ -void Symbol::setPen(const QPen& pen) -{ - prepareGeometryChange(); - m_pen = pen; - if (m_symbolType == ClosedArrow) - m_pen.setStyle(Qt::solid-kf6Line); -} - -/** - * @return The brush used to fill symbol. - */ -QBrush Symbol::brush() const -{ - return m_brush; -} - -/** - * Sets the brush used to fill symbol. - */ -void Symbol::setBrush(const QBrush &brush) -{ - m_brush = brush; - update(); -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/associationline.h umbrello-kf6-15.08.1/umbrello/widgets/associationline.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/associationline.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/associationline.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,207 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef ASSOCIATIONLINE_H -#define ASSOCIATIONLINE_H - -#include "basictypes.h" - -#include -#include -#include -#include - -// forward declarations -class AssociationWidget; -class QDomDocument; -class QDomElement; -class QPainter; - -/** - * This class provides with various symbols that can be embedded in - * AssociationLine. It also provides with convenience methods to align - * the symbol to AssociationLine. - */ -class Symbol : public QGraphicsItem -{ - public: - typedef QPair SymbolEndPoints; - - /** - * This enumeration lists all the symbols that can be used as - * embedded on AssociationLine. - */ - enum SymbolType { - None = -1, - OpenArrow, - ClosedArrow, - CrowFeet, - Diamond, - Subset, - Circle, - Count - }; - - explicit Symbol(SymbolType symbolType, QGraphicsItem *parent = 0); - virtual ~Symbol(); - - SymbolType symbolType() const; - void setSymbolType(SymbolType symbolType); - - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); - - virtual QRectF boundingRect() const; - virtual QPainterPath shape() const; - - void alignTo(const QLineF& line); - SymbolEndPoints symbolEndPoints() const; - - QPen pen() const; - void setPen(const QPen &pen); - - QBrush brush() const; - void setBrush(const QBrush& brush); - - private: - QPen m_pen; ///< pen used to draw Symbol - QBrush m_brush; ///< brush used to fill Symbol - SymbolType m_symbolType; ///< current symbol being represented by this item - - /// A structure to hold a table of values for all symbols. - struct SymbolProperty { - QRectF boundRect; - QPainterPath shape; - QLineF axisLine; - SymbolEndPoints endPoints; - }; - - static SymbolProperty symbolTable[Symbol::Count]; ///< a table which stores all symbol properties - static void setupSymbolTable(); -}; - -/** - * A convenience class that encapsulates geometry management, handles - * mouse and hover events, embeds and aligns symbols and finally draws the - * lines and points. - * Context menu events are handled in AssociationWidget. - * - * This class is infact a draw and event handling proxy for - * AssociationWidget. - * - * @note m_activePointIndex and m_activeSegmentIndex can't be - * active at same time! - * - * @author Gopala Krishna - * @author Andi Fischer - * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org - */ -class AssociationLine : public QGraphicsObject -{ - Q_OBJECT - Q_ENUMS(LayoutType) -public: - enum LayoutType { - Direct = 1, - Orthogonal, - Polyline, - Spline - }; - - static QString toString(LayoutType layout); - static LayoutType fromString(const QString& layout); - - explicit AssociationLine(AssociationWidget *association); - virtual ~AssociationLine(); - - QPointF point(int index) const; - bool setPoint(int index, const QPointF& point); - QPointF startPoint() const; - QPointF endPoint() const; - - void insertPoint(int index, const QPointF& point); - void removePoint(int index); - - int count() const; - void cleanup(); - - void optimizeLinePoints(); - - int closestPointIndex(const QPointF& point, qreal delta = Delta) const; - int closestSegmentIndex(const QPointF& point, qreal delta = Delta) const; - - bool isEndPointIndex(int index) const; - bool isEndSegmentIndex(int index) const; - - bool setEndPoints(const QPointF &start, const QPointF &end); - - void dumpPoints(); - - bool loadFromXMI(QDomElement &qElement); - void saveToXMI(QDomDocument &qDoc, QDomElement &qElement); - - QBrush brush() const; - QPen pen() const; - - virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget); - - QPainterPath path() const; - - QRectF boundingRect() const; - QPainterPath shape() const; - - LayoutType layout() const; - void setLayout(LayoutType layout); - - void mousePressEvent(QGraphicsSceneMouseEvent *event); - void mouseMoveEvent(QGraphicsSceneMouseEvent *event); - void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); - - void hoverEnterEvent(QGraphicsSceneHoverEvent *event); - void hoverMoveEvent(QGraphicsSceneHoverEvent *event); - void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); - - void calculateInitialEndPoints(); - - void reconstructSymbols(); - -private: - void setStartSymbol(Symbol::SymbolType symbolType); - void setEndSymbol(Symbol::SymbolType symbolType); - - void createSubsetSymbol(); - void removeSubsetSymbol(); - - void createCollaborationLine(); - void removeCollaborationLine(); - - void alignSymbols(); - - void createSplinePoints(); - - AssociationWidget *m_associationWidget; ///< association widget for which this line represents - QVector m_points; ///< points representing the association line - int m_activePointIndex; ///< index of active point which can be dragged to modify association line - int m_activeSegmentIndex; ///< index of active segment - Symbol *m_startSymbol; ///< symbol drawn at the end of "first" line segment - Symbol *m_endSymbol; ///< symbol drawn at the end of "last" line segment - Symbol *m_subsetSymbol; ///< subset symbol - QGraphicsLineItem *m_collaborationLineItem; ///< parallel arrow line drawn in case of collaboration message - Symbol *m_collaborationLineHead; ///< arrow head drawn at end of m_collaborationLineItem - LayoutType m_layout; - - static QPainterPath createBezierCurve(QVector points); - static QPainterPath createOrthogonalPath(QVector points); - - static const qreal Delta; ///< default delta for fuzzy recognition of points closer to point - static const qreal SelectedPointDiameter; ///< radius of circles drawn to show "selection" - static const qreal SelfAssociationMinimumHeight; ///< minimum height for self association's loop -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/associationwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/associationwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/associationwidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/associationwidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,4407 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "associationwidget.h" - -// app includes -#include "association.h" -#include "associationline.h" -#include "associationpropertiesdialog.h" -#include "assocrules.h" -#include "attribute.h" -#include "classifier.h" -#include "classifierwidget.h" -#include "debug_utils.h" -#include "docwindow.h" -#include "entity.h" -#include "floatingtextwidget.h" -#include "listpopupmenu.h" -#include "messagewidget.h" -#include "objectwidget.h" -#include "operation.h" -#include "optionstate.h" -#include "uml.h" -#include "umldoc.h" -#include "umlscene.h" -#include "umlview.h" -#include "umlwidget.h" -#include "widget_utils.h" - -// kde includes -#if QT_VERSION < 0x050000 -#include -#include -#include -#endif -#include - -// qt includes -#if QT_VERSION >= 0x050000 -#include -#include -#include -#endif -#include -#include -#include -#include - -// system includes -#include - -#define DBG_AW() DEBUG(QLatin1String("AssociationWidget")) -DEBUG_REGISTER_DISABLED(AssociationWidget) - -using namespace Uml; - -/** - * Constructor is private because the static create() methods shall - * be used for constructing AssociationWidgets. - * - * @param scene The parent view of this widget. - */ -AssociationWidget::AssociationWidget(UMLScene *scene) - : WidgetBase(scene, WidgetBase::wt_Association), - m_positions_len(0), - m_activated(false), - m_unNameLineSegment(-1), - m_nLinePathSegmentIndex(-1), - m_pAssocClassLine(0), - m_pAssocClassLineSel0(0), - m_pAssocClassLineSel1(0), - m_associationLine(new AssociationLine(this)), - m_associationClass(0), - m_associationType(Uml::AssociationType::Association), - m_nameWidget(0) -{ - // floating text widgets objects owned by this association - m_role[RoleType::A].changeabilityWidget = 0; - m_role[RoleType::B].changeabilityWidget = 0; - m_role[RoleType::A].multiplicityWidget = 0; - m_role[RoleType::B].multiplicityWidget = 0; - m_role[RoleType::A].roleWidget = 0; - m_role[RoleType::B].roleWidget = 0; - m_role[RoleType::A].umlWidget = 0; - m_role[RoleType::B].umlWidget = 0; - - // associationwidget attributes - m_role[RoleType::A].m_WidgetRegion = Uml::Region::Error; - m_role[RoleType::B].m_WidgetRegion = Uml::Region::Error; - m_role[RoleType::A].m_nIndex = 0; - m_role[RoleType::B].m_nIndex = 0; - m_role[RoleType::A].m_nTotalCount = 0; - m_role[RoleType::B].m_nTotalCount = 0; - m_role[RoleType::A].visibility = Uml::Visibility::Public; - m_role[RoleType::B].visibility = Uml::Visibility::Public; - m_role[RoleType::A].changeability = Uml::Changeability::Changeable; - m_role[RoleType::B].changeability = Uml::Changeability::Changeable; - - setFlag(QGraphicsLineItem::ItemIsSelectable); - setAcceptHoverEvents(true); -} - -/** - * This constructor is really only for loading from XMI, otherwise it - * should not be allowed as it creates an incomplete associationwidget. - * - * @param scene The parent view of this widget. - */ -AssociationWidget* AssociationWidget::create(UMLScene *scene) -{ - AssociationWidget* instance = new AssociationWidget(scene); - return instance; -} - -/** - * Preferred constructor (static factory method.) - * - * @param scene The parent view of this widget. - * @param pWidgetA Pointer to the role A widget for the association. - * @param assocType The AssociationType::Enum for this association. - * @param pWidgetB Pointer to the role B widget for the association. - * @param umlobject Pointer to the underlying UMLObject (if applicable.) - */ -AssociationWidget* AssociationWidget::create - (UMLScene *scene, UMLWidget* pWidgetA, - Uml::AssociationType::Enum assocType, UMLWidget* pWidgetB, - UMLObject *umlobject /* = NULL */) -{ - AssociationWidget* instance = new AssociationWidget(scene); - if (umlobject) { - instance->setUMLObject(umlobject); - } else { - // set up UMLAssociation obj if assoc is represented and both roles are UML objects - if (Uml::AssociationType::hasUMLRepresentation(assocType)) { - UMLObject* umlRoleA = pWidgetA->umlObject(); - UMLObject* umlRoleB = pWidgetB->umlObject(); - if (umlRoleA != NULL && umlRoleB != NULL) { - bool swap; - - // This is not correct. We could very easily have more than one - // of the same type of association between the same two objects. - // Just create the association. This search should have been - // done BEFORE creation of the widget, if it mattered to the code. - // But lets leave check in here for the time being so that debugging - // output is shown, in case there is a collision with code elsewhere. - UMLDoc *doc = UMLApp::app()->document(); - UMLAssociation *myAssoc = doc->findAssociation(assocType, umlRoleA, umlRoleB, &swap); - if (myAssoc != NULL) { - switch (assocType) { - case Uml::AssociationType::Generalization: - case Uml::AssociationType::Dependency: - case Uml::AssociationType::Association_Self: - case Uml::AssociationType::Coll_Message_Self: - case Uml::AssociationType::Seq_Message_Self: - case Uml::AssociationType::Containment: - case Uml::AssociationType::Realization: - DBG_AW() << "Ignoring second construction of same assoctype " - << assocType << " between " << umlRoleA->name() - << " and " << umlRoleB->name(); - break; - default: - DBG_AW() << "constructing a similar or exact same assoctype " - << assocType << " between " << umlRoleA->name() << " and " - << umlRoleB->name() << "as an already existing assoc (swap=" - << swap << ")"; - // now, just create a new association anyways - myAssoc = NULL; - break; - } - } - if (myAssoc == NULL) { - myAssoc = new UMLAssociation(assocType, umlRoleA, umlRoleB); - // CHECK: myAssoc is not yet inserted at any parent UMLPackage - - // need to check carefully that all callers do this, lest it be - // orphaned. - // ToolBarStateAssociation::addAssociationInViewAndDoc() is - // okay in this regard. - } - instance->setUMLAssociation(myAssoc); - } - } - } - - instance->setWidgetForRole(pWidgetA, RoleType::A); - instance->setWidgetForRole(pWidgetB, RoleType::B); - - instance->setAssociationType(assocType); - - instance->calculateEndingPoints(); - - instance->associationLine()->calculateInitialEndPoints(); - instance->associationLine()->reconstructSymbols(); - - //The AssociationWidget is set to Activated because it already has its side widgets - instance->setActivated(true); - - // sync UML meta-data to settings here - instance->mergeAssociationDataIntoUMLRepresentation(); - - // Collaboration messages need a name label because it's that - // which lets operator== distinguish them, which in turn - // permits us to have more than one message between two objects. - if (instance->isCollaboration()) { - // Create a temporary name to bring on setName() - int collabID = instance->m_scene->generateCollaborationId(); - instance->setName(QLatin1Char('m') + QString::number(collabID)); - } - - return instance; -} - -/** - * Destructor. - */ -AssociationWidget::~AssociationWidget() -{ - delete m_associationLine; -} - -/** - * Overriding the method from WidgetBase because we need to do - * something extra in case this AssociationWidget represents - * an attribute of a classifier. - */ -void AssociationWidget::setUMLObject(UMLObject *obj) -{ - WidgetBase::setUMLObject(obj); - if (obj == NULL) - return; - UMLClassifier *klass = NULL; - UMLAttribute *attr = NULL; - UMLEntity *ent = NULL; - const UMLObject::ObjectType ot = obj->baseType(); - switch (ot) { - case UMLObject::ot_Association: - setUMLAssociation(dynamic_cast(obj)); - break; - case UMLObject::ot_Operation: - setOperation(dynamic_cast(obj)); - break; - case UMLObject::ot_Attribute: - klass = static_cast(obj->parent()); - connect(klass, SIGNAL(attributeRemoved(UMLClassifierListItem*)), - this, SLOT(slotClassifierListItemRemoved(UMLClassifierListItem*))); - attr = static_cast(obj); - connect(attr, SIGNAL(attributeChanged()), this, SLOT(slotAttributeChanged())); - break; - case UMLObject::ot_EntityAttribute: - ent = static_cast(obj->parent()); - connect(ent, SIGNAL(entityAttributeRemoved(UMLClassifierListItem*)), - this, SLOT(slotClassifierListItemRemoved(UMLClassifierListItem*))); - break; - case UMLObject::ot_ForeignKeyConstraint: - ent = static_cast(obj->parent()); - connect(ent, SIGNAL(entityConstraintRemoved(UMLClassifierListItem*)), - this, SLOT(slotClassifierListItemRemoved(UMLClassifierListItem*))); - break; - default: - uError() << "cannot associate UMLObject of type " << UMLObject::toString(ot); - break; - } -} - -/** - * Set all 'owned' child widgets to this font. - */ -void AssociationWidget::lwSetFont (QFont font) -{ - if (m_nameWidget) { - m_nameWidget->setFont(font); - } - if (m_role[RoleType::A].roleWidget) { - m_role[RoleType::A].roleWidget->setFont(font); - } - if (m_role[RoleType::B].roleWidget) { - m_role[RoleType::B].roleWidget->setFont(font); - } - if (m_role[RoleType::A].multiplicityWidget) { - m_role[RoleType::A].multiplicityWidget->setFont(font); - } - if (m_role[RoleType::B].multiplicityWidget) { - m_role[RoleType::B].multiplicityWidget->setFont(font); - } - if (m_role[RoleType::A].changeabilityWidget) - m_role[RoleType::A].changeabilityWidget->setFont(font); - if (m_role[RoleType::B].changeabilityWidget) - m_role[RoleType::B].changeabilityWidget->setFont(font); -} - -/** - * Overrides operation from LinkWidget. - * Required by FloatingTextWidget. - * @todo Move to LinkWidget. - */ -UMLClassifier *AssociationWidget::operationOwner() -{ - Uml::RoleType::Enum role = (isCollaboration() ? Uml::RoleType::B : Uml::RoleType::A); - UMLObject *o = widgetForRole(role)->umlObject(); - if (!o) { - return 0; - } - UMLClassifier *c = dynamic_cast(o); - if (!c) { - uError() << "widgetForRole(" << role << ") is not a classifier"; - } - return c; -} - -/** - * Implements operation from LinkWidget. - * Motivated by FloatingTextWidget. - */ -UMLOperation *AssociationWidget::operation() -{ - return dynamic_cast(m_umlObject); -} - -/** - * Implements operation from LinkWidget. - * Motivated by FloatingTextWidget. - */ -void AssociationWidget::setOperation(UMLOperation *op) -{ - if (m_umlObject) - disconnect(m_umlObject, SIGNAL(modified()), m_nameWidget, SLOT(setMessageText())); - m_umlObject = op; - if (m_umlObject) - connect(m_umlObject, SIGNAL(modified()), m_nameWidget, SLOT(setMessageText())); - if (m_nameWidget) - m_nameWidget->setMessageText(); -} - -/** - * Overrides operation from LinkWidget. - * Required by FloatingTextWidget. - */ -QString AssociationWidget::customOpText() -{ - return name(); -} - -/** - * Overrides operation from LinkWidget. - * Required by FloatingTextWidget. - */ -void AssociationWidget::setCustomOpText(const QString &opText) -{ - setName(opText); -} - -/** - * Calls setTextPosition on all the labels. - * Overrides operation from LinkWidget. - */ -void AssociationWidget::resetTextPositions() -{ - if (m_role[RoleType::A].multiplicityWidget) { - setTextPosition(TextRole::MultiA); - } - if (m_role[RoleType::B].multiplicityWidget) { - setTextPosition(Uml::TextRole::MultiB); - } - if (m_role[RoleType::A].changeabilityWidget) { - setTextPosition(Uml::TextRole::ChangeA); - } - if (m_role[RoleType::B].changeabilityWidget) { - setTextPosition(Uml::TextRole::ChangeB); - } - if (m_nameWidget) { - setTextPosition(Uml::TextRole::Name); - } - if (m_role[RoleType::A].roleWidget) { - setTextPosition(Uml::TextRole::RoleAName); - } - if (m_role[RoleType::B].roleWidget) { - setTextPosition(Uml::TextRole::RoleBName); - } -} - -/** - * Overrides operation from LinkWidget. - * Required by FloatingTextWidget. - * - * @param ft The text widget which to update. - */ -void AssociationWidget::setMessageText(FloatingTextWidget *ft) -{ - if (isCollaboration()) { - ft->setSequenceNumber(m_SequenceNumber); - if (m_umlObject != NULL) { - ft->setText(operationText(m_scene)); - } else { - ft->setText(name()); - } - } else { - ft->setText(name()); - } -} - -/** - * Sets the text of the given FloatingTextWidget. - * Overrides operation from LinkWidget. - * Required by FloatingTextWidget. - */ -void AssociationWidget::setText(FloatingTextWidget *ft, const QString &text) -{ - Uml::TextRole::Enum role = ft->textRole(); - switch (role) { - case Uml::TextRole::Name: - setName(text); - break; - case Uml::TextRole::RoleAName: - setRoleName(text, RoleType::A); - break; - case Uml::TextRole::RoleBName: - setRoleName(text, RoleType::B); - break; - case Uml::TextRole::MultiA: - setMultiplicity(text, RoleType::A); - break; - case Uml::TextRole::MultiB: - setMultiplicity(text, RoleType::B); - break; - default: - uWarning() << "Unhandled TextRole: " << Uml::TextRole::toString(role); - break; - } -} - -/** - * Shows the association properties dialog and updates the - * corresponding texts if its execution is successful. - */ -void AssociationWidget::showPropertiesDialog() -{ - UMLApp::app()->docWindow()->updateDocumentation(); - QPointer dlg = new AssociationPropertiesDialog(static_cast(m_scene->activeView()), this); - if (dlg->exec()) { - //rules built into these functions to stop updating incorrect values - setName(name()); - - setRoleName(roleName(RoleType::A), RoleType::A); - setRoleName(roleName(RoleType::B), RoleType::B); - - setDocumentation(documentation()); - - setRoleDocumentation(roleDocumentation(RoleType::A), RoleType::A); - setRoleDocumentation(roleDocumentation(RoleType::B), RoleType::B); - - setMultiplicity(multiplicity(RoleType::A), RoleType::A); - setMultiplicity(multiplicity(RoleType::B), RoleType::B); - - setVisibility(visibility(RoleType::A), RoleType::A); - setVisibility(visibility(RoleType::B), RoleType::B); - - setChangeability(changeability(RoleType::A), RoleType::A); - setChangeability(changeability(RoleType::B), RoleType::B); - - UMLApp::app()->docWindow()->showDocumentation(this, true); - } - delete dlg; -} - -/** - * Overrides operation from LinkWidget. - * Required by FloatingTextWidget. - * - * @param op Return this AssociationWidget's operation string. - */ -QString AssociationWidget::lwOperationText() -{ - return name(); -} - -/** - * Overrides operation from LinkWidget. - * Required by FloatingTextWidget. - * - * @return classifier - */ -UMLClassifier* AssociationWidget::lwClassifier() -{ - UMLObject *o = widgetForRole(RoleType::B)->umlObject(); - UMLClassifier *c = dynamic_cast(o); - return c; -} - -/** - * Overrides operation from LinkWidget. - * Required by FloatingTextWidget. - * - * @param op The new operation string to set. - */ -void AssociationWidget::setOperationText(const QString &op) -{ - if (!op.isEmpty()) { - setName(op); - } -} - -/** - * Calculates the m_unNameLineSegment value according to the new - * NameText topleft corner PT. - * It iterates through all AssociationLine's segments and for each one - * calculates the sum of PT's distance to the start point + PT's - * distance to the end point. The segment with the smallest sum will - * be the RoleTextSegment (if this segment moves then the RoleText - * will move with it). It sets m_unNameLineSegment to the start point - * of the chosen segment. - * - * Overrides operation from LinkWidget (i.e. this method is also - * required by FloatingTextWidget.) - */ -void AssociationWidget::calculateNameTextSegment() -{ - if (!m_nameWidget) { - return; - } - //changed to use the middle of the text - //i think this will give a better result. - //never know what sort of lines people come up with - //and text could be long to give a false reading - qreal xt = m_nameWidget->x(); - qreal yt = m_nameWidget->y(); - xt += m_nameWidget->width() / 2; - yt += m_nameWidget->height() / 2; - int size = m_associationLine->count(); - //sum of length(PTP1) and length(PTP2) - qreal total_length = 0; - qreal smallest_length = 0; - for (int i = 0; i < size - 1; ++i) { - QPointF pi = m_associationLine->point( i ); - QPointF pj = m_associationLine->point( i+1 ); - qreal xtiDiff = xt - pi.x(); - qreal xtjDiff = xt - pj.x(); - qreal ytiDiff = yt - pi.y(); - qreal ytjDiff = yt - pj.y(); - total_length = sqrt( double(xtiDiff * xtiDiff + ytiDiff * ytiDiff) ) - + sqrt( double(xtjDiff * xtjDiff + ytjDiff * ytjDiff) ); - //this gives the closest point - if (total_length < smallest_length || i == 0) { - smallest_length = total_length; - m_unNameLineSegment = i; - } - } -} - -/** - * Returns the UMLAssociation representation of this object. - * - * @return Pointer to the UMLAssociation that is represented by - * this AsociationWidget. - */ -UMLAssociation* AssociationWidget::association() const -{ - if (m_umlObject == NULL || m_umlObject->baseType() != UMLObject::ot_Association) - return NULL; - return static_cast(m_umlObject); -} - -/** - * Returns the UMLAttribute representation of this object. - * - * @return Pointer to the UMLAttribute that is represented by - * this AsociationWidget. - */ -UMLAttribute* AssociationWidget::attribute() const -{ - if (m_umlObject == NULL) - return NULL; - UMLObject::ObjectType ot = m_umlObject->baseType(); - if (ot != UMLObject::ot_Attribute && ot != UMLObject::ot_EntityAttribute) - return NULL; - return static_cast(m_umlObject); -} - -#if 0 //:TODO: -/** - * Overrides the assignment operator. - */ -AssociationWidget& AssociationWidget::operator=(const AssociationWidget& other) -{ - *m_associationLine = *other.m_associationLine; - - if (other.m_nameWidget) { - m_nameWidget = new FloatingTextWidget(m_scene); - *m_nameWidget = *(other.m_nameWidget); - } else { - m_nameWidget = NULL; - } - - for (unsigned r = (unsigned)A; r <= (unsigned)B; ++r) { - WidgetRole& lhs = m_role[r]; - const WidgetRole& rhs = other.m_role[r]; - lhs.m_nIndex = rhs.m_nIndex; - lhs.m_nTotalCount = rhs.m_nTotalCount; - - if (rhs.multiplicityWidget) { - lhs.multiplicityWidget = new FloatingTextWidget(m_scene); - *(lhs.multiplicityWidget) = *(rhs.multiplicityWidget); - } else { - lhs.multiplicityWidget = NULL; - } - - if (rhs.roleWidget) { - lhs.roleWidget = new FloatingTextWidget(m_scene); - *(lhs.roleWidget) = *(rhs.roleWidget); - } else { - lhs.roleWidget = NULL; - } - - if (rhs.changeabilityWidget) { - lhs.changeabilityWidget = new FloatingTextWidget(m_scene); - *(lhs.changeabilityWidget) = *(rhs.changeabilityWidget); - } else { - lhs.changeabilityWidget = NULL; - } - - lhs.umlWidget = rhs.umlWidget; - lhs.m_WidgetRegion = rhs.m_WidgetRegion; - } - - m_activated = other.m_activated; - m_unNameLineSegment = other.m_unNameLineSegment; - m_pMenu = other.m_pMenu; - setUMLAssociation(other.association()); - setSelected(other.isSelected()); - - return *this; -} -#endif //:TODO: - -/** - * Overrides the equality test operator. - */ -bool AssociationWidget::operator==(const AssociationWidget& other) const -{ - if (this == &other) - return true; - - // if no model representation exists, then the widgets are not equal - if (association() == NULL && other.association() == NULL) - return false; - - if (!m_umlObject || !other.m_umlObject ) { - if (!other.m_umlObject && m_umlObject) - return false; - if (other.m_umlObject && !m_umlObject) - return false; - - } else if (m_umlObject != other.m_umlObject) - return false; - - if (associationType() != other.associationType()) - return false; - - if (widgetIDForRole(RoleType::A) != other.widgetIDForRole(RoleType::A)) - return false; - - if (widgetIDForRole(RoleType::B) != other.widgetIDForRole(RoleType::B)) - return false; - - if (widgetForRole(RoleType::A)->baseType() == WidgetBase::wt_Object && - other.widgetForRole(RoleType::A)->baseType() == WidgetBase::wt_Object) { - ObjectWidget *ownA = static_cast(widgetForRole(RoleType::A)); - ObjectWidget *otherA = static_cast(other.widgetForRole(RoleType::A)); - if (ownA->localID() != otherA->localID()) - return false; - } - - if (widgetForRole(RoleType::B)->baseType() == WidgetBase::wt_Object && - other.widgetForRole(RoleType::B)->baseType() == WidgetBase::wt_Object) { - ObjectWidget *ownB = static_cast(widgetForRole(RoleType::B)); - ObjectWidget *otherB = static_cast(other.widgetForRole(RoleType::B)); - if (ownB->localID() != otherB->localID()) - return false; - } - - // Two objects in a collaboration can have multiple messages between each other. - // Here we depend on the messages having names, and the names must be different. - // That is the reason why collaboration messages have strange initial names like - // "m29997" or similar. - return (name() == other.name()); -} - -/** - * Overrides the != operator. - */ -bool AssociationWidget::operator!=(AssociationWidget& other) const -{ - return !(*this == other); -} - -/** - * Returns a pointer to the association widget's line path. - */ -AssociationLine* AssociationWidget::associationLine() const -{ - return m_associationLine; -} - -/** - * Activates the AssociationWidget after a load. - * - * @return true for success - */ -bool AssociationWidget::activate() -{ - if (m_umlObject == NULL && - AssociationType::hasUMLRepresentation(m_associationType)) { - UMLObject *myObj = umlDoc()->findObjectById(m_nId); - if (myObj == NULL) { - uError() << "cannot find UMLObject " << Uml::ID::toString(m_nId); - return false; - } else { - const UMLObject::ObjectType ot = myObj->baseType(); - if (ot == UMLObject::ot_Association) { - UMLAssociation * myAssoc = static_cast(myObj); - setUMLAssociation(myAssoc); - } else { - setUMLObject(myObj); - setAssociationType(m_associationType); - } - } - } - - if (m_activated) - return true; - - Uml::AssociationType::Enum type = associationType(); - - if (m_role[RoleType::A].umlWidget == NULL) - setWidgetForRole(m_scene->findWidget(widgetIDForRole(RoleType::A)), RoleType::A); - if (m_role[RoleType::B].umlWidget == NULL) - setWidgetForRole(m_scene->findWidget(widgetIDForRole(RoleType::B)), RoleType::B); - - if (!m_role[RoleType::A].umlWidget || !m_role[RoleType::B].umlWidget) { - DEBUG(DBG_SRC) << "Cannot make association!"; - return false; - } - - calculateEndingPoints(); - - if (AssocRules::allowRole(type)) { - for (unsigned r = RoleType::A; r <= RoleType::B; ++r) { - WidgetRole& robj = m_role[r]; - if (robj.roleWidget == NULL) - continue; - robj.roleWidget->setLink(this); - TextRole::Enum tr = (r == RoleType::A ? TextRole::RoleAName : TextRole::RoleBName); - robj.roleWidget->setTextRole(tr); - Uml::Visibility::Enum vis = visibility(Uml::RoleType::fromInt(r)); - robj.roleWidget->setPreText(Uml::Visibility::toString(vis, true)); - - if (FloatingTextWidget::isTextValid(robj.roleWidget->text())) - robj.roleWidget->show(); - else - robj.roleWidget->hide(); - if (m_scene->type() == DiagramType::Collaboration) - robj.roleWidget->setUMLObject(robj.umlWidget->umlObject()); - robj.roleWidget->activate(); - } - } - - if (m_nameWidget != NULL) { - m_nameWidget->setLink(this); - m_nameWidget->setTextRole(calculateNameType(TextRole::Name)); - - if (FloatingTextWidget::isTextValid(m_nameWidget->text())) { - m_nameWidget->show(); - } else { - m_nameWidget->hide(); - } - m_nameWidget->activate(); - calculateNameTextSegment(); - } - - for (unsigned r = RoleType::A; r <= RoleType::B; ++r) { - WidgetRole& robj = m_role[r]; - - FloatingTextWidget* pMulti = robj.multiplicityWidget; - if (pMulti != NULL && - AssocRules::allowMultiplicity(type, robj.umlWidget->baseType())) { - pMulti->setLink(this); - TextRole::Enum tr = (r == RoleType::A ? TextRole::MultiA : TextRole::MultiB); - pMulti->setTextRole(tr); - if (FloatingTextWidget::isTextValid(pMulti->text())) - pMulti->show(); - else - pMulti->hide(); - pMulti->activate(); - } - - FloatingTextWidget* pChangeWidget = robj.changeabilityWidget; - if (pChangeWidget != NULL) { - pChangeWidget->setLink(this); - TextRole::Enum tr = (r == RoleType::A ? TextRole::ChangeA : TextRole::ChangeB); - pChangeWidget->setTextRole(tr); - if (FloatingTextWidget::isTextValid(pChangeWidget->text())) - pChangeWidget->show(); - else - pChangeWidget->hide (); - pChangeWidget->activate(); - } - } - - // Prepare the association class line if needed. - if (m_associationClass && !m_pAssocClassLine) { - createAssocClassLine(); - } - - m_activated = true; - return true; -} - -/** - * Set the widget of the given role. - * Add this AssociationWidget at the widget. - * If this AssociationWidget has an underlying UMLAssociation then set - * the widget's underlying UMLObject at the UMLAssociation's role object. - * - * @param widget Pointer to the UMLWidget. - * @param role Role for which to set the widget. - */ -void AssociationWidget::setWidgetForRole(UMLWidget* widget, Uml::RoleType::Enum role) -{ - m_role[role].umlWidget = widget; - if (widget) { - m_role[role].umlWidget->addAssoc(this); - if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) - association()->setObject(widget->umlObject(), role); - } -} - -/** - * Return the multiplicity FloatingTextWidget widget of the given role. - * - * @return Pointer to the multiplicity FloatingTextWidget object. - */ -FloatingTextWidget* AssociationWidget::multiplicityWidget(Uml::RoleType::Enum role) const -{ - return m_role[role].multiplicityWidget; -} - -/** - * Read property of FloatingTextWidget* m_nameWidget. - * - * @return Pointer to the FloatingTextWidget name widget. - */ -FloatingTextWidget* AssociationWidget::nameWidget() const -{ - return m_nameWidget; -} - -/** - * Return the given role's FloatingTextWidget object. - * - * @return Pointer to the role's FloatingTextWidget widget. - */ -FloatingTextWidget* AssociationWidget::roleWidget(Uml::RoleType::Enum role) const -{ - return m_role[role].roleWidget; -} - -/** - * Return the given role's changeability FloatingTextWidget widget. - */ -FloatingTextWidget* AssociationWidget::changeabilityWidget(Uml::RoleType::Enum role) const -{ - return m_role[role].changeabilityWidget; -} - -/** - * Return the FloatingTextWidget object indicated by the given TextRole::Enum. - * - * @return Pointer to the text role's FloatingTextWidget widget. - */ -FloatingTextWidget* AssociationWidget::textWidgetByRole(Uml::TextRole::Enum tr) const -{ - switch (tr) { - case Uml::TextRole::MultiA: - return m_role[RoleType::A].multiplicityWidget; - case Uml::TextRole::MultiB: - return m_role[RoleType::B].multiplicityWidget; - case Uml::TextRole::Name: - case Uml::TextRole::Coll_Message: - return m_nameWidget; - case Uml::TextRole::RoleAName: - return m_role[RoleType::A].roleWidget; - case Uml::TextRole::RoleBName: - return m_role[RoleType::B].roleWidget; - case Uml::TextRole::ChangeA: - return m_role[RoleType::A].changeabilityWidget; - case Uml::TextRole::ChangeB: - return m_role[RoleType::B].changeabilityWidget; - default: - break; - } - return NULL; -} - -/** - * Returns the m_nameWidget's text. - * - * @return Text of the FloatingTextWidget name widget. - */ -QString AssociationWidget::name() const -{ - if (m_nameWidget == NULL) - return QString(); - return m_nameWidget->text(); -} - -/** - * Sets the text in the FloatingTextWidget widget representing the Name - * of this association. - */ -void AssociationWidget::setName(const QString &strName) -{ - // set attribute of UMLAssociation associated with this associationwidget - UMLAssociation *umla = association(); - if (umla) - umla->setName(strName); - - bool newLabel = false; - if (!m_nameWidget) { - // Don't construct the FloatingTextWidget if the string is empty. - if (! FloatingTextWidget::isTextValid(strName)) - return; - - newLabel = true; - m_nameWidget = new FloatingTextWidget(m_scene, calculateNameType(Uml::TextRole::Name), strName); - m_nameWidget->setParentItem(this); - m_nameWidget->setLink(this); - } else { - m_nameWidget->setText(strName); - if (! FloatingTextWidget::isTextValid(strName)) { - //m_nameWidget->hide(); - m_scene->removeWidget(m_nameWidget); - m_nameWidget = NULL; - return; - } - } - - setTextPosition(Uml::TextRole::Name); - if (newLabel) { - m_nameWidget->setActivated(); - m_scene->addFloatingTextWidget(m_nameWidget); - } - - m_nameWidget->show(); -} - -void AssociationWidget::setStereotype(const QString &stereo) { - UMLAssociation *umlassoc = association(); - if (umlassoc) { - umlassoc->setStereotype(stereo); - if (m_nameWidget) { - m_nameWidget->setText(umlassoc->stereotype(true)); - } else { - uDebug() << "not setting " << stereo << " because m_nameWidget is NULL"; - } - } else { - uDebug() << "not setting " << stereo << " because association is NULL"; - } -} - -/** - * Return the given role's FloatingTextWidget widget text. - * - * @return The name set at the FloatingTextWidget. - */ -QString AssociationWidget::roleName(Uml::RoleType::Enum role) const -{ - if (m_role[role].roleWidget == NULL) - return QString(); - return m_role[role].roleWidget->text(); -} - -/** - * Sets the text to the FloatingTextWidget that display the Role text of this - * association. - * For this function to work properly, the associated widget - * should already be set. - */ -void AssociationWidget::setRoleName(const QString &strRole, Uml::RoleType::Enum role) -{ - Uml::AssociationType::Enum type = associationType(); - //if the association is not supposed to have a Role FloatingTextWidget - if (!AssocRules::allowRole(type)) { - return; - } - - TextRole::Enum tr = (role == RoleType::A ? TextRole::RoleAName : TextRole::RoleBName); - setFloatingText(tr, strRole, m_role[role].roleWidget); - if (m_role[role].roleWidget) { - Uml::Visibility::Enum vis = visibility(role); - if (FloatingTextWidget::isTextValid(m_role[role].roleWidget->text())) { - m_role[role].roleWidget->setPreText(Uml::Visibility::toString(vis, true)); - //m_role[role].roleWidget->show(); - } else { - m_role[role].roleWidget->setPreText(QString()); - //m_role[role].roleWidget->hide(); - } - } - - // set attribute of UMLAssociation associated with this associationwidget - if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) - association()->setRoleName(strRole, role); -} - -/** - * Set the documentation on the given role. - */ -void AssociationWidget::setRoleDocumentation(const QString &doc, Uml::RoleType::Enum role) -{ - if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) - association()->setRoleDoc(doc, role); - else - m_role[role].roleDocumentation = doc; -} - -/** - * Returns the given role's documentation. - */ -QString AssociationWidget::roleDocumentation(Uml::RoleType::Enum role) const -{ - if (m_umlObject == NULL || m_umlObject->baseType() != UMLObject::ot_Association) - return QString(); - UMLAssociation *umla = static_cast(m_umlObject); - return umla->getRoleDoc(role); -} - -/** - * Change, create, or delete the FloatingTextWidget indicated by the given TextRole::Enum. - * - * @param tr TextRole::Enum of the FloatingTextWidget to change or create. - * @param text Text string that controls the action: - * If empty and ft is NULL then setFloatingText() is a no-op. - * If empty and ft is non-NULL then the existing ft is deleted. - * If non-empty and ft is NULL then a new FloatingTextWidget is created - * and returned in ft with the text set. - * If non-empty and ft is non-NULL then the existing ft text is modified. - * @param ft Reference to the pointer to FloatingTextWidget to change or create. - * On creation/deletion, the pointer value will be changed. - */ -void AssociationWidget::setFloatingText(Uml::TextRole::Enum role, - const QString &text, - FloatingTextWidget* &ft) -{ - if (! FloatingTextWidget::isTextValid(text)) { - if (ft) { - // Remove preexisting FloatingTextWidget - m_scene->removeWidget(ft); // physically deletes ft - ft = NULL; - } - return; - } - - if (ft == NULL) { - ft = new FloatingTextWidget(m_scene, role, text); - ft->setParentItem(this); - ft->setLink(this); - ft->activate(); - setTextPosition(role); - m_scene->addFloatingTextWidget(ft); - } else { - bool newLabel = ft->text().isEmpty(); - ft->setText(text); - if (newLabel) - setTextPosition(role); - } - - ft->show(); -} - -/** - * Return the given role's multiplicity text. - * - * @return Text of the given role's multiplicity widget. - */ -QString AssociationWidget::multiplicity(Uml::RoleType::Enum role) const -{ - if (m_role[role].multiplicityWidget == NULL) - return QString(); - return m_role[role].multiplicityWidget->text(); -} - -/** - * Sets the text in the FloatingTextWidget representing the multiplicity - * at the given side of the association. - */ -void AssociationWidget::setMultiplicity(const QString& text, Uml::RoleType::Enum role) -{ - TextRole::Enum tr = (role == RoleType::A ? TextRole::MultiA : TextRole::MultiB); - - setFloatingText(tr, text, m_role[role].multiplicityWidget); - - if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) - association()->setMultiplicity(text, role); -} - -/** - * Gets the visibility on the given role of the association. - */ -Visibility::Enum AssociationWidget::visibility(Uml::RoleType::Enum role) const -{ - const UMLAssociation *assoc = association(); - if (assoc) - return assoc->visibility(role); - const UMLAttribute *attr = attribute(); - if (attr) - return attr->visibility(); - return m_role[role].visibility; -} - -/** - * Sets the visibility on the given role of the association. - */ -void AssociationWidget::setVisibility(Visibility::Enum value, Uml::RoleType::Enum role) -{ - if (value == visibility(role)) { - return; - } - if (m_umlObject) { - // update our model object - const UMLObject::ObjectType ot = m_umlObject->baseType(); - if (ot == UMLObject::ot_Association) - association()->setVisibility(value, role); - else if (ot == UMLObject::ot_Attribute) - attribute()->setVisibility(value); - } - m_role[role].visibility = value; - // update role pre-text attribute as appropriate - if (m_role[role].roleWidget) { - QString scopeString = Visibility::toString(value, true); - m_role[role].roleWidget->setPreText(scopeString); - } -} - -/** - * Gets the changeability on the given end of the Association. - */ -Uml::Changeability::Enum AssociationWidget::changeability(Uml::RoleType::Enum role) const -{ - if (m_umlObject == NULL || m_umlObject->baseType() != UMLObject::ot_Association) - return m_role[role].changeability; - UMLAssociation *umla = static_cast(m_umlObject); - return umla->changeability(role); -} - -/** - * Sets the changeability on the given end of the Association. - */ -void AssociationWidget::setChangeability(Uml::Changeability::Enum value, Uml::RoleType::Enum role) -{ - if (value == changeability(role)) - return; - QString changeString = Uml::Changeability::toString(value); - if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) // update our model object - association()->setChangeability(value, role); - m_role[role].changeability = value; - // update our string representation - setChangeWidget(changeString, role); -} - -/** - * For internal purpose-kf6s only. - * Other classes/users should use setChangeability() instead. - */ -void AssociationWidget::setChangeWidget(const QString &strChangeWidget, Uml::RoleType::Enum role) -{ - bool newLabel = false; - TextRole::Enum tr = (role == RoleType::A ? TextRole::ChangeA : TextRole::ChangeB); - - if (!m_role[role].changeabilityWidget) { - // Don't construct the FloatingTextWidget if the string is empty. - if (strChangeWidget.isEmpty()) - return; - - newLabel = true; - m_role[role].changeabilityWidget = new FloatingTextWidget(m_scene, tr, strChangeWidget); - m_role[role].changeabilityWidget->setParentItem(this); - m_role[role].changeabilityWidget->setLink(this); - m_scene->addFloatingTextWidget(m_role[role].changeabilityWidget); - m_role[role].changeabilityWidget->setPreText(QLatin1String("{")); // all types have this - m_role[role].changeabilityWidget->setPostText(QLatin1String("}")); // all types have this - } else { - if (m_role[role].changeabilityWidget->text().isEmpty()) { - newLabel = true; - } - m_role[role].changeabilityWidget->setText(strChangeWidget); - } - m_role[role].changeabilityWidget->setActivated(); - - if (newLabel) { - setTextPosition(tr); - } - - if (FloatingTextWidget::isTextValid(m_role[role].changeabilityWidget->text())) - m_role[role].changeabilityWidget->show(); - else - m_role[role].changeabilityWidget->hide(); -} - -/** - * Returns true if the line path starts at the given widget. - */ -bool AssociationWidget::linePathStartsAt(const UMLWidget* widget) -{ -//:TODO: -// QPointF lpStart = m_associationLine->point(0); -// int startX = lpStart.x(); -// int startY = lpStart.y(); -// int wX = widget->x(); -// int wY = widget->y(); -// int wWidth = widget->width(); -// int wHeight = widget->height(); -// bool result = (startX >= wX && startX <= wX + wWidth && -// startY >= wY && startY <= wY + wHeight); -// return result; - bool result = widget->contains(m_associationLine->point(0)); - DEBUG(DBG_SRC) << "widget=" << widget->name() << " / result=" << result; - return result; -} - -/** - * This function calculates which role should be set for the m_nameWidget FloatingTextWidget. - */ -Uml::TextRole::Enum AssociationWidget::calculateNameType(Uml::TextRole::Enum defaultRole) -{ - TextRole::Enum result = defaultRole; - if (m_scene->type() == DiagramType::Collaboration) { - if (m_role[RoleType::A].umlWidget == m_role[RoleType::B].umlWidget) { - result = TextRole::Coll_Message;//for now same as other Coll_Message - } else { - result = TextRole::Coll_Message; - } - } else if (m_scene->type() == DiagramType::Sequence) { - if (m_role[RoleType::A].umlWidget == m_role[RoleType::B].umlWidget) { - result = TextRole::Seq_Message_Self; - } else { - result = TextRole::Seq_Message; - } - } - - return result; -} - -/** - * Gets the given role widget. - * - * @return Pointer to the role's UMLWidget. - */ -UMLWidget* AssociationWidget::widgetForRole(Uml::RoleType::Enum role) const -{ - return m_role[role].umlWidget; -} - -/** - * Sets the associated widgets. - * - * @param widgetA Pointer the role A widget for the association. - * @param assocType The AssociationType::Enum for this association. - * @param widgetB Pointer the role B widget for the association. - */ -bool AssociationWidget::setWidgets(UMLWidget* widgetA, - Uml::AssociationType::Enum assocType, - UMLWidget* widgetB) -{ - //if the association already has a WidgetB or WidgetA associated, then - //it cannot be changed to other widget, that would require a deletion - //of the association and the creation of a new one - if ((m_role[RoleType::A].umlWidget && (m_role[RoleType::A].umlWidget != widgetA)) || - (m_role[RoleType::B].umlWidget && (m_role[RoleType::B].umlWidget != widgetB))) { - return false; - } - setWidgetForRole(widgetA, RoleType::A); - setAssociationType(assocType); - setWidgetForRole(widgetB, RoleType::B); - - calculateEndingPoints(); - return true; -} - -/** - * CleansUp all the association's data in the related widgets. - */ -void AssociationWidget::cleanup() -{ - //let any other associations know we are going so they can tidy their positions up - if (m_role[RoleType::A].m_nTotalCount > 2) - updateAssociations(m_role[RoleType::A].m_nTotalCount - 1, m_role[RoleType::A].m_WidgetRegion, RoleType::A); - if (m_role[RoleType::B].m_nTotalCount > 2) - updateAssociations(m_role[RoleType::B].m_nTotalCount - 1, m_role[RoleType::B].m_WidgetRegion, RoleType::B); - - for (unsigned r = RoleType::A; r <= RoleType::B; ++r) { - WidgetRole& robj = m_role[r]; - - if (robj.umlWidget) { - robj.umlWidget->removeAssoc(this); - robj.umlWidget = 0; - } - if (robj.roleWidget) { - m_scene->removeWidget(robj.roleWidget); - robj.roleWidget = 0; - } - if (robj.multiplicityWidget) { - m_scene->removeWidget(robj.multiplicityWidget); - robj.multiplicityWidget = 0; - } - if (robj.changeabilityWidget) { - m_scene->removeWidget(robj.changeabilityWidget); - robj.changeabilityWidget = 0; - } - } - - if (m_nameWidget) { - m_scene->removeWidget(m_nameWidget); - m_nameWidget = 0; - } - - if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) { - /* - We do not remove the UMLAssociation from the document. - Why? - Well, for example we might be in the middle of - a cut/paste. If the UMLAssociation is removed by the cut - then upon pasteing we have a problem. - This is not quite clean yet - there should be a way to - explicitly delete a UMLAssociation. The Right Thing would - be to have a ListView representation for UMLAssociation. - ` - IF we are cut n pasting, why are we handling this association as a pointer? - We should be using the XMI representation for a cut and paste. This - allows us to be clean here, AND a choice of recreating the object - w/ same id IF its a "cut", or a new object if its a "copy" operation - (in which case we wouldnt be here, in cleanup()). - */ - setUMLAssociation(0); - } - - m_associationLine->cleanup(); - removeAssocClassLine(); -} - -/** - * @brief Return state if the assocation line point in the near of the last context - * menu event position is addable or not. - * A point is addable if the association is not an Exception and there is no point in the near. - * - * @return true if point is addable - */ -bool AssociationWidget::isPointAddable() -{ - if (!isSelected() || associationType() == Uml::AssociationType::Exception) - return false; - int i = m_associationLine->closestPointIndex(m_eventScenePos); - return i == -1; -} - -/** - * @brief Return state if the assocation line point in the near of the last context - * menu event position is removable or not. - * A point is removable if the association is not an Exception and is not the start or end point. - * - * @return true if point is removable - */ -bool AssociationWidget::isPointRemovable() -{ - if (!isSelected() || associationType() == Uml::AssociationType::Exception || m_associationLine->count() <= 2) - return false; - int i = m_associationLine->closestPointIndex(m_eventScenePos); - return i > 0 && i < m_associationLine->count() - 1; -} - -/** - * Set our internal umlAssociation. - */ -void AssociationWidget::setUMLAssociation (UMLAssociation * assoc) -{ - if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) { - UMLAssociation *umla = association(); - - // safety check. Did some num-nuts try to set the existing - // association again? If so, just bail here - if (umla == assoc) - return; - - //umla->disconnect(this); //Qt does disconnect automatically upon destruction. - umla->nrof_parent_widgets--; - - // ANSWER: This is the wrong treatment of cut and paste. Associations that - // are being cut/n pasted should be serialized to XMI, then reconstituted - // (IF a paste operation) rather than passing around object pointers. Its - // just too hard otherwise to prevent problems in the code. Bottom line: we need to - // delete orphaned associations or we well get code crashes and memory leaks. - if (umla->nrof_parent_widgets <= 0) { - //umla->deleteLater(); - } - - m_umlObject = NULL; - } - - if (assoc) { - m_umlObject = assoc; - - // move counter to "0" from "-1" (which means, no assocwidgets) - if (assoc->nrof_parent_widgets < 0) - assoc->nrof_parent_widgets = 0; - - assoc->nrof_parent_widgets++; - connect(assoc, SIGNAL(modified()), this, SLOT(syncToModel())); - } - -} - -/** - * Returns true if the Widget is either at the starting or ending side of the association. - */ -bool AssociationWidget::containsAsEndpoint(UMLWidget* widget) -{ - return (widget == m_role[RoleType::A].umlWidget || widget == m_role[RoleType::B].umlWidget); -} - -/** - * Returns true if this AssociationWidget represents a collaboration message. - */ -bool AssociationWidget::isCollaboration() const -{ - Uml::AssociationType::Enum at = associationType(); - return (at == AssociationType::Coll_Message_Synchronous - || at == AssociationType::Coll_Message_Asynchronous - || at == AssociationType::Coll_Message_Self); -} - -/** - * Returns true if this AssociationWidget represents a self message. - */ -bool AssociationWidget::isSelf() const -{ - return widgetForRole(Uml::RoleType::A) == widgetForRole(Uml::RoleType::B); -} - -/** - * Gets the association's type. - * - * @return This AssociationWidget's AssociationType::Enum. - */ -Uml::AssociationType::Enum AssociationWidget::associationType() const -{ - if (m_umlObject == NULL || m_umlObject->baseType() != UMLObject::ot_Association) - return m_associationType; - UMLAssociation *umla = static_cast(m_umlObject); - return umla->getAssocType(); -} - -/** - * Sets the association's type. - * - * @param type The AssociationType::Enum to set. - */ -void AssociationWidget::setAssociationType(Uml::AssociationType::Enum type) -{ - if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) { - association()->setAssociationType(type); - } - m_associationType = type; - // If the association new type is not supposed to have Multiplicity - // FloatingTexts and a Role FloatingTextWidget then set the texts - // to empty. - // NB We do not physically delete the floatingtext widgets here because - // those widgets are also stored in the UMLView::m_WidgetList. - if (!AssocRules::allowMultiplicity(type, widgetForRole(RoleType::A)->baseType())) { - if (m_role[RoleType::A].multiplicityWidget) { - m_role[RoleType::A].multiplicityWidget->setName(QString()); - } - if (m_role[RoleType::B].multiplicityWidget) { - m_role[RoleType::B].multiplicityWidget->setName(QString()); - } - } - if (!AssocRules::allowRole(type)) { - if (m_role[RoleType::A].roleWidget) { - m_role[RoleType::A].roleWidget->setName(QString()); - } - if (m_role[RoleType::B].roleWidget) { - m_role[RoleType::B].roleWidget->setName(QString()); - } - setRoleDocumentation(QString(), RoleType::A); - setRoleDocumentation(QString(), RoleType::B); - } - m_associationLine->reconstructSymbols(); -} - -/** - * Gets the ID of the given role widget. - */ -Uml::ID::Type AssociationWidget::widgetIDForRole(Uml::RoleType::Enum role) const -{ - if (m_role[role].umlWidget == NULL) { - if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) { - UMLAssociation *umla = static_cast(m_umlObject); - return umla->getObjectId(role); - } - uError() << "umlWidget is NULL"; - return Uml::ID::None; - } - if (m_role[role].umlWidget->baseType() == WidgetBase::wt_Object) - return static_cast(m_role[role].umlWidget)->localID(); - Uml::ID::Type id = m_role[role].umlWidget->id(); - return id; -} - -/** - * Gets the local ID of the given role widget. - */ -Uml::ID::Type AssociationWidget::widgetLocalIDForRole(Uml::RoleType::Enum role) const -{ - if (m_role[role].umlWidget == NULL) { - if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) { - UMLAssociation *umla = static_cast(m_umlObject); - return umla->getObjectId(role); - } - uError() << "umlWidget is NULL"; - return Uml::ID::None; - } - if (m_role[role].umlWidget->baseType() == WidgetBase::wt_Object) - return static_cast(m_role[role].umlWidget)->localID(); - Uml::ID::Type id = m_role[role].umlWidget->localID(); - return id; -} - -/** - * Returns a QString Object representing this AssociationWidget. - */ -QString AssociationWidget::toString() const -{ - QString string; - static const QChar colon(QLatin1Char(':')); - - if (widgetForRole(RoleType::A)) { - string = widgetForRole(RoleType::A)->name(); - } - string.append(colon); - - if (m_role[RoleType::A].roleWidget) { - string += m_role[RoleType::A].roleWidget->text(); - } - string.append(colon); - string.append(Uml::AssociationType::toStringI18n(associationType())); - string.append(colon); - - if (widgetForRole(RoleType::B)) { - string += widgetForRole(RoleType::B)->name(); - } - - string.append(colon); - if (m_role[RoleType::B].roleWidget) { - string += m_role[RoleType::B].roleWidget->text(); - } - - return string; -} - -/** - * Adds a break point (if left mouse button). - */ -void AssociationWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) -{ - if (event->button() == Qt::LeftButton) { - uDebug() << "widget = " << name() << " / type = " << baseTypeStr(); - showPropertiesDialog(); - event->accept(); - } -} - -/** - * Overrides moveEvent. - */ -void AssociationWidget::moveEvent(QGraphicsSceneMouseEvent *me) -{ - // 2004-04-30: Achim Spangler - // Simple Approach to block moveEvent during load of XMI - /// @todo avoid trigger of this event during load - - if (umlDoc()->loading()) { - // hmmh - change of position during load of XMI - // -> there is something wrong - // -> avoid movement during opening - // -> print warn and stay at old position - uWarning() << "called during load of XMI for ViewType: " - << m_scene->type() << ", and BaseType: " << baseType(); - return; - } - /*to be here a line segment has moved. - we need to see if the three text widgets needs to be moved. - there are a few things to check first though: - - 1) Do they exist - 2) does it need to move: - 2a) for the multi widgets only move if they changed region, otherwise they are close enough - 2b) for role name move if the segment it is on moves. - */ - //first see if either the first or last segments moved, else no need to recalculate their point positions - - QPointF oldNamePoint = calculateTextPosition(TextRole::Name); - QPointF oldMultiAPoint = calculateTextPosition(TextRole::MultiA); - QPointF oldMultiBPoint = calculateTextPosition(TextRole::MultiB); - QPointF oldChangeAPoint = calculateTextPosition(TextRole::ChangeA); - QPointF oldChangeBPoint = calculateTextPosition(TextRole::ChangeB); - QPointF oldRoleAPoint = calculateTextPosition(TextRole::RoleAName); - QPointF oldRoleBPoint = calculateTextPosition(TextRole::RoleBName); - - int movingPoint = m_associationLine->closestPointIndex(me->scenePos()); - if (movingPoint != -1) - m_associationLine->setPoint(movingPoint, me->scenePos()); - int pos = m_associationLine->count() - 1;//set to last point for widget b - - if ( movingPoint == 1 || (movingPoint == pos-1) ) { - calculateEndingPoints(); - } - if (m_role[RoleType::A].changeabilityWidget && (movingPoint == 1)) { - setTextPositionRelatively(TextRole::ChangeA, oldChangeAPoint); - } - if (m_role[RoleType::B].changeabilityWidget && (movingPoint == 1)) { - setTextPositionRelatively(TextRole::ChangeB, oldChangeBPoint); - } - if (m_role[RoleType::A].multiplicityWidget && (movingPoint == 1)) { - setTextPositionRelatively(TextRole::MultiA, oldMultiAPoint); - } - if (m_role[RoleType::B].multiplicityWidget && (movingPoint == pos-1)) { - setTextPositionRelatively(TextRole::MultiB, oldMultiBPoint); - } - - if (m_nameWidget) { - if (movingPoint == m_unNameLineSegment || - movingPoint - 1 == m_unNameLineSegment) { - setTextPositionRelatively(TextRole::Name, oldNamePoint); - } - } - - if (m_role[RoleType::A].roleWidget) { - setTextPositionRelatively(TextRole::RoleAName, oldRoleAPoint); - } - if (m_role[RoleType::B].roleWidget) { - setTextPositionRelatively(TextRole::RoleBName, oldRoleBPoint); - } - - if (m_pAssocClassLine) { - computeAssocClassLine(); - } -} - -/** - * Calculates and sets the first and last point in the Association's AssociationLine. - * Each point is a middle point of its respecting UMLWidget's Bounding rectangle - * or a corner of it. - * This method picks which sides to use for the association. - */ -void AssociationWidget::calculateEndingPoints() -{ - /* - * For each UMLWidget the diagram is divided in four regions by its diagonals - * as indicated below - * Region 2 - * \ / - * \ / - * +--------+ - * | \ / | - * Region 1 | >< | Region 3 - * | / \ | - * +--------+ - * / \ - * / \ - * Region 4 - * - * Each diagonal is defined by two corners of the bounding rectangle - * - * To calculate the first point in the AssociationLine we have to find out in which - * Region (defined by WidgetA's diagonals) is WidgetB's center - * (let's call it Region M.) After that the first point will be the middle - * point of the rectangle's side contained in Region M. - * - * To calculate the last point in the AssociationLine we repeat the above but - * in the opposite direction (from widgetB to WidgetA) - */ - - UMLWidget *pWidgetA = m_role[RoleType::A].umlWidget; - UMLWidget *pWidgetB = m_role[RoleType::B].umlWidget; - if (!pWidgetA || !pWidgetB) { - uWarning() << "Returning - one of the role widgets is not set."; - return; - } - - int size = m_associationLine->count(); - if (size < 2) { - QPointF pA = pWidgetA->pos(); - QPointF pB = pWidgetB->pos(); - QPolygonF polyA = pWidgetA->shape().toFillPolygon().translated(pA); - QPolygonF polyB = pWidgetB->shape().toFillPolygon().translated(pB); - QLineF nearestPoints = Widget_Utils::closestPoints(polyA, polyB); - if (nearestPoints.isNull()) { - uError() << "Widget_Utils::closestPoints failed, falling back to simple widget positions"; - } else { - pA = nearestPoints.p1(); - pB = nearestPoints.p2(); - } - m_associationLine->setEndPoints(pA, pB); - } - - // See if an association to self. - // See if it needs to be set up before we continue: - // If self association/message and doesn't have the minimum 4 points - // then create it. Make sure no points are out of bounds of viewing area. - // This only happens on first time through that we are worried about. - if (isSelf() && size < 4) { - createPointsSelfAssociation(); - return; - } - - if (associationType() == AssociationType::Exception && size < 4) { - createPointsException(); - updatePointsException(); - return; - } - - // If the line has more than one segment change the values to calculate - // from widget to point 1. - qreal xB = pWidgetB->x() + pWidgetB->width() / 2; - qreal yB = pWidgetB->y() + pWidgetB->height() / 2; - if (size > 2) { - QPointF p = m_associationLine->point(1); - xB = p.x(); - yB = p.y(); - } - doUpdates(QPointF(xB, yB), RoleType::A); - - // Now do the same for widgetB. - // If the line has more than one segment change the values to calculate - // from widgetB to the last point away from it. - qreal xA = pWidgetA->x() + pWidgetA->width() / 2; - qreal yA = pWidgetA->y() + pWidgetA->height() / 2; - if (size > 2 ) { - QPointF p = m_associationLine->point(size - 2); - xA = p.x(); - yA = p.y(); - } - doUpdates(QPointF(xA, yA), RoleType::B); - - computeAssocClassLine(); -} - -/** - * Used by @ref calculateEndingPoints. - */ -void AssociationWidget::doUpdates(const QPointF &otherP, RoleType::Enum role) -{ - // Find widget region. - Uml::Region::Enum oldRegion = m_role[role].m_WidgetRegion; - UMLWidget *pWidget = m_role[role].umlWidget; - QRectF rc(pWidget->x(), pWidget->y(), - pWidget->width(), pWidget->height()); - Uml::Region::Enum region = m_role[role].m_WidgetRegion; // alias for brevity - region = findPointRegion(rc, otherP); - // Move some regions to the standard ones. - switch( region ) { - case Uml::Region::NorthWest: - region = Uml::Region::North; - break; - case Uml::Region::NorthEast: - region = Uml::Region::East; - break; - case Uml::Region::SouthEast: - region = Uml::Region::South; - break; - case Uml::Region::SouthWest: - case Uml::Region::Center: - region = Uml::Region::West; - break; - default: - break; - } - int regionCount = getRegionCount(region, role) + 2; //+2 = (1 for this one and one to halve it) - int totalCount = m_role[role].m_nTotalCount; - if (oldRegion != region) { - updateRegionLineCount(regionCount - 1, regionCount, region, role); - updateAssociations(totalCount - 1, oldRegion, role); - } else if (totalCount != regionCount) { - updateRegionLineCount(regionCount - 1, regionCount, region, role); - } else { - updateRegionLineCount(m_role[role].m_nIndex, totalCount, region, role); - } - updateAssociations(regionCount, region, role); -} - -/** - * Read property of bool m_activated. - */ -bool AssociationWidget::isActivated() const -{ - return m_activated; -} - -/** - * Set the m_activated flag of a widget but does not perform the Activate method. - */ -void AssociationWidget::setActivated(bool active) -{ - m_activated = active; -} - -/** - * Synchronize this widget from the UMLAssociation. - */ -void AssociationWidget::syncToModel() -{ - UMLAssociation *uml = association(); - - if (uml == NULL) { - UMLAttribute *attr = attribute(); - if (attr == NULL) - return; - setVisibility(attr->visibility(), RoleType::B); - setRoleName(attr->name(), RoleType::B); - return; - } - // block signals until finished - uml->blockSignals(true); - - setName(uml->name()); - setRoleName(uml->getRoleName(RoleType::A), RoleType::A); - setRoleName(uml->getRoleName(RoleType::B), RoleType::B); - setVisibility(uml->visibility(RoleType::A), RoleType::A); - setVisibility(uml->visibility(RoleType::B), RoleType::B); - setChangeability(uml->changeability(RoleType::A), RoleType::A); - setChangeability(uml->changeability(RoleType::B), RoleType::B); - setMultiplicity(uml->getMultiplicity(RoleType::A), RoleType::A); - setMultiplicity(uml->getMultiplicity(RoleType::B), RoleType::B); - - uml->blockSignals(false); -} - -/** - * Merges/syncs the association widget data into UML object - * representation. - * This will synchronize UMLAssociation w/ this new Widget - * CHECK: Can we get rid of this. - */ -void AssociationWidget::mergeAssociationDataIntoUMLRepresentation() -{ - UMLAssociation *umlassoc = association(); - UMLAttribute *umlattr = attribute(); - if (umlassoc == NULL && umlattr == NULL) - return; - - // block emit modified signal, or we get a horrible loop - m_umlObject->blockSignals(true); - - // would be desirable to do the following - // so that we can be sure its back to initial state - // in case we missed something here. - //uml->init(); - - // floating text widgets - FloatingTextWidget *text = nameWidget(); - if (text) - m_umlObject->setName(text->text()); - - text = roleWidget(RoleType::A); - if (text && umlassoc) - umlassoc->setRoleName(text->text(), RoleType::A); - - text = roleWidget(RoleType::B); - if (text) { - if (umlassoc) - umlassoc->setRoleName(text->text(), RoleType::B); - else if (umlattr) - umlattr->setName(text->text()); - } - - text = multiplicityWidget(RoleType::A); - if (text && umlassoc) - umlassoc->setMultiplicity(text->text(), RoleType::A); - - text = multiplicityWidget(RoleType::B); - if (text && umlassoc) - umlassoc->setMultiplicity(text->text(), RoleType::B); - - // unblock - m_umlObject->blockSignals(false); -} - -/** - * Auxiliary method for widgetMoved(): - * Saves all ideally computed floatingtext positions before doing any - * kind of change. This is necessary because a single invocation of - * calculateEndingPoints() modifies the AssociationLine ending points on ALL - * AssociationWidgets. This means that if we don't save the old ideal - * positions then they are irretrievably lost as soon as - * calculateEndingPoints() is invoked. - */ -void AssociationWidget::saveIdealTextPositions() -{ - m_oldNamePoint = calculateTextPosition(TextRole::Name); - m_oldMultiAPoint = calculateTextPosition(TextRole::MultiA); - m_oldMultiBPoint = calculateTextPosition(TextRole::MultiB); - m_oldChangeAPoint = calculateTextPosition(TextRole::ChangeA); - m_oldChangeBPoint = calculateTextPosition(TextRole::ChangeB); - m_oldRoleAPoint = calculateTextPosition(TextRole::RoleAName); - m_oldRoleBPoint = calculateTextPosition(TextRole::RoleBName); -} - -/** - * Adjusts the ending point of the association that connects to Widget. - */ -void AssociationWidget::widgetMoved(UMLWidget* widget, qreal dx, qreal dy) -{ - Q_UNUSED(dx); Q_UNUSED(dy); - - // Simple Approach to block moveEvent during load of XMI - /// @todo avoid trigger of this event during load - if (umlDoc()->loading()) { - // change of position during load of XMI - // -> there is something wrong - // -> avoid movement during opening - // -> print warn and stay at old position - DEBUG(DBG_SRC) << "called during load of XMI for ViewType: " << m_scene->type() - << ", and BaseType: " << baseTypeStr(); - return; - } - - DEBUG(DBG_SRC) << "association type=" << Uml::AssociationType::toString(associationType()); - if (associationType() == AssociationType::Exception) { - updatePointsException(); - setTextPosition(TextRole::Name); - } - else { - calculateEndingPoints(); - computeAssocClassLine(); - } - - // Assoc to self - move all points: - if (isSelf()) { - updatePointsSelfAssociation(); - - if (m_nameWidget && !m_nameWidget->isSelected()) { - setTextPositionRelatively(TextRole::Name, m_oldNamePoint); - } - - }//end if widgetA = widgetB - else if (m_role[RoleType::A].umlWidget == widget) { - if (m_nameWidget && m_unNameLineSegment == 0 && !m_nameWidget->isSelected() ) { - //only calculate position and move text if the segment it is on is moving - setTextPositionRelatively(TextRole::Name, m_oldNamePoint); - } - }//end if widgetA moved - else if (m_role[RoleType::B].umlWidget == widget) { - const int size = m_associationLine->count(); - if (m_nameWidget && (m_unNameLineSegment == size-2) && !m_nameWidget->isSelected() ) { - //only calculate position and move text if the segment it is on is moving - setTextPositionRelatively(TextRole::Name, m_oldNamePoint); - } - }//end if widgetB moved - - if (m_role[RoleType::A].roleWidget && !m_role[RoleType::A].roleWidget->isSelected()) { - setTextPositionRelatively(TextRole::RoleAName, m_oldRoleAPoint); - } - if (m_role[RoleType::B].roleWidget && !m_role[RoleType::B].roleWidget->isSelected()) { - setTextPositionRelatively(TextRole::RoleBName, m_oldRoleBPoint); - } - if (m_role[RoleType::A].multiplicityWidget && !m_role[RoleType::A].multiplicityWidget->isSelected()) { - setTextPositionRelatively(TextRole::MultiA, m_oldMultiAPoint); - } - if (m_role[RoleType::B].multiplicityWidget && !m_role[RoleType::B].multiplicityWidget->isSelected()) { - setTextPositionRelatively(TextRole::MultiB, m_oldMultiBPoint); - } - if (m_role[RoleType::A].changeabilityWidget && !m_role[RoleType::A].changeabilityWidget->isSelected()) { - setTextPositionRelatively(TextRole::ChangeA, m_oldChangeAPoint); - } - if (m_role[RoleType::B].changeabilityWidget && !m_role[RoleType::B].changeabilityWidget->isSelected()) { - setTextPositionRelatively(TextRole::ChangeB, m_oldChangeBPoint); - } -} - -/** - * Creates the points of the self association. - * Method called when a widget end points are calculated by calculateEndingPoints(). - */ -void AssociationWidget::createPointsSelfAssociation() -{ - UMLWidget *pWidgetA = m_role[RoleType::A].umlWidget; - - const int DISTANCE = 50; - qreal x = pWidgetA->x(); - qreal y = pWidgetA->y(); - qreal h = pWidgetA->height(); - qreal w = pWidgetA->width(); - // see if above widget ok to start - if (y - DISTANCE > 0) { - m_associationLine->setEndPoints(QPointF(x + w / 4, y) , QPointF(x + w * 3 / 4, y)); - m_associationLine->insertPoint(1, QPointF(x + w / 4, y - DISTANCE)); - m_associationLine->insertPoint(2, QPointF(x + w * 3 / 4, y - DISTANCE)); - m_role[RoleType::A].m_WidgetRegion = m_role[RoleType::B].m_WidgetRegion = Uml::Region::North; - } else { - m_associationLine->setEndPoints(QPointF(x + w / 4, y + h), QPointF(x + w * 3 / 4, y + h)); - m_associationLine->insertPoint(1, QPointF(x + w / 4, y + h + DISTANCE)); - m_associationLine->insertPoint(2, QPointF(x + w * 3 / 4, y + h + DISTANCE)); - m_role[RoleType::A].m_WidgetRegion = m_role[RoleType::B].m_WidgetRegion = Uml::Region::South; - } -} - -/** - * Adjusts the points of the self association. - * Method called when a widget was moved by widgetMoved(widget, x, y). - */ -void AssociationWidget::updatePointsSelfAssociation() -{ - UMLWidget *pWidgetA = m_role[RoleType::A].umlWidget; - - const int DISTANCE = 50; - qreal x = pWidgetA->x(); - qreal y = pWidgetA->y(); - qreal h = pWidgetA->height(); - qreal w = pWidgetA->width(); - // see if above widget ok to start - if (y - DISTANCE > 0) { - m_associationLine->setEndPoints(QPointF(x + w / 4, y) , QPointF(x + w * 3 / 4, y)); - m_associationLine->setPoint(1, QPointF(x + w / 4, y - DISTANCE)); - m_associationLine->setPoint(2, QPointF(x + w * 3 / 4, y - DISTANCE)); - m_role[RoleType::A].m_WidgetRegion = m_role[RoleType::B].m_WidgetRegion = Uml::Region::North; - } else { - m_associationLine->setEndPoints(QPointF(x + w / 4, y + h), QPointF(x + w * 3 / 4, y + h)); - m_associationLine->setPoint(1, QPointF(x + w / 4, y + h + DISTANCE)); - m_associationLine->setPoint(2, QPointF(x + w * 3 / 4, y + h + DISTANCE)); - m_role[RoleType::A].m_WidgetRegion = m_role[RoleType::B].m_WidgetRegion = Uml::Region::South; - } -} - -/** - * Creates the points of the association exception. - * Method called when a widget end points are calculated by calculateEndingPoints(). - */ -void AssociationWidget::createPointsException() -{ - UMLWidget *pWidgetA = m_role[RoleType::A].umlWidget; - UMLWidget *pWidgetB = m_role[RoleType::B].umlWidget; - - qreal xa = pWidgetA->x(); - qreal ya = pWidgetA->y(); - qreal ha = pWidgetA->height(); - qreal wa = pWidgetA->width(); - - qreal xb = pWidgetB->x(); - qreal yb = pWidgetB->y(); - qreal hb = pWidgetB->height(); - //qreal wb = pWidgetB->width(); - - m_associationLine->setEndPoints(QPointF(xa + wa , ya + ha/2) , QPointF(xb , yb + hb/2)); - m_associationLine->insertPoint(1, QPointF(xa + wa , ya + ha/2)); - m_associationLine->insertPoint(2, QPointF(xb , yb + hb/2)); -} - -/** - * Adjusts the points of the association exception. - * Method called when a widget was moved by widgetMoved(widget, x, y). - */ -void AssociationWidget::updatePointsException() -{ - UMLWidget *pWidgetA = m_role[RoleType::A].umlWidget; - UMLWidget *pWidgetB = m_role[RoleType::B].umlWidget; - - qreal xa = pWidgetA->x(); - qreal ya = pWidgetA->y(); - qreal ha = pWidgetA->height(); - qreal wa = pWidgetA->width(); - - qreal xb = pWidgetB->x(); - qreal yb = pWidgetB->y(); - qreal hb = pWidgetB->height(); - qreal wb = pWidgetB->width(); - qreal xmil, ymil; - qreal xdeb, ydeb; - qreal xfin, yfin; - qreal ESPACEX, ESPACEY; - QPointF p1; - QPointF p2; - //calcul des coordonnées au milieu de la flèche eclair - if (xb - xa - wa >= 45) { - ESPACEX = 0; - xdeb = xa + wa; - xfin = xb; - } else if (xa - xb - wb > 45) { - ESPACEX = 0; - xdeb = xa; - xfin = xb + wb; - } else { - ESPACEX = 15; - xdeb = xa + wa/2; - xfin = xb + wb/2; - } - - xmil = xdeb + (xfin - xdeb)/2; - - if (yb - ya - ha >= 45) { - ESPACEY = 0; - ydeb = ya + ha; - yfin = yb; - } else if (ya - yb - hb > 45) { - ESPACEY = 0; - ydeb = ya; - yfin = yb + hb; - } else { - ESPACEY = 15; - ydeb = ya + ha/2; - yfin = yb + hb/2; - } - - ymil = ydeb + (yfin - ydeb)/2; - - p1.setX(xmil + (xfin - xmil)*1/2); p1.setY(ymil + (yfin - ymil)*1/3); - p2.setX(xmil - (xmil - xdeb)*1/2); p2.setY(ymil - (ymil - ydeb)*1/3); - - if (abs(p1.x() - p2.x()) <= 10) - ESPACEX = 15; - if (abs(p1.y() - p2.y()) <= 10) - ESPACEY = 15; - - m_associationLine->setEndPoints(QPointF(xdeb, ydeb), QPointF(xfin, yfin)); - m_associationLine->setPoint(1, QPointF(p1.x() + ESPACEX, p1.y() + ESPACEY)); - m_associationLine->setPoint(2, QPointF(p2.x() - ESPACEX, p2.y() - ESPACEY)); - - m_role[RoleType::A].m_WidgetRegion = m_role[RoleType::B].m_WidgetRegion = Uml::Region::North; -} - -/** - * Finds out which region of rectangle 'rect' contains the point 'pos' and returns the region - * number: - * 1 = Region 1 - * 2 = Region 2 - * 3 = Region 3 - * 4 = Region 4 - * 5 = On diagonal 2 between Region 1 and 2 - * 6 = On diagonal 1 between Region 2 and 3 - * 7 = On diagonal 2 between Region 3 and 4 - * 8 = On diagonal 1 between Region 4 and 1 - * 9 = On diagonal 1 and On diagonal 2 (the center) - */ -Uml::Region::Enum AssociationWidget::findPointRegion(const QRectF& rect, const QPointF &pos) -{ - qreal w = rect.width(); - qreal h = rect.height(); - qreal x = rect.x(); - qreal y = rect.y(); - qreal slope2 = w / h; - qreal slope1 = slope2 *(-1.0); - qreal b1 = x + w - (slope1 * y); - qreal b2 = x - (slope2 * y); - - qreal eval1 = slope1 * pos.y() + b1; - qreal eval2 = slope2 * pos.y() + b2; - - Uml::Region::Enum result = Uml::Region::Error; - //if inside region 1 - if (eval1 > pos.x() && eval2 > pos.x()) { - result = Uml::Region::West; - } - //if inside region 2 - else if (eval1 > pos.x() && eval2 < pos.x()) { - result = Uml::Region::North; - } - //if inside region 3 - else if (eval1 < pos.x() && eval2 < pos.x()) { - result = Uml::Region::East; - } - //if inside region 4 - else if (eval1 < pos.x() && eval2 > pos.x()) { - result = Uml::Region::South; - } - //if inside region 5 - else if (eval1 == pos.x() && eval2 < pos.x()) { - result = Uml::Region::NorthWest; - } - //if inside region 6 - else if (eval1 < pos.x() && eval2 == pos.x()) { - result = Uml::Region::NorthEast; - } - //if inside region 7 - else if (eval1 == pos.x() && eval2 > pos.x()) { - result = Uml::Region::SouthEast; - } - //if inside region 8 - else if (eval1 > pos.x() && eval2 == pos.x()) { - result = Uml::Region::SouthWest; - } - //if inside region 9 - else if (eval1 == pos.x() && eval2 == pos.x()) { - result = Uml::Region::Center; - } - return result; -} - -/** - * Returns a point with interchanged X and Y coordinates. - */ -QPointF AssociationWidget::swapXY(const QPointF &p) -{ - QPointF swapped( p.y(), p.x() ); - return swapped; -} - -#if 0 // not used at the moment -/** - * Calculates which point of segment P1P2 has a distance equal to - * Distance from P1. - * Let's say such point is PX, the distance from P1 to PX must be equal - * to Distance and if PX is not a point of the segment P1P2 then the - * function returns (-1, -1). - */ -QPointF AssociationWidget::calculatePointAtDistance(const QPointF &P1, const QPointF &P2, float Distance) -{ - /* - the distance D between points (x1, y1) and (x3, y3) has the following formula: - --- ------------------------------ - D = \ / 2 2 - \ / (x3 - x1) + (y3 - y1) - - D, x1 and y1 are known and the point (x3, y3) is inside line (x1, y1)(x2, y2), so if the - that line has the formula y = mx + b - then y3 = m*x3 + b - - 2 2 2 - D = (x3 - x1) + (y3 - y1) - - 2 2 2 2 2 - D = x3 - 2*x3*x1 + x1 + y3 - 2*y3*y1 + y1 - - 2 2 2 2 2 - D - x1 - y1 = x3 - 2*x3*x1 + y3 - 2*y3*y1 - - 2 2 2 2 2 - D - x1 - y1 = x3 - 2*x3*x1 + (m*x3 + b) - 2*(m*x3 + b)*y1 - - 2 2 2 2 2 2 - D - x1 - y1 + 2*b*y1 - b = (m + 1)*x3 + (-2*x1 + 2*m*b -2*m*y1)*x3 - - 2 2 2 2 - C = - D + x1 + y1 - 2*b*y1 + b - - - 2 - A = (m + 1) - - B = (-2*x1 + 2*m*b -2*m*y1) - - and we have - 2 - A * x3 + B * x3 - C = 0 - - --------------- - -B + --- / 2 - \/ B - 4*A*C - sol_1 = -------------------------------- - 2*A - - - --------------- - -B - --- / 2 - \/ B - 4*A*C - sol_2 = -------------------------------- - 2*A - - - then in the distance formula we have only one variable x3 and that is easy - to calculate - */ - int x1 = P1.y(); - int y1 = P1.x(); - int x2 = P2.y(); - int y2 = P2.x(); - - if (x2 == x1) { - return QPointF(x1, y1 + (int)Distance); - } - float slope = ((float)y2 - (float)y1) / ((float)x2 - (float)x1); - float b = (y1 - slope*x1); - float A = (slope * slope) + 1; - float B = (2*slope*b) - (2*x1) - (2*slope*y1); - float C = (b*b) - (Distance*Distance) + (x1*x1) + (y1*y1) - (2*b*y1); - float t = B*B - 4*A*C; - - if (t < 0) { - return QPointF(-1, -1); - } - float sol_1 = ((-1* B) + sqrt(t)) / (2*A); - float sol_2 = ((-1*B) - sqrt(t)) / (2*A); - - if (sol_1 < 0.0 && sol_2 < 0.0) { - return QPointF(-1, -1); - } - QPointF sol1Point((int)(slope*sol_1 + b), (int)(sol_1)); - QPointF sol2Point((int)(slope*sol_2 + b), (int)(sol_2)); - if (sol_1 < 0 && sol_2 >=0) { - if (x2 > x1) { - if (x1 <= sol_2 && sol_2 <= x2) - return sol2Point; - } else { - if (x2 <= sol_2 && sol_2 <= x1) - return sol2Point; - } - } else if (sol_1 >= 0 && sol_2 < 0) { - if (x2 > x1) { - if (x1 <= sol_1 && sol_1 <= x2) - return sol1Point; - } else { - if (x2 <= sol_1 && sol_1 <= x1) - return sol1Point; - } - } else { - if (x2 > x1) { - if (x1 <= sol_1 && sol_1 <= x2) - return sol1Point; - if (x1 <= sol_2 && sol_2 <= x2) - return sol2Point; - } else { - if (x2 <= sol_1 && sol_1 <= x1) - return sol1Point; - if (x2 <= sol_2 && sol_2 <= x1) - return sol2Point; - } - } - return QPointF(-1, -1); -} - -/** - * Calculates which point of a perpendicular line to segment P1P2 that contains P2 - * has a distance equal to Distance from P2, - * Lets say such point is P3, the distance from P2 to P3 must be equal to Distance - */ -QPointF AssociationWidget::calculatePointAtDistanceOnPerpendicular(const QPointF &P1, const QPointF &P2, float Distance) -{ - /* - the distance D between points (x2, y2) and (x3, y3) has the following formula: - - --- ------------------------------ - D = \ / 2 2 - \ / (x3 - x2) + (y3 - y2) - - D, x2 and y2 are known and line P2P3 is perpendicular to line (x1, y1)(x2, y2), so if the - line P1P2 has the formula y = m*x + b, - then (x1 - x2) - m = -----------, because it is perpendicular to line P1P2 - (y2 - y1) - - also y2 = m*x2 + b - => b = y2 - m*x2 - - then P3 = (x3, m*x3 + b) - - 2 2 2 - D = (x3 - x2) + (y3 - y2) - - 2 2 2 2 2 - D = x3 - 2*x3*x2 + x2 + y3 - 2*y3*y2 + y2 - - 2 2 2 2 2 - D - x2 - y2 = x3 - 2*x3*x2 + y3 - 2*y3*y2 - - - - 2 2 2 2 2 - D - x2 - y2 = x3 - 2*x3*x2 + (m*x3 + b) - 2*(m*x3 + b)*y2 - - 2 2 2 2 2 2 - D - x2 - y2 + 2*b*y2 - b = (m + 1)*x3 + (-2*x2 + 2*m*b -2*m*y2)*x3 - - 2 2 2 2 - C = - D + x2 + y2 - 2*b*y2 + b - - 2 - A = (m + 1) - - B = (-2*x2 + 2*m*b -2*m*y2) - - and we have - 2 - A * x3 + B * x3 - C = 0 - - - --------------- - --- / 2 - -B + \/ B - 4*A*C - sol_1 = -------------------------------- - 2*A - - - --------------- - --- / 2 - -B - \/ B - 4*A*C - sol_2 = -------------------------------- - 2*A - - then in the distance formula we have only one variable x3 and that is easy - to calculate - */ - if (P1.x() == P2.x()) { - return QPointF((int)(P2.x() + Distance), P2.y()); - } - const int x1 = P1.y(); - const int y1 = P1.x(); - const int x2 = P2.y(); - const int y2 = P2.x(); - - float slope = ((float)x1 - (float)x2) / ((float)y2 - (float)y1); - float b = (y2 - slope*x2); - float A = (slope * slope) + 1; - float B = (2*slope*b) - (2*x2) - (2*slope*y2); - float C = (b*b) - (Distance*Distance) + (x2*x2) + (y2*y2) - (2*b*y2); - float t = B*B - 4*A*C; - if (t < 0) { - return QPointF(-1, -1); - } - float sol_1 = ((-1* B) + sqrt(t)) / (2*A); - - float sol_2 = ((-1*B) - sqrt(t)) / (2*A); - - if (sol_1 < 0 && sol_2 < 0) { - return QPointF(-1, -1); - } - QPointF sol1Point((int)(slope*sol_1 + b), (int)sol_1); - QPointF sol2Point((int)(slope*sol_2 + b), (int)sol_2); - if (sol_1 < 0 && sol_2 >=0) { - return sol2Point; - } else if (sol_1 >= 0 && sol_2 < 0) { - return sol1Point; - } else { // Choose one solution, either will work fine - if (slope >= 0) { - if (sol_1 <= sol_2) - return sol2Point; - else - return sol1Point; - } else { - if (sol_1 <= sol_2) - return sol1Point; - else - return sol2Point; - } - - } - return QPointF(-1, -1); // never reached, just keep compilers happy -} - -/** - * Calculates the intersection (PS) between line P1P2 and a perpendicular line containing - * P3, the result is returned in ResultingPoint. and result value represents the distance - * between ResultingPoint and P3; if this value is negative an error ocurred. - */ -float AssociationWidget::perpendicularProjection(const QPointF& P1, const QPointF& P2, const QPointF& P3, - QPointF& ResultingPoint) -{ - //line P1P2 is Line 1 = y=slope1*x + b1 - - //line P3PS is Line 1 = y=slope2*x + b2 - - float slope2 = 0; - float slope1 = 0; - float sx = 0, sy = 0; - int y2 = P2.x(); - int y1 = P1.x(); - int x2 = P2.y(); - int x1 = P1.y(); - int y3 = P3.x(); - int x3 = P3.y(); - float distance = 0; - float b1 = 0; - - float b2 = 0; - - if (x2 == x1) { - sx = x2; - sy = y3; - } else if (y2 == y1) { - sy = y2; - sx = x3; - } else { - slope1 = (y2 - y1)/ (x2 - x1); - slope2 = (x1 - x2)/ (y2 - y1); - b1 = y2 - (slope1 * x2); - b2 = y3 - (slope2 * x3); - sx = (b2 - b1) / (slope1 - slope2); - sy = slope1*sx + b1; - } - distance = (int)(sqrt(((x3 - sx)*(x3 - sx)) + ((y3 - sy)*(y3 - sy)))); - - ResultingPoint.setX((int)sy); - ResultingPoint.setY((int)sx); - - return distance; -} -#endif - -/** - * Calculates the position of the text widget depending on the role - * that widget is playing. - * Returns the point at which to put the widget. - */ -QPointF AssociationWidget::calculateTextPosition(Uml::TextRole::Enum role) -{ - const int SPACE = 2; - QPointF p(-1, -1), q(-1, -1); - - // used to find out if association end point (p) - // is at top or bottom edge of widget. - - if (role == TextRole::MultiA || role == TextRole::ChangeA || role == TextRole::RoleAName) { - p = m_associationLine->point(0); - q = m_associationLine->point(1); - } else if (role == TextRole::MultiB || role == TextRole::ChangeB || role == TextRole::RoleBName) { - const int lastSegment = m_associationLine->count() - 1; - p = m_associationLine->point(lastSegment); - q = m_associationLine->point(lastSegment - 1); - } else if (role != TextRole::Name) { - uError() << "called with unsupported TextRole::Enum " << role; - return QPointF(-1, -1); - } - - FloatingTextWidget *text = textWidgetByRole(role); - int textW = 0, textH = 0; - if (text) { - textW = text->width(); - textH = text->height(); - } - - qreal x = 0.0, y = 0.0; - - if (role == TextRole::MultiA || role == TextRole::MultiB) { - const bool isHorizontal = (p.y() == q.y()); - const int atBottom = p.y() + SPACE; - const int atTop = p.y() - SPACE - textH; - const int atLeft = p.x() - SPACE - textW; - const int atRight = p.x() + SPACE; - y = (p.y() > q.y()) == isHorizontal ? atBottom : atTop; - x = (p.x() < q.x()) == isHorizontal ? atRight : atLeft; - - } else if (role == TextRole::ChangeA || role == TextRole::ChangeB) { - - if (p.y() > q.y()) - y = p.y() - SPACE - (textH * 2); - else - y = p.y() + SPACE + textH; - - if (p.x() < q.x()) - x = p.x() + SPACE; - else - x = p.x() - SPACE - textW; - - } else if (role == TextRole::RoleAName || role == TextRole::RoleBName) { - - if (p.y() > q.y()) - y = p.y() - SPACE - textH; - else - y = p.y() + SPACE; - - if (p.x() < q.x()) - x = p.x() + SPACE; - else - x = p.x() - SPACE - textW; - - } else if (role == TextRole::Name) { - - calculateNameTextSegment(); - if (m_unNameLineSegment == -1) { - uWarning() << "TODO:negative line segment index"; - m_unNameLineSegment = 0; - } - x = ( m_associationLine->point(m_unNameLineSegment).x() + - m_associationLine->point(m_unNameLineSegment + 1).x() ) / 2; - y = ( m_associationLine->point(m_unNameLineSegment).y() + - m_associationLine->point(m_unNameLineSegment + 1).y() ) / 2; - } - - if (text) { - constrainTextPos(x, y, textW, textH, role); - } - p = QPointF( x, y ); - return p; -} - -/** - * Return the mid point between p0 and p1 - */ -QPointF AssociationWidget::midPoint(const QPointF& p0, const QPointF& p1) -{ - QPointF midP; - if (p0.x() < p1.x()) - midP.setX(p0.x() + (p1.x() - p0.x()) / 2); - else - midP.setX(p1.x() + (p0.x() - p1.x()) / 2); - if (p0.y() < p1.y()) - midP.setY(p0.y() + (p1.y() - p0.y()) / 2); - else - midP.setY(p1.y() + (p0.y() - p1.y()) / 2); - return midP; -} - -/** - * Constrains the FloatingTextWidget X and Y values supplied. - * Implements the abstract operation from LinkWidget. - * - * @param textX Candidate X value (may be modified by the constraint.) - * @param textY Candidate Y value (may be modified by the constraint.) - * @param textWidth Width of the text. - * @param textHeight Height of the text. - * @param tr Uml::Text_Role of the text. - */ -void AssociationWidget::constrainTextPos(qreal &textX, qreal &textY, - qreal textWidth, qreal textHeight, - Uml::TextRole::Enum tr) -{ - const int textCenterX = textX + textWidth / 2; - const int textCenterY = textY + textHeight / 2; - const int lastSegment = m_associationLine->count() - 1; - QPointF p0, p1; - switch (tr) { - case TextRole::RoleAName: - case TextRole::MultiA: - case TextRole::ChangeA: - p0 = m_associationLine->point(0); - p1 = m_associationLine->point(1); - // If we are dealing with a single line then tie the - // role label to the proper half of the line, i.e. - // the role label must be closer to the "other" - // role object. - if (lastSegment == 1) - p1 = midPoint(p0, p1); - break; - case TextRole::RoleBName: - case TextRole::MultiB: - case TextRole::ChangeB: - p0 = m_associationLine->point(lastSegment - 1); - p1 = m_associationLine->point(lastSegment); - if (lastSegment == 1) - p0 = midPoint(p0, p1); - break; - case TextRole::Name: - case TextRole::Coll_Message: // CHECK: collab.msg texts seem to be TextRole::Name - case TextRole::State: // CHECK: is this used? - // Find the linepath segment to which the (textX, textY) is closest - // and constrain to the corridor of that segment (see farther below) - { - int minDistSquare = 100000; // utopian initial value - int lpIndex = 0; - for (int i = 0; i < lastSegment; ++i) { - p0 = m_associationLine->point(i); - p1 = m_associationLine->point(i + 1); - QPointF midP = midPoint(p0, p1); - const int deltaX = textCenterX - midP.x(); - const int deltaY = textCenterY - midP.y(); - const int cSquare = deltaX * deltaX + deltaY * deltaY; - if (cSquare < minDistSquare) { - minDistSquare = cSquare; - lpIndex = i; - } - } - p0 = m_associationLine->point(lpIndex); - p1 = m_associationLine->point(lpIndex + 1); - } - break; - default: - uError() << "unexpected TextRole::Enum " << tr; - return; - break; - } - /* Constraint: - The midpoint between p0 and p1 is taken to be the center of a circle - with radius D/2 where D is the distance between p0 and p1. - The text center needs to be within this circle else it is constrained - to the nearest point on the circle. - */ - p0 = swapXY(p0); // go to the natural coordinate system - p1 = swapXY(p1); // with (0,0) in the lower left corner - QPointF midP = midPoint(p0, p1); - // If (textX,textY) is not inside the circle around midP then - // constrain (textX,textY) to the nearest point on that circle. - const int x0 = p0.x(); - const int y0 = p0.y(); - const int x1 = p1.x(); - const int y1 = p1.y(); - double r = sqrt((double)((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0))) / 2; - if (textWidth > r) - r = textWidth; - // swap textCenter{X,Y} to convert from Qt coord.system. - const QPointF origTextCenter(textCenterY, textCenterX); - const int relX = abs(origTextCenter.x() - midP.x()); - const int relY = abs(origTextCenter.y() - midP.y()); - const double negativeWhenInsideCircle = relX * relX + relY * relY - r * r; - if (negativeWhenInsideCircle <= 0.0) { - return; - } - /* - The original constraint was to snap the text position to the - midpoint but that creates unpleasant visual jitter: - textX = midP.y() - textWidth / 2; // go back to Qt coord.sys. - textY = midP.x() - textHeight / 2; // go back to Qt coord.sys. - - Rather, we project the text position onto the closest point - on the circle: - - Circle equation: - relX^2 + relY^2 - r^2 = 0, or in other words - relY^2 = r^2 - relX^2, or - relY = sqrt(r^2 - relX^2) - Line equation: - relY = a * relX + b - We can omit "b" because relX and relY are already relative to - the circle origin, therefore we can also write: - a = relY / relX - To obtain the point of intersection between the circle of radius r - and the line connecting the circle origin with the point (relX, relY), - we equate the relY: - a * x = sqrt(r^2 - x^2), or in other words - a^2 * x^2 = r^2 - x^2, or - x^2 * (a^2 + 1) = r^2, or - x^2 = r^2 / (a^2 + 1), or - x = sqrt(r^2 / (a^2 + 1)) - and then - y = a * x - The resulting x and y are relative to the circle origin so we just add - the circle origin (X, Y) to obtain the constrained (textX, textY). - */ - // Handle the special case, relX = 0. - if (relX == 0) { - if (origTextCenter.y() > midP.y()) - textX = midP.y() + (int)r; // go back to Qt coord.sys. - else - textX = midP.y() - (int)r; // go back to Qt coord.sys. - textX -= textWidth / 2; - return; - } - const double a = (double)relY / (double)relX; - const double x = sqrt(r*r / (a*a + 1)); - const double y = a * x; - if (origTextCenter.x() > midP.x()) - textY = midP.x() + (int)x; // go back to Qt coord.sys. - else - textY = midP.x() - (int)x; // go back to Qt coord.sys. - textY -= textHeight / 2; - if (origTextCenter.y() > midP.y()) - textX = midP.y() + (int)y; // go back to Qt coord.sys. - else - textX = midP.y() - (int)y; // go back to Qt coord.sys. - textX -= textWidth / 2; -} - -/** - * Puts the text widget with the given role at the given position. - * This method calls @ref calculateTextPostion to get the needed position. - * I.e. the line segment it is on has moved and it should move the same - * amount as the line. - */ -void AssociationWidget::setTextPosition(Uml::TextRole::Enum role) -{ - bool startMove = false; - if (m_role[RoleType::A].multiplicityWidget && m_role[RoleType::A].multiplicityWidget->getStartMove()) - startMove = true; - else if (m_role[RoleType::B].multiplicityWidget && m_role[RoleType::B].multiplicityWidget->getStartMove()) - startMove = true; - else if (m_role[RoleType::A].changeabilityWidget && m_role[RoleType::A].changeabilityWidget->getStartMove()) - startMove = true; - else if (m_role[RoleType::B].changeabilityWidget && m_role[RoleType::B].changeabilityWidget->getStartMove()) - startMove = true; - else if (m_role[RoleType::A].roleWidget && m_role[RoleType::A].roleWidget->getStartMove()) - startMove = true; - else if (m_role[RoleType::B].roleWidget && m_role[RoleType::B].roleWidget->getStartMove()) - startMove = true; - else if (m_nameWidget && m_nameWidget->getStartMove()) - startMove = true; - if (startMove) { - return; - } - FloatingTextWidget *ft = textWidgetByRole(role); - if (ft == NULL) - return; - QPointF pos = calculateTextPosition(role); - ft->setX(pos.x()); - ft->setY(pos.y()); -} - -/** - * Moves the text widget with the given role by the difference between - * the two points. - */ -void AssociationWidget::setTextPositionRelatively(Uml::TextRole::Enum role, const QPointF &oldPosition) -{ - bool startMove = false; - if (m_role[RoleType::A].multiplicityWidget && m_role[RoleType::A].multiplicityWidget->getStartMove()) - startMove = true; - else if (m_role[RoleType::B].multiplicityWidget && m_role[RoleType::B].multiplicityWidget->getStartMove()) - startMove = true; - else if (m_role[RoleType::A].changeabilityWidget && m_role[RoleType::A].changeabilityWidget->getStartMove()) - startMove = true; - else if (m_role[RoleType::B].changeabilityWidget && m_role[RoleType::B].changeabilityWidget->getStartMove()) - startMove = true; - else if (m_role[RoleType::A].roleWidget && m_role[RoleType::A].roleWidget->getStartMove()) - startMove = true; - else if (m_role[RoleType::B].roleWidget && m_role[RoleType::B].roleWidget->getStartMove()) - startMove = true; - else if (m_nameWidget && m_nameWidget->getStartMove()) - startMove = true; - - if (startMove) { - return; - } - FloatingTextWidget *ft = textWidgetByRole(role); - if (ft == NULL) - return; - qreal ftX = ft->x(); - qreal ftY = ft->y(); - - QPointF pos = calculateTextPosition(role); - int relX = pos.x() - oldPosition.x(); - int relY = pos.y() - oldPosition.y(); - qreal ftNewX = ftX + relX; - qreal ftNewY = ftY + relY; - - bool oldIgnoreSnapToGrid = ft->getIgnoreSnapToGrid(); - ft->setIgnoreSnapToGrid(true); - ft->setX(ftNewX); - ft->setY(ftNewY); - ft->setIgnoreSnapToGrid(oldIgnoreSnapToGrid); -} - -/** - * Remove dashed connecting line for association class. - */ -void AssociationWidget::removeAssocClassLine() -{ - delete m_pAssocClassLineSel0; - m_pAssocClassLineSel0 = 0; - delete m_pAssocClassLineSel1; - m_pAssocClassLineSel1 = 0; - delete m_pAssocClassLine; - m_pAssocClassLine = 0; - if (m_associationClass) { - m_associationClass->setClassAssociationWidget(0); - m_associationClass = 0; - } -} - -/** - * Creates the association class connecting line. - */ -void AssociationWidget::createAssocClassLine() -{ - if (m_pAssocClassLine == NULL) { - m_pAssocClassLine = new QGraphicsLineItem(this); - } - QPen pen(lineColor(), lineWidth(), Qt::DashLine); - m_pAssocClassLine->setPen(pen); - // decoration points - m_pAssocClassLineSel0 = Widget_Utils::decoratePoint(m_pAssocClassLine->line().p1(), - m_pAssocClassLine); - m_pAssocClassLineSel1 = Widget_Utils::decoratePoint(m_pAssocClassLine->line().p2(), - m_pAssocClassLine); - computeAssocClassLine(); - selectAssocClassLine(false); -} - -/** - * Creates the association class connecting line using the specified - * ClassifierWidget. - * - * @param classifier The ClassifierWidget to use. - * @param linePathSegmentIndex The index of the segment where the - * association class is created. - */ -void AssociationWidget::createAssocClassLine(ClassifierWidget* classifier, - int linePathSegmentIndex) -{ - m_nLinePathSegmentIndex = linePathSegmentIndex; - - if (m_nLinePathSegmentIndex < 0) { - return; - } - - m_associationClass = classifier; - m_associationClass->setClassAssociationWidget(this); - m_associationClass->addAssoc(this); // to get widgetMoved(...) for association classes - - createAssocClassLine(); -} - -/** - * Compute the end points of m_pAssocClassLine in case this - * association has an attached association class. - * TODO: The decoration points make no sense for now, because they are not movable. - */ -void AssociationWidget::computeAssocClassLine() -{ - if (m_associationClass == NULL || m_pAssocClassLine == NULL) { - return; - } - if (m_nLinePathSegmentIndex < 0) { - uError() << "m_nLinePathSegmentIndex is not set"; - return; - } - - QPointF segStart = m_associationLine->point(m_nLinePathSegmentIndex); - QPointF segEnd = m_associationLine->point(m_nLinePathSegmentIndex + 1); - const qreal midSegX = segStart.x() + (segEnd.x() - segStart.x()) / 2.0; - const qreal midSegY = segStart.y() + (segEnd.y() - segStart.y()) / 2.0; - QPointF segmentMidPoint(midSegX, midSegY); - - QLineF possibleAssocLine = QLineF(segmentMidPoint, - m_associationClass->mapRectToScene(m_associationClass->rect()).center()); - QPointF intersectionPoint; - QLineF::IntersectType type = intersect(m_associationClass->mapRectToScene(m_associationClass->boundingRect()), - possibleAssocLine, - &intersectionPoint); - // DEBUG(DBG_SRC) << "intersect type=" << type << " / point=" << intersectionPoint; - - if (type == QLineF::BoundedIntersection) { - m_pAssocClassLine->setLine(midSegX, midSegY, - intersectionPoint.x(), intersectionPoint.y()); - - if (m_pAssocClassLineSel0 && m_pAssocClassLineSel1) { - m_pAssocClassLineSel0->setPos(m_pAssocClassLine->line().p1()); - m_pAssocClassLineSel1->setPos(m_pAssocClassLine->line().p2()); - } - } -} - -/** - * Renders the association class connecting line selected. - */ -void AssociationWidget::selectAssocClassLine(bool sel) -{ - if (m_pAssocClassLineSel0 && m_pAssocClassLineSel1) { - m_pAssocClassLineSel0->setVisible(sel); - m_pAssocClassLineSel1->setVisible(sel); - } -} - -/** - * Sets the association to be selected. - */ -void AssociationWidget::mousePressEvent(QGraphicsSceneMouseEvent * me) -{ - // clear other selected stuff on the screen of ShiftKey - if (me->modifiers() != Qt::ShiftModifier) { - m_scene->clearSelected(); - } - - if (me->button() == Qt::LeftButton && me->modifiers() == Qt::ControlModifier) { - if (checkRemovePoint(me->scenePos())) - return; - } - - // make sure we should be here depending on the button - if (me->button() != Qt::RightButton && me->button() != Qt::LeftButton) { - return; - } - QPointF mep = me->scenePos(); - // see if `mep' is on the connecting line to the association class - if (onAssocClassLine(mep)) { - setSelected(true); - selectAssocClassLine(); - return; - } - setSelected(!isSelected()); - associationLine()->mousePressEvent(me); -} - -/** - * Displays the right mouse buttom menu if right button is pressed. - */ -void AssociationWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent * me) -{ - associationLine()->mouseReleaseEvent(me); -} - -/** - * Handles the selection from the popup menu. - */ -void AssociationWidget::slotMenuSelection(QAction* action) -{ - QString oldText, newText; - QRegExpValidator v(QRegExp(QLatin1String(".*")), 0); - Uml::AssociationType::Enum atype = associationType(); - Uml::RoleType::Enum r = RoleType::B; - ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); - DEBUG(DBG_SRC) << "menu selection = " << ListPopupMenu::toString(sel); - - // if it's a collaboration message we now just use the code in floatingtextwidget - // this means there's some redundant code below but that's better than duplicated code - if (isCollaboration() && sel != ListPopupMenu::mt_Delete) { - m_nameWidget->slotMenuSelection(action); - return; - } - - switch(sel) { - case ListPopupMenu::mt_Properties: - if (atype == AssociationType::Seq_Message || atype == AssociationType::Seq_Message_Self) { - // show op dlg for seq. diagram here - // don't worry about here, I don't think it can get here as - // line is widget on seq. diagram - // here just in case - remove later after testing - DEBUG(DBG_SRC) << "mt_Properties: assoctype is " << atype; - } else { //standard assoc dialog - UMLApp::app()->docWindow()->updateDocumentation(false); - showPropertiesDialog(); - } - break; - - case ListPopupMenu::mt_Add_Point: - checkAddPoint(m_eventScenePos); - break; - - case ListPopupMenu::mt_Delete_Point: - checkRemovePoint(m_eventScenePos); - break; - - case ListPopupMenu::mt_Delete: - if (m_pAssocClassLineSel0) - removeAssocClassLine(); - else if (association()) - m_scene->removeAssocInViewAndDoc(this); - else - m_scene->removeAssoc(this); - break; - - case ListPopupMenu::mt_Rename_MultiA: - r = RoleType::A; // fall through - case ListPopupMenu::mt_Rename_MultiB: - if (m_role[r].multiplicityWidget) - oldText = m_role[r].multiplicityWidget->text(); - else - oldText = QString(); -#if QT_VERSION >= 0x050000 - newText = QInputDialog::getText(m_scene->activeView(), - i18n("Multiplicity"), - i18n("Enter multiplicity:"), - QLineEdit::Normal, - oldText, NULL); -#else - newText = KInputDialog::getText(i18n("Multiplicity"), - i18n("Enter multiplicity:"), - oldText, NULL, m_scene->activeView(), &v); -#endif - if (newText != oldText) { - if (FloatingTextWidget::isTextValid(newText)) { - setMultiplicity(newText, r); - } else { - m_scene->removeWidget(m_role[r].multiplicityWidget); - m_role[r].multiplicityWidget = NULL; - } - } - break; - - case ListPopupMenu::mt_Rename_Name: - if (m_nameWidget) - oldText = m_nameWidget->text(); - else - oldText = QString(); -#if QT_VERSION >= 0x050000 - newText = QInputDialog::getText(m_scene->activeView(), - i18n("Association Name"), - i18n("Enter association name:"), - QLineEdit::Normal, - oldText, NULL); -#else - newText = KInputDialog::getText(i18n("Association Name"), - i18n("Enter association name:"), - oldText, NULL, m_scene->activeView(), &v); -#endif - if (newText != oldText) { - if (FloatingTextWidget::isTextValid(newText)) { - setName(newText); - } else { - m_scene->removeWidget(m_nameWidget); - m_nameWidget = NULL; - } - } - break; - - case ListPopupMenu::mt_Rename_RoleAName: - r = RoleType::A; // fall through - case ListPopupMenu::mt_Rename_RoleBName: - if (m_role[r].roleWidget) - oldText = m_role[r].roleWidget->text(); - else - oldText = QString(); -#if QT_VERSION >= 0x050000 - newText = QInputDialog::getText(m_scene->activeView(), - i18n("Role Name"), - i18n("Enter role name:"), - QLineEdit::Normal, - oldText, NULL); -#else - newText = KInputDialog::getText(i18n("Role Name"), - i18n("Enter role name:"), - oldText, NULL, m_scene->activeView(), &v); -#endif - if (newText != oldText) { - if (FloatingTextWidget::isTextValid(newText)) { - setRoleName(newText, r); - } else { - m_scene->removeWidget(m_role[r].roleWidget); - m_role[r].roleWidget = NULL; - } - } - break; - - case ListPopupMenu::mt_Change_Font: - { -#if QT_VERSION >= 0x050000 - bool ok = false; - QFont fnt = QFontDialog::getFont(&ok, font(), m_scene->activeView()); - if (ok) -#else - QFont fnt = font(); - if (KFontDialog::getFont(fnt, KFontChooser::NoDisplayFlags, m_scene->activeView())) -#endif - lwSetFont(fnt); - } - break; - - case ListPopupMenu::mt_Line_Color: - { -#if QT_VERSION >= 0x050000 - QColor newColor = QColorDialog::getColor(lineColor()); - if (newColor != lineColor()) { -#else - QColor newColor; - if (KColorDialog::getColor(newColor)) { -#endif - m_scene->selectionSetLineColor(newColor); - umlDoc()->setModified(true); - } - } - break; - - case ListPopupMenu::mt_Cut: - m_scene->setStartedCut(); - UMLApp::app()->slotEditCut(); - break; - - case ListPopupMenu::mt_Copy: - UMLApp::app()->slotEditCopy(); - break; - - case ListPopupMenu::mt_Paste: - UMLApp::app()->slotEditPaste(); - break; - - case ListPopupMenu::mt_Reset_Label_Positions: - resetTextPositions(); - break; - - case ListPopupMenu::mt_LayoutDirect: - m_associationLine->setLayout(AssociationLine::Direct); - break; - case ListPopupMenu::mt_LayoutSpline: - m_associationLine->setLayout(AssociationLine::Spline); - break; - case ListPopupMenu::mt_LayoutOrthogonal: - m_associationLine->setLayout(AssociationLine::Orthogonal); - break; - case ListPopupMenu::mt_LayoutPolyline: - m_associationLine->setLayout(AssociationLine::Polyline); - break; - - default: - DEBUG(DBG_SRC) << "MenuType " << ListPopupMenu::toString(sel) << " not implemented"; - break; - }//end switch -} - -/** - * Return the first font found being used by any child widget. (They - * could be different fonts, so this is a slightly misleading method.) - */ -QFont AssociationWidget::font() const -{ - //:TODO: find a general font for the association - QFont font; - - if (m_role[RoleType::A].roleWidget) - font = m_role[RoleType::A].roleWidget->font(); - else if (m_role[RoleType::B].roleWidget) - font = m_role[RoleType::B].roleWidget->font(); - else if (m_role[RoleType::A].multiplicityWidget) - font = m_role[RoleType::A].multiplicityWidget->font(); - else if (m_role[RoleType::B].multiplicityWidget) - font = m_role[RoleType::B].multiplicityWidget->font(); - else if (m_role[RoleType::A].changeabilityWidget) - font = m_role[RoleType::A].changeabilityWidget->font(); - else if (m_role[RoleType::B].changeabilityWidget) - font = m_role[RoleType::B].changeabilityWidget->font(); - else if (m_nameWidget) - font = m_nameWidget->font(); - else - font = m_role[RoleType::A].umlWidget->font(); - - return font; -} - -/** - * Set all 'owned' child widgets to this text color. - */ -void AssociationWidget::setTextColor(const QColor &color) -{ - WidgetBase::setTextColor(color); - if (m_nameWidget) { - m_nameWidget->setTextColor(color); - } - if (m_role[RoleType::A].roleWidget) { - m_role[RoleType::A].roleWidget->setTextColor(color); - } - if (m_role[RoleType::B].roleWidget) { - m_role[RoleType::B].roleWidget->setTextColor(color); - } - if (m_role[RoleType::A].multiplicityWidget) { - m_role[RoleType::A].multiplicityWidget->setTextColor(color); - } - if (m_role[RoleType::B].multiplicityWidget) { - m_role[RoleType::B].multiplicityWidget->setTextColor(color); - } - if (m_role[RoleType::A].changeabilityWidget) - m_role[RoleType::A].changeabilityWidget->setTextColor(color); - if (m_role[RoleType::B].changeabilityWidget) - m_role[RoleType::B].changeabilityWidget->setTextColor(color); -} - -bool AssociationWidget::checkAddPoint(const QPointF &scenePos) -{ - if (associationType() == AssociationType::Exception) { - return false; - } - - // if there is no point around the mouse pointer, we insert a new one - if (m_associationLine->closestPointIndex(scenePos) < 0) { - int i = m_associationLine->closestSegmentIndex(scenePos); - if (i < 0) { - DEBUG(DBG_SRC) << "no closest segment found!"; - return false; - } - m_associationLine->insertPoint(i + 1, scenePos); - if (m_nLinePathSegmentIndex == i) { - QPointF segStart = m_associationLine->point(i); - QPointF segEnd = m_associationLine->point(i + 2); - const int midSegX = segStart.x() + (segEnd.x() - segStart.x()) / 2; - const int midSegY = segStart.y() + (segEnd.y() - segStart.y()) / 2; - /* - DEBUG(DBG_SRC) << "segStart=" << segStart << ", segEnd=" << segEnd - << ", midSeg=(" << midSegX << "," << midSegY - << "), mp=" << mp; - */ - if (midSegX > scenePos.x() || midSegY < scenePos.y()) { - m_nLinePathSegmentIndex++; - DEBUG(DBG_SRC) << "setting m_nLinePathSegmentIndex to " - << m_nLinePathSegmentIndex; - computeAssocClassLine(); - } - m_associationLine->update(); - calculateNameTextSegment(); - umlDoc()->setModified(true); - setSelected(true); - } - return true; - } - else { - DEBUG(DBG_SRC) << "found point already close enough!"; - return false; - } -} - -/** - * Remove point close to the given point and redraw the association. - * @param scenePos point which should be removed - * @return success status of the remove action - */ -bool AssociationWidget::checkRemovePoint(const QPointF &scenePos) -{ - int i = m_associationLine->closestPointIndex(scenePos); - if (i == -1) - return false; - - m_associationLine->setSelected(false); - - // there was a point so we remove the point - m_associationLine->removePoint(i); - - // Maybe reattach association class connecting line - // to different association linepath segment. - const int numberOfLines = m_associationLine->count() - 1; - if (m_nLinePathSegmentIndex >= numberOfLines) { - m_nLinePathSegmentIndex = numberOfLines - 1; - } - calculateEndingPoints(); - - // select the line path - m_associationLine->setSelected(true); - - m_associationLine->update(); - - calculateNameTextSegment(); - umlDoc()->setModified(true); - return true; -} - -/** - * Moves the break point being dragged. - */ -void AssociationWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* me) -{ - if (me->buttons() != Qt::LeftButton) { - return; - } - - setSelected(true); - - associationLine()->mouseMoveEvent(me); - moveEvent(me); - m_scene->resizeSceneToItems(); -} - -/** - * Returns the Region the widget to line intersection is for the given - * widget in this Association. If the given widget is not in the - * Association then Region::Error is returned. - * Used by @ref calculateEndingPoints to work these positions out for - * another Association - since the number of Associations on the same - * region for the same widget will mean the lines will need to be - * spread out across the region. - */ -//Uml::Region::Enum AssociationWidget::getWidgetRegion(AssociationWidget * widget) const -//{ -// if (widget->widgetForRole(RoleType::A) == m_role[RoleType::A].umlWidget) -// return m_role[RoleType::A].m_WidgetRegion; -// if (widget->widgetForRole(RoleType::B) == m_role[RoleType::B].umlWidget) -// return m_role[RoleType::B].m_WidgetRegion; -// return Uml::Region::Error; -//} - -/** - * Returns the number of lines there are on the given region for - * either widget A or B of the association. - */ -int AssociationWidget::getRegionCount(Uml::Region::Enum region, Uml::RoleType::Enum role) -{ - if ((region == Uml::Region::Error) | (umlScene() == NULL)) { - return 0; - } - int widgetCount = 0; - AssociationWidgetList list = m_scene->associationList(); - foreach (AssociationWidget* assocwidget, list) { - //don't count this association - if (assocwidget == this) - continue; - const WidgetRole& otherA = assocwidget->m_role[RoleType::A]; - const WidgetRole& otherB = assocwidget->m_role[RoleType::B]; - const UMLWidget *a = otherA.umlWidget; - const UMLWidget *b = otherB.umlWidget; - /* - //don't count associations to self if both of their end points are on the same region - //they are different and placement won't interfere with them - if (a == b && otherA.m_WidgetRegion == otherB.m_WidgetRegion) - continue; - */ - if (m_role[role].umlWidget == a && region == otherA.m_WidgetRegion) - widgetCount++; - else if (m_role[role].umlWidget == b && region == otherB.m_WidgetRegion) - widgetCount++; - }//end foreach - return widgetCount; -} - -/** - * Find the border point of the given rect when a line is drawn from the - * given point to the rect. - * @param rect rect of a classifier - * @param line a line to the rect - * @param intersectionPoint the intercept point on the border of the rect - * @return the type of the intersection @ref QLineF::IntersectType - */ -QLineF::IntersectType AssociationWidget::intersect(const QRectF &rect, const QLineF &line, - QPointF* intersectionPoint) -{ - QList lines; - lines << QLineF(rect.topLeft(), rect.topRight()); - lines << QLineF(rect.topRight(), rect.bottomRight()); - lines << QLineF(rect.bottomRight(), rect.bottomLeft()); - lines << QLineF(rect.bottomLeft(), rect.topLeft()); - foreach (const QLineF& rectLine, lines) { - QLineF::IntersectType type = rectLine.intersect(line, intersectionPoint); - if (type == QLineF::BoundedIntersection) { - return type; - } - } - return QLineF::NoIntersection; -} - -/** - * Given a rectangle and a point, findInterceptOnEdge computes the - * connecting line between the middle point of the rectangle and - * the point, and returns the intercept of this line with the - * the edge of the rectangle identified by `region'. - * When the region is North or South, the X value is returned (Y is - * constant.) - * When the region is East or West, the Y value is returned (X is - * constant.) - * @todo This is buggy. Try replacing by intersect() - */ -qreal AssociationWidget::findInterceptOnEdge(const QRectF &rect, - Uml::Region::Enum region, - const QPointF &point) -{ - // The Qt coordinate system has (0, 0) in the top left corner. - // In order to go to the regular XY coordinate system with (0, 0) - // in the bottom left corner, we swap the X and Y axis. - // That's why the following assignments look twisted. - const qreal rectHalfWidth = rect.height() / 2.0; - const qreal rectHalfHeight = rect.width() / 2.0; - const qreal rectMidX = rect.y() + rectHalfWidth; - const qreal rectMidY = rect.x() + rectHalfHeight; - const qreal dX = rectMidX - point.y(); - const qreal dY = rectMidY - point.x(); - switch (region) { - case Uml::Region::West: - region = Uml::Region::South; - break; - case Uml::Region::North: - region = Uml::Region::West; - break; - case Uml::Region::East: - region = Uml::Region::North; - break; - case Uml::Region::South: - region = Uml::Region::East; - break; - default: - break; - } - // Now we have regular coordinates with the point (0, 0) in the - // bottom left corner. - if (region == Uml::Region::North || region == Uml::Region::South) { - if (dX == 0) - return rectMidY; - // should be rectMidX, but we go back to Qt coord.sys. - if (dY == 0) { - uError() << "usage error: " << "North/South (dY == 0)"; - return -1.0; - } - const qreal m = dY / dX; - qreal relativeX; - if (region == Uml::Region::North) - relativeX = rectHalfHeight / m; - else - relativeX = -rectHalfHeight / m; - return (rectMidY + relativeX); - // should be rectMidX, but we go back to Qt coord.sys. - } else { - if (dY == 0) - return rectMidX; - // should be rectMidY, but we go back to Qt coord.sys. - if (dX == 0) { - uError() << "usage error: " << "East/West (dX == 0)"; - return -1.0; - } - const qreal m = dY / dX; - qreal relativeY = m * rectHalfWidth; - if (region == Uml::Region::West) - relativeY = -relativeY; - return (rectMidX + relativeY); - // should be rectMidY, but we go back to Qt coord.sys. - } -} - -/** - * Auxiliary method for updateAssociations(): - * Put position into m_positions and assoc into m_ordered at the - * correct index. - * m_positions and m_ordered move in parallel and are sorted by - * ascending position. - */ -void AssociationWidget::insertIntoLists(qreal position, const AssociationWidget* assoc) -{ - bool did_insertion = false; - for (int index = 0; index < m_positions_len; ++index) { - if (position < m_positions[index]) { - for (int moveback = m_positions_len; moveback > index; moveback--) - m_positions[moveback] = m_positions[moveback - 1]; - m_positions[index] = position; - m_ordered.insert(index, const_cast(assoc)); - did_insertion = true; - break; - } - } - if (! did_insertion) { - m_positions[m_positions_len] = position; - m_ordered.append(const_cast(assoc)); - } - m_positions_len++; -} - -/** - * Tells all the other view associations the new count for the - * given widget on a certain region. And also what index they should be. - */ -void AssociationWidget::updateAssociations(int totalCount, - Uml::Region::Enum region, - Uml::RoleType::Enum role) -{ - if ((region == Uml::Region::Error) | (umlScene() == NULL)) { - return; - } - AssociationWidgetList list = m_scene->associationList(); - - UMLWidget *ownWidget = m_role[role].umlWidget; - m_positions_len = 0; - m_ordered.clear(); - // we order the AssociationWidget list by region and x/y value - foreach (AssociationWidget* assocwidget, list) { - WidgetRole *roleA = &assocwidget->m_role[RoleType::A]; - WidgetRole *roleB = &assocwidget->m_role[RoleType::B]; - UMLWidget *wA = roleA->umlWidget; - UMLWidget *wB = roleB->umlWidget; - // Skip self associations. - if (wA == wB) - continue; - // Now we must find out with which end the assocwidget connects - // to the input widget (ownWidget). - bool inWidgetARegion = (ownWidget == wA && - region == roleA->m_WidgetRegion); - bool inWidgetBRegion = (ownWidget == wB && - region == roleB->m_WidgetRegion); - if (!inWidgetARegion && !inWidgetBRegion) - continue; - // Determine intercept position on the edge indicated by `region'. - UMLWidget * otherWidget = (inWidgetARegion ? wB : wA); - AssociationLine *linepath = assocwidget->associationLine(); - QPointF refpoint; - if (assocwidget->linePathStartsAt(otherWidget)) - refpoint = linepath->point(linepath->count() - 2); - else - refpoint = linepath->point(1); - // The point is authoritative if we're called for the second time - // (i.e. role==B) or it is a waypoint on the line path. - bool pointIsAuthoritative = (role == RoleType::B || linepath->count() > 2); - if (! pointIsAuthoritative) { - // If the point is not authoritative then we use the other - // widget's center. - refpoint.setX(otherWidget->x() + otherWidget->width() / 2); - refpoint.setY(otherWidget->y() + otherWidget->height() / 2); - } - qreal intercept = findInterceptOnEdge(ownWidget->rect(), region, refpoint); - if (intercept < 0) { - DEBUG(DBG_SRC) << "error from findInterceptOnEdge for" - << " assocType=" << assocwidget->associationType() - << " ownWidget=" << ownWidget->name() - << " otherWidget=" << otherWidget->name(); - continue; - } - insertIntoLists(intercept, assocwidget); - } // while ((assocwidget = assoc_it.current())) - - // we now have an ordered list and we only have to call updateRegionLineCount - int index = 1; - foreach (AssociationWidget* assocwidget, m_ordered ) { - if (ownWidget == assocwidget->widgetForRole(RoleType::A)) { - assocwidget->updateRegionLineCount(index++, totalCount, region, RoleType::A); - } else if (ownWidget == assocwidget->widgetForRole(RoleType::B)) { - assocwidget->updateRegionLineCount(index++, totalCount, region, RoleType::B); - } - } // for (assocwidget = ordered.first(); ...) -} - -/** - * Called to tell the association that another association has added - * a line to the region of one of its widgets. The widget is identified - * by its role (A or B). - * - * Called by @ref updateAssociations which is called by - * @ref calculateEndingPoints when required. - */ -void AssociationWidget::updateRegionLineCount(int index, int totalCount, - Uml::Region::Enum region, - Uml::RoleType::Enum role) -{ - if ((region == Uml::Region::Error) | (umlScene() == NULL)) { - return; - } - // If the association is to self and the line ends are on the same region then - // use a different calculation. - if (isSelf() && - m_role[RoleType::A].m_WidgetRegion == m_role[RoleType::B].m_WidgetRegion) { - UMLWidget * pWidget = m_role[RoleType::A].umlWidget; - qreal x = pWidget->x(); - qreal y = pWidget->y(); - qreal wh = pWidget->height(); - qreal ww = pWidget->width(); - int size = m_associationLine->count(); - // See if above widget ok to place assoc. - switch( m_role[RoleType::A].m_WidgetRegion ) { - case Uml::Region::North: - m_associationLine->setPoint( 0, QPointF( x + ( ww / 4 ), y ) ); - m_associationLine->setPoint( size - 1, QPointF(x + ( ww * 3 / 4 ), y ) ); - break; - - case Uml::Region::South: - m_associationLine->setPoint( 0, QPointF( x + ( ww / 4 ), y + wh ) ); - m_associationLine->setPoint( size - 1, QPointF( x + ( ww * 3 / 4 ), y + wh ) ); - break; - - case Uml::Region::East: - m_associationLine->setPoint( 0, QPointF( x + ww, y + ( wh / 4 ) ) ); - m_associationLine->setPoint( size - 1, QPointF( x + ww, y + ( wh * 3 / 4 ) ) ); - break; - - case Uml::Region::West: - m_associationLine->setPoint( 0, QPointF( x, y + ( wh / 4 ) ) ); - m_associationLine->setPoint( size - 1, QPointF( x, y + ( wh * 3 / 4 ) ) ); - break; - default: - break; - }//end switch - - return; - } - - WidgetRole& robj = m_role[role]; - UMLWidget * pWidget = robj.umlWidget; - - robj.m_nIndex = index; - robj.m_nTotalCount = totalCount; - qreal x = pWidget->x(); - qreal y = pWidget->y(); - qreal ww = pWidget->width(); - qreal wh = pWidget->height(); - const bool angular = Settings::optionState().generalState.angularlines; - qreal ch = 0; - qreal cw = 0; - if (angular) { - uint nind = (role == RoleType::A ? 1 : m_associationLine->count() - 2); - QPointF neighbour = m_associationLine->point(nind); - if (neighbour.x() < x) - cw = 0; - else if (neighbour.x() > x + ww) - cw = 0 + ww; - else - cw = neighbour.x() - x; - if (neighbour.y() < y) - ch = 0; - else if (neighbour.y() > y + wh) - ch = 0 + wh; - else - ch = neighbour.y() - y; - } else { - ch = wh * index / totalCount; - cw = ww * index / totalCount; - } - - qreal newX = x + cw; - qreal newY = y + ch; - - QPointF pt; - if (angular) { - pt = QPointF(newX, newY); - } else { - UMLWidget *pWidgetA = m_role[RoleType::A].umlWidget; - UMLWidget *pWidgetB = m_role[RoleType::B].umlWidget; - QList polyListA = pWidgetA->shape().toSubpathPolygons(); - QPolygonF polyA = polyListA.at(0); - if (polyListA.size() > 1) { - for (int i = 1; i < polyListA.size(); i++) { - polyA = polyA.united(polyListA.at(i)); - } - } - polyA = polyA.translated(pWidgetA->pos()); - QList polyListB = pWidgetB->shape().toSubpathPolygons(); - QPolygonF polyB = polyListB.at(0); - if (polyListB.size() > 1) { - for (int i = 1; i < polyListB.size(); i++) { - polyB = polyB.united(polyListB.at(i)); - } - } - polyB = polyB.translated(pWidgetB->pos()); - QLineF nearestPoints = Widget_Utils::closestPoints(polyA, polyB); - if (nearestPoints.isNull()) { - uError() << "Widget_Utils::closestPoints failed, falling back to simple widget positions"; - switch(region) { - case Uml::Region::West: - pt.setX(x); - pt.setY(newY); - break; - case Uml::Region::North: - pt.setX(newX); - pt.setY(y); - break; - case Uml::Region::East: - pt.setX(x + ww); - pt.setY(newY); - break; - case Uml::Region::South: - pt.setX(newX); - pt.setY(y + wh); - break; - case Uml::Region::Center: - pt.setX(x + ww / 2); - pt.setY(y + wh / 2); - break; - default: - break; - } - } else { - if (role == RoleType::A) - pt = nearestPoints.p1(); - else - pt = nearestPoints.p2(); - } - } - if (role == RoleType::A) { - m_associationLine->setPoint(0, pt); - } - else { - m_associationLine->setPoint(m_associationLine->count() - 1, pt); - } -} - -/** - * Sets the state of whether the widget is selected. - * - * @param _select The state of whether the widget is selected. - */ -void AssociationWidget::setSelected(bool _select /* = true */) -{ - WidgetBase::setSelected(_select); - if ( m_nameWidget) - m_nameWidget->setSelected( _select ); - if ( m_role[RoleType::A].roleWidget ) - m_role[RoleType::A].roleWidget->setSelected( _select ); - if ( m_role[RoleType::B].roleWidget ) - m_role[RoleType::B].roleWidget->setSelected( _select ); - if ( m_role[RoleType::A].multiplicityWidget ) - m_role[RoleType::A].multiplicityWidget->setSelected( _select ); - if ( m_role[RoleType::B].multiplicityWidget ) - m_role[RoleType::B].multiplicityWidget->setSelected( _select ); - if ( m_role[RoleType::A].changeabilityWidget) - m_role[RoleType::A].changeabilityWidget->setSelected( _select ); - if ( m_role[RoleType::B].changeabilityWidget) - m_role[RoleType::B].changeabilityWidget->setSelected( _select ); - - // Update the docwindow for this association. - // This is done last because each of the above setSelected calls - // overwrites the docwindow, but we want the main association doc - // to win. - if (_select) { - if (m_scene->selectedCount() == 0) - UMLApp::app()->docWindow()->showDocumentation(this, false); - } else - UMLApp::app()->docWindow()->updateDocumentation(true); - - m_associationLine->setSelected(_select); - if (! _select) { - // For now, if _select is true we don't make the assoc class line - // selected. But that's certainly open for discussion. - // At any rate, we need to deselect the assoc class line - // if _select is false. - selectAssocClassLine(false); - } - UMLApp::app()->document()->writeToStatusBar(_select ? i18n("Press Ctrl with left mouse click to delete a point") : QString()); -} - -/** - * Reimplement method from WidgetBase in order to check owned floating texts. - * - * @param p Point to be checked. - * - * @return m_nameWidget if m_nameWidget is non NULL and m_nameWidget->onWidget(p) returns non NULL; - * m_role[0].(multiplicity|changeability|role)Widget if the resp. widget is non NULL and - * its onWidget(p) returns non NULL; - * m_role[1].(multiplicity|changeability|role)Widget if the resp. widget is non NULL and - * its onWidget(p) returns non NULL; - * else NULL. - */ -UMLWidget* AssociationWidget::onWidget(const QPointF &p) -{ - if (m_nameWidget && m_nameWidget->onWidget(p)) { - return m_nameWidget; - } - for (int i = 0; i <= 1; i++) { - const WidgetRole& r = m_role[i]; - if (r.multiplicityWidget && r.multiplicityWidget->onWidget(p)) - return r.multiplicityWidget; - if (r.changeabilityWidget && r.changeabilityWidget->onWidget(p)) - return r.changeabilityWidget; - if (r.roleWidget && r.roleWidget->onWidget(p)) - return r.roleWidget; - } - return NULL; -} - -/** - * Returns true if the given point is on the connecting line to - * the association class. Returns false if there is no association - * class attached, or if the given point is not on the connecting - * line. - */ -bool AssociationWidget::onAssocClassLine(const QPointF &point) -{ - bool onLine = false; - if (m_pAssocClassLine) { -//:TODO: -// const QPointF mapped = m_pAssocClassLine->mapFromParent(point); -// bool onLine = m_pAssocClassLine->contains(mapped); -// return onLine; - UMLSceneItemList list = m_scene->collisions(point); - UMLSceneItemList::iterator end(list.end()); - for (UMLSceneItemList::iterator item_it(list.begin()); item_it != end; ++item_it) { - if (*item_it == m_pAssocClassLine) { - onLine = true; - break; - } - } - } - DEBUG(DBG_SRC) << onLine; - return onLine; -} - -/** - * Returns true if the given point is on the association line. - * A circle (rectangle) around the point is used to obtain more tolerance. - * @param point the point to check - * @return flag whether point is on association line - */ -bool AssociationWidget::onAssociation(const QPointF& point) -{ - // check the path - const qreal diameter(4.0); - QPainterPath path = m_associationLine->shape(); - if (path.contains(point)) { - DEBUG(DBG_SRC) << "on path"; - return true; - } - // check also the points - if (m_associationLine->layout() == AssociationLine::Spline) { - if (m_associationLine->closestPointIndex(point, diameter) > -1) { - DEBUG(DBG_SRC) << "on spline point"; - return true; - } - } - return onAssocClassLine(point); -} - -/** - * Set all association points to x coordinate. - */ -void AssociationWidget::setXEntireAssoc(qreal x) -{ - for (int i = 0; i < m_associationLine->count(); ++i) { - QPointF p = m_associationLine->point(i); - p.setX(x); - m_associationLine->setPoint(i, p); - } -} - -/** - * Set all association points to y coordinate. - */ -void AssociationWidget::setYEntireAssoc(qreal y) -{ - for (int i = 0; i < m_associationLine->count(); ++i) { - QPointF p = m_associationLine->point(i); - p.setY(y); - m_associationLine->setPoint(i, p); - } -} - -/** - * Moves all the mid points (all expcept start /end) by the given amount. - */ -void AssociationWidget::moveMidPointsBy(qreal x, qreal y) -{ - int pos = m_associationLine->count() - 1; - for (int i = 1; i < (int)pos; ++i) { - QPointF p = m_associationLine->point( i ); - qreal newX = p.x() + x; - qreal newY = p.y() + y; - p.setX( newX ); - p.setY( newY ); - m_associationLine->setPoint( i, p ); - } -} - -/** - * Moves the entire association by the given offset. - */ -void AssociationWidget::moveEntireAssoc(qreal x, qreal y) -{ - //TODO: ADD SUPPORT FOR ASSOC. ON SEQ. DIAGRAMS WHEN NOTES BACK IN. - moveMidPointsBy(x, y); - calculateEndingPoints(); - calculateNameTextSegment(); - resetTextPositions(); -} - -/** - * Returns the bounding rectangle of all segments of the association. - */ -QRectF AssociationWidget::boundingRect() const -{ - return m_associationLine->boundingRect(); -} - -/** - * Returns the shape of all segments of the association. - */ -QPainterPath AssociationWidget::shape() const -{ - return m_associationLine->shape(); -} - -/** - * Connected to UMLClassifier::attributeRemoved() or UMLEntity::constraintRemoved() - * in case this AssociationWidget is linked to a clasifier list item - * (an attribute or a foreign key constraint) - * - * @param obj The UMLClassifierListItem removed. - */ -void AssociationWidget::slotClassifierListItemRemoved(UMLClassifierListItem* obj) -{ - if (obj != m_umlObject) { - DEBUG(DBG_SRC) << "obj=" << obj << ": m_umlObject=" << m_umlObject; - return; - } - m_umlObject = 0; - m_scene->removeAssoc(this); -} - -/** - * Connected to UMLObject::modified() in case this - * AssociationWidget is linked to a classifer's attribute type. - */ -void AssociationWidget::slotAttributeChanged() -{ - UMLAttribute *attr = attribute(); - if (attr == NULL) { - uError() << "attribute() returns NULL"; - return; - } - setVisibility(attr->visibility(), RoleType::B); - setRoleName(attr->name(), RoleType::B); -} - -void AssociationWidget::clipSize() -{ - if (m_nameWidget) - m_nameWidget->clipSize(); - - if (m_role[RoleType::A].multiplicityWidget) - m_role[RoleType::A].multiplicityWidget->clipSize(); - - if (m_role[RoleType::B].multiplicityWidget) - m_role[RoleType::B].multiplicityWidget->clipSize(); - - if (m_role[RoleType::A].roleWidget) - m_role[RoleType::A].roleWidget->clipSize(); - - if (m_role[RoleType::B].roleWidget) - m_role[RoleType::B].roleWidget->clipSize(); - - if (m_role[RoleType::A].changeabilityWidget) - m_role[RoleType::A].changeabilityWidget->clipSize(); - - if (m_role[RoleType::B].changeabilityWidget) - m_role[RoleType::B].changeabilityWidget->clipSize(); - - if (m_associationClass) - m_associationClass->clipSize(); -} - -/** - * Event handler for context menu events, called from the line segments. - */ -void AssociationWidget::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) -{ - const Uml::AssociationType::Enum type = associationType(); - ListPopupMenu::MenuType menuType = ListPopupMenu::mt_Association_Selected; - if ((type == Uml::AssociationType::Anchor) || - onAssocClassLine(event->scenePos())) { - menuType = ListPopupMenu::mt_Anchor; - } else if (isCollaboration()) { - menuType = ListPopupMenu::mt_Collaboration_Message; - } else if (!association()) { - menuType = ListPopupMenu::mt_AttributeAssociation; - } else if (AssocRules::allowRole(type)) { - menuType = ListPopupMenu::mt_FullAssociation; - } - - event->accept(); - DEBUG(DBG_SRC) << "menue type = " << ListPopupMenu::toString(menuType) - << " / association = " << Uml::AssociationType::toString(type); - - UMLScene *scene = umlScene(); - QWidget *parent = 0; - if (scene) { - parent = scene->activeView(); - } - - if (!isSelected() && scene && !scene->selectedItems().isEmpty()) { - Qt::KeyboardModifiers forSelection = (Qt::ControlModifier | Qt::ShiftModifier); - if ((event->modifiers() & forSelection) == 0) { - scene->clearSelection(); - } - } - setSelected(true); - m_eventScenePos = event->scenePos(); - ListPopupMenu popup(parent, menuType, this); - QAction *triggered = popup.exec(event->screenPos()); - ListPopupMenu *parentMenu = ListPopupMenu::menuFromAction(triggered); - - if (!parentMenu) { - uWarning() << "Action's data field does not contain ListPopupMenu pointer"; - return; - } - - WidgetBase *ownerWidget = parentMenu->ownerWidget(); - // assert because logic is based on only WidgetBase being the owner of - // ListPopupMenu actions executed in this context menu. - Q_ASSERT_X(ownerWidget != 0, "AssociationWidget::contextMenuEvent", - "ownerWidget is null which means action belonging to UMLView, UMLScene" - " or UMLObject is the one triggered in ListPopupMenu"); - - ownerWidget->slotMenuSelection(triggered); -} - -/** - * Reimplemented event handler for hover enter events. - */ -void AssociationWidget::hoverEnterEvent(QGraphicsSceneHoverEvent *event) -{ - associationLine()->hoverEnterEvent(event); -} - -/** - * Reimplemented event handler for hover leave events. - */ -void AssociationWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) -{ - associationLine()->hoverLeaveEvent(event); -} - -/** - * Reimplemented event handler for hover move events. - */ -void AssociationWidget::hoverMoveEvent(QGraphicsSceneHoverEvent *event) -{ - associationLine()->hoverMoveEvent(event); -} - -/** - * Saves this widget to the "assocwidget" XMI element. - */ -void AssociationWidget::saveToXMI(QDomDocument &qDoc, QDomElement &qElement) -{ - QDomElement assocElement = qDoc.createElement(QLatin1String("assocwidget")); - - WidgetBase::saveToXMI(qDoc, assocElement); - LinkWidget::saveToXMI(qDoc, assocElement); - if (m_umlObject) { - assocElement.setAttribute(QLatin1String("xmi.id"), Uml::ID::toString(m_umlObject->id())); - } - assocElement.setAttribute(QLatin1String("type"), associationType()); - if (!association()) { - assocElement.setAttribute(QLatin1String("visibilityA"), visibility(RoleType::A)); - assocElement.setAttribute(QLatin1String("visibilityB"), visibility(RoleType::B)); - assocElement.setAttribute(QLatin1String("changeabilityA"), changeability(RoleType::A)); - assocElement.setAttribute(QLatin1String("changeabilityB"), changeability(RoleType::B)); - if (m_umlObject == NULL) { - assocElement.setAttribute(QLatin1String("roleAdoc"), roleDocumentation(RoleType::A)); - assocElement.setAttribute(QLatin1String("roleBdoc"), roleDocumentation(RoleType::B)); - assocElement.setAttribute(QLatin1String("documentation"), documentation()); - } - } - assocElement.setAttribute(QLatin1String("widgetaid"), Uml::ID::toString(widgetIDForRole(RoleType::A))); - assocElement.setAttribute(QLatin1String("widgetbid"), Uml::ID::toString(widgetIDForRole(RoleType::B))); - assocElement.setAttribute(QLatin1String("indexa"), m_role[RoleType::A].m_nIndex); - assocElement.setAttribute(QLatin1String("indexb"), m_role[RoleType::B].m_nIndex); - assocElement.setAttribute(QLatin1String("totalcounta"), m_role[RoleType::A].m_nTotalCount); - assocElement.setAttribute(QLatin1String("totalcountb"), m_role[RoleType::B].m_nTotalCount); - m_associationLine->saveToXMI(qDoc, assocElement); - - if (m_nameWidget) { - m_nameWidget->saveToXMI(qDoc, assocElement); - } - - if (multiplicityWidget(RoleType::A)) { - multiplicityWidget(RoleType::A)->saveToXMI(qDoc, assocElement); - } - - if (multiplicityWidget(RoleType::B)) { - multiplicityWidget(RoleType::B)->saveToXMI(qDoc, assocElement); - } - - if (roleWidget(RoleType::A)) { - roleWidget(RoleType::A)->saveToXMI(qDoc, assocElement); - } - - if (roleWidget(RoleType::B)) { - roleWidget(RoleType::B)->saveToXMI(qDoc, assocElement); - } - - if (changeabilityWidget(RoleType::A)) { - changeabilityWidget(RoleType::A)->saveToXMI(qDoc, assocElement); - } - - if (changeabilityWidget(RoleType::B)) { - changeabilityWidget(RoleType::B)->saveToXMI(qDoc, assocElement); - } - - if (m_associationClass) { - QString acid = Uml::ID::toString(m_associationClass->id()); - assocElement.setAttribute(QLatin1String("assocclass"), acid); - assocElement.setAttribute(QLatin1String("aclsegindex"), m_nLinePathSegmentIndex); - } - - qElement.appendChild(assocElement); -} - -/** - * Uses the supplied widgetList for resolving - * the role A and role B widgets. (The other loadFromXMI() queries - * the UMLView for these widgets.) - * Required for clipboard operations. - */ -bool AssociationWidget::loadFromXMI(QDomElement& qElement, - const UMLWidgetList& widgets, - const MessageWidgetList* messages) -{ - if (!WidgetBase::loadFromXMI(qElement)) { - return false; - } - - if (!LinkWidget::loadFromXMI(qElement)) { - return false; - } - - // load child widgets first - QString widgetaid = qElement.attribute(QLatin1String("widgetaid"), QLatin1String("-1")); - QString widgetbid = qElement.attribute(QLatin1String("widgetbid"), QLatin1String("-1")); - Uml::ID::Type aId = Uml::ID::fromString(widgetaid); - Uml::ID::Type bId = Uml::ID::fromString(widgetbid); - UMLWidget *pWidgetA = Widget_Utils::findWidget(aId, widgets, messages); - if (!pWidgetA) { - uError() << "cannot find widget for roleA id " << Uml::ID::toString(aId); - return false; - } - UMLWidget *pWidgetB = Widget_Utils::findWidget(bId, widgets, messages); - if (!pWidgetB) { - uError() << "cannot find widget for roleB id " << Uml::ID::toString(bId); - return false; - } - setWidgetForRole(pWidgetA, RoleType::A); - setWidgetForRole(pWidgetB, RoleType::B); - - QString type = qElement.attribute(QLatin1String("type"), QLatin1String("-1")); - Uml::AssociationType::Enum aType = Uml::AssociationType::fromInt(type.toInt()); - - QString id = qElement.attribute(QLatin1String("xmi.id"), QLatin1String("-1")); - bool oldStyleLoad = false; - if (id == QLatin1String("-1")) { - // xmi.id not present, ergo either a pure widget association, - // or old (pre-1.2) style: - // Everything is loaded from the AssociationWidget. - // UMLAssociation may or may not be saved - if it is, it's a dummy. - // Create the UMLAssociation if both roles are UML objects; - // else load the info locally. - - if (Uml::AssociationType::hasUMLRepresentation(aType)) { - // lack of an association in our widget AND presence of - // both uml objects for each role clearly identifies this - // as reading in an old-school file. Note it as such, and - // create, and add, the UMLAssociation for this widget. - // Remove this special code when backwards compatibility - // with older files isn't important anymore. -b.t. - UMLObject* umlRoleA = pWidgetA->umlObject(); - UMLObject* umlRoleB = pWidgetB->umlObject(); - if (!m_umlObject && umlRoleA && umlRoleB) { - oldStyleLoad = true; // flag for further special config below - if (aType == AssociationType::Aggregation || aType == AssociationType::Composition) { - uWarning()<<" Old Style save file? swapping roles on association widget"<umlObject(); - umlRoleB = pWidgetB->umlObject(); - } - - setUMLAssociation(umlDoc()->createUMLAssociation(umlRoleA, umlRoleB, aType)); - } - } - - setDocumentation(qElement.attribute(QLatin1String("documentation"))); - setRoleDocumentation(qElement.attribute(QLatin1String("roleAdoc")), RoleType::A); - setRoleDocumentation(qElement.attribute(QLatin1String("roleBdoc")), RoleType::B); - - // visibility defaults to Public if it cant set it here.. - QString visibilityA = qElement.attribute(QLatin1String("visibilityA"), QLatin1String("0")); - int vis = visibilityA.toInt(); - if (vis >= 200) { // bkwd compat. - vis -= 200; - } - setVisibility((Uml::Visibility::Enum)vis, RoleType::A); - - QString visibilityB = qElement.attribute(QLatin1String("visibilityB"), QLatin1String("0")); - vis = visibilityB.toInt(); - if (vis >= 200) { // bkwd compat. - vis -= 200; - } - setVisibility((Uml::Visibility::Enum)vis, RoleType::B); - - // Changeability defaults to "Changeable" if it cant set it here.. - QString changeabilityA = qElement.attribute(QLatin1String("changeabilityA"), QLatin1String("0")); - if (changeabilityA.toInt() > 0) - setChangeability(Uml::Changeability::fromInt(changeabilityA.toInt()), RoleType::A); - - QString changeabilityB = qElement.attribute(QLatin1String("changeabilityB"), QLatin1String("0")); - if (changeabilityB.toInt() > 0) - setChangeability(Uml::Changeability::fromInt(changeabilityB.toInt()), RoleType::B); - - } else { - - // we should disconnect any prior association (can this happen??) - if (m_umlObject && m_umlObject->baseType() == UMLObject::ot_Association) { - UMLAssociation *umla = association(); - umla->disconnect(this); - umla->nrof_parent_widgets--; - } - - // New style: The xmi.id is a reference to the UMLAssociation. - // If the UMLObject is not found right now, we try again later - // during the type resolution pass - see activate(). - m_nId = Uml::ID::fromString(id); - UMLObject *myObj = umlDoc()->findObjectById(m_nId); - if (myObj) { - const UMLObject::ObjectType ot = myObj->baseType(); - if (ot != UMLObject::ot_Association) { - setUMLObject(myObj); - } else { - UMLAssociation * myAssoc = static_cast(myObj); - setUMLAssociation(myAssoc); - if (type == QLatin1String("-1")) - aType = myAssoc->getAssocType(); - } - } - } - - setAssociationType(aType); - - QString indexa = qElement.attribute(QLatin1String("indexa"), QLatin1String("0")); - QString indexb = qElement.attribute(QLatin1String("indexb"), QLatin1String("0")); - QString totalcounta = qElement.attribute(QLatin1String("totalcounta"), QLatin1String("0")); - QString totalcountb = qElement.attribute(QLatin1String("totalcountb"), QLatin1String("0")); - m_role[RoleType::A].m_nIndex = indexa.toInt(); - m_role[RoleType::B].m_nIndex = indexb.toInt(); - m_role[RoleType::A].m_nTotalCount = totalcounta.toInt(); - m_role[RoleType::B].m_nTotalCount = totalcountb.toInt(); - - QString assocclassid = qElement.attribute(QLatin1String("assocclass")); - if (! assocclassid.isEmpty()) { - Uml::ID::Type acid = Uml::ID::fromString(assocclassid); - UMLWidget *w = Widget_Utils::findWidget(acid, widgets); - if (w) { - ClassifierWidget* aclWidget = static_cast(w); - QString aclSegIndex = qElement.attribute(QLatin1String("aclsegindex"), QLatin1String("0")); - createAssocClassLine(aclWidget, aclSegIndex.toInt()); - } else { - uError() << "cannot find assocclass " << assocclassid; - } - } - - //now load child elements - QDomNode node = qElement.firstChild(); - QDomElement element = node.toElement(); - while (!element.isNull()) { - QString tag = element.tagName(); - if (tag == QLatin1String("linepath")) { - if (!m_associationLine->loadFromXMI(element)) { - return false; - } - } else if (tag == QLatin1String("floatingtext") || - tag == QLatin1String("UML:FloatingTextWidget")) { // for bkwd compatibility - QString r = element.attribute(QLatin1String("role"), QLatin1String("-1")); - if (r == QLatin1String("-1")) - return false; - Uml::TextRole::Enum role = Uml::TextRole::fromInt(r.toInt()); - FloatingTextWidget *ft = new FloatingTextWidget(m_scene, role, QString(), Uml::ID::Reserved); - if (! ft->loadFromXMI(element)) { - // Most likely cause: The FloatingTextWidget is empty. - delete ft; - node = element.nextSibling(); - element = node.toElement(); - continue; - } - // always need this - ft->setParentItem(this); - ft->setLink(this); - ft->setSequenceNumber(m_SequenceNumber); - ft->setFontCmd(ft->font()); - - switch(role) { - case Uml::TextRole::MultiA: - m_role[RoleType::A].multiplicityWidget = ft; - if (oldStyleLoad) - setMultiplicity(m_role[RoleType::A].multiplicityWidget->text(), RoleType::A); - break; - - case Uml::TextRole::MultiB: - m_role[RoleType::B].multiplicityWidget = ft; - if (oldStyleLoad) - setMultiplicity(m_role[RoleType::B].multiplicityWidget->text(), RoleType::B); - break; - - case Uml::TextRole::ChangeA: - m_role[RoleType::A].changeabilityWidget = ft; - break; - - case Uml::TextRole::ChangeB: - m_role[RoleType::B].changeabilityWidget = ft; - break; - - case Uml::TextRole::Name: - m_nameWidget = ft; - if (oldStyleLoad) - setName(m_nameWidget->text()); - break; - - case Uml::TextRole::Coll_Message: - case Uml::TextRole::Coll_Message_Self: - m_nameWidget = ft; - ft->setLink(this); - ft->setActivated(); - if (FloatingTextWidget::isTextValid(ft->text())) - ft->show(); - else - ft->hide(); - break; - - case Uml::TextRole::RoleAName: - m_role[RoleType::A].roleWidget = ft; - setRoleName(ft->text(), RoleType::A); - break; - case Uml::TextRole::RoleBName: - m_role[RoleType::B].roleWidget = ft; - setRoleName(ft->text(), RoleType::B); - break; - default: - DEBUG(DBG_SRC) << "unexpected FloatingTextWidget (TextRole::Enum " << role << ")"; - delete ft; - break; - } - } - node = element.nextSibling(); - element = node.toElement(); - } - - return true; -} - -/** - * Queries the UMLView for resolving the role A and role B widgets. - * .... - */ -bool AssociationWidget::loadFromXMI(QDomElement& qElement) -{ - UMLScene *scene = umlScene(); - if (scene) { - const UMLWidgetList& widgetList = scene->widgetList(); - const MessageWidgetList& messageList = scene->messageList(); - return loadFromXMI(qElement, widgetList, &messageList); - } - else { - DEBUG(DBG_SRC) << "This isn't on UMLScene yet, so can neither fetch" - "messages nor widgets on umlscene"; - return false; - } -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/associationwidget.h umbrello-kf6-15.08.1/umbrello/widgets/associationwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/associationwidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/associationwidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,328 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef ASSOCIATIONWIDGET_H -#define ASSOCIATIONWIDGET_H - -#include "associationwidgetlist.h" -#include "linkwidget.h" -#include "messagewidgetlist.h" -#include "umlwidgetlist.h" -#include "widgetbase.h" - -class AssociationLine; -class ClassifierWidget; -class UMLScene; -class UMLAssociation; -class UMLAttribute; -class UMLClassifierListItem; -class UMLOperation; - -/** - * This class represents an association inside a diagram. - * - * Constructor is made non accessible: - * Users shall use the static create() methods for constructing AssociationWidgets. - * - * Associations exist not only between UML objects. For example, when a Note is - * attached to a UML object, the Note itself is not a UML object. - * This class supports both kinds of associations. An association where one or - * both roles are not a UML object is called a "pure widget association". - * - * An AssociationWidget where both roles are UML objects has a corresponding - * UMLAssociation. The UMLAssociation can be retrieved using the getAssociation - * method. - * A pure widget association does not have a corresponding UMLAssociation. - * The getAssociation method returns NULL in this case. - * - * @author Gustavo Madrigal - * @author Gopala Krishna - * @short This class represents an association inside a diagram. - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class AssociationWidget : public WidgetBase, public LinkWidget -{ - Q_OBJECT -public: - static AssociationWidget* create(UMLScene *scene); - static AssociationWidget* create - (UMLScene *scene, UMLWidget* WidgetA, - Uml::AssociationType::Enum assocType, UMLWidget* WidgetB, - UMLObject *umlobject = NULL); - - virtual ~AssociationWidget(); - - virtual void setUMLObject(UMLObject *obj); - - //---------- LinkWidget Interface methods implementation from now on. - - virtual void lwSetFont(QFont font); - virtual UMLClassifier *operationOwner(); - - virtual UMLOperation *operation(); - virtual void setOperation(UMLOperation *op); - - virtual QString customOpText(); - virtual void setCustomOpText(const QString &opText); - - virtual void resetTextPositions(); - - virtual void setMessageText(FloatingTextWidget *ft); - virtual void setText(FloatingTextWidget *ft, const QString &newText); - - virtual void showPropertiesDialog(); - - virtual QString lwOperationText(); - virtual UMLClassifier *lwClassifier(); - virtual void setOperationText(const QString &op); - - virtual void constrainTextPos(qreal &textX, qreal &textY, - qreal textWidth, qreal textHeight, - Uml::TextRole::Enum tr); - - virtual void calculateNameTextSegment(); - - //---------- End LinkWidget Interface methods implementation. - - UMLAssociation* association() const; - UMLAttribute* attribute() const; - -// AssociationWidget& operator=(const AssociationWidget& other); - bool operator==(const AssociationWidget& other) const; - bool operator!=(AssociationWidget& other) const; - - FloatingTextWidget* textWidgetByRole(Uml::TextRole::Enum tr) const; - - FloatingTextWidget* nameWidget() const; - QString name() const; - void setName(const QString &strRole); - void setStereotype(const QString &stereo); - - FloatingTextWidget* roleWidget(Uml::RoleType::Enum role) const; - QString roleName(Uml::RoleType::Enum role) const; - void setRoleName(const QString &strRole, Uml::RoleType::Enum role); - - QString roleDocumentation(Uml::RoleType::Enum role) const; - void setRoleDocumentation(const QString& doc, Uml::RoleType::Enum role); - - FloatingTextWidget* multiplicityWidget(Uml::RoleType::Enum role) const; - QString multiplicity(Uml::RoleType::Enum role) const; - void setMultiplicity(const QString& text, Uml::RoleType::Enum role); - - Uml::Visibility::Enum visibility(Uml::RoleType::Enum role) const; - void setVisibility(Uml::Visibility::Enum value, Uml::RoleType::Enum role); - - FloatingTextWidget* changeabilityWidget(Uml::RoleType::Enum role) const; - Uml::Changeability::Enum changeability(Uml::RoleType::Enum role) const; - void setChangeability(Uml::Changeability::Enum value, Uml::RoleType::Enum role); - - Uml::ID::Type widgetIDForRole(Uml::RoleType::Enum role) const; - Uml::ID::Type widgetLocalIDForRole(Uml::RoleType::Enum role) const; - UMLWidget* widgetForRole(Uml::RoleType::Enum role) const; - void setWidgetForRole(UMLWidget* widget, Uml::RoleType::Enum role); - - bool setWidgets(UMLWidget* widgetA, Uml::AssociationType::Enum assocType, UMLWidget* widgetB); - - bool containsAsEndpoint(UMLWidget* widget); - - Uml::AssociationType::Enum associationType() const; - void setAssociationType(Uml::AssociationType::Enum type); - - bool isCollaboration() const; - bool isSelf() const; - - QString toString() const; - - bool isActivated() const; - void setActivated(bool active); - - AssociationLine* associationLine() const; - - virtual bool activate(); - virtual QRectF boundingRect() const; - virtual QPainterPath shape() const; - - void widgetMoved(UMLWidget* widget, qreal x, qreal y); - - void saveIdealTextPositions(); - - UMLWidget* onWidget(const QPointF &p); - bool onAssociation(const QPointF& point); - bool onAssocClassLine(const QPointF& point); - - void createAssocClassLine(); - void createAssocClassLine(ClassifierWidget* classifierWidget, - int linePathSegmentIndex); - - void selectAssocClassLine(bool sel = true); - void removeAssocClassLine(); - void computeAssocClassLine(); - - void setXEntireAssoc(qreal x); - void setYEntireAssoc(qreal y); - - void moveMidPointsBy(qreal x, qreal y); - void moveEntireAssoc(qreal x, qreal y); - - QFont font() const; - - virtual void setTextColor(const QColor &color); - - void calculateEndingPoints(); - - void clipSize(); - - bool loadFromXMI(QDomElement& qElement, const UMLWidgetList& widgets, - const MessageWidgetList* messages); - virtual bool loadFromXMI(QDomElement& qElement); - virtual void saveToXMI(QDomDocument &qDoc, QDomElement &qElement); - - void cleanup(); - - bool isPointAddable(); - bool isPointRemovable(); - - //:TODO: the following four methods should be protected - virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); - virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event); - virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); - virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); - - virtual void setSelected(bool _select); -public Q_SLOTS: //:TODO: all virtual? - virtual void slotMenuSelection(QAction* action); - void slotClassifierListItemRemoved(UMLClassifierListItem* obj); - void slotAttributeChanged(); - - void syncToModel(); - -protected: - virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *event); - - virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event); - virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); - virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event); - -private: - QPointF calculateTextPosition(Uml::TextRole::Enum role); - void setTextPosition(Uml::TextRole::Enum role); - void setTextPositionRelatively(Uml::TextRole::Enum role, const QPointF &oldPosition); - void setFloatingText(Uml::TextRole::Enum role, const QString& text, FloatingTextWidget* &ft); - - AssociationWidget(UMLScene *scene); - - void setUMLAssociation(UMLAssociation * assoc); - - void mergeAssociationDataIntoUMLRepresentation(); - - static Uml::Region::Enum findPointRegion(const QRectF& rect, const QPointF& pos); - static qreal findInterceptOnEdge(const QRectF &rect, Uml::Region::Enum region, const QPointF &point); - static QLineF::IntersectType intersect(const QRectF &rect, const QLineF &line, - QPointF* intersectionPoint); - - void moveEvent(QGraphicsSceneMouseEvent *me); - - Uml::TextRole::Enum calculateNameType(Uml::TextRole::Enum defaultRoleType); - - static QPointF swapXY(const QPointF &p); - - // not used at the moment - // static QPointF calculatePointAtDistance(const QPointF &P1, const QPointF &P2, float Distance); - // static QPointF calculatePointAtDistanceOnPerpendicular(const QPointF &P1, const QPointF &P2, float Distance); - // static float perpendicularProjection(const QPointF& P1, const QPointF& P2, const QPointF& P3, QPointF& ResultingPoint); - - static QPointF midPoint(const QPointF& p0, const QPointF& p1); - - void createPointsSelfAssociation(); - void updatePointsSelfAssociation(); - void createPointsException(); - void updatePointsException(); - - /** - * The WidgetRole struct gathers all information pertaining to the role. - * The AssociationWidget class contains two WidgetRole objects, one for each - * side of the association (A and B). - */ - struct WidgetRole { - - FloatingTextWidget* multiplicityWidget; ///< information regarding multiplicity - FloatingTextWidget* changeabilityWidget; ///< information regarding changeability - FloatingTextWidget* roleWidget; ///< role's label of this association - - UMLWidget* umlWidget; ///< UMLWidget at this role's side of this association - - Uml::Region::Enum m_WidgetRegion; ///< region of this role's widget - - int m_nIndex; ///< the index of where the line is on the region for this role - int m_nTotalCount; ///< total amount of associations on the region this role's line is on - - // The following items are only used if m_pObject is not set. - Uml::Visibility::Enum visibility; - Uml::Changeability::Enum changeability; - QString roleDocumentation; - - }; - - void updateRegionLineCount(int index, int totalCount, - Uml::Region::Enum region, Uml::RoleType::Enum role); - - void updateAssociations(int totalCount, Uml::Region::Enum region, Uml::RoleType::Enum role); - - int getRegionCount(Uml::Region::Enum region, Uml::RoleType::Enum role); - - void doUpdates(const QPointF &otherP, Uml::RoleType::Enum role); - - void setChangeWidget(const QString &strChangeWidget, Uml::RoleType::Enum role); - - bool checkAddPoint(const QPointF &scenePos); - bool checkRemovePoint(const QPointF &scenePos); - - bool linePathStartsAt(const UMLWidget* widget); - - void insertIntoLists(qreal position, const AssociationWidget* assoc); - - qreal m_positions[100]; ///< auxiliary variable for updateAssociations() - int m_positions_len; ///< auxiliary variable for updateAssociations() - AssociationWidgetList m_ordered; ///< auxiliary variable for updateAssociations() - - bool m_activated; ///< flag which is true if the activate method has been called for this class instance - - /** - * When the association has a Role Floating Text this text should move - * when the AssociationLine moves but only if the closest segment to the - * role text moves. - * This segment is: - * m_associationLine[m_unNameLineSegment] -- m_associationLine[m_unNameLineSegment+1] - */ - int m_unNameLineSegment; - - QPointF m_oldNamePoint; ///< Position of name floatingtext saved by saveIdealTextPositions() - QPointF m_oldMultiAPoint; ///< Position of role A multiplicity floatingtext saved by saveIdealTextPositions() - QPointF m_oldMultiBPoint; ///< Position of role B multiplicity floatingtext saved by saveIdealTextPositions() - QPointF m_oldChangeAPoint; ///< Position of role A changeability floatingtext saved by saveIdealTextPositions() - QPointF m_oldChangeBPoint; ///< Position of role B changeability floatingtext saved by saveIdealTextPositions() - QPointF m_oldRoleAPoint; ///< Position of role A name floatingtext saved by saveIdealTextPositions() - QPointF m_oldRoleBPoint; ///< Position of role B name floatingtext saved by saveIdealTextPositions() - - int m_nLinePathSegmentIndex; ///< anchor for m_pAssocClassLine - QGraphicsLineItem *m_pAssocClassLine; ///< used for connecting assoc. class - QGraphicsRectItem *m_pAssocClassLineSel0; ///< selection decoration for the start point of the assoc. class line - QGraphicsRectItem *m_pAssocClassLineSel1; ///< selection decoration for the end point of the assoc. class line - - AssociationLine *m_associationLine; ///< the definition points for the association line - ClassifierWidget *m_associationClass; ///< used if we have an assoc. class - Uml::AssociationType::Enum m_associationType; ///< is only used if m_pObject is not set - WidgetRole m_role[2]; - FloatingTextWidget* m_nameWidget; ///< displays the name of this association - QPointF m_eventScenePos; ///< holds scene pos of contextMenuEvent() - -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/boxwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/boxwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/boxwidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/boxwidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,79 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "boxwidget.h" - -// app includes -#include "uml.h" -#include "umldoc.h" - -// qt includes -#include - -/** - * Constructs a BoxWidget. - * - * @param scene The parent to this widget. - * @param id The ID to assign (-1 will prompt a new ID.) - * @param type The WidgetType (wt_Box.) - */ -BoxWidget::BoxWidget(UMLScene * scene, Uml::ID::Type id, WidgetType type) - : UMLWidget(scene, type, id) -{ - setSize(100, 80); - m_usesDiagramLineColor = false; // boxes be black - m_lineColor = QColor("black"); - setZValue(-10); -} - -/** - * Destructor. - */ -BoxWidget::~BoxWidget() -{ -} - -/** - * Draws a rectangle. - */ -void BoxWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - Q_UNUSED(option); - Q_UNUSED(widget); - setPenFromSettings(painter); - painter->drawRect(0, 0, width(), height()); - - UMLWidget::paint(painter, option, widget); -} - -/** - * Saves the widget to the "boxwidget" XMI element. - * Note: For loading from XMI, the inherited parent method is used. - */ -void BoxWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) -{ - QDomElement boxElement = qDoc.createElement(QLatin1String("boxwidget")); - UMLWidget::saveToXMI(qDoc, boxElement); - qElement.appendChild(boxElement); -} - -/** - * Show a properties dialog for a BoxWidget. - */ -void BoxWidget::showPropertiesDialog() -{ - QColor newColor = QColorDialog::getColor(lineColor()); // krazy:exclude=qclasses - if (newColor != lineColor()) { - setLineColor(newColor); - setUsesDiagramLineColor(false); - umlDoc()->setModified(true); - } -} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/boxwidget.h umbrello-kf6-15.08.1/umbrello/widgets/boxwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/boxwidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/boxwidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,39 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef BOXWIDGET_H -#define BOXWIDGET_H - -//app includes -#include "umlwidget.h" - -/** - * Displays a rectangular box. - * These widgets are diagram specific. They will still need a unique id - * from the @ref UMLDoc class for deletion and other purpose-kf6s. - * - * @short Displays a box. - * @author Jonathan Riddell - * @see UMLWidget - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class BoxWidget : public UMLWidget -{ -public: - explicit BoxWidget(UMLScene * scene, Uml::ID::Type id = Uml::ID::None, WidgetType type = WidgetBase::wt_Box); - virtual ~BoxWidget(); - - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); - - virtual void showPropertiesDialog(); -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/categorywidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/categorywidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/categorywidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/categorywidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,148 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header file -#include "categorywidget.h" - -// local includes -#include "category.h" -#include "debug_utils.h" -#include "umlview.h" -#include "listpopupmenu.h" - -// qt includes -#include - -/** - * Creates a Category widget. - * - * @param scene The parent of the widget. - * @param o The UMLCategory to represent. - */ -CategoryWidget::CategoryWidget(UMLScene * scene, UMLCategory *o) - : UMLWidget(scene, WidgetBase::wt_Category, o) -{ - m_fixedAspectRatio = true; -} - -/** - * Destructor. - */ -CategoryWidget::~CategoryWidget() -{ -} - -/** - * Overrides the standard paint event. - */ -void CategoryWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - Q_UNUSED(option); - Q_UNUSED(widget); - - UMLWidget::setPenFromSettings(painter); - if (UMLWidget::useFillColor()) - painter->setBrush(UMLWidget::fillColor()); - QFont font = UMLWidget::font(); - font.setUnderline(false); - font.setBold(false); - font.setItalic(m_umlObject->isAbstract()); - painter->setFont(font); - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - // the height is our radius - const int h = height(); - const int w = width(); - const int r = h > w ? h : w; - - //int middleX = w / 2; - const int textStartY = (r / 2) - (fontHeight / 2); - - // draw a circle - painter->drawEllipse(0, 0, r, r); - painter->setPen(textColor()); - - QString letterType(QLatin1Char('D')); - switch(static_cast(m_umlObject)->getType()) { - case UMLCategory::ct_Disjoint_Specialisation: - letterType = QLatin1Char('D'); - break; - case UMLCategory::ct_Overlapping_Specialisation: - letterType = QLatin1Char('O'); - break; - case UMLCategory::ct_Union: - letterType = QLatin1Char('U'); - break; - default: - break; - } - - painter->drawText(UC_MARGIN, textStartY, r - UC_MARGIN * 2, fontHeight, Qt::AlignCenter, letterType); - UMLWidget::setPenFromSettings(painter); - - UMLWidget::paint(painter, option, widget); -} - -/** - * Overrides method from UMLWidget. - */ -QSizeF CategoryWidget::minimumSize() const -{ - const UMLWidget::FontType ft = (m_umlObject->isAbstract() ? FT_BOLD_ITALIC : FT_BOLD); - const QFontMetrics &fm = UMLWidget::getFontMetrics(ft); - const int fontHeight = fm.lineSpacing(); - int radius = UC_RADIUS + fontHeight + UC_MARGIN; - - return QSizeF(radius, radius); -} - -/** - * Saves this Category to file. - */ -void CategoryWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) -{ - QDomElement categoryElement = qDoc.createElement(QLatin1String("categorywidget")); - UMLWidget::saveToXMI(qDoc, categoryElement); - qElement.appendChild(categoryElement); -} - -/** - * Will be called when a menu selection has been made from the - * popup menu. - * - * @param action The action that has been selected. - */ -void CategoryWidget::slotMenuSelection(QAction* action) -{ - UMLCategory* catObj = static_cast(umlObject()); - if (!catObj) { - uWarning() << "No UMLCategory for this widget."; - return; - } - - ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); - switch(sel) { - case ListPopupMenu::mt_DisjointSpecialisation: - catObj->setType(UMLCategory::ct_Disjoint_Specialisation); - break; - - case ListPopupMenu::mt_OverlappingSpecialisation: - catObj->setType(UMLCategory::ct_Overlapping_Specialisation); - break; - - case ListPopupMenu::mt_Union: - catObj->setType(UMLCategory::ct_Union); - break; - - default: - UMLWidget::slotMenuSelection(action); - } -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/categorywidget.h umbrello-kf6-15.08.1/umbrello/widgets/categorywidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/categorywidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/categorywidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,56 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef CATEGORYWIDGET_H -#define CATEGORYWIDGET_H - -#include "umlwidget.h" - -#define UC_MARGIN 5 -#define UC_RADIUS 30 - -class UMLCategory; - -/** - * This class is the graphical version of a UMLCategory. A CategoryWidget is created - * by a @ref UMLView. An CategoryWidget belongs to only one @ref UMLView instance. - * When the @ref UMLView instance that this class belongs to, it will be automatically deleted. - * - * If the Category class that this CategoryWidget is displaying is deleted, the @ref UMLView will - * make sure that this instance is also deleted. - * - * The CategoryWidget class inherits from the @ref UMLWidget class which adds most of the functionality - * to this class. - * - * @short A graphical version of a UMLCategory. - * @author Sharan Rao - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class CategoryWidget : public UMLWidget -{ - Q_OBJECT -public: - CategoryWidget(UMLScene * scene, UMLCategory *o); - virtual ~CategoryWidget(); - - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - - void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); - // For loading we can use the loadFromXMI() inherited from UMLWidget. - -protected: - QSizeF minimumSize() const; - -public slots: - void slotMenuSelection(QAction* action); - -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/classifierwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/classifierwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/classifierwidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/classifierwidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,1420 +0,0 @@ -/*************************************************************************** - * 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) 2004-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "classifierwidget.h" - -// app includes -#include "floatingtextwidget.h" -#include "associationwidget.h" -#include "associationline.h" -#include "classifier.h" -#include "cmds.h" -#include "debug_utils.h" -#include "listpopupmenu.h" -#include "object_factory.h" -#include "operation.h" -#include "template.h" -#include "uml.h" -#include "umldoc.h" -#include "umlview.h" - -#define PACKAGE_MARGIN 5 - -// qt includes -#include - -DEBUG_REGISTER_DISABLED(ClassifierWidget) - -const int ClassifierWidget::MARGIN = 5; -const int ClassifierWidget::CIRCLE_SIZE = 30; -const int ClassifierWidget::SOCKET_INCREMENT = 10; - -/** - * Constructs a ClassifierWidget. - * - * @param scene The parent of this ClassifierWidget. - * @param c The UMLClassifier to represent. - */ -ClassifierWidget::ClassifierWidget(UMLScene * scene, UMLClassifier *c) - : UMLWidget(scene, WidgetBase::wt_Class, c), - m_pAssocWidget(0), m_pInterfaceName(0) -{ - const Settings::OptionState& ops = m_scene->optionState(); - setVisualPropertyCmd(ShowVisibility, ops.classState.showVisibility); - setVisualPropertyCmd(ShowOperations, ops.classState.showOps); - setVisualPropertyCmd(ShowPublicOnly, ops.classState.showPublicOnly); - setVisualPropertyCmd(ShowPackage, ops.classState.showPackage); - m_attributeSignature = Uml::SignatureType::ShowSig; - /*:TODO: - setVisualProperty(ShowOperationSignature, ops.classState.showOpSig); - Cannot do that because we get "pure virtual method called". Open code: - */ - if(!ops.classState.showOpSig) { - if (visualProperty(ShowVisibility)) - m_operationSignature = Uml::SignatureType::NoSig; - else - m_operationSignature = Uml::SignatureType::NoSigNoVis; - - } else if (visualProperty(ShowVisibility)) - m_operationSignature = Uml::SignatureType::ShowSig; - else - m_operationSignature = Uml::SignatureType::SigNoVis; - - setVisualPropertyCmd(ShowAttributes, ops.classState.showAtts); - setVisualPropertyCmd(ShowStereotype, ops.classState.showStereoType); - setVisualPropertyCmd(DrawAsCircle, false); - - setShowAttSigs(ops.classState.showAttSig); - - if (c && c->isInterface()) { - m_baseType = WidgetBase::wt_Interface; - m_visualProperties = ShowOperations | ShowVisibility | ShowStereotype; - setShowStereotype(true); - updateSignatureTypes(); - } -} - -/** - * Constructs a ClassifierWidget. - * - * @param scene The parent of this ClassifierWidget. - * @param c The UMLClassifier to represent. - */ -ClassifierWidget::ClassifierWidget(UMLScene * scene, UMLPackage *o) - : UMLWidget(scene, WidgetBase::wt_Package, o), - m_pAssocWidget(0), - m_pInterfaceName(0) -{ - const Settings::OptionState& ops = m_scene->optionState(); - setVisualPropertyCmd(ShowVisibility, ops.classState.showVisibility); - setVisualPropertyCmd(ShowOperations, ops.classState.showOps); - setVisualPropertyCmd(ShowPublicOnly, ops.classState.showPublicOnly); - setVisualPropertyCmd(ShowPackage, ops.classState.showPackage); - m_attributeSignature = Uml::SignatureType::ShowSig; - - if(!ops.classState.showOpSig) { - if (visualProperty(ShowVisibility)) - m_operationSignature = Uml::SignatureType::NoSig; - else - m_operationSignature = Uml::SignatureType::NoSigNoVis; - - } else if (visualProperty(ShowVisibility)) - m_operationSignature = Uml::SignatureType::ShowSig; - else - m_operationSignature = Uml::SignatureType::SigNoVis; - - setVisualPropertyCmd(ShowAttributes, ops.classState.showAtts); - setVisualPropertyCmd(ShowStereotype, ops.classState.showStereoType); - setVisualPropertyCmd(DrawAsPackage, true); - - setShowAttSigs(ops.classState.showAttSig); -} - -/** - * Destructor. - */ -ClassifierWidget::~ClassifierWidget() -{ - if (m_pAssocWidget) - m_pAssocWidget->removeAssocClassLine(); - if (m_pInterfaceName) { - delete m_pInterfaceName; - m_pInterfaceName = 0; - } -} - -/** - * Return the UMLClassifier which this ClassifierWidget - * represents. - */ -UMLClassifier *ClassifierWidget::classifier() const -{ - return dynamic_cast(m_umlObject); -} - -/** - * @return the visual properties - */ -ClassifierWidget::VisualProperties ClassifierWidget::visualProperties() const -{ - return m_visualProperties; -} - -/** - * Set an OR combination of properties stored in \a properties on this - * widget. - */ -void ClassifierWidget::setVisualProperties(VisualProperties properties) -{ - // Don't do anything if the argument is equal to current status. - if (quint32(m_visualProperties) == quint32(properties)) { - return; - } - - m_visualProperties = properties; - updateSignatureTypes(); -} - -/** - * @return The status of the property passed in. - * - * @note Use @ref attributeSignature() and @ref - * operationSignature() to get signature status. This - * method only indicates whether signature is visible or not. - */ -bool ClassifierWidget::visualProperty(VisualProperty property) const -{ - if (property == ShowAttributeSignature) { - return (m_attributeSignature == Uml::SignatureType::ShowSig - || m_attributeSignature == Uml::SignatureType::SigNoVis); - } - - else if(property == ShowOperationSignature) { - return (m_operationSignature == Uml::SignatureType::ShowSig - || m_operationSignature == Uml::SignatureType::SigNoVis); - } - - return m_visualProperties.testFlag(property); -} - -/** - * A convenient method to set and reset individual VisualProperty - * - * Undo command. - * - * @param property The property to be set/reset. - * @param enable True/false to set/reset. (default = true) - * - * @note This method handles ShowAttributeSignature and - * ShowOperationSignature specially. - */ -void ClassifierWidget::setVisualProperty(VisualProperty property, bool enable) -{ - if (visualProperty(property) != enable) { - UMLApp::app()->executeCommand(new Uml::CmdChangeVisualProperty(this, property, enable)); - } -} - -/** - * A convenient method to set and reset individual VisualProperty - * - * @param property The property to be set/reset. - * @param enable True/false to set/reset. (default = true) - * - * @note This method handles ShowAttributeSignature and - * ShowOperationSignature specially. - */ -void ClassifierWidget::setVisualPropertyCmd(VisualProperty property, bool enable) -{ - // Handle ShowAttributeSignature and ShowOperationSignature - // specially. - - if (property == ShowAttributeSignature) { - if (!enable) { - m_attributeSignature = visualProperty(ShowVisibility) ? - Uml::SignatureType::NoSig : Uml::SignatureType::NoSigNoVis; - } else { - m_attributeSignature = visualProperty(ShowVisibility) ? - Uml::SignatureType::ShowSig : Uml::SignatureType::SigNoVis; - } - //:TODO: updateTextItemGroups(); - updateSignatureTypes(); - } - - else if (property == ShowOperationSignature) { - if (!enable) { - m_operationSignature = visualProperty(ShowVisibility) ? - Uml::SignatureType::NoSig : Uml::SignatureType::NoSigNoVis; - } else { - m_operationSignature = visualProperty(ShowVisibility) ? - Uml::SignatureType::ShowSig : Uml::SignatureType::SigNoVis; - } - //:TODO: updateTextItemGroups(); - updateSignatureTypes(); - } - - else if (property == ShowStereotype) { - // Now just update flag and use base method for actual work. - if (enable) { - m_visualProperties |= property; - } else { - m_visualProperties &= ~property; - } - setShowStereotype(enable); - } - - else if (property == DrawAsCircle) { - // Don't do anything if the flag status is same. - if (visualProperty(property) == enable) - return; - if (enable) { - m_visualProperties |= property; - } else { - m_visualProperties &= ~property; - } - setDrawAsCircle(enable); - } - - // Some other flag. - else { - // Don't do anything if the flag status is same. - if (visualProperty(property) == enable) { - return; - } - - // Call setVisualProperties appropriately based on enbable. - if (enable) { - setVisualProperties(visualProperties() | property); - } else { - setVisualProperties(visualProperties() & ~property); - } - } -} - -/** - * A convenient method to toggle individual VisualProperty of this - * widget. - * - * @param property The property to be toggled. - * - * @note This method handles ShowAttributeSignature and - * ShowOperationSignature specially. - */ -void ClassifierWidget::toggleVisualProperty(VisualProperty property) -{ - bool oppositeStatus; - if (property == ShowOperationSignature) { - oppositeStatus = !(m_operationSignature == Uml::SignatureType::ShowSig - || m_operationSignature == Uml::SignatureType::SigNoVis); - } - else if (property == ShowAttributeSignature) { - oppositeStatus = !(m_attributeSignature == Uml::SignatureType::ShowSig - || m_attributeSignature == Uml::SignatureType::SigNoVis); - } - else { - oppositeStatus = !visualProperty(property); - } - - DEBUG(DBG_SRC) << "VisualProperty: " << property << " to opposite status " << oppositeStatus; - setVisualProperty(property, oppositeStatus); -} - -/** - * Updates m_operationSignature to match m_showVisibility. - */ -void ClassifierWidget::updateSignatureTypes() -{ - //turn on scope - if (visualProperty(ShowVisibility)) { - if (m_operationSignature == Uml::SignatureType::NoSigNoVis) { - m_operationSignature = Uml::SignatureType::NoSig; - } else if (m_operationSignature == Uml::SignatureType::SigNoVis) { - m_operationSignature = Uml::SignatureType::ShowSig; - } - } - //turn off scope - else { - if (m_operationSignature == Uml::SignatureType::ShowSig) { - m_operationSignature = Uml::SignatureType::SigNoVis; - } else if (m_operationSignature == Uml::SignatureType::NoSig) { - m_operationSignature = Uml::SignatureType::NoSigNoVis; - } - } - if (visualProperty(ShowVisibility)) { - if (m_attributeSignature == Uml::SignatureType::NoSigNoVis) - m_attributeSignature = Uml::SignatureType::NoSig; - else if (m_attributeSignature == Uml::SignatureType::SigNoVis) - m_attributeSignature = Uml::SignatureType::ShowSig; - } else { - if (m_attributeSignature == Uml::SignatureType::ShowSig) - m_attributeSignature = Uml::SignatureType::SigNoVis; - else if(m_attributeSignature == Uml::SignatureType::NoSig) - m_attributeSignature = Uml::SignatureType::NoSigNoVis; - } - updateGeometry(); - update(); -} - -/** - * Returns whether to show attribute signatures. - * Only applies when m_umlObject->getBaseType() is ot_Class. - * - * @return Status of how attribute signatures are shown. - */ -Uml::SignatureType::Enum ClassifierWidget::attributeSignature() const -{ - return m_attributeSignature; -} - -/** - * Sets the type of signature to display for an attribute. - * Only applies when m_umlObject->getBaseType() is ot_Class. - * - * @param sig Type of signature to display for an attribute. - */ -void ClassifierWidget::setAttributeSignature(Uml::SignatureType::Enum sig) -{ - m_attributeSignature = sig; - updateSignatureTypes(); - updateGeometry(); - update(); -} - -/** - * @return The Uml::SignatureType::Enum value for the operations. - */ -Uml::SignatureType::Enum ClassifierWidget::operationSignature() const -{ - return m_operationSignature; -} - -/** - * Set the type of signature to display for an Operation - * - * @param sig Type of signature to display for an operation. - */ -void ClassifierWidget::setOperationSignature(Uml::SignatureType::Enum sig) -{ - m_operationSignature = sig; - updateSignatureTypes(); - updateGeometry(); - update(); -} - -/** - * Sets whether to show attribute signature - * Only applies when m_umlObject->getBaseType() is ot_Class. - * - * @param _status True if attribute signatures shall be shown. - */ -void ClassifierWidget::setShowAttSigs(bool _status) -{ - if(!_status) { - if (visualProperty(ShowVisibility)) - m_attributeSignature = Uml::SignatureType::NoSig; - else - m_attributeSignature = Uml::SignatureType::NoSigNoVis; - } - else if (visualProperty(ShowVisibility)) - m_attributeSignature = Uml::SignatureType::ShowSig; - else - m_attributeSignature = Uml::SignatureType::SigNoVis; - if (UMLApp::app()->document()->loading()) - return; - updateGeometry(); - update(); -} - -/** - * Toggles whether to show attribute signatures. - * Only applies when m_umlObject->getBaseType() is ot_Class. - */ -void ClassifierWidget::toggleShowAttSigs() -{ - if (m_attributeSignature == Uml::SignatureType::ShowSig || - m_attributeSignature == Uml::SignatureType::SigNoVis) { - if (visualProperty(ShowVisibility)) { - m_attributeSignature = Uml::SignatureType::NoSig; - } else { - m_attributeSignature = Uml::SignatureType::NoSigNoVis; - } - } else if (visualProperty(ShowVisibility)) { - m_attributeSignature = Uml::SignatureType::ShowSig; - } else { - m_attributeSignature = Uml::SignatureType::SigNoVis; - } - updateGeometry(); - update(); -} - -/** - * Return the number of displayed members of the given ObjectType. - * Takes into consideration m_showPublicOnly but not other settings. - */ -int ClassifierWidget::displayedMembers(UMLObject::ObjectType ot) const -{ - int count = 0; - UMLClassifier *umlc = this->classifier(); - if (!umlc) - return count; - UMLClassifierListItemList list = umlc->getFilteredList(ot); - foreach (UMLClassifierListItem *m, list) { - if (!(visualProperty(ShowPublicOnly) && m->visibility() != Uml::Visibility::Public)) - count++; - } - return count; -} - -/** - * Overrides method from UMLWidget. - */ -QSizeF ClassifierWidget::minimumSize() const -{ - return calculateSize(); -} - -/** - * Calculate content related size of widget. - * Overrides method from UMLWidget. - */ -QSizeF ClassifierWidget::calculateSize(bool withExtensions /* = true */) const -{ - if (!m_umlObject) { - return UMLWidget::minimumSize(); - } - if (m_umlObject->baseType() == UMLObject::ot_Package) { - return calculateAsPackageSize(); - } - UMLClassifier *umlc = this->classifier(); - if (!umlc) { - uError() << "Internal error - classifier() returns NULL"; - return UMLWidget::minimumSize(); - } - if (umlc->isInterface() && visualProperty(DrawAsCircle)) { - return calculateAsCircleSize(); - } - - const bool showNameOnly = !visualProperty(ShowAttributes) && - !visualProperty(ShowOperations) && - !visualProperty(ShowDocumentation); - - const QFontMetrics &fm = getFontMetrics(UMLWidget::FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - // width is the width of the longest 'word' - int width = 0, height = 0; - // consider stereotype - if (visualProperty(ShowStereotype) && !m_umlObject->stereotype().isEmpty()) { - height += fontHeight; - // ... width - const QFontMetrics &bfm = UMLWidget::getFontMetrics(UMLWidget::FT_BOLD); - const int stereoWidth = bfm.size(0, m_umlObject->stereotype(true)).width(); - if (stereoWidth > width) - width = stereoWidth; - } else if (showNameOnly) { - height += MARGIN; - } - - // consider name - height += fontHeight; - // ... width - QString displayedName; - if (visualProperty(ShowPackage)) - displayedName = m_umlObject->fullyQualifiedName(); - else - displayedName = m_umlObject->name(); - const UMLWidget::FontType nft = (m_umlObject->isAbstract() ? FT_BOLD_ITALIC : FT_BOLD); - const int nameWidth = UMLWidget::getFontMetrics(nft).size(0, displayedName).width(); - if (nameWidth > width) - width = nameWidth; - -#ifdef ENABLE_WIDGET_SHOW_DOC - // consider documentation - if (visualProperty(ShowDocumentation)) { - if (!documentation().isEmpty()) { - QRect brect = fm.boundingRect(QRect(0, 0, this->width()-2*MARGIN, this->height()-height), Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, documentation()); - height += brect.height(); - if (!visualProperty(ShowOperations) && !visualProperty(ShowAttributes)) { - if (brect.width() >= width) - width = brect.width(); - } - } - else - height += fontHeight / 2; - } -#endif - - // consider attributes - if (visualProperty(ShowAttributes)) { - const int numAtts = displayedAttributes(); - if (numAtts > 0) { - height += fontHeight * numAtts; - // calculate width of the attributes - UMLClassifierListItemList list = umlc->getFilteredList(UMLObject::ot_Attribute); - foreach (UMLClassifierListItem *a, list) { - if (visualProperty(ShowPublicOnly) && a->visibility() != Uml::Visibility::Public) - continue; - const int attWidth = fm.size(0, a->toString(m_attributeSignature)).width(); - if (attWidth > width) - width = attWidth; - } - } - else - height += fontHeight / 2; - } - - // consider operations - if (visualProperty(ShowOperations)) { - const int numOps = displayedOperations(); - if (numOps > 0) { - height += numOps * fontHeight; - // ... width - UMLOperationList list(umlc->getOpList()); - foreach (UMLOperation* op, list) { - if (visualProperty(ShowPublicOnly) && op->visibility() != Uml::Visibility::Public) - continue; - const QString displayedOp = op->toString(m_operationSignature); - UMLWidget::FontType oft; - oft = (op->isAbstract() ? UMLWidget::FT_ITALIC : UMLWidget::FT_NORMAL); - const int w = UMLWidget::getFontMetrics(oft).size(0, displayedOp).width(); - if (w > width) - width = w; - } - } - else - height += fontHeight / 2; - } - - if (withExtensions) { - // consider template box _as last_ ! - QSize templatesBoxSize = calculateTemplatesBoxSize(); - if (templatesBoxSize.width() != 0) { - // add width to largest 'word' - width += templatesBoxSize.width() / 2; - } - if (templatesBoxSize.height() != 0) { - height += templatesBoxSize.height() - MARGIN; - } - } - - // allow for height margin - if (showNameOnly) { - height += MARGIN; - } - - // allow for width margin - width += MARGIN * 2; - - return QSizeF(width, height); -} - -/** - * Calculcates the size of the templates box in the top left - * if it exists, returns QSize(0, 0) if it doesn't. - * - * @return QSize of the templates flap. - */ -QSize ClassifierWidget::calculateTemplatesBoxSize() const -{ - if (!classifier()) - return QSize(0, 0); - UMLTemplateList list = classifier()->getTemplateList(); - int count = list.count(); - if (count == 0) { - return QSize(0, 0); - } - - QFont font = UMLWidget::font(); - font.setItalic(false); - font.setUnderline(false); - font.setBold(false); - const QFontMetrics fm(font); - - int width = 0; - int height = count * fm.lineSpacing() + (MARGIN*2); - - foreach (UMLTemplate *t, list) { - int textWidth = fm.size(0, t->toString()).width(); - if (textWidth > width) - width = textWidth; - } - - width += (MARGIN*2); - return QSize(width, height); -} - -/** - * Return the number of displayed attributes. - */ -int ClassifierWidget::displayedAttributes() const -{ - if (!visualProperty(ShowAttributes)) - return 0; - return displayedMembers(UMLObject::ot_Attribute); -} - -/** - * Return the number of displayed operations. - */ -int ClassifierWidget::displayedOperations() const -{ - if (!visualProperty(ShowOperations)) - return 0; - return displayedMembers(UMLObject::ot_Operation); -} - -/** - * Set the AssociationWidget when this ClassWidget acts as - * an association class. - */ -void ClassifierWidget::setClassAssociationWidget(AssociationWidget *assocwidget) -{ - if (!classifier()) { - uError() << "Class association cannot be applied to package"; - return; - } - m_pAssocWidget = assocwidget; - UMLAssociation *umlassoc = NULL; - if (assocwidget) - umlassoc = assocwidget->association(); - classifier()->setClassAssoc(umlassoc); -} - -/** - * Return the AssociationWidget when this classifier acts as - * an association class (else return NULL.) - */ -AssociationWidget *ClassifierWidget::classAssociationWidget() const -{ - return m_pAssocWidget; -} - -/** - * Overrides standard method. - * Auxiliary to reimplementations in the derived classes. - */ -void ClassifierWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - Q_UNUSED(option); - Q_UNUSED(widget); - setPenFromSettings(painter); - if (UMLWidget::useFillColor()) - painter->setBrush(UMLWidget::fillColor()); - else { - painter->setBrush(m_scene->backgroundColor()); - } - if (m_umlObject->baseType() == UMLObject::ot_Package) { - drawAsPackage(painter, option); - UMLWidget::paint(painter, option, widget); - return; - } - UMLClassifier *umlc = this->classifier(); - if (!umlc) { - uError() << "Internal error - classifier() returns NULL"; - return; - } - if (umlc->isInterface() && visualProperty(DrawAsCircle)) { - drawAsCircle(painter, option); - UMLWidget::paint(painter, option, widget); - return; - } - - // Draw the bounding rectangle - QSize templatesBoxSize = calculateTemplatesBoxSize(); - int bodyOffsetY = 0; - if (templatesBoxSize.height() > 0) - bodyOffsetY += templatesBoxSize.height() - MARGIN; - int w = width(); - if (templatesBoxSize.width() > 0) - w -= templatesBoxSize.width() / 2; - int h = height(); - if (templatesBoxSize.height() > 0) - h -= templatesBoxSize.height() - MARGIN; - painter->drawRect(0, bodyOffsetY, w, h); - - QFont font = UMLWidget::font(); - font.setUnderline(false); - font.setItalic(false); - const QFontMetrics &fm = UMLWidget::getFontMetrics(UMLWidget::FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - - //If there are any templates then draw them - UMLTemplateList tlist = umlc->getTemplateList(); - if (tlist.count() > 0) { - setPenFromSettings(painter); - QPen pen = painter->pen(); - pen.setStyle(Qt::DotLine); - painter->setPen(pen); - painter->drawRect(width() - templatesBoxSize.width(), 0, - templatesBoxSize.width(), templatesBoxSize.height()); - painter->setPen(QPen(textColor())); - font.setBold(false); - painter->setFont(font); - const int x = width() - templatesBoxSize.width() + MARGIN; - int y = MARGIN; - foreach (UMLTemplate *t, tlist) { - QString text = t->toString(); - painter->drawText(x, y, fm.size(0, text).width(), fontHeight, Qt::AlignVCenter, text); - y += fontHeight; - } - } - - const int textX = MARGIN; - const int textWidth = w - MARGIN * 2; - - painter->setPen(QPen(textColor())); - - // draw stereotype - font.setBold(true); - const bool showNameOnly = !visualProperty(ShowAttributes) && - !visualProperty(ShowOperations) && - !visualProperty(ShowDocumentation); - - int nameHeight = fontHeight; - if (visualProperty(ShowStereotype) && !m_umlObject->stereotype().isEmpty()) { - painter->setFont(font); - painter->drawText(textX, bodyOffsetY, textWidth, fontHeight, Qt::AlignCenter, m_umlObject->stereotype(true)); - bodyOffsetY += fontHeight; - } else if (showNameOnly) { - nameHeight = h; - } - - // draw name - QString name; - if (visualProperty(ShowPackage)) { - name = m_umlObject->fullyQualifiedName(); - } else { - name = this->name(); - } - font.setItalic(m_umlObject->isAbstract()); - painter->setFont(font); - painter->drawText(textX, bodyOffsetY, textWidth, nameHeight, Qt::AlignCenter, name); - bodyOffsetY += fontHeight; - font.setBold(false); - font.setItalic(false); - painter->setFont(font); - -#ifdef ENABLE_WIDGET_SHOW_DOC - // draw documentation - if (visualProperty(ShowDocumentation)) { - setPenFromSettings(painter); - painter->drawLine(0, bodyOffsetY, w, bodyOffsetY); - painter->setPen(textColor()); - - if (!documentation().isEmpty()) { - QRect brect = fm.boundingRect(QRect(0, 0, w-2*MARGIN, h-bodyOffsetY), Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, documentation()); - if (brect.width() > width() + 2*MARGIN) - brect.setWidth(width()-2*MARGIN); - brect.adjust(textX, bodyOffsetY, textX, bodyOffsetY); - painter->drawText(brect, Qt::AlignCenter | Qt::TextWordWrap, documentation()); - bodyOffsetY += brect.height(); - } - else - bodyOffsetY += fontHeight / 2; - } -#endif - // draw attributes - if (visualProperty(ShowAttributes)) { - // draw dividing line between doc/name and attributes - setPenFromSettings(painter); - painter->drawLine(0, bodyOffsetY, w, bodyOffsetY); - painter->setPen(textColor()); - - const int numAtts = displayedAttributes(); - if (numAtts > 0) { - drawMembers(painter, UMLObject::ot_Attribute, m_attributeSignature, textX, - bodyOffsetY, fontHeight); - bodyOffsetY += fontHeight * numAtts; - } - else - bodyOffsetY += fontHeight / 2; - } - - // draw operations - if (visualProperty(ShowOperations)) { - // draw dividing line between attributes and operations - setPenFromSettings(painter); - painter->drawLine(0, bodyOffsetY, w, bodyOffsetY); - painter->setPen(QPen(textColor())); - - const int numOps = displayedOperations(); - if (numOps >= 0) { - drawMembers(painter, UMLObject::ot_Operation, m_operationSignature, textX, - bodyOffsetY, fontHeight); - } - } - - UMLWidget::paint(painter, option, widget); -} - -/** - * @return The shape of the ClassifierWidget. - */ -QPainterPath ClassifierWidget::shape() const -{ - QPainterPath path; - if (classifier() && classifier()->isInterface() && visualProperty(DrawAsCircle)) { - path.addEllipse(rect()); - return path; - } -#ifdef ENABLE_WIDGET_SHOW_DOC - QSizeF mainSize = rect().size(); -#else - QSizeF mainSize = calculateSize(false); -#endif - QSize templatesBoxSize = calculateTemplatesBoxSize(); - qreal mainY = 0.0; - if (templatesBoxSize.height() > 0) { - mainY += templatesBoxSize.height() - MARGIN; - path.addRect(QRectF(mainSize.width() - templatesBoxSize.width() / 2, 0.0, - templatesBoxSize.width(), templatesBoxSize.height())); - } - path.addRect(QRectF(0.0, mainY, mainSize.width(), mainSize.height())); - return path; -} - -/** - * Draws the interface as a circle. - * Only applies when m_umlObject->getBaseType() is ot_Interface. - */ -void ClassifierWidget::drawAsCircle(QPainter *painter, const QStyleOptionGraphicsItem *option) -{ - const int w = width(); - - if (m_Assocs.size() > 1) { - painter->drawEllipse(w/2 - CIRCLE_SIZE/2, SOCKET_INCREMENT / 2, CIRCLE_SIZE, CIRCLE_SIZE); - // Draw socket for required interface. - const qreal angleSpan = 180; // 360.0 / (m_Assocs.size() + 1.0); - const int arcDiameter = CIRCLE_SIZE + SOCKET_INCREMENT; - QRect requireArc(w/2 - arcDiameter/2, 0, arcDiameter, arcDiameter); - const QPointF center(x() + w/2, y() + arcDiameter/2); - const qreal cX = center.x(); - const qreal cY = center.y(); - foreach (AssociationWidget *aw, m_Assocs) { - const Uml::AssociationType::Enum aType = aw->associationType(); - if (aType == Uml::AssociationType::UniAssociation || - aType == Uml::AssociationType::Association) // provider - continue; - UMLWidget *otherEnd = aw->widgetForRole(Uml::RoleType::A); - const WidgetBase::WidgetType oType = otherEnd->baseType(); - if (oType != WidgetBase::wt_Component && oType != WidgetBase::wt_Port) - continue; - - AssociationLine *assocLine = aw->associationLine(); - const QPointF p(assocLine->endPoint()); - const qreal tolerance = 18.0; - bool drawArc = true; - qreal midAngle; - if (p.x() < cX - tolerance) { - if (p.y() < cY - tolerance) - midAngle = 135; - else if (p.y() > cY + tolerance) - midAngle = 225; - else - midAngle = 180; - } else if (p.x() > cX + tolerance) { - if (p.y() < cY - tolerance) - midAngle = 45; - else if (p.y() > cY + tolerance) - midAngle = 315; - else - midAngle = 0; - } else { - if (p.y() < cY - tolerance) - midAngle = 90; - else if (p.y() > cY + tolerance) - midAngle = 270; - else - drawArc = false; - } - if (drawArc) { - // uDebug() << "number of assocs: " << m_Assocs.size() - // << ", p: " << p << ", center: " << center - // << ", midAngle: " << midAngle << ", angleSpan: " << angleSpan; - painter->drawArc(requireArc, 16 * (midAngle - angleSpan/2), 16 * angleSpan); - } else { - uError() << "socket: assocLine endPoint " << p - << " too close to own center" << center; - } - } - } - else - painter->drawEllipse(w/2 - CIRCLE_SIZE/2, 0, CIRCLE_SIZE, CIRCLE_SIZE); - - UMLWidget::paint(painter, option); -} - -/** - * Calculates the size of the object when drawn as a circle. - * Only applies when m_umlObject->getBaseType() is ot_Interface. - */ -QSize ClassifierWidget::calculateAsCircleSize() const -{ - int circleSize = CIRCLE_SIZE; - if (m_Assocs.size() > 1) - circleSize += SOCKET_INCREMENT; - return QSize(circleSize, circleSize); -} - -void ClassifierWidget::drawAsPackage(QPainter *painter, const QStyleOptionGraphicsItem *option) -{ - Q_UNUSED(option); - - int w = width(); - int h = height(); - QFont font = UMLWidget::font(); - font.setBold(true); - //FIXME italic is true when a package is first created until you click elsewhere, not sure why - font.setItalic(false); - const QFontMetrics &fm = getFontMetrics(FT_BOLD); - const int fontHeight = fm.lineSpacing(); - - painter->drawRect(0, 0, 50, fontHeight); - if (m_umlObject->stereotype() == QLatin1String("subsystem")) { - const int fHalf = fontHeight / 2; - const int symY = fHalf; - const int symX = 38; - painter->drawLine(symX, symY, symX, symY + fHalf - 2); // left leg - painter->drawLine(symX + 8, symY, symX + 8, symY + fHalf - 2); // right leg - painter->drawLine(symX, symY, symX + 8, symY); // waist - painter->drawLine(symX + 4, symY, symX + 4, symY - fHalf + 2); // head - } - painter->drawRect(0, fontHeight - 1, w, h - fontHeight); - - painter->setPen(textColor()); - painter->setFont(font); - - int lines = 1; - QString stereotype = m_umlObject->stereotype(); - if (!stereotype.isEmpty()) { - painter->drawText(0, fontHeight + PACKAGE_MARGIN, - w, fontHeight, Qt::AlignCenter, m_umlObject->stereotype(true)); - lines = 2; - } - - painter->drawText(0, (fontHeight*lines) + PACKAGE_MARGIN, - w, fontHeight, Qt::AlignCenter, name()); -} - -QSize ClassifierWidget::calculateAsPackageSize() const -{ - const QFontMetrics &fm = getFontMetrics(FT_BOLD_ITALIC); - const int fontHeight = fm.lineSpacing(); - - int lines = 1; - - int width = fm.width(m_umlObject->name()); - - int tempWidth = 0; - if (!m_umlObject->stereotype().isEmpty()) { - tempWidth = fm.width(m_umlObject->stereotype(true)); - lines = 2; - } - if (tempWidth > width) - width = tempWidth; - width += PACKAGE_MARGIN * 2; - if (width < 70) - width = 70; // minumin width of 70 - - int height = (lines*fontHeight) + fontHeight + (PACKAGE_MARGIN * 2); - - return QSize(width, height); -} - -/** - * Auxiliary method for draw() of child classes: - * Draw the attributes or operations. - * - * @param p QPainter to paint to. - * @param ot Object type to draw, either ot_Attribute or ot_Operation. - * @param sigType Governs details of the member display. - * @param x X coordinate at which to draw the texts. - * @param y Y coordinate at which text drawing commences. - * @param fontHeight The font height. - */ -void ClassifierWidget::drawMembers(QPainter * painter, UMLObject::ObjectType ot, Uml::SignatureType::Enum sigType, - int x, int y, int fontHeight) -{ - UMLClassifier *umlc = classifier(); - if (!umlc) { - return; - } - QFont f = UMLWidget::font(); - f.setBold(false); - UMLClassifierListItemList list = umlc->getFilteredList(ot); - painter->setClipping(true); - painter->setClipRect(rect()); - foreach (UMLClassifierListItem *obj, list) { - if (visualProperty(ShowPublicOnly) && obj->visibility() != Uml::Visibility::Public) - continue; - QString text = obj->toString(sigType); - f.setItalic(obj->isAbstract()); - f.setUnderline(obj->isStatic()); - painter->setFont(f); - QFontMetrics fontMetrics(f); - painter->drawText(x, y, fontMetrics.size(0, text).width(), fontHeight, Qt::AlignVCenter, text); - f.setItalic(false); - f.setUnderline(false); - painter->setFont(f); - y += fontHeight; - } - painter->setClipping(false); -} - -/** - * Override method from UMLWidget in order to additionally check m_pInterfaceName. - * - * @param p Point to be checked. - * - * @return 'this' if UMLWidget::onWidget(p) returns non NULL; - * m_pInterfaceName if m_pName is non NULL and - * m_pInterfaceName->onWidget(p) returns non NULL; else NULL. - */ -UMLWidget* ClassifierWidget::onWidget(const QPointF &p) -{ - if (UMLWidget::onWidget(p) != NULL) - return this; - if (getDrawAsCircle() && m_pInterfaceName) { - uDebug() << "floatingtext: " << m_pInterfaceName->text(); - return m_pInterfaceName->onWidget(p); - } - return NULL; -} - -/** - * Reimplement function from UMLWidget. - */ -UMLWidget* ClassifierWidget::widgetWithID(Uml::ID::Type id) -{ - if (UMLWidget::widgetWithID(id)) - return this; - if (getDrawAsCircle() && m_pInterfaceName && m_pInterfaceName->widgetWithID(id)) - return m_pInterfaceName; - return NULL; -} - -void ClassifierWidget::setDocumentation(const QString &doc) -{ - WidgetBase::setDocumentation(doc); - updateGeometry(); -} - -/** - * Sets whether to draw as circle. - * Only applies when m_umlObject->getBaseType() is ot_Interface. - * - * @param drawAsCircle True if widget shall be drawn as circle. - */ -void ClassifierWidget::setDrawAsCircle(bool drawAsCircle) -{ - setVisualPropertyCmd(DrawAsCircle, drawAsCircle); - const int circleSize = CIRCLE_SIZE + SOCKET_INCREMENT; - if (drawAsCircle) { - setX(x() + (width()/2 - circleSize/2)); - setY(y() + (height()/2 - circleSize/2)); - setSize(circleSize, circleSize); - if (m_pInterfaceName) { - m_pInterfaceName->show(); - } else { - m_pInterfaceName = new FloatingTextWidget(m_scene, Uml::TextRole::Floating, name()); - m_pInterfaceName->setParentItem(this); - m_pInterfaceName->setText(name()); // to get geometry update - m_pInterfaceName->setX(circleSize/2 - m_pInterfaceName->width() / 2); - m_pInterfaceName->setY(circleSize + SOCKET_INCREMENT); - } - m_resizable = false; - } else { - setSize(ClassifierWidget::minimumSize()); - setX(x() - (width()/2 - circleSize/2)); - setY(y() - (height()/2 - circleSize/2)); - if (m_pInterfaceName) - m_pInterfaceName->hide(); - m_resizable = true; - } - updateGeometry(); - update(); -} - -/** - * Returns whether to draw as circle. - * Only applies when m_umlObject->getBaseType() is ot_Interface. - * - * @return True if widget is drawn as circle. - */ -bool ClassifierWidget::getDrawAsCircle() const -{ - return visualProperty(DrawAsCircle); -} - -/** - * Toggles whether to draw as circle. - * Only applies when m_umlObject->getBaseType() is ot_Interface. - */ -void ClassifierWidget::toggleDrawAsCircle() -{ - toggleVisualProperty(DrawAsCircle); - updateSignatureTypes(); - updateGeometry(); - update(); -} - -/** - * Changes this classifier from an interface to a class. - * Attributes and stereotype visibility is got from the view OptionState. - * This widget is also updated. - */ -void ClassifierWidget::changeToClass() -{ - m_baseType = WidgetBase::wt_Class; - m_umlObject->setBaseType(UMLObject::ot_Class); - setVisualPropertyCmd(DrawAsCircle, false); - const Settings::OptionState& ops = m_scene->optionState(); - setVisualProperty(ShowAttributes, ops.classState.showAtts); - setVisualProperty(ShowStereotype, ops.classState.showStereoType); - - updateGeometry(); - update(); -} - -/** - * Changes this classifier from a class to an interface. - * Attributes are hidden and stereotype is shown. - * This widget is also updated. - */ -void ClassifierWidget::changeToInterface() -{ - m_baseType = WidgetBase::wt_Interface; - m_umlObject->setBaseType(UMLObject::ot_Interface); - - setVisualProperty(ShowAttributes, false); - setVisualProperty(ShowStereotype, true); - - updateGeometry(); - update(); -} - -/** - * Changes this classifier from an "class-or-package" to a package. - * This widget is also updated. - */ -void ClassifierWidget::changeToPackage() -{ - m_baseType = WidgetBase::wt_Package; - m_umlObject->setBaseType(UMLObject::ot_Package); - - setVisualProperty(ShowAttributes, false); - setVisualProperty(ShowStereotype, true); - - updateGeometry(); - update(); -} - -/** - * Extends base method to adjust also the association of a class - * association. - * Executes the base method and then, if file isn't loading and the - * classifier acts as a class association, the association position is - * updated. - * TODO: This is never called. - * - * param x The x-coordinate. - * param y The y-coordinate. - */ -//void ClassifierWidget::adjustAssociations(int x, int y) -//{ -// DEBUG(DBG_SRC) << "x=" << x << " / y=" << y; -// UMLWidget::adjustAssocs(x, y); - -// if (m_doc->loading() || m_pAssocWidget == 0) { -// return; -// } - -// //:TODO: the following is also called from UMLWidgetr::ajdustAssocs(...) -// // and then AssociationWidget::widgetMoved(...) -// //m_pAssocWidget->computeAssocClassLine(); -//} - -/** - * Loads the "classwidget" or "interfacewidget" XML element. - */ -bool ClassifierWidget::loadFromXMI(QDomElement & qElement) -{ - if (!UMLWidget::loadFromXMI(qElement)) { - return false; - } - - QString showatts = qElement.attribute(QLatin1String("showattributes"), QLatin1String("0")); - QString showops = qElement.attribute(QLatin1String("showoperations"), QLatin1String("1")); - QString showpubliconly = qElement.attribute(QLatin1String("showpubliconly"), QLatin1String("0")); - QString showattsigs = qElement.attribute(QLatin1String("showattsigs"), QLatin1String("600")); - QString showopsigs = qElement.attribute(QLatin1String("showopsigs"), QLatin1String("600")); - QString showpackage = qElement.attribute(QLatin1String("showpackage"), QLatin1String("0")); - QString showscope = qElement.attribute(QLatin1String("showscope"), QLatin1String("0")); - QString drawascircle = qElement.attribute(QLatin1String("drawascircle"), QLatin1String("0")); -#ifdef ENABLE_WIDGET_SHOW_DOC - QString showDocumentation = qElement.attribute(QLatin1String("showdocumentation"), QLatin1String("0")); -#endif - - setVisualPropertyCmd(ShowAttributes, (bool)showatts.toInt()); - setVisualPropertyCmd(ShowOperations, (bool)showops.toInt()); - setVisualPropertyCmd(ShowPublicOnly, (bool)showpubliconly.toInt()); - setVisualPropertyCmd(ShowPackage, (bool)showpackage.toInt()); - setVisualPropertyCmd(ShowVisibility, (bool)showscope.toInt()); - setVisualPropertyCmd(DrawAsCircle, (bool)drawascircle.toInt()); -#ifdef ENABLE_WIDGET_SHOW_DOC - setVisualPropertyCmd(ShowDocumentation, (bool)showDocumentation.toInt()); -#endif - - m_attributeSignature = Uml::SignatureType::fromInt(showattsigs.toInt()); - m_operationSignature = Uml::SignatureType::fromInt(showopsigs.toInt()); - - if (!getDrawAsCircle()) - return true; - - // Optional child element: floatingtext - QDomNode node = qElement.firstChild(); - QDomElement element = node.toElement(); - if (!element.isNull()) { - QString tag = element.tagName(); - if (tag == QLatin1String("floatingtext")) { - if (m_pInterfaceName == NULL) { - m_pInterfaceName = new FloatingTextWidget(m_scene, - Uml::TextRole::Floating, - name(), Uml::ID::Reserved); - m_pInterfaceName->setParentItem(this); - } - if (!m_pInterfaceName->loadFromXMI(element)) { - // Most likely cause: The FloatingTextWidget is empty. - delete m_pInterfaceName; - m_pInterfaceName = NULL; - } else { - m_pInterfaceName->activate(); - m_pInterfaceName->update(); - } - } else { - uError() << "unknown tag " << tag; - } - } - - return true; -} - -/** - * Creates the "classwidget" or "interfacewidget" XML element. - */ -void ClassifierWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) -{ - QDomElement conceptElement; - UMLClassifier *umlc = classifier(); - if (umlc && umlc->isInterface()) - conceptElement = qDoc.createElement(QLatin1String("interfacewidget")); - else - conceptElement = qDoc.createElement(QLatin1String("classwidget")); - UMLWidget::saveToXMI(qDoc, conceptElement); - conceptElement.setAttribute(QLatin1String("showoperations"), visualProperty(ShowOperations)); - conceptElement.setAttribute(QLatin1String("showpubliconly"), visualProperty(ShowPublicOnly)); - conceptElement.setAttribute(QLatin1String("showopsigs"), m_operationSignature); - conceptElement.setAttribute(QLatin1String("showpackage"), visualProperty(ShowPackage)); - conceptElement.setAttribute(QLatin1String("showscope"), visualProperty(ShowVisibility)); - conceptElement.setAttribute(QLatin1String("showattributes"), visualProperty(ShowAttributes)); - conceptElement.setAttribute(QLatin1String("showattsigs"), m_attributeSignature); -#ifdef ENABLE_WIDGET_SHOW_DOC - conceptElement.setAttribute(QLatin1String("showdocumentation"),visualProperty(ShowDocumentation)); -#endif - if (umlc && (umlc->isInterface() || umlc->isAbstract())) { - conceptElement.setAttribute(QLatin1String("drawascircle"), visualProperty(DrawAsCircle)); - if (visualProperty(DrawAsCircle) && m_pInterfaceName) { - m_pInterfaceName->saveToXMI(qDoc, conceptElement); - } - } - qElement.appendChild(conceptElement); -} - -/** - * Will be called when a menu selection has been made from the - * popup menu. - * - * @param action The action that has been selected. - */ -void ClassifierWidget::slotMenuSelection(QAction* action) -{ - ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); - switch (sel) { - case ListPopupMenu::mt_Attribute: - case ListPopupMenu::mt_Operation: - case ListPopupMenu::mt_Template: - { - UMLObject::ObjectType ot = ListPopupMenu::convert_MT_OT(sel); - UMLClassifier *umlc = classifier(); - if (!umlc) { - uError() << "Internal error - classifier() returns NULL"; - return; - } - if (Object_Factory::createChildObject(umlc, ot)) { - updateGeometry(); - update(); - UMLApp::app()->document()->setModified(); - } - break; - } - case ListPopupMenu::mt_Show_Operations: - toggleVisualProperty(ShowOperations); - break; - - case ListPopupMenu::mt_Show_Attributes: - toggleVisualProperty(ShowAttributes); - break; - - case ListPopupMenu::mt_Show_Documentation: - toggleVisualProperty(ShowDocumentation); - break; - - case ListPopupMenu::mt_Show_Public_Only: - toggleVisualProperty(ShowPublicOnly); - break; - - case ListPopupMenu::mt_Show_Operation_Signature: - toggleVisualProperty(ShowOperationSignature); - break; - - case ListPopupMenu::mt_Show_Attribute_Signature: - toggleVisualProperty(ShowAttributeSignature); - break; - - case ListPopupMenu::mt_Visibility: - toggleVisualProperty(ShowVisibility); - break; - - case ListPopupMenu::mt_Show_Packages: - toggleVisualProperty(ShowPackage); - break; - - case ListPopupMenu::mt_Show_Stereotypes: - toggleVisualProperty(ShowStereotype); - break; - - case ListPopupMenu::mt_DrawAsCircle: - toggleVisualProperty(DrawAsCircle); - break; - - case ListPopupMenu::mt_ChangeToClass: - changeToClass(); - break; - - case ListPopupMenu::mt_ChangeToInterface: - changeToInterface(); - break; - - case ListPopupMenu::mt_ChangeToPackage: - changeToPackage(); - break; - - default: - UMLWidget::slotMenuSelection(action); - break; - } -} - -/** - * Slot to show/hide attributes based on \a state. - */ -void ClassifierWidget::slotShowAttributes(bool state) -{ - setVisualProperty(ShowAttributes, state); -} - -/** - * Slot to show/hide operations based on \a state. - */ -void ClassifierWidget::slotShowOperations(bool state) -{ - setVisualProperty(ShowOperations, state); -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/classifierwidget.h umbrello-kf6-15.08.1/umbrello/widgets/classifierwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/classifierwidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/classifierwidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,146 +0,0 @@ -/*************************************************************************** - * 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) 2004-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef CLASSIFIERWIDGET_H -#define CLASSIFIERWIDGET_H - -#include "basictypes.h" -#include "umlobject.h" -#include "umlwidget.h" - -class AssociationWidget; -class FloatingTextWidget; -class QPainter; -class UMLClassifier; - -/** - * @short Common implementation for class widget and interface widget - * - * @author Oliver Kellogg - * @author Gopala Krishna - * - * @see UMLWidget - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class ClassifierWidget : public UMLWidget -{ - Q_OBJECT - Q_ENUMS(VisualProperty) -public: - /** - * This enumeration lists the visual properties that can be easily - * set, reset and toggled and all these operate on an integer - * which stores all the flag status. - */ - enum VisualProperty { - ShowStereotype = 0x1, - ShowOperations = 0x2, - ShowPublicOnly = 0x4, - ShowVisibility = 0x8, - ShowPackage = 0x10, - ShowAttributes = 0x20, - DrawAsCircle = 0x40, - ShowOperationSignature = 0x60, ///< only in setter - ShowAttributeSignature = 0x80, ///< only in setter - DrawAsPackage = 0x100, - ShowDocumentation = 0x200, - }; - - Q_DECLARE_FLAGS(VisualProperties, VisualProperty) - - ClassifierWidget(UMLScene * scene, UMLClassifier * o); - ClassifierWidget(UMLScene * scene, UMLPackage * o); - virtual ~ClassifierWidget(); - - UMLClassifier *classifier() const; - - VisualProperties visualProperties() const; - void setVisualProperties(VisualProperties properties); - - bool visualProperty(VisualProperty property) const; - void setVisualProperty(VisualProperty property, bool enable = true); - void setVisualPropertyCmd(VisualProperty property, bool enable = true); - void toggleVisualProperty(VisualProperty property); - - int displayedAttributes() const; - int displayedOperations() const; - - Uml::SignatureType::Enum attributeSignature() const; - void setAttributeSignature(Uml::SignatureType::Enum sig); - - Uml::SignatureType::Enum operationSignature() const; - void setOperationSignature(Uml::SignatureType::Enum sig); - - void setShowAttSigs(bool _show); - void toggleShowAttSigs(); - - bool getDrawAsCircle() const; - void setDrawAsCircle(bool drawAsCircle); - void toggleDrawAsCircle(); - - void changeToClass(); - void changeToInterface(); - void changeToPackage(); - - AssociationWidget *classAssociationWidget() const; - void setClassAssociationWidget(AssociationWidget *assocwidget); -// virtual void adjustAssociations(int x, int y); - - UMLWidget* onWidget(const QPointF& p); - UMLWidget* widgetWithID(Uml::ID::Type id); - - virtual void setDocumentation(const QString& doc); - - QSizeF calculateSize(bool withExtensions = true) const; - - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - virtual QPainterPath shape() const; - - virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); - virtual bool loadFromXMI(QDomElement & qElement); - -public Q_SLOTS: - virtual void slotMenuSelection(QAction* action); - -private Q_SLOTS: - void slotShowAttributes(bool state); - void slotShowOperations(bool state); - -private: - void updateSignatureTypes(); - QSize calculateTemplatesBoxSize() const; - - QSizeF minimumSize() const; - - void drawAsCircle(QPainter *p, const QStyleOptionGraphicsItem *option); - QSize calculateAsCircleSize() const; - - void drawAsPackage(QPainter *painter, const QStyleOptionGraphicsItem *option); - QSize calculateAsPackageSize() const; - - int displayedMembers(UMLObject::ObjectType ot) const; - void drawMembers(QPainter *painter, UMLObject::ObjectType ot, Uml::SignatureType::Enum sigType, - int x, int y, int fontHeight); - - static const int MARGIN; ///< text width margin - static const int CIRCLE_SIZE; ///< size of circle when interface is rendered as such - static const int SOCKET_INCREMENT; ///< augmentation of circle for socket (required interface) - - VisualProperties m_visualProperties; - Uml::SignatureType::Enum m_attributeSignature; ///< Loaded/saved item. - Uml::SignatureType::Enum m_operationSignature; ///< Loaded/saved item. - AssociationWidget *m_pAssocWidget; ///< related AssociationWidget in case this classifier acts as an association class - FloatingTextWidget *m_pInterfaceName; ///< Separate widget for name in case of interface drawn as circle - -}; - -Q_DECLARE_OPERATORS_FOR_FLAGS(ClassifierWidget::VisualProperties) - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/combinedfragmentwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/combinedfragmentwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/combinedfragmentwidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/combinedfragmentwidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,477 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "combinedfragmentwidget.h" - -// app includes -#include "debug_utils.h" -#include "dialog_utils.h" -#include "listpopupmenu.h" -#include "uml.h" -#include "umldoc.h" -#include "umlscene.h" -#include "umlview.h" - -// kde includes -#include -#if QT_VERSION < 0x050000 -#include -#endif - -// qt includes -#if QT_VERSION >= 0x050000 -#include -#endif -#include -#include - -/** - * Creates a Combined Fragment widget. - * - * @param scene The parent of the widget. - * @param combinedfragmentType The type of combined fragment. - * @param id The ID to assign (-1 will prompt a new ID.) - */ -CombinedFragmentWidget::CombinedFragmentWidget(UMLScene * scene, CombinedFragmentType combinedfragmentType, Uml::ID::Type id) - : UMLWidget(scene, WidgetBase::wt_CombinedFragment, id) -{ - setCombinedFragmentType(combinedfragmentType); -} - -/** - * Destructor. - */ -CombinedFragmentWidget::~CombinedFragmentWidget() -{ - for (QList::iterator it=m_dashLines.begin() ; it!=m_dashLines.end() ; ++it) { - delete(*it); - } -} - -/** - * Overrides the standard paint event. - */ -void CombinedFragmentWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - Q_UNUSED(option); - Q_UNUSED(widget); - - int w = width(); - int h = height(); - int line_width = 45; - int old_Y; - - setPenFromSettings(painter); - - if (m_CombinedFragment == Ref) { - if (UMLWidget::useFillColor()) { - painter->setBrush(UMLWidget::fillColor()); - } - } - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - const QString combined_fragment_value = name(); - int textStartY = (h / 2) - (fontHeight / 2); - painter->drawRect(0, 0, w, h); - - painter->setPen(textColor()); - painter->setFont(UMLWidget::font()); - QString temp = QLatin1String("loop"); - - switch (m_CombinedFragment) - { - case Ref : - painter->drawText(COMBINED_FRAGMENT_MARGIN, textStartY, w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignCenter, combined_fragment_value); - painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("ref")); - break; - - case Opt : - painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, - w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("opt")); - break; - - case Break : - painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, - w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("break")); - break; - - case Loop : - if (combined_fragment_value != QLatin1String("-")) - { - temp += QLatin1String(" [") + combined_fragment_value + QLatin1Char(']'); - line_width += (combined_fragment_value.size() + 2) * 8; - } - painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, temp); - - break; - - case Neg : - painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, - w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("neg")); - break; - - case Crit : - painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, - w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("critical")); - break; - - case Ass : - painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, - w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("assert")); - break; - - case Alt : - if (combined_fragment_value != QLatin1String("-")) - { - temp = QLatin1Char('[') + combined_fragment_value + QLatin1Char(']'); - painter->drawText(COMBINED_FRAGMENT_MARGIN, 20, w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, temp); - if (m_dashLines.size() == 1 && m_dashLines.first()->y() < y() + 20 + fontHeight) - m_dashLines.first()->setY(y() + h/2); - } - painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, - w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("alt")); - // dash lines - //m_dashLines.first()->paint(painter); - // TODO: move to UMLWidget::calculateSize api - for (QList::iterator it=m_dashLines.begin() ; it!=m_dashLines.end() ; ++it) { - (*it)->setX(x()); - old_Y = (*it)->getYMin(); - (*it)->setYMin(y()); - (*it)->setYMax(y() + height()); - (*it)->setY(y() + (*it)->y() - old_Y); - (*it)->setSize(w, (*it)->height()); - (*it)->setLineColor(lineColor()); - (*it)->setLineWidth(lineWidth()); - } - - break; - - case Par : - painter->drawText(COMBINED_FRAGMENT_MARGIN, 0, - w - COMBINED_FRAGMENT_MARGIN * 2, fontHeight, Qt::AlignLeft, QLatin1String("parallel")); - // dash lines - if (m_dashLines.size() != 0) { - //m_dashLines.first()->paint(painter); - // TODO: move to UMLWidget::calculateSize api - for (QList::iterator it=m_dashLines.begin() ; it!=m_dashLines.end() ; ++it) { - (*it)->setX(x()); - old_Y = (*it)->getYMin(); - (*it)->setYMin(y()); - (*it)->setYMax(y() + height()); - (*it)->setY(y() + (*it)->y() - old_Y); - (*it)->setSize(w, (*it)->height()); - (*it)->setLineColor(lineColor()); - (*it)->setLineWidth(lineWidth()); - } - } - break; - - default : break; - } - - setPenFromSettings(painter); - painter->drawLine(0, 20, line_width, 20); - painter->drawLine(line_width, 20, line_width + 10, 10); - painter->drawLine(line_width + 10, 10, line_width + 10, 0); - - UMLWidget::paint(painter, option, widget); -} - -/** - * Overrides method from UMLWidget. - */ -QSizeF CombinedFragmentWidget::minimumSize() const -{ - int width = 10, height = 10; - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - const int textWidth = fm.width(name()); - height = fontHeight; - width = textWidth + 60 > COMBINED_FRAGMENT_WIDTH ? textWidth + 60: COMBINED_FRAGMENT_WIDTH; - if (m_CombinedFragment == Loop) - width += int((float)textWidth * 0.4f); - if (m_CombinedFragment == Alt) - height += fontHeight + 40; - height = height > COMBINED_FRAGMENT_HEIGHT ? height : COMBINED_FRAGMENT_HEIGHT; - width += COMBINED_FRAGMENT_MARGIN * 2; - height += COMBINED_FRAGMENT_MARGIN * 2; - - return QSizeF(width, height); -} - -/** - * Returns the type of combined fragment. - */ -CombinedFragmentWidget::CombinedFragmentType CombinedFragmentWidget::combinedFragmentType() const -{ - return m_CombinedFragment; -} - -/** - * Sets the type of combined fragment. - */ -void CombinedFragmentWidget::setCombinedFragmentType(CombinedFragmentType combinedfragmentType) -{ - m_CombinedFragment = combinedfragmentType; - UMLWidget::m_resizable = true ; //(m_CombinedFragment == Normal); - // creates a dash line if the combined fragment type is alternative or parallel - if (m_CombinedFragment == Alt && m_dashLines.isEmpty()) - { - m_dashLines.push_back(new FloatingDashLineWidget(m_scene, Uml::ID::None, this)); - if (m_CombinedFragment == Alt) - { - m_dashLines.back()->setText(QLatin1String("else")); - } - // TODO: move to UMLWidget::calculateSize api - m_dashLines.back()->setX(x()); - m_dashLines.back()->setYMin(y()); - m_dashLines.back()->setYMax(y() + height()); - m_dashLines.back()->setY(y() + height()/2); - m_dashLines.back()->setSize(width(), m_dashLines.back()->height()); - m_scene->widgetList().append(m_dashLines.back()); - } -} - -/** - * Returns the type of combined fragment. - */ -CombinedFragmentWidget::CombinedFragmentType CombinedFragmentWidget::combinedFragmentType(const QString& type) const -{ - if (type == QLatin1String("Reference")) - return (CombinedFragmentWidget::Ref); - if (type == QLatin1String("Option")) - return (CombinedFragmentWidget::Opt); - if (type == QLatin1String("Break")) - return (CombinedFragmentWidget::Break); - if (type == QLatin1String("Loop")) - return (CombinedFragmentWidget::Loop); - if (type == QLatin1String("Negative")) - return (CombinedFragmentWidget::Neg); - if (type == QLatin1String("Critical")) - return (CombinedFragmentWidget::Crit); - if (type == QLatin1String("Assertion")) - return (CombinedFragmentWidget::Ass); - if (type == QLatin1String("Alternative")) - return (CombinedFragmentWidget::Alt); - if (type == QLatin1String("Parallel")) - return (CombinedFragmentWidget::Par); - // Shouldn't happen - Q_ASSERT(0); - return (CombinedFragmentWidget::Ref); -} - -/** - * Sets the type of combined fragment. - */ -void CombinedFragmentWidget::setCombinedFragmentType(const QString& combinedfragmentType) -{ - setCombinedFragmentType(combinedFragmentType(combinedfragmentType)); -} - -/** - * ... - */ -void CombinedFragmentWidget::askNameForWidgetType(UMLWidget* &targetWidget, const QString& dialogTitle, - const QString& dialogPrompt, const QString& defaultName) -{ - Q_UNUSED(defaultName); - bool pressedOK = false; - const QStringList list = QStringList() - << QLatin1String("Reference") - << QLatin1String("Option") - << QLatin1String("Break") - << QLatin1String("Loop") - << QLatin1String("Negative") - << QLatin1String("Critical") - << QLatin1String("Assertion") - << QLatin1String("Alternative") - << QLatin1String("Parallel") ; -#if QT_VERSION >= 0x050000 - QPointer inputDlg = new QInputDialog(); - inputDlg->setComboBoxItems(list); - inputDlg->setOptions(QInputDialog::UseListViewForComboBoxItems); - inputDlg->setWindowTitle(dialogTitle); - inputDlg->setLabelText(dialogPrompt); - pressedOK = inputDlg->exec(); - QStringList result; - result.append(inputDlg->textValue()); - delete inputDlg; -#else - const QStringList select = list; - QStringList result = KInputDialog::getItemList (dialogTitle, dialogPrompt, list, select, false, &pressedOK, UMLApp::app()); -#endif - if (pressedOK) { - QString type = result.join(QString()); - dynamic_cast(targetWidget)->setCombinedFragmentType(type); - if (type == QLatin1String("Reference")) - Dialog_Utils::askNameForWidget(targetWidget, i18n("Enter the name of the diagram referenced"), i18n("Enter the name of the diagram referenced"), i18n("Diagram name")); - else if (type == QLatin1String(QLatin1String("Loop"))) - Dialog_Utils::askNameForWidget(targetWidget, i18n("Enter the guard of the loop"), i18n("Enter the guard of the loop"), i18n("-")); - else if (type == QLatin1String("Alternative")) - Dialog_Utils::askNameForWidget(targetWidget, i18n("Enter the first alternative name"), i18n("Enter the first alternative name"), i18n("-")); - } else { - targetWidget->cleanup(); - delete targetWidget; - targetWidget = NULL; - } -} - -/** - * Saves the widget to the "combinedFragmentwidget" XMI element. - */ -void CombinedFragmentWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) -{ - QDomElement combinedFragmentElement = qDoc.createElement(QLatin1String("combinedFragmentwidget")); - UMLWidget::saveToXMI(qDoc, combinedFragmentElement); - combinedFragmentElement.setAttribute(QLatin1String("combinedFragmentname"), m_Text); - combinedFragmentElement.setAttribute(QLatin1String("documentation"), m_Doc); - combinedFragmentElement.setAttribute(QLatin1String("CombinedFragmenttype"), m_CombinedFragment); - - // save the corresponding floating dash lines - for (QList::iterator it = m_dashLines.begin() ; it != m_dashLines.end() ; ++it) { - (*it)-> saveToXMI(qDoc, combinedFragmentElement); - } - - qElement.appendChild(combinedFragmentElement); -} - -/** - * Loads the widget from the "CombinedFragmentwidget" XMI element. - */ -bool CombinedFragmentWidget::loadFromXMI(QDomElement & qElement) -{ - if (!UMLWidget::loadFromXMI(qElement)) - return false; - m_Text = qElement.attribute(QLatin1String("combinedFragmentname")); - m_Doc = qElement.attribute(QLatin1String("documentation")); - QString type = qElement.attribute(QLatin1String("CombinedFragmenttype")); - - //now load child elements - QDomNode node = qElement.firstChild(); - QDomElement element = node.toElement(); - while (!element.isNull()) { - QString tag = element.tagName(); - if (tag == QLatin1String("floatingdashlinewidget")) { - FloatingDashLineWidget * fdlwidget = new FloatingDashLineWidget(m_scene, Uml::ID::None, this); - m_dashLines.push_back(fdlwidget); - if (!fdlwidget->loadFromXMI(element)) { - // Most likely cause: The FloatingTextWidget is empty. - delete m_dashLines.back(); - return false; - } - else { - m_scene->widgetList().append(fdlwidget); - fdlwidget->clipSize(); - } - } else { - uError() << "unknown tag " << tag; - } - node = node.nextSibling(); - element = node.toElement(); - } - // m_dashLines = listline; - setCombinedFragmentType((CombinedFragmentType)type.toInt()); - - return true; -} - -void CombinedFragmentWidget::removeDashLine(FloatingDashLineWidget *line) -{ - if (m_dashLines.contains(line)) - m_dashLines.removeOne(line); -} - -/** - * Overrides the function from UMLWidget. Deletes all FloatingDashLineWidgets - * that are associated with this instance. - */ -void CombinedFragmentWidget::cleanup() -{ - foreach (FloatingDashLineWidget* w, m_dashLines) - { - if (!w->isSelected()) { - // no need to make this undoable, since the dashlines will be - // reconstructed when deleting the combined fragment is undone. - umlScene()->removeWidgetCmd(w); - } - } -} - -/** - * Overrides the function from UMLWidget. - * - * @param action The command to be executed. - */ -void CombinedFragmentWidget::slotMenuSelection(QAction* action) -{ - ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); - switch (sel) { - // for alternative or parallel combined fragments - case ListPopupMenu::mt_AddInteractionOperand: - m_dashLines.push_back(new FloatingDashLineWidget(m_scene, Uml::ID::None, this)); - if (m_CombinedFragment == Alt) - { - m_dashLines.back()->setText(QLatin1String("else")); - } - // TODO: move to UMLWidget::calculateSize api - m_dashLines.back()->setX(x()); - m_dashLines.back()->setYMin(y()); - m_dashLines.back()->setYMax(y() + height()); - m_dashLines.back()->setY(y() + height() / 2); - m_dashLines.back()->setSize(width(), m_dashLines.back()->height()); - m_scene->setupNewWidget(m_dashLines.back()); - break; - - case ListPopupMenu::mt_Rename: - { - bool ok = false; - QString name = m_Text; - -#if QT_VERSION >= 0x050000 - if (m_CombinedFragment == Alt) { - name = QInputDialog::getText(Q_NULLPTR, - i18n("Enter first alternative"), i18n("Enter first alternative :"), - QLineEdit::Normal, - m_Text, &ok); - } - else if (m_CombinedFragment == Ref) { - name = QInputDialog::getText(Q_NULLPTR, - i18n("Enter referenced diagram name"), i18n("Enter referenced diagram name :"), - QLineEdit::Normal, - m_Text, &ok); - } - else if (m_CombinedFragment == Loop) { - name = QInputDialog::getText(Q_NULLPTR, - i18n("Enter the guard of the loop"), i18n("Enter the guard of the loop:"), - QLineEdit::Normal, - m_Text, &ok); - } -#else - if (m_CombinedFragment == Alt) { - name = KInputDialog::getText(i18n("Enter first alternative"), i18n("Enter first alternative :"), m_Text, &ok); - } - else if (m_CombinedFragment == Ref) { - name = KInputDialog::getText(i18n("Enter referenced diagram name"), i18n("Enter referenced diagram name :"), m_Text, &ok); - } - else if (m_CombinedFragment == Loop) { - name = KInputDialog::getText(i18n("Enter the guard of the loop"), i18n("Enter the guard of the loop:"), m_Text, &ok); - } -#endif - if (ok && name.length() > 0) - m_Text = name; - } - break; - - default: - UMLWidget::slotMenuSelection(action); - } -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/combinedfragmentwidget.h umbrello-kf6-15.08.1/umbrello/widgets/combinedfragmentwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/combinedfragmentwidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/combinedfragmentwidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,91 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef COMBINEDFRAGMENTWIDGET_H -#define COMBINEDFRAGMENTWIDGET_H - -#include "umlwidget.h" -#include "worktoolbar.h" -#include "floatingdashlinewidget.h" - -#include - -#define COMBINED_FRAGMENT_MARGIN 5 -#define COMBINED_FRAGMENT_WIDTH 100 -#define COMBINED_FRAGMENT_HEIGHT 50 - -/** - * This class is the graphical version of a UML combined fragment. A combinedfragmentWidget is created - * by a @ref UMLView. An combinedfragmentWidget belongs to only one @ref UMLView instance. - * When the @ref UMLView instance that this class belongs to, it will be automatically deleted. - * - * The combinedfragmentWidget class inherits from the @ref UMLWidget class which adds most of the functionality - * to this class. - * - * @short A graphical version of a UML combined fragment. - * @author Hassan KOUCH - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class CombinedFragmentWidget : public UMLWidget -{ - Q_OBJECT - -public: - enum CombinedFragmentType - { - Ref = 0, - Opt, - Break, - Loop, - Neg, - Crit, - Ass, - Alt, - Par - }; - - explicit CombinedFragmentWidget(UMLScene * scene, - CombinedFragmentType combinedfragmentType = Ref, - Uml::ID::Type id = Uml::ID::None); - virtual ~CombinedFragmentWidget(); - - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - - CombinedFragmentType combinedFragmentType() const; - CombinedFragmentType combinedFragmentType(const QString& combinedfragmentType) const; - void setCombinedFragmentType(CombinedFragmentType combinedfragmentType); - void setCombinedFragmentType(const QString& combinedfragmentType); - - void askNameForWidgetType(UMLWidget* &targetWidget, const QString& dialogTitle, - const QString& dialogPrompt, const QString& defaultName); - - void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); - bool loadFromXMI(QDomElement & qElement); - void removeDashLine(FloatingDashLineWidget *line); - - virtual void cleanup(); - -public slots: - void slotMenuSelection(QAction* action); - - -protected: - QSizeF minimumSize() const; - - /// Type of CombinedFragment. - CombinedFragmentType m_CombinedFragment; - -private: - /// Dash lines of an alternative or parallel combined fragment - QList m_dashLines ; - -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/componentwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/componentwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/componentwidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/componentwidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,207 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "componentwidget.h" - -// app includes -#include "component.h" -#include "debug_utils.h" -#include "umlscene.h" -#include "umlview.h" -#include "optionstate.h" -#include "umldoc.h" -#include "package.h" -#include "portwidget.h" - -/** - * Constructs a ComponentWidget. - * - * @param scene The parent of this ComponentWidget. - * @param c The UMLComponent this will be representing. - */ -ComponentWidget::ComponentWidget(UMLScene * scene, UMLComponent *c) - : UMLWidget(scene, WidgetBase::wt_Component, c) -{ - setSize(100, 30); - //set defaults from m_scene - if (m_scene) { - //check to see if correct - const Settings::OptionState& ops = m_scene->optionState(); - m_showStereotype = ops.classState.showStereoType; - } -} - -/** - * Destructor. - */ -ComponentWidget::~ComponentWidget() -{ -} - -/** - * Reimplemented from UMLWidget::paint to paint component - * widget. - */ -void ComponentWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - Q_UNUSED(option); - Q_UNUSED(widget); - - UMLComponent *umlcomp = static_cast(m_umlObject); - if (umlcomp == NULL) - return; - setPenFromSettings(painter); - QPen origPen = painter->pen(); - QPen pen = origPen; - if (umlcomp->getExecutable()) { - pen.setWidth(origPen.width() + 2); - painter->setPen(pen); - } - if (UMLWidget::useFillColor()) { - painter->setBrush(UMLWidget::fillColor()); - } else { - painter->setBrush(m_scene->backgroundColor()); - } - - const int w = width(); - const int h = height(); - const int halfHeight = h / 2; - int textXOffset = 0; - QFont font = UMLWidget::font(); - font.setBold(true); - const QFontMetrics &fm = getFontMetrics(FT_BOLD); - const int fontHeight = fm.lineSpacing(); - QString nameStr = name(); - const QString stereotype = m_umlObject->stereotype(); - - if (Settings::optionState().generalState.uml2) { - painter->drawRect(0, 0, w, h); - // draw small component symbol in upper right corner - painter->setPen(origPen); - painter->drawRect(w - 17, 5, 11, 13); - painter->drawRect(w - 19, 7, 2, 2); - painter->drawRect(w - 19, 11, 2, 2); - painter->setPen(pen); - } else { - painter->drawRect(2*COMPONENT_MARGIN, 0, w - 2*COMPONENT_MARGIN, h); - painter->drawRect(0, halfHeight - fontHeight/2 - fontHeight, COMPONENT_MARGIN*4, fontHeight); - painter->drawRect(0, halfHeight + fontHeight/2, COMPONENT_MARGIN*4, fontHeight); - textXOffset = COMPONENT_MARGIN * 4; - } - - painter->setPen(textColor()); - painter->setFont(font); - - int lines = 1; - - if (!stereotype.isEmpty()) { - painter->drawText(textXOffset, halfHeight - fontHeight, - w - textXOffset, fontHeight, Qt::AlignCenter, - m_umlObject->stereotype(true)); - lines = 2; - } - - if (UMLWidget::isInstance()) { - font.setUnderline(true); - painter->setFont(font); - nameStr = UMLWidget::instanceName() + QLatin1String(" : ") + nameStr; - } - - if (lines == 1) { - painter->drawText(textXOffset, halfHeight - (fontHeight/2), - w - textXOffset, fontHeight, Qt::AlignCenter, nameStr); - } else { - painter->drawText(textXOffset, halfHeight, - w - textXOffset, fontHeight, Qt::AlignCenter, nameStr); - } - - UMLWidget::paint(painter, option, widget); -} - -/** - * Overridden from UMLWidget due to emission of signal sigCompMoved() - */ -void ComponentWidget::moveWidgetBy(qreal diffX, qreal diffY) -{ - UMLWidget::moveWidgetBy(diffX, diffY); - emit sigCompMoved(diffX, diffY); -} - -/** - * Override method from UMLWidget for adjustment of attached PortWidgets. - */ -void ComponentWidget::adjustAssocs(qreal dx, qreal dy) -{ - if (m_doc->loading()) { - // don't recalculate the assocs during load of XMI - // -> return immediately without action - return; - } - UMLWidget::adjustAssocs(dx, dy); - UMLPackage *comp = static_cast(m_umlObject); - foreach (UMLObject *o, comp->containedObjects()) { - uIgnoreZeroPointer(o); - if (o->baseType() != UMLObject::ot_Port) - continue; - UMLWidget *portW = m_scene->widgetOnDiagram(o->id()); - if (portW) - portW->adjustAssocs(dx, dy); - } -} - -/** - * Saves to the "componentwidget" XMI element. - */ -void ComponentWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) -{ - QDomElement conceptElement = qDoc.createElement(QLatin1String("componentwidget")); - UMLWidget::saveToXMI(qDoc, conceptElement); - qElement.appendChild(conceptElement); -} - -/** - * Overrides method from UMLWidget. - */ -QSizeF ComponentWidget::minimumSize() const -{ - if (!m_umlObject) { - return QSizeF(70, 70); - } - const QFontMetrics &fm = getFontMetrics(FT_BOLD_ITALIC); - const int fontHeight = fm.lineSpacing(); - - QString name = m_umlObject->name(); - if (UMLWidget::isInstance()) { - name = UMLWidget::instanceName() + QLatin1String(" : ") + name; - } - - int width = fm.width(name); - - int stereoWidth = 0; - if (!m_umlObject->stereotype().isEmpty()) { - stereoWidth = fm.width(m_umlObject->stereotype(true)); - } - if (stereoWidth > width) - width = stereoWidth; - width += COMPONENT_MARGIN * 6; - width = 70>width ? 70 : width; //minumin width of 70 - - int height = (2*fontHeight) + (COMPONENT_MARGIN * 3); - - UMLComponent *umlcomp = static_cast(m_umlObject); - if (umlcomp && umlcomp->getExecutable()) { - width += 2; - height += 2; - } - - return QSizeF(width, height); -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/componentwidget.h umbrello-kf6-15.08.1/umbrello/widgets/componentwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/componentwidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/componentwidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,58 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef COMPONENTWIDGET_H -#define COMPONENTWIDGET_H - -#include "umlwidget.h" - -class UMLComponent; - -#define COMPONENT_MARGIN 10 - -/** - * Defines a graphical version of the Component. Most of the functionality - * will come from the @ref UMLComponent class. - * - * @short A graphical version of a Component. - * @author Jonathan Riddell - * @see UMLWidget - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class ComponentWidget : public UMLWidget -{ - Q_OBJECT -public: - ComponentWidget(UMLScene * scene, UMLComponent *c); - virtual ~ComponentWidget(); - - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - virtual void moveWidgetBy(qreal diffX, qreal diffY); - virtual void adjustAssocs(qreal dx, qreal dy); - - virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); - -signals: - /** - * Emitted when the component widget is moved. - * Provides the delta X and delta Y amount by which the widget was moved - * relative to the previous position. - * Slots into PortWidget::slotCompMoved() - * @param diffX The difference between previous and new X value. - * @param diffY The difference between previous and new Y value. - */ - void sigCompMoved(qreal diffX, qreal diffY); - -protected: - QSizeF minimumSize() const; - -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/datatypewidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/datatypewidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/datatypewidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/datatypewidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,129 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "datatypewidget.h" - -// app includes -#include "classifier.h" -#include "classifierlistitem.h" -#include "debug_utils.h" -#include "operation.h" -#include "umldoc.h" -#include "umlscene.h" -#include "umlview.h" - -// qt includes -#include - -/** - * Constructs an DatatypeWidget. - * - * @param scene The parent of this DatatypeWidget. - * @param d The UMLClassifier this will be representing. - */ -DatatypeWidget::DatatypeWidget(UMLScene *scene, UMLClassifier *d) - : UMLWidget(scene, WidgetBase::wt_Datatype, d) -{ - setSize(100, 30); -} - -/** - * Standard deconstructor. - */ -DatatypeWidget::~DatatypeWidget() -{ -} - -/** - * Overrides standard method. - */ -void DatatypeWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - setPenFromSettings(painter); - if (UMLWidget::useFillColor()) { - painter->setBrush(UMLWidget::fillColor()); - } else { - painter->setBrush(m_scene->backgroundColor()); - } - - int w = width(); - int h = height(); - - QFontMetrics &fm = getFontMetrics(FT_NORMAL); - int fontHeight = fm.lineSpacing(); - - painter->drawRect(0, 0, w, h); - painter->setPen(textColor()); - - QFont font = UMLWidget::font(); - font.setBold(true); - painter->setFont(font); - painter->drawText(DATATYPE_MARGIN, 0, - w - DATATYPE_MARGIN* 2, fontHeight, - Qt::AlignCenter, m_umlObject->stereotype(true)); - - font.setItalic(m_umlObject->isAbstract()); - painter->setFont(font); - painter->drawText(DATATYPE_MARGIN, fontHeight, - w - DATATYPE_MARGIN * 2, fontHeight, Qt::AlignCenter, name()); - - UMLWidget::paint(painter, option, widget); -} - -/** - * Loads from a "datatypewidget" XMI element. - */ -bool DatatypeWidget::loadFromXMI(QDomElement & qElement) -{ - return UMLWidget::loadFromXMI(qElement); -} - -/** - * Saves to the "datatypewidget" XMI element. - */ -void DatatypeWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) -{ - QDomElement conceptElement = qDoc.createElement(QLatin1String("datatypewidget")); - UMLWidget::saveToXMI(qDoc, conceptElement); - qElement.appendChild(conceptElement); -} - -/** - * Overrides method from UMLWidget. - */ -QSizeF DatatypeWidget::minimumSize() const -{ - if (!m_umlObject) { - return UMLWidget::minimumSize(); - } - int width, height; - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - - int lines = 1;//always have one line - for name - lines++; //for the stereotype - - height = width = 0; - height += lines * fontHeight; - - //now set the width of the concept - //set width to name to start with - //set width to name to start with - width = getFontMetrics(FT_BOLD_ITALIC).boundingRect(m_umlObject->fullyQualifiedName()).width(); - int w = getFontMetrics(FT_BOLD).boundingRect(m_umlObject->stereotype(true)).width(); - - width = w > width?w:width; - - //allow for width margin - width += DATATYPE_MARGIN * 2; - - return QSizeF(width, height); -} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/datatypewidget.h umbrello-kf6-15.08.1/umbrello/widgets/datatypewidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/datatypewidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/datatypewidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,48 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef DATATYPEWIDGET_H -#define DATATYPEWIDGET_H - -#include "umlwidget.h" - -class UMLClassifier; - -#define DATATYPE_MARGIN 5 - -/** - * Defines a graphical version of the datatype. Most of the functionality - * will come from the @ref UMLWidget class from which class inherits from. - * - * @short A graphical version of an datatype. - * @author Jonathan Riddell - * @see UMLWidget - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class DatatypeWidget : public UMLWidget -{ - Q_OBJECT -public: - DatatypeWidget(UMLScene *scene, UMLClassifier *d); - virtual ~DatatypeWidget(); - - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - - bool loadFromXMI(QDomElement& qElement); - void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); - -public Q_SLOTS: - -protected: - QSizeF minimumSize() const; - -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/entitywidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/entitywidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/entitywidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/entitywidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,246 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "entitywidget.h" - -// app includes -#include "classifier.h" -#include "classifierlistitem.h" -#include "debug_utils.h" -#include "entity.h" -#include "entityattribute.h" -#include "foreignkeyconstraint.h" -#include "listpopupmenu.h" -#include "object_factory.h" -#include "uml.h" -#include "umlclassifierlistitemlist.h" -#include "umldoc.h" -#include "umlscene.h" -#include "umlview.h" -#include "uniqueconstraint.h" - -/** - * Constructs an EntityWidget. - * - * @param scene The parent of this EntityWidget. - * @param o The UMLObject this will be representing. - */ -EntityWidget::EntityWidget(UMLScene *scene, UMLObject* o) - : UMLWidget(scene, WidgetBase::wt_Entity, o) -{ - setSize(100, 30); -} - -/** - * Destructor. - */ -EntityWidget::~EntityWidget() -{ -} - -/** - * Draws the entity as a rectangle with a box underneith with a list of literals - */ -void EntityWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - Q_UNUSED(option); - Q_UNUSED(widget); - - setPenFromSettings(painter); - if(UMLWidget::useFillColor()) - painter->setBrush(UMLWidget::fillColor()); - else - painter->setBrush(m_scene->backgroundColor()); - - const int w = width(); - const int h = height(); - - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - int fontHeight = fm.lineSpacing(); - const QString name = this->name(); - - painter->drawRect(0, 0, w, h); - painter->setPen(textColor()); - - QFont font = UMLWidget::font(); - font.setBold(true); - painter->setFont(font); - int y = 0; - if (!m_umlObject->stereotype().isEmpty()) { - painter->drawText(ENTITY_MARGIN, 0, - w - ENTITY_MARGIN * 2, fontHeight, - Qt::AlignCenter, m_umlObject->stereotype(true)); - font.setItalic(m_umlObject->isAbstract()); - painter->setFont(font); - painter->drawText(ENTITY_MARGIN, fontHeight, - w - ENTITY_MARGIN * 2, fontHeight, Qt::AlignCenter, name); - font.setBold(false); - font.setItalic(false); - painter->setFont(font); - y = fontHeight * 2; - } else { - font.setItalic(m_umlObject->isAbstract()); - painter->setFont(font); - painter->drawText(ENTITY_MARGIN, 0, - w - ENTITY_MARGIN * 2, fontHeight, Qt::AlignCenter, name); - font.setBold(false); - font.setItalic(false); - painter->setFont(font); - - y = fontHeight; - } - - setPenFromSettings(painter); - - painter->drawLine(0, y, w, y); - - QFontMetrics fontMetrics(font); - UMLClassifier *classifier = (UMLClassifier*)m_umlObject; - UMLClassifierListItem* entityattribute = 0; - UMLClassifierListItemList list = classifier->getFilteredList(UMLObject::ot_EntityAttribute); - foreach (entityattribute, list) { - QString text = entityattribute->name(); - painter->setPen(textColor()); - UMLEntityAttribute* casted = dynamic_cast(entityattribute); - if(casted && casted->indexType() == UMLEntityAttribute::Primary) - { - font.setUnderline(true); - painter->setFont(font); - font.setUnderline(false); - } - painter->drawText(ENTITY_MARGIN, y, - fontMetrics.width(text), fontHeight, Qt::AlignVCenter, text); - painter->setFont(font); - y+=fontHeight; - } - - UMLWidget::paint(painter, option, widget); -} - -/** - * Saves to the "entitywidget" XMI element. - */ -void EntityWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) -{ - QDomElement conceptElement = qDoc.createElement(QLatin1String("entitywidget")); - UMLWidget::saveToXMI(qDoc, conceptElement); - qElement.appendChild(conceptElement); -} - -/** - * Will be called when a menu selection has been made from the popup - * menu. - * - * @param action The action that has been selected. - */ -void EntityWidget::slotMenuSelection(QAction* action) -{ - ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); - switch(sel) { - case ListPopupMenu::mt_EntityAttribute: - if (Object_Factory::createChildObject(static_cast(m_umlObject), - UMLObject::ot_EntityAttribute)) { - UMLApp::app()->document()->setModified(); - } - break; - - case ListPopupMenu::mt_PrimaryKeyConstraint: - case ListPopupMenu::mt_UniqueConstraint: - if (UMLObject* obj = Object_Factory::createChildObject(static_cast(m_umlObject), - UMLObject::ot_UniqueConstraint)) { - UMLApp::app()->document()->setModified(); - - if (sel == ListPopupMenu::mt_PrimaryKeyConstraint) { - UMLUniqueConstraint* uc = static_cast(obj); - static_cast(m_umlObject)->setAsPrimaryKey(uc); - } - } - break; - - case ListPopupMenu::mt_ForeignKeyConstraint: - if (Object_Factory::createChildObject(static_cast(m_umlObject), - UMLObject::ot_ForeignKeyConstraint)) { - UMLApp::app()->document()->setModified(); - - } - break; - - case ListPopupMenu::mt_CheckConstraint: - if (Object_Factory::createChildObject(static_cast(m_umlObject), - UMLObject::ot_CheckConstraint)) { - UMLApp::app()->document()->setModified(); - - } - break; - - default: - UMLWidget::slotMenuSelection(action); - } -} - -/** - * Overrides method from UMLWidget. - */ -QSizeF EntityWidget::minimumSize() const -{ - if (!m_umlObject) { - return UMLWidget::minimumSize(); - } - - int width, height; - QFont font = UMLWidget::font(); - font.setItalic(false); - font.setUnderline(false); - font.setBold(false); - const QFontMetrics fm(font); - - const int fontHeight = fm.lineSpacing(); - - int lines = 1;//always have one line - for name - if (!m_umlObject->stereotype().isEmpty()) { - lines++; - } - - const int numberOfEntityAttributes = ((UMLEntity*)m_umlObject)->entityAttributes(); - - height = width = 0; - //set the height of the entity - - lines += numberOfEntityAttributes; - if (numberOfEntityAttributes == 0) { - height += fontHeight / 2; //no entity literals, so just add a bit of space - } - - height += lines * fontHeight; - - //now set the width of the concept - //set width to name to start with - // FIXME spaces to get round beastie with font width, - // investigate UMLWidget::getFontMetrics() - width = getFontMetrics(FT_BOLD_ITALIC).boundingRect(QLatin1Char(' ') + name() + - QLatin1Char(' ')).width(); - const int w = getFontMetrics(FT_BOLD).boundingRect(m_umlObject->stereotype(true)).width(); - - width = w > width ? w : width; - - UMLClassifier* classifier = (UMLClassifier*)m_umlObject; - UMLClassifierListItemList list = classifier->getFilteredList(UMLObject::ot_EntityAttribute); - UMLClassifierListItem* listItem = 0; - foreach (listItem, list) { - int w = fm.width(listItem->name()); - width = w > width?w:width; - } - - //allow for width margin - width += ENTITY_MARGIN * 2; - - return QSizeF(width, height); -} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/entitywidget.h umbrello-kf6-15.08.1/umbrello/widgets/entitywidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/entitywidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/entitywidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,49 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef ENTITYWIDGET_H -#define ENTITYWIDGET_H - -#include "umlwidget.h" - -class UMLScene; - -#define ENTITY_MARGIN 5 - -/** - * Defines a graphical version of the entity. Most of the functionality - * will come from the @ref UMLWidget class from which class inherits from. - * - * @short A graphical version of an entity. - * @author Jonathan Riddell - * @see UMLWidget - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class EntityWidget : public UMLWidget -{ - Q_OBJECT -public: - explicit EntityWidget(UMLScene *scene, UMLObject* o); - virtual ~EntityWidget(); - - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - - // UMLWidget::loadFromXMI is used to load this widget. - virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); - -public Q_SLOTS: - virtual void slotMenuSelection(QAction* action); - -protected: - QSizeF minimumSize() const; - -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/enumwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/enumwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/enumwidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/enumwidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,262 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "enumwidget.h" - -// app includes -#include "classifier.h" -#include "classifierlistitem.h" -#include "debug_utils.h" -#include "enum.h" -#include "enumliteral.h" -#include "listpopupmenu.h" -#include "object_factory.h" -#include "uml.h" -#include "umlclassifierlistitemlist.h" -#include "umldoc.h" -#include "umlscene.h" -#include "umlview.h" - -/** - * Constructs an instance of EnumWidget. - * - * @param scene The parent of this EnumWidget. - * @param o The UMLObject this will be representing. - */ -EnumWidget::EnumWidget(UMLScene *scene, UMLObject* o) - : UMLWidget(scene, WidgetBase::wt_Enum, o), - m_showPackage(false) -{ - setSize(100, 30); - //set defaults from m_scene - if (m_scene) { - //check to see if correct - const Settings::OptionState& ops = m_scene->optionState(); - m_showPackage = ops.classState.showPackage; - } else { - // For completeness only. Not supposed to happen. - m_showPackage = false; - } -} - -/** - * Destructor. - */ -EnumWidget::~EnumWidget() -{ -} - -/** - * Returns the status of whether to show Package. - * - * @return True if package is shown. - */ -bool EnumWidget::showPackage() const -{ - return m_showPackage; -} - -/** - * Set the status of whether to show Package. - * - * @param _status True if package shall be shown. - */ -void EnumWidget::setShowPackage(bool _status) -{ - m_showPackage = _status; - updateGeometry(); - update(); -} - -/** - * Toggles the status of whether to show package. - */ -void EnumWidget::toggleShowPackage() -{ - m_showPackage = !m_showPackage; - updateGeometry(); - update(); -} - -/** - * Draws the enum as a rectangle with a box underneith with a list of literals - * Reimplemented from UMLWidget::paint - */ -void EnumWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - Q_UNUSED(option); - Q_UNUSED(widget); - - setPenFromSettings(painter); - if(UMLWidget::useFillColor()) - painter->setBrush(UMLWidget::fillColor()); - else - painter->setBrush(m_scene->backgroundColor()); - - const int w = width(); - const int h = height(); - - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - QString name; - if (m_showPackage) { - name = m_umlObject->fullyQualifiedName(); - } else { - name = this->name(); - } - - painter->drawRect(0, 0, w, h); - painter->setPen(textColor()); - - QFont font = UMLWidget::font(); - font.setBold(true); - painter->setFont(font); - painter->drawText(ENUM_MARGIN, 0, - w - ENUM_MARGIN * 2, fontHeight, - Qt::AlignCenter, m_umlObject->stereotype(true)); - - font.setItalic(m_umlObject->isAbstract()); - painter->setFont(font); - painter->drawText(ENUM_MARGIN, fontHeight, - w - ENUM_MARGIN * 2, fontHeight, Qt::AlignCenter, name); - font.setBold(false); - font.setItalic(false); - painter->setFont(font); - - int y = fontHeight * 2; - - setPenFromSettings(painter); - - painter->drawLine(0, y, w, y); - - QFontMetrics fontMetrics(font); - UMLClassifier *classifier = (UMLClassifier*)m_umlObject; - UMLClassifierListItem* enumLiteral = 0; - UMLClassifierListItemList list = classifier->getFilteredList(UMLObject::ot_EnumLiteral); - foreach (enumLiteral, list) { - QString text = enumLiteral->name(); - painter->setPen(textColor()); - painter->drawText(ENUM_MARGIN, y, - fontMetrics.width(text), fontHeight, Qt::AlignVCenter, text); - y+=fontHeight; - } - - UMLWidget::paint(painter, option, widget); -} - -/** - * Loads from an "enumwidget" XMI element. - */ -bool EnumWidget::loadFromXMI(QDomElement & qElement) -{ - if (!UMLWidget::loadFromXMI(qElement)) { - return false; - } - QString showpackage = qElement.attribute(QLatin1String("showpackage"), QLatin1String("0")); - - m_showPackage = (bool)showpackage.toInt(); - - return true; -} - -/** - * Saves to the "enumwidget" XMI element. - */ -void EnumWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) -{ - QDomElement conceptElement = qDoc.createElement(QLatin1String("enumwidget")); - UMLWidget::saveToXMI(qDoc, conceptElement); - - conceptElement.setAttribute(QLatin1String("showpackage"), m_showPackage); - qElement.appendChild(conceptElement); -} - -/** - * Will be called when a menu selection has been made from the - * popup menu. - * - * @param action The action that has been selected. - */ -void EnumWidget::slotMenuSelection(QAction* action) -{ - ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); - if (sel == ListPopupMenu::mt_EnumLiteral) { - if (Object_Factory::createChildObject(static_cast(m_umlObject), - UMLObject::ot_EnumLiteral)) { - /* I don't know why it works without these calls: - updateComponentSize(); - update(); - */ - UMLApp::app()->document()->setModified(); - } - return; - } - UMLWidget::slotMenuSelection(action); -} - -/** - * Overrides method from UMLWidget. - */ -QSizeF EnumWidget::minimumSize() const -{ - if (!m_umlObject) { - return UMLWidget::minimumSize(); - } - - int width, height; - QFont font = UMLWidget::font(); - font.setItalic(false); - font.setUnderline(false); - font.setBold(false); - const QFontMetrics fm(font); - - const int fontHeight = fm.lineSpacing(); - - int lines = 1;//always have one line - for name - lines++; //for the stereotype - - const int numberOfEnumLiterals = ((UMLEnum*)m_umlObject)->enumLiterals(); - - height = width = 0; - //set the height of the enum - - lines += numberOfEnumLiterals; - if (numberOfEnumLiterals == 0) { - height += fontHeight / 2; //no enum literals, so just add a bit of space - } - - height += lines * fontHeight; - - //now set the width of the concept - //set width to name to start with - if (m_showPackage) { - width = getFontMetrics(FT_BOLD_ITALIC).boundingRect(m_umlObject->fullyQualifiedName()).width(); - } else { - width = getFontMetrics(FT_BOLD_ITALIC).boundingRect(name()).width(); - } - int w = getFontMetrics(FT_BOLD).boundingRect(m_umlObject->stereotype(true)).width(); - - - width = w > width?w:width; - - UMLClassifier *classifier = (UMLClassifier*)m_umlObject; - UMLClassifierListItemList list = classifier->getFilteredList(UMLObject::ot_EnumLiteral); - UMLClassifierListItem* listItem = 0; - foreach (listItem, list) { - int w = fm.width(listItem->name()); - width = w > width?w:width; - } - - //allow for width margin - width += ENUM_MARGIN * 2; - - return QSizeF(width, height); -} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/enumwidget.h umbrello-kf6-15.08.1/umbrello/widgets/enumwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/enumwidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/enumwidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,52 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef ENUMWIDGET_H -#define ENUMWIDGET_H - -#include "umlwidget.h" - -#define ENUM_MARGIN 5 - -/** - * Defines a graphical version of the enum. Most of the functionality - * will come from the @ref UMLWidget class from which class inherits from. - * - * @short A graphical version of an enum. - * @author Jonathan Riddell - * @see UMLWidget - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class EnumWidget : public UMLWidget -{ - Q_OBJECT -public: - explicit EnumWidget(UMLScene *scene, UMLObject* o); - virtual ~EnumWidget(); - - bool showPackage() const; - void setShowPackage(bool _status); - void toggleShowPackage(); - - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - - virtual bool loadFromXMI(QDomElement& qElement); - virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); - -public Q_SLOTS: - virtual void slotMenuSelection(QAction* action); - -protected: - QSizeF minimumSize() const; - - bool m_showPackage; -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/floatingdashlinewidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/floatingdashlinewidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/floatingdashlinewidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/floatingdashlinewidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,199 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ -// own header -#include "floatingdashlinewidget.h" -#include "combinedfragmentwidget.h" - -//kde includes -#if QT_VERSION < 0x050000 -#include -#endif -#include - -//app includes -#include "debug_utils.h" -#include "umlview.h" -#include "widget_utils.h" -#include "listpopupmenu.h" - -// qt includes -#if QT_VERSION >= 0x050000 -#include -#endif -#include - -DEBUG_REGISTER_DISABLED(FloatingDashLineWidget) - -/** - * Creates a floating dash line. - * @param scene The parent of the widget - * @param id The ID to assign (-1 will prompt a new ID) - * @param parent The CombinedFragmentWidget which acts as the parent - */ -FloatingDashLineWidget::FloatingDashLineWidget(UMLScene * scene, Uml::ID::Type id, CombinedFragmentWidget *parent) - : UMLWidget(scene, WidgetBase::wt_FloatingDashLine, id), - m_yMin(0), - m_yMax(0), - m_parent(parent) -{ - m_resizable = false; - m_Text = QString(); - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - setSize(10, fontHeight); -} - -/** - * Destructor. - */ -FloatingDashLineWidget::~FloatingDashLineWidget() -{ - if (m_parent) - m_parent->removeDashLine(this); -} - -/** - * Overrides the standard paint event. - */ -void FloatingDashLineWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - Q_UNUSED(option); - Q_UNUSED(widget); - - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - painter->setPen(textColor()); - painter->setFont(UMLWidget::font()); - painter->drawText(FLOATING_DASH_LINE_TEXT_MARGIN, 0, - width() - FLOATING_DASH_LINE_TEXT_MARGIN * 2, fontHeight, - Qt::AlignLeft, QLatin1Char('[') + m_Text + QLatin1Char(']')); - painter->setPen(QPen(UMLWidget::lineColor(), 0, Qt::DashLine)); - painter->drawLine(0, 0, width(), 0); - - UMLWidget::paint(painter, option, widget); -} - -/** - * Sets m_text. - */ -void FloatingDashLineWidget::setText(const QString& text) -{ - m_Text = text; -} - -/** - * Returns true if the given point is near the floatingdashline. - */ -bool FloatingDashLineWidget::onLine(const QPointF& point) -{ - // check if the given point is the start or end point of the line - if (((abs((long)(y() + height() - point.y()))) <= POINT_DELTA) || (abs((long)(y() - point.y())) <= POINT_DELTA)) { - return true; - } - // check if the given point is the start or end point of the line - return false; -} - -void FloatingDashLineWidget::slotMenuSelection(QAction* action) -{ - ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); - switch(sel) { - case ListPopupMenu::mt_Rename: - { - bool ok = false; - QString name = m_Text; -#if QT_VERSION >= 0x050000 - name = QInputDialog::getText(Q_NULLPTR, - i18n("Enter alternative Name"), i18n("Enter the alternative:"), - QLineEdit::Normal, - m_Text, &ok); -#else - name = KInputDialog::getText(i18n("Enter alternative Name"), i18n("Enter the alternative:"), m_Text, &ok); -#endif - if (ok && name.length() > 0) - m_Text = name; - } - break; - default: - UMLWidget::slotMenuSelection(action); - } -} - -/** - * Overrides the setY method. - */ -void FloatingDashLineWidget::setY(qreal y) -{ - if(y >= m_yMin + FLOATING_DASH_LINE_MARGIN && y <= m_yMax - FLOATING_DASH_LINE_MARGIN) - UMLWidget::setY(y); -} - -/** - * Sets m_yMin. - */ -void FloatingDashLineWidget::setYMin(qreal yMin) -{ - m_yMin = yMin; -} - -/** - * Sets m_yMax. - */ -void FloatingDashLineWidget::setYMax(qreal yMax) -{ - m_yMax = yMax; -} - -/** - * Returns m_yMin. - */ -qreal FloatingDashLineWidget::getYMin() const -{ - return m_yMin; -} - -/** - * Returns the difference between the y-coordinate of the dash line and m_yMin. - */ -qreal FloatingDashLineWidget::getDiffY() const -{ - return (y() - getYMin()); -} - -/** - * Creates the "floatingdashline" XMI element. - */ -void FloatingDashLineWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) -{ - QDomElement textElement = qDoc.createElement(QLatin1String("floatingdashlinewidget")); - UMLWidget::saveToXMI(qDoc, textElement); - textElement.setAttribute(QLatin1String("text"), m_Text); - textElement.setAttribute(QLatin1String("y"), y()); - textElement.setAttribute(QLatin1String("minY"), m_yMin); - textElement.setAttribute(QLatin1String("maxY"), m_yMax); - - qElement.appendChild(textElement); -} - -/** - * Loads the "floatingdashline" XMI element. - */ -bool FloatingDashLineWidget::loadFromXMI(QDomElement & qElement) -{ - if(!UMLWidget::loadFromXMI(qElement)) { - return false; - } - DEBUG(DBG_SRC) << "load......."; - m_yMax = qElement.attribute(QLatin1String("maxY")).toFloat(); - m_yMin = qElement.attribute(QLatin1String("minY")).toFloat(); - m_Text = qElement.attribute(QLatin1String("text")); - return true; -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/floatingdashlinewidget.h umbrello-kf6-15.08.1/umbrello/widgets/floatingdashlinewidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/floatingdashlinewidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/floatingdashlinewidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,77 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef FLOATINGDASHLINEWIDGET_H -#define FLOATINGDASHLINEWIDGET_H - -#include "umlwidget.h" -class CombinedFragmentWidget; - -#define FLOATING_DASH_LINE_MARGIN 25 -#define FLOATING_DASH_LINE_TEXT_MARGIN 5 - -/* how many pixels a user could click around a point */ -#define POINT_DELTA 5 - -/** - * This class is used to draw dash lines for UML combined fragments. A FloatingDashLineWidget - * belongs to one @ref CombinedFragmentWidget instance. - * - * The FloatingDashLineWidget class inherits from the @ref UMLWidget class. - * - * @short A dash line for UML combined fragments. - * @author Thomas GALLINARI - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class FloatingDashLineWidget : public UMLWidget -{ - Q_OBJECT -public: - explicit FloatingDashLineWidget(UMLScene * scene, Uml::ID::Type id = Uml::ID::None, CombinedFragmentWidget *parent = 0); - ~FloatingDashLineWidget(); - - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option = 0, QWidget *widget = 0); - - void slotMenuSelection(QAction* action); - - bool onLine(const QPointF& point); - - void setText(const QString& text); - - void setY(qreal y); - void setYMin(qreal yMin); - void setYMax(qreal yMax); - qreal getYMin() const; - qreal getDiffY() const; - - void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); - bool loadFromXMI(QDomElement & qElement); - -private: - /** - * Text associated to the dash line - */ - QString m_text; - - /** - * Minimum value of the Y-coordinate of the dash line - * (= y-coordinate of the combined fragment) - */ - int m_yMin; - - /** - * Maximum value of the Y-coordinate of the dash line - * (= y-coordinate of the combined fragment + height of the combined fragment) - */ - int m_yMax; - CombinedFragmentWidget *m_parent; -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/floatingtextwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/floatingtextwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/floatingtextwidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/floatingtextwidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,854 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "floatingtextwidget.h" - -// local includes -#include "association.h" -#include "associationwidget.h" -#include "associationpropertiesdialog.h" -#include "classifier.h" -#include "cmds.h" -#include "debug_utils.h" -#include "linkwidget.h" -#include "classifierwidget.h" -#include "listpopupmenu.h" -#include "messagewidget.h" -#include "model_utils.h" -#include "object_factory.h" -#include "operation.h" -#include "selectoperationdialog.h" -#include "uml.h" -#include "umldoc.h" -#include "umlview.h" - -// kde includes -#if QT_VERSION < 0x050000 -#include -#include -#endif -#include - -// qt includes -#if QT_VERSION >= 0x050000 -#include -#include -#endif -#include -#include -#include -#include - -DEBUG_REGISTER_DISABLED(FloatingTextWidget) - -/** - * Constructs a FloatingTextWidget instance. - * - * @param scene The parent of this FloatingTextWidget. - * @param role The role this FloatingTextWidget will take up. - * @param text The main text to display. - * @param id The ID to assign (-1 will prompt a new ID.) - */ -FloatingTextWidget::FloatingTextWidget(UMLScene * scene, Uml::TextRole::Enum role, const QString& text, Uml::ID::Type id) - : UMLWidget(scene, WidgetBase::wt_Text, id), - m_linkWidget(0), - m_preText(QString()), - m_postText(QString()), - m_textRole(role), - m_unconstrainedPositionX(0), - m_unconstrainedPositionY(0), - m_movementDirectionX(0), - m_movementDirectionY(0) -{ - m_Text = text; - m_resizable = false; - setZValue(10); //make sure always on top. -} - -/** - * Destructor. - */ -FloatingTextWidget::~FloatingTextWidget() -{ -} - -/** - * Use to get the _main body_ of text (e.g. prepended and appended - * text is omitted) as currently displayed by the widget. - * - * @return The main text currently being displayed by the widget. - */ -QString FloatingTextWidget::text() const -{ - // test to make sure not just the ":" between the seq number and - // the actual message widget - - // hmm. this section looks like it could have been avoided by - // using pre-, post- text instead of storing in the main body of - // the text -b.t. - if (m_textRole == Uml::TextRole::Seq_Message || m_textRole == Uml::TextRole::Seq_Message_Self || - m_textRole == Uml::TextRole::Coll_Message || m_textRole == Uml::TextRole::Coll_Message_Self) { - if (m_Text.length() <= 1 || m_Text == QLatin1String(": ")) - return QString(); - } - return m_Text; -} - -/** - * Set the main body of text to display. - * - * @param t The text to display. - */ -void FloatingTextWidget::setText(const QString &t) -{ - if (m_textRole == Uml::TextRole::Seq_Message || m_textRole == Uml::TextRole::Seq_Message_Self) { - QString op; - if (m_linkWidget) - op = m_linkWidget->lwOperationText(); - if (op.length() > 0) { - if (!m_scene->showOpSig()) - op.replace(QRegExp(QLatin1String("\\(.*\\)")), QLatin1String("()")); - m_Text = op; - } - else - m_Text = t; - } - else { - m_Text = t; - } - - QSizeF s = minimumSize(); - setSize(s.width(), s.height()); - - updateGeometry(); - update(); -} - -/** - * Set some text to be prepended to the main body of text. - * @param t The text to prepend to main body which is displayed. - */ -void FloatingTextWidget::setPreText(const QString &t) -{ - m_preText = t; - updateGeometry(); - update(); -} - -/** - * Set some text to be appended to the main body of text. - * @param t The text to append to main body which is displayed. - */ -void FloatingTextWidget::setPostText(const QString &t) -{ - m_postText = t; - updateGeometry(); - update(); -} - -/** - * Use to get the total text (prepended + main body + appended) - * currently displayed by the widget. - * - * @return The text currently being displayed by the widget. - */ -QString FloatingTextWidget::displayText() const -{ - QString displayText; - if (!m_SequenceNumber.isEmpty()) - displayText = m_SequenceNumber + QLatin1String(": ") + m_Text; - else - displayText = m_Text; - displayText.prepend(m_preText); - displayText.append(m_postText); - return displayText; -} - -/** - * Return state if no pre, post and main text is empty - * @return true if widget contains no text - */ -bool FloatingTextWidget::isEmpty() -{ - return m_Text.isEmpty() && m_preText.isEmpty() && m_postText.isEmpty(); -} - -/** - * Overrides method from UMLWidget. - */ -QSizeF FloatingTextWidget::minimumSize() const -{ - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - int h = fm.lineSpacing(); - int w = fm.width(displayText()); - return QSizeF(w + 8, h + 4); // give a small margin -} - -/** - * Method used by setText: its called by cmdsetTxt, Don't use it! - * - * @param t The text to display. - */ -void FloatingTextWidget::setTextcmd(const QString &t) -{ - UMLApp::app()->executeCommand(new Uml::CmdSetTxt(this, t)); -} - -/** - * Displays a dialog box to change the text. - */ -void FloatingTextWidget::showChangeTextDialog() -{ - bool ok = false; -#if QT_VERSION >= 0x050000 - QString newText = QInputDialog::getText(m_scene->activeView(), - i18n("Change Text"), i18n("Enter new text:"), - QLineEdit::Normal, - text(), &ok); -#else - QString newText = KInputDialog::getText(i18n("Change Text"), i18n("Enter new text:"), text(), &ok, m_scene->activeView()); -#endif - if (ok && newText != text() && isTextValid(newText)) { - setText(newText); - setVisible(!text().isEmpty()); - updateGeometry(); - update(); - } - if (!isTextValid(newText)) - hide(); -} - -/** - * Shows an operation dialog box. - * - * @param enableAutoIncrement Enable auto increment checkbox - */ -void FloatingTextWidget::showOperationDialog(bool enableAutoIncrement) -{ - if (!m_linkWidget) { - uError() << "m_linkWidget is NULL"; - return; - } - QString seqNum = m_linkWidget->sequenceNumber(); - UMLClassifier* c = m_linkWidget->lwClassifier(); - QString opText = m_linkWidget->lwOperationText(); - if (!c) { - uError() << "m_linkWidget->lwClassifier() returns a NULL classifier"; - return; - } - - QPointer selectDialog = new SelectOperationDialog(m_scene->activeView(), c, enableAutoIncrement); - if (enableAutoIncrement && m_scene->autoIncrementSequence()) { - seqNum = m_scene->autoIncrementSequenceValue(); - selectDialog->setAutoIncrementSequence(true); - } - selectDialog->setSeqNumber(seqNum); - if (m_linkWidget->operation() == 0) { - selectDialog->setCustomOp(opText); - } else { - selectDialog->setClassOp(opText); - } - if (selectDialog->exec()) { - seqNum = selectDialog->getSeqNumber(); - opText = selectDialog->getOpText(); - if (selectDialog->isClassOp()) { - Model_Utils::OpDescriptor od; - Model_Utils::Parse_Status st = Model_Utils::parseOperation(opText, od, c); - if (st == Model_Utils::PS_OK) { - UMLClassifierList selfAndAncestors = c->findSuperClassConcepts(); - selfAndAncestors.prepend(c); - UMLOperation *op = 0; - foreach (UMLClassifier *cl, selfAndAncestors) { - op = cl->findOperation(od.m_name, od.m_args); - if (op) { - break; - } - } - if (!op) { - // The op does not yet exist. Create a new one. - UMLObject *o = c->createOperation(od.m_name, 0, &od.m_args); - op = static_cast(o); - } - if (od.m_pReturnType) { - op->setType(od.m_pReturnType); - } - - m_linkWidget->setOperation(op); - opText.clear(); - } else { - m_linkWidget->setOperation(0); - } - } else { - m_linkWidget->setOperation(0); - } - m_linkWidget->setSequenceNumber(seqNum); - m_linkWidget->setOperationText(opText); - if (enableAutoIncrement) { - m_scene->setAutoIncrementSequence(selectDialog->autoIncrementSequence()); - } - setMessageText(); - } - delete selectDialog; -} - -/** - * Show the properties for a FloatingTextWidget. - * Depending on the role of the floating text wiget, the options dialog - * for the floating text widget, the rename dialog for floating text or - * the options dialog for the link widget are shown. - */ -void FloatingTextWidget::showPropertiesDialog() -{ - if (m_textRole == Uml::TextRole::Coll_Message || m_textRole == Uml::TextRole::Coll_Message_Self || - m_textRole == Uml::TextRole::Seq_Message || m_textRole == Uml::TextRole::Seq_Message_Self) { - showOperationDialog(false); - } else if (m_textRole == Uml::TextRole::Floating) { - // double clicking on a text line opens the dialog to change the text - handleRename(); - } else if (m_linkWidget) { - m_linkWidget->showPropertiesDialog(); - } -} - -/** - * Use to get the pre-text which is prepended to the main body of - * text to be displayed. - * - * @return The pre-text currently displayed by the widget. - */ -QString FloatingTextWidget::preText() const -{ - return m_preText; -} - -/** - * Use to get the post-text which is appended to the main body of - * text to be displayed. - * - * @return The post-text currently displayed by the widget. - */ -QString FloatingTextWidget::postText() const -{ - return m_postText; -} - -/** - * Activate the FloatingTextWidget after the saved data has been loaded - * - * @param ChangeLog Pointer to the IDChangeLog. - * @return true for success - */ -bool FloatingTextWidget::activate(IDChangeLog* ChangeLog /*= 0 */) -{ - if (! UMLWidget::activate(ChangeLog)) - return false; - update(); - return true; -} - -/** - * Set the LinkWidget that this FloatingTextWidget is related to. - * - * @param l The related LinkWidget. - */ -void FloatingTextWidget::setLink(LinkWidget * l) -{ - m_linkWidget = l; -} - -/** - * Returns the LinkWidget this floating text is related to. - * - * @return The LinkWidget this floating text is related to. - */ -LinkWidget * FloatingTextWidget::link() const -{ - return m_linkWidget; -} - -/** - * Sets the role type of this FloatingTextWidget. - * - * @param role The TextRole::Enum of this FloatingTextWidget. - */ -void FloatingTextWidget::setTextRole(Uml::TextRole::Enum role) -{ - m_textRole = role; -} - -/** - * Return the role of the text widget - * @return The TextRole::Enum of this FloatingTextWidget. - */ -Uml::TextRole::Enum FloatingTextWidget::textRole() const -{ - return m_textRole; -} - -/** - * Handle the ListPopupMenu::mt_Rename case of the slotMenuSelection. - * Given an own method because it requires rather lengthy code. - */ -void FloatingTextWidget::handleRename() -{ - QRegExpValidator v(QRegExp(QLatin1String(".*")), 0); - QString t; - if (m_textRole == Uml::TextRole::RoleAName || m_textRole == Uml::TextRole::RoleBName) { - t = i18n("Enter role name:"); - } else if (m_textRole == Uml::TextRole::MultiA || m_textRole == Uml::TextRole::MultiB) { - t = i18n("Enter multiplicity:"); - /* - // NO! shouldn't be allowed - } else if (m_textRole == Uml::TextRole::ChangeA || m_textRole == Uml::TextRole::ChangeB) { - t = i18n("Enter changeability"); - */ - } else if (m_textRole == Uml::TextRole::Name) { - t = i18n("Enter association name:"); - } else if (m_textRole == Uml::TextRole::Floating) { - t = i18n("Enter new text:"); - } else { - t = i18n("ERROR"); - } - bool ok = false; -#if QT_VERSION >= 0x050000 - QString newText = QInputDialog::getText(m_scene->activeView(), - i18n("Rename"), t, - QLineEdit::Normal, - text(), &ok); -#else - QString newText = KInputDialog::getText(i18n("Rename"), t, text(), &ok, m_scene->activeView(), &v); -#endif - if (!ok || newText == text()) { - return; - } - - UMLApp::app()->executeCommand(new Uml::CmdHandleRename(this, newText)); -} - -/** - * Changes the text of linked widget. - * @param newText the new text - */ -void FloatingTextWidget::changeName(const QString& newText) -{ - if (m_linkWidget && !isTextValid(newText)) { - AssociationWidget *assoc = dynamic_cast(m_linkWidget); - if (assoc) { - switch (m_textRole) { - case Uml::TextRole::MultiA: - assoc->setMultiplicity(QString(), Uml::RoleType::A); - break; - case Uml::TextRole::MultiB: - assoc->setMultiplicity(QString(), Uml::RoleType::B); - break; - case Uml::TextRole::RoleAName: - assoc->setRoleName(QString(), Uml::RoleType::A); - break; - case Uml::TextRole::RoleBName: - assoc->setRoleName(QString(), Uml::RoleType::B); - break; - case Uml::TextRole::ChangeA: - assoc->setChangeability(Uml::Changeability::Changeable, Uml::RoleType::A); - break; - case Uml::TextRole::ChangeB: - assoc->setChangeability(Uml::Changeability::Changeable, Uml::RoleType::B); - break; - default: - assoc->setName(QString()); - break; - } - } - else { - MessageWidget *msg = dynamic_cast(m_linkWidget); - if (msg) { - msg->setName(QString()); - m_scene->removeWidget(this); - } - } - return; - } - - if (m_linkWidget && m_textRole != Uml::TextRole::Seq_Message - && m_textRole != Uml::TextRole::Seq_Message_Self) { - m_linkWidget->setText(this, newText); - } - else { - setText(newText); - UMLApp::app()->document()->setModified(true); - } - - setVisible(true); - updateGeometry(); - update(); -} - -/** - * Write property of QString m_SequenceNumber. - */ -void FloatingTextWidget::setSequenceNumber(const QString &sequenceNumber) -{ - m_SequenceNumber = sequenceNumber; -} - -/** - * Read property of QString m_SequenceNumber. - */ -QString FloatingTextWidget::sequenceNumber() const -{ - return m_SequenceNumber; -} - -/** - * For a text to be valid it must be non-empty, i.e. have a length - * larger than zero, and have at least one non whitespace character. - * - * @param text The string to analyze. - * @return True if the given text is valid. - */ -bool FloatingTextWidget::isTextValid(const QString &text) -{ - int length = text.length(); - if(length < 1) - return false; - for(int i=0;iconstrainTextPos(newX, newY, width(), height(), textRole()); - } - - return QPointF(newX, newY); -} - -/** - * Overridden from UMLWidget. - * Moves the widget to a new position using the difference between the - * current position and the new position. - * If the floating text widget is part of a sequence message, and the - * message widget is selected, it does nothing: the message widget will - * update the text position when it's moved. - * In any other case, the floating text widget constrains its move using - * constrainPosition. When the position of the floating text is constrained, - * it's kept at that position until it can be moved to another valid - * position (m_unconstrainedPositionX/Y and m_movementDirectionX/Y are - * used for that). - * Moreover, if is part of a sequence message (and the message widget - * isn't selected), it updates the position of the message widget. - * @see constrainPosition - * - * @param diffX The difference between current X position and new X position. - * @param diffY The difference between current Y position and new Y position. - */ -void FloatingTextWidget::moveWidgetBy(qreal diffX, qreal diffY) -{ - if (textRole() == Uml::TextRole::Seq_Message_Self) - return; - - if (textRole() == Uml::TextRole::Seq_Message - && ((MessageWidget*)link())->isSelected()) { - return; - } - - m_unconstrainedPositionX += diffX; - m_unconstrainedPositionY += diffY; - QPointF constrainedPosition = constrainPosition(diffX, diffY); - - qreal newX = constrainedPosition.x(); - qreal newY = constrainedPosition.y(); - - if (!m_movementDirectionX) { - if (m_unconstrainedPositionX != constrainedPosition.x()) { - m_movementDirectionX = (diffX > 0)? 1: -1; - } - } else if ((m_movementDirectionX < 0 && m_unconstrainedPositionX > x()) || - (m_movementDirectionX > 0 && m_unconstrainedPositionX < x()) ) { - newX = m_unconstrainedPositionX; - m_movementDirectionX = 0; - } - - if (!m_movementDirectionY) { - if (m_unconstrainedPositionY != constrainedPosition.y()) { - m_movementDirectionY = (diffY > 0)? 1: -1; - } - } else if ((m_movementDirectionY < 0 && m_unconstrainedPositionY > y()) || - (m_movementDirectionY > 0 && m_unconstrainedPositionY < y()) ) { - newY = m_unconstrainedPositionY; - m_movementDirectionY = 0; - } - - setX(newX); - setY(newY); - - if (link()) { - link()->calculateNameTextSegment(); - if (textRole() == Uml::TextRole::Seq_Message) { - MessageWidget* messageWidget = (MessageWidget*)link(); - messageWidget->setY(newY + height()); - } - } -} - -/** - * Overridden from UMLWidget. - * Modifies the value of the diffX and diffY variables used to move the - * widgets. - * The values are constrained using constrainPosition. - * @see constrainPosition - * - * @param diffX The difference between current X position and new X position. - * @param diffY The difference between current Y position and new Y position. - */ -void FloatingTextWidget::constrainMovementForAllWidgets(qreal &diffX, qreal &diffY) -{ - QPointF constrainedPosition = constrainPosition(diffX, diffY); - - diffX = constrainedPosition.x() - x(); - diffY = constrainedPosition.y() - y(); -} - -/** - * Override method from UMLWidget in order to additionally check widget parentage. - * - * @param p Point to be checked. - * - * @return 'this' if UMLWidget::onWidget(p) returns non NULL; - * else NULL. - */ -UMLWidget* FloatingTextWidget::onWidget(const QPointF &p) -{ - WidgetBase *pw = dynamic_cast(parentItem()); - if (pw == NULL) { - return WidgetBase::onWidget(p); - } - const WidgetBase::WidgetType t = pw->baseType(); - bool isWidgetChild = false; - if (t == WidgetBase::wt_Interface) { - ClassifierWidget *cw = static_cast(pw); - isWidgetChild = cw->getDrawAsCircle(); - } else if (t == wt_Association || - t == WidgetBase::wt_Port || t == WidgetBase::wt_Pin) { - isWidgetChild = true; - } - if (!isWidgetChild) { - return WidgetBase::onWidget(p); - } - const qreal w = width(); - const qreal h = height(); - const qreal left = pw->x() + x(); - const qreal right = left + w; - const qreal top = pw->y() + y(); - const qreal bottom = top + h; - // uDebug() << "child_of_pw; p=(" << p.x() << "," << p.y() << "), " - // << "x=" << left << ", y=" << top << ", w=" << w << ", h=" << h - // << "; right=" << right << ", bottom=" << bottom; - if (p.x() >= left && p.x() <= right && - p.y() >= top && p.y() <= bottom) { // Qt coord.sys. origin in top left corner - // uDebug() << "floatingtext: " << m_Text; - return this; - } - return NULL; -} - -/** - * Overrides default method - */ -void FloatingTextWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - Q_UNUSED(option); - Q_UNUSED(widget); - - int w = width(); - int h = height(); - painter->setFont(UMLWidget::font()); - painter->setPen(textColor()); - painter->drawText(0, 0, w, h, Qt::AlignCenter, displayText()); - - UMLWidget::paint(painter, option, widget); -} - -/** - * Loads the "floatingtext" XMI element. - */ -bool FloatingTextWidget::loadFromXMI(QDomElement & qElement) -{ - if(!UMLWidget::loadFromXMI(qElement)) - return false; - - m_unconstrainedPositionX = x(); - m_unconstrainedPositionY = y(); - QString role = qElement.attribute(QLatin1String("role")); - if(!role.isEmpty()) - m_textRole = Uml::TextRole::fromInt(role.toInt()); - - m_preText = qElement.attribute(QLatin1String("pretext")); - m_postText = qElement.attribute(QLatin1String("posttext")); - setText(qElement.attribute(QLatin1String("text"))); // use setText for geometry update - // If all texts are empty then this is a useless widget. - // In that case we return false. - // CAVEAT: The caller should not interpret the false return value - // as an indication of failure since previous umbrello-kf6 versions - // saved lots of these empty FloatingTexts. - bool usefulWidget = !isEmpty(); - return usefulWidget; -} - -/** - * Reimplemented from UMLWidget::saveToXMI to save the widget - * data into XMI 'floatingtext' element. - */ -void FloatingTextWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) -{ - if (isEmpty()) - return; - - QDomElement textElement = qDoc.createElement(QLatin1String("floatingtext")); - UMLWidget::saveToXMI(qDoc, textElement); - textElement.setAttribute(QLatin1String("text"), m_Text); - textElement.setAttribute(QLatin1String("pretext"), m_preText); - textElement.setAttribute(QLatin1String("posttext"), m_postText); - - /* No need to save these - the messagewidget already did it. - m_Operation = qElement.attribute("operation"); - m_SeqNum = qElement.attribute("seqnum"); - */ - - textElement.setAttribute(QLatin1String("role"), m_textRole); - qElement.appendChild(textElement); -} - -/** - * Called when a menu selection has been made. - * - * @param action The action that has been selected. - */ -void FloatingTextWidget::slotMenuSelection(QAction* action) -{ - ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); - switch(sel) { - case ListPopupMenu::mt_Properties: - showPropertiesDialog(); - break; - - case ListPopupMenu::mt_Delete: - hide(); // This is only a workaround; if set then m_linkWidget should - // really delete this FloatingTextWidget. - update(); - m_scene->removeWidget(this); - break; - - case ListPopupMenu::mt_New_Operation: // needed by AssociationWidget - case ListPopupMenu::mt_Operation: - { - if (m_linkWidget == 0) { - DEBUG(DBG_SRC) << "mt_Operation: m_linkWidget is NULL"; - return; - } - UMLClassifier* c = m_linkWidget->operationOwner(); - if (c == 0) { - bool ok = false; -#if QT_VERSION >= 0x050000 - QString opText = QInputDialog::getText(m_scene->activeView(), - i18nc("operation name", "Name"), - i18n("Enter operation name:"), - QLineEdit::Normal, - text(), &ok); -#else - QString opText = KInputDialog::getText(i18nc("operation name", "Name"), - i18n("Enter operation name:"), - text(), &ok, m_scene->activeView()); -#endif - if (ok) - m_linkWidget->setCustomOpText(opText); - return; - } - UMLClassifierListItem* umlObj = Object_Factory::createChildObject(c, UMLObject::ot_Operation); - if (umlObj) { - UMLOperation* newOperation = static_cast(umlObj); - m_linkWidget->setOperation(newOperation); - } - } - break; - - case ListPopupMenu::mt_Select_Operation: - showOperationDialog(false); - break; - - case ListPopupMenu::mt_Rename: - handleRename(); - break; - - case ListPopupMenu::mt_Change_Font: - { -#if QT_VERSION >= 0x050000 - bool ok = false; - QFont fnt = QFontDialog::getFont(&ok, font(), m_scene->activeView()); - if (ok) { -#else - QFont fnt = font(); - if(KFontDialog::getFont(fnt, KFontChooser::NoDisplayFlags, m_scene->activeView())) { -#endif - if(m_textRole == Uml::TextRole::Floating || m_textRole == Uml::TextRole::Seq_Message) { - setFont(fnt); - } else if (m_linkWidget) { - m_linkWidget->lwSetFont(fnt); - } - } - } - break; - - case ListPopupMenu::mt_Reset_Label_Positions: - if (m_linkWidget) - m_linkWidget->resetTextPositions(); - break; - - default: - UMLWidget::slotMenuSelection(action); - break; - }//end switch -} - -/** - * Sets the text for this label if it is acting as a sequence diagram - * message or a collaboration diagram message. - */ -void FloatingTextWidget::setMessageText() -{ - if (m_linkWidget) { - m_linkWidget->setMessageText(this); - QSizeF s = minimumSize(); - setSize(s.width(), s.height()); - - } - setVisible(!text().isEmpty()); -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/floatingtextwidget.h umbrello-kf6-15.08.1/umbrello/widgets/floatingtextwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/floatingtextwidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/floatingtextwidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,131 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef FLOATINGTEXTWIDGET_H -#define FLOATINGTEXTWIDGET_H - -#include "basictypes.h" -#include "umlwidget.h" - -class LinkWidget; -class UMLScene; - -/** - * @short Displays a line of text or an operation. - * - * This is a multipurpose-kf6 class. In its simplest form it will display a - * line of text. - * It can also be setup to be the text for an operation with regard to the - * @ref MessageWidget on the sequence diagram. - * It is also used for the text required for an association. - * - * The differences between all these different uses will be the popup menu - * that is associated with it. - * - * @author Paul Hensgen - * @see UMLWidget - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class FloatingTextWidget : public UMLWidget -{ - Q_OBJECT -public: - explicit FloatingTextWidget(UMLScene * scene, Uml::TextRole::Enum role = Uml::TextRole::Floating, - const QString& text = QString(), Uml::ID::Type id = Uml::ID::None); - virtual ~FloatingTextWidget(); - - QString text() const; - void setText(const QString &t); - - void setTextcmd(const QString &t); - - QString preText() const; - void setPreText(const QString &t); - - QString postText() const; - void setPostText(const QString &t); - - QString displayText() const; - - bool isEmpty(); - - void showChangeTextDialog(); - void showOperationDialog(bool enableAutoIncrement = true); - virtual void showPropertiesDialog(); - - LinkWidget* link() const; - void setLink(LinkWidget * l); - - bool activate(IDChangeLog* ChangeLog = 0); - - Uml::TextRole::Enum textRole() const; - void setTextRole(Uml::TextRole::Enum role); - - void handleRename(); - void changeName(const QString& newText); - - void setSequenceNumber(const QString &sequenceNumber); - QString sequenceNumber() const; - - static bool isTextValid(const QString &text); - - UMLWidget* onWidget(const QPointF& p); - - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - - virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); - virtual bool loadFromXMI(QDomElement& qElement); - -public Q_SLOTS: - virtual void slotMenuSelection(QAction* action); - void setMessageText(); - -protected: - QSizeF minimumSize() const; - - virtual void moveWidgetBy(qreal diffX, qreal diffY); - virtual void constrainMovementForAllWidgets(qreal &diffX, qreal &diffY); - -private: - QPointF constrainPosition(qreal diffX, qreal diffY); - - /// The association or message widget we may be linked to. - LinkWidget * m_linkWidget; - - //////////////////// Data loaded/saved: - - /// Prepended text (such as for scope of association Role or method) - QString m_preText; - /// Ending text (such as bracket on changability notation for association Role) - QString m_postText; - /// The role the text widget will enact. - Uml::TextRole::Enum m_textRole; - - //////// - - /// The horizontal position the widget would have if its move wasn't constrained. - qreal m_unconstrainedPositionX; - - /// The vertical position the widget would have if its move wasn't constrained. - qreal m_unconstrainedPositionY; - - /// The X direction the widget was moved when the constrain was applied. - /// -1 means left, 1 means right. - int m_movementDirectionX; - - /// The Y direction the widget was moved when the constrain was applied. - /// -1 means up, 1 means down. - int m_movementDirectionY; - - /// Contains sequence number for sequence or collaboration diagram message. - QString m_SequenceNumber; -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/forkjoinwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/forkjoinwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/forkjoinwidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/forkjoinwidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,205 +0,0 @@ -/*************************************************************************** - * 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) 2005-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "forkjoinwidget.h" - -//app includes -#include "debug_utils.h" -#include "umlview.h" -#include "umldoc.h" -#include "listpopupmenu.h" - -// qt includes -#include - -/** - * Constructs a ForkJoinWidget. - * - * @param scene The parent to this widget. - * @param ori Whether to draw the plate horizontally or vertically. - * @param id The ID to assign (-1 will prompt a new ID.) - */ -ForkJoinWidget::ForkJoinWidget(UMLScene * scene, Qt::Orientation ori, Uml::ID::Type id) - : BoxWidget(scene, id, WidgetBase::wt_ForkJoin), - m_orientation(ori) -{ - setSize(10, 40); - m_usesDiagramFillColor = false; - setFillColorCmd(QColor("black")); -} - -/** - * Destructor. - */ -ForkJoinWidget::~ForkJoinWidget() -{ -} - -/** - * Get whether to draw the plate vertically or horizontally. - */ -Qt::Orientation ForkJoinWidget::orientation() const -{ - return m_orientation; -} - -/** - * Set whether to draw the plate vertically or horizontally. - */ -void ForkJoinWidget::setOrientation(Qt::Orientation ori) -{ - m_orientation = ori; - updateGeometry(); - UMLWidget::adjustAssocs(x(), y()); -} - -/** - * Reimplemented from UMLWidget::paint to draw the plate of - * fork join. - */ -void ForkJoinWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - Q_UNUSED(option); - Q_UNUSED(widget); - - painter->fillRect(0, 0, width(), height(), fillColor()); - - UMLWidget::paint(painter, option, widget); -} - -/** - * Reimplemented from UMLWidget::loadFromXMI to load widget - * info from XMI element - 'forkjoin'. - */ -bool ForkJoinWidget::loadFromXMI(QDomElement& qElement) -{ - if (!UMLWidget::loadFromXMI(qElement)) { - return false; - } - - QString drawVerticalStr = qElement.attribute(QLatin1String("drawvertical"), QLatin1String("0")); - bool drawVertical = (bool)drawVerticalStr.toInt(); - if (drawVertical) { - setOrientation(Qt::Vertical); - } - else { - setOrientation(Qt::Horizontal); - } - - return true; -} - -/** - * Reimplemented from UMLWidget::saveToXMI to save widget info - * into XMI element - 'forkjoin'. - */ -void ForkJoinWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) -{ - QDomElement fjElement = qDoc.createElement(QLatin1String("forkjoin")); - UMLWidget::saveToXMI(qDoc, fjElement); - bool drawVertical = true; - if (m_orientation == Qt::Horizontal) { - drawVertical = false; - } - fjElement.setAttribute(QLatin1String("drawvertical"), drawVertical); - qElement.appendChild(fjElement); -} - -/** - * Show a properties dialog for a Fork/Join Widget. - */ -void ForkJoinWidget::showPropertiesDialog() -{ - QColor newColor = QColorDialog::getColor(fillColor()); // krazy:exclude=qclasses - if (newColor != fillColor()) { - setFillColor(newColor); - setUsesDiagramFillColor(false); - umlDoc()->setModified(true); - } -} - -/** - * Reimplemented form UMLWidget::slotMenuSelection to handle - * Flip action. - */ -void ForkJoinWidget::slotMenuSelection(QAction* action) -{ - ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); - switch (sel) { - case ListPopupMenu::mt_Fill_Color: - showPropertiesDialog(); - break; - - case ListPopupMenu::mt_Flip: - switch (m_orientation) { - case Qt::Vertical: - setOrientation(Qt::Horizontal); - break; - case Qt::Horizontal: - default: - setOrientation(Qt::Vertical); - break; - } - break; - default: - break; - } -} - -/** - * Overrides the function from UMLWidget. - */ -QSizeF ForkJoinWidget::minimumSize() const -{ - if (m_orientation == Qt::Vertical) { - return QSizeF(4, 40); - } else { - return QSizeF(40, 4); - } -} - -/** - * Reimplement method from UMLWidget to suppress the resize corner. - * Although the ForkJoinWidget supports resizing, we suppress the - * resize corner because it is too large for this very slim widget. - */ -void ForkJoinWidget::paintSelected(QPainter * p, int offsetX, int offsetY) -{ - Q_UNUSED(p); - Q_UNUSED(offsetX); - Q_UNUSED(offsetY); -} - -/** - * Reimplement method from UMLWidget. - */ -void ForkJoinWidget::constrain(qreal& width, qreal& height) -{ - if (m_orientation == Qt::Vertical) { - if (width < 4) - width = 4; - else if (width > 10) - width = 10; - if (height < 40) - height = 40; - else if (height > 100) - height = 100; - } else { - if (height < 4) - height = 4; - else if (height > 10) - height = 10; - if (width < 40) - width = 40; - else if (width > 100) - width = 100; - } -} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/forkjoinwidget.h umbrello-kf6-15.08.1/umbrello/widgets/forkjoinwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/forkjoinwidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/forkjoinwidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,57 +0,0 @@ -/*************************************************************************** - * 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) 2005-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef FORKJOINWIDGET_H -#define FORKJOINWIDGET_H - -//app includes -#include "boxwidget.h" - -/** - * @short Displays a fork/join plate in a state diagram. - * - * @author Oliver Kellogg - * - * @see UMLWidget - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class ForkJoinWidget : public BoxWidget -{ - Q_OBJECT - Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation) -public: - explicit ForkJoinWidget(UMLScene * scene, Qt::Orientation ori = Qt::Horizontal, Uml::ID::Type id = Uml::ID::None); - virtual ~ForkJoinWidget(); - - Qt::Orientation orientation() const; - void setOrientation(Qt::Orientation ori); - - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - - virtual bool loadFromXMI(QDomElement & qElement); - virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); - - void showPropertiesDialog(); - -public Q_SLOTS: - virtual void slotMenuSelection(QAction* action); - -protected: - QSizeF minimumSize() const; - - virtual void paintSelected(QPainter * p, int offsetX = 0, int offsetY = 0); - - void constrain(qreal& width, qreal& height); - -private: - Qt::Orientation m_orientation; ///< whether to draw the plate horizontally or vertically -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/layoutgrid.cpp umbrello-kf6-15.08.1/umbrello/widgets/layoutgrid.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/layoutgrid.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/layoutgrid.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,113 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2011 by Andi Fischer * - * Copyright (C) 2012 by Ralf Habacker * - * * - * This 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, or (at your option) * - * any later version. * - * * - * This software is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR purpose-kf6. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this package; see the file COPYING. If not, write to * - * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * - * Boston, MA 02110-1301, USA. * - ***************************************************************************/ - -#include "layoutgrid.h" - -#include "debug_utils.h" -#include "umlscene.h" - -#include -#include - -#define DBG_LOG() DEBUG(QLatin1String("LayoutGrid")) -DEBUG_REGISTER_DISABLED(LayoutGrid) - -/** - * Constructor. - */ -LayoutGrid::LayoutGrid(UMLScene *scene) - : m_scene(scene), - m_gridSpacingX(25), - m_gridSpacingY(25), - m_gridDotColor(Qt::gray), - m_isVisible(false) -{ -} - -/** - * Destructor. - */ -LayoutGrid::~LayoutGrid() -{ -} - -void LayoutGrid::paint(QPainter *painter, const QRectF &rect) -{ - if (!isVisible()) - return; - - int gridSizeX = gridSpacingX(); - int gridSizeY = gridSpacingY(); - - qreal left = int(rect.left()) - (int(rect.left()) % gridSizeX); - qreal top = int(rect.top()) - (int(rect.top()) % gridSizeY); - - QVarLengthArray lines; - - for (qreal x = left; x < rect.right(); x += gridSizeX) - lines.append(QLineF(x, rect.top(), x, rect.bottom())); - for (qreal y = top; y < rect.bottom(); y += gridSizeY) - lines.append(QLineF(rect.left(), y, rect.right(), y)); - - painter->setPen(m_gridDotColor); - painter->drawLines(lines.data(), lines.size()); -} - -int LayoutGrid::gridSpacingX() const -{ - return m_gridSpacingX; -} - -int LayoutGrid::gridSpacingY() const -{ - return m_gridSpacingY; -} - -void LayoutGrid::setGridSpacing(int sizeX, int sizeY) -{ - DBG_LOG() << "x = " << sizeX << " / y = " << sizeY; - m_gridSpacingX= sizeX; - m_gridSpacingY= sizeY; -} - -const QColor& LayoutGrid::gridDotColor() const -{ - return m_gridDotColor; -} - -void LayoutGrid::setGridDotColor(const QColor& color) -{ - DBG_LOG() << "color = " << color; - m_gridDotColor = color; -} - -bool LayoutGrid::isVisible() const -{ - return m_isVisible; -} - -void LayoutGrid::setVisible(bool visible) -{ - if (m_isVisible != visible) { - DBG_LOG() << "visible = " << visible; - m_isVisible = visible; - m_scene->update(); - } -} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/layoutgrid.h umbrello-kf6-15.08.1/umbrello/widgets/layoutgrid.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/layoutgrid.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/layoutgrid.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,76 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2011 by Andi Fischer * - * Copyright (C) 2012 by Ralf Habacker * - * * - * This 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, or (at your option) * - * any later version. * - * * - * This software is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR purpose-kf6. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this package; see the file COPYING. If not, write to * - * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * - * Boston, MA 02110-1301, USA. * - ***************************************************************************/ - -#ifndef LAYOUTGRID_H -#define LAYOUTGRID_H - -#include -#include - -class UMLScene; -class QRectF; - -/** - * @author Andi Fischer - * This class handles the layout grid, which is drawn in the background - * of the scene. It is used only in UMLScene. - */ -class LayoutGrid -{ -public: - explicit LayoutGrid(UMLScene *scene); - ~LayoutGrid(); - - void paint(QPainter *painter, const QRectF &rect); - - QRect gridRect() const; - void setGridRect(const QRect& rect); - - int gridSpacingX() const; - int gridSpacingY() const; - void setGridSpacing(int sizeX, int sizeY); - - const QColor& gridDotColor() const; - void setGridDotColor(const QColor& color); - - const QColor& gridCrossColor() const; - void setGridCrossColor(const QColor& color); - - const QColor& textColor() const; - void setTextColor(const QColor& color); - - QFont textFont() const; - void setTextFont(const QFont& font); - - bool isVisible() const; - void setVisible(bool visible); - - bool isTextVisible() const; - void setTextVisible(bool visible); - -private: - UMLScene *m_scene; - int m_gridSpacingX; - int m_gridSpacingY; - QColor m_gridDotColor; - bool m_isVisible; -}; - -#endif // LAYOUTGRID_H diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/linkwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/linkwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/linkwidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/linkwidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,121 +0,0 @@ -/*************************************************************************** - * 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) 2004-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "linkwidget.h" - -// app includes -#include "classifier.h" -#include "operation.h" -#include "uml.h" -#include "umlobject.h" -#include "umlview.h" - -LinkWidget::LinkWidget() -{ -} - -LinkWidget::~LinkWidget() -{ -} - -/** - * Motivated by FloatingTextWidget::slotMenuSelection(mt_Operation) - */ -UMLClassifier *LinkWidget::operationOwner() -{ - UMLOperation *op = operation(); - if (op == NULL) - return NULL; - return static_cast(op->parent()); -} - -/** - * Return the operation text. - * When no scene parameter is given, the scene of the current view - * is taken instead. - * @param scene the given scene - * @return the operation text - */ -QString LinkWidget::operationText(UMLScene *scene) -{ - UMLOperation *op = operation(); - if (op == NULL) - return customOpText(); - if (scene == NULL) - scene = UMLApp::app()->currentView()->umlScene(); - Uml::SignatureType::Enum sigType; - if (scene && scene->showOpSig()) - sigType = Uml::SignatureType::SigNoVis; - else - sigType = Uml::SignatureType::NoSigNoVis; - QString opText = op->toString(sigType); - return opText; -} - -/** - * Motivated by FloatingTextWidget::slotMenuSelection(mt_Reset_Label_Positions) - * Only applies to AssociationWidget. - */ -void LinkWidget::resetTextPositions() -{ -} - -/** - * Motivated by FloatingTextWidget::mouseDoubleClickEvent() - * Only applies to AssociationWidget. - */ -void LinkWidget::showPropertiesDialog() -{ -} - -/** - * Motivated by FloatingTextWidget::setLink(). - * Only applies to AssociationWidget. - */ -void LinkWidget::calculateNameTextSegment() -{ -} - - -/** - * Write property of QString m_SequenceNumber. - */ -void LinkWidget::setSequenceNumber(const QString &sequenceNumber) -{ - m_SequenceNumber = sequenceNumber; -} - -/** - * Read property of QString m_SequenceNumber. - */ -QString LinkWidget::sequenceNumber() const -{ - return m_SequenceNumber; -} - -/** - * Load data from XMI. - */ -bool LinkWidget::loadFromXMI(QDomElement &qElement) -{ - m_SequenceNumber = qElement.attribute(QLatin1String("seqnum")); - return true; -} - -/** - * Save data to XMI. - */ -void LinkWidget::saveToXMI(QDomDocument &qDoc, QDomElement &qElement) -{ - Q_UNUSED(qDoc); - - qElement.setAttribute(QLatin1String("seqnum"), m_SequenceNumber); -} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/linkwidget.h umbrello-kf6-15.08.1/umbrello/widgets/linkwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/linkwidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/linkwidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,123 +0,0 @@ -/*************************************************************************** - * 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) 2004-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef LINKWIDGET_H -#define LINKWIDGET_H - -#include "basictypes.h" -#include "umlscene.h" - -#include - -// forward declarations -class UMLClassifier; -class UMLOperation; -class FloatingTextWidget; - -/** - * This is an interface realized by AssociationWidget and MessageWidget. - * The design of this interface was driven by the requirements of - * class FloatingTextWidget. As the architecture of umbrello-kf6 evolves (for - * example, if the class FloatingTextWidget is redesigned), it can be - * cleaned up. - * - * @short Interface to FloatingTextWidget for AssociationWidget and MessageWidget. - * @author Oliver Kellogg - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class LinkWidget -{ -public: - LinkWidget(); - virtual ~LinkWidget(); - - /** - * Sets the font the widget is to use. - * Abstract operation implemented by inheriting classes. - * Motivated by FloatingTextWidget::slotMenuSelection(mt_Operation) - * - * @param font Font to be set. - */ - virtual void lwSetFont(QFont font) = 0; - - virtual UMLClassifier *operationOwner(); - - /** - * Motivated by FloatingTextWidget::slotMenuSelection(mt_Operation) - */ - virtual UMLOperation *operation() = 0; - - /** - * Motivated by FloatingTextWidget::slotMenuSelection(mt_Operation) - */ - virtual void setOperation(UMLOperation *op) = 0; - - /** - * Motivated by getOperationText() - */ - virtual QString customOpText() = 0; - - /** - * Motivated by FloatingTextWidget::slotMenuSelection(mt_Operation) - */ - virtual void setCustomOpText(const QString &opText) = 0; - - QString operationText(UMLScene *scene = 0); - - virtual void resetTextPositions(); - - /** - * Motivated by FloatingTextWidget::setMessageText() - */ - virtual void setMessageText(FloatingTextWidget *ft) = 0; - - /** - * Motivated by FloatingTextWidget::handleRename() - */ - virtual void setText(FloatingTextWidget *ft, const QString &newText) = 0; - - virtual void showPropertiesDialog(); - - /** - * Motivated by FloatingTextWidget::showOpDialog() - */ - virtual QString lwOperationText() = 0; - - /** - * Motivated by FloatingTextWidget::showOpDialog() - */ - virtual UMLClassifier *lwClassifier() = 0; - - /** - * Motivated by FloatingTextWidget::showOpDialog() - */ - virtual void setOperationText(const QString &op) = 0; - - /** - * Abstract operation implemented by inheriting classes. - * Motivated by FloatingTextWidget::mouseMoveEvent() - */ - virtual void constrainTextPos(qreal &textX, qreal &textY, - qreal textWidth, qreal textHeight, - Uml::TextRole::Enum tr) = 0; - - virtual void calculateNameTextSegment(); - - void setSequenceNumber(const QString &sequenceNumber); - QString sequenceNumber() const; - - virtual bool loadFromXMI(QDomElement &qElement); - virtual void saveToXMI(QDomDocument &qDoc, QDomElement &qElement); - -protected: - QString m_SequenceNumber; -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/messagewidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/messagewidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/messagewidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/messagewidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,1385 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// onw header -#include "messagewidget.h" - -//app includes -#include "classifier.h" -#include "debug_utils.h" -#include "floatingtextwidget.h" -#include "listpopupmenu.h" -#include "objectwidget.h" -#include "operation.h" -#include "uml.h" -#include "umldoc.h" -#include "umlview.h" -#include "uniqueid.h" -#include "idchangelog.h" - -//qt includes -#include -#include -#include -#include - -//kde includes -#include - -DEBUG_REGISTER_DISABLED(MessageWidget) - -static const int circleWidth = 10; - -/** - * Constructs a MessageWidget. - * - * This method is used for creation, synchronous and synchronous message types. - * - * @param scene The parent to this class. - * @param a The role A widget for this message. - * @param b The role B widget for this message. - * @param y The vertical position to display this message. - * @param sequenceMessageType Whether synchronous or asynchronous - * @param id A unique id used for deleting this object cleanly. - * The default (-1) will prompt generation of a new ID. - */ -MessageWidget::MessageWidget(UMLScene * scene, ObjectWidget* a, ObjectWidget* b, - int y, Uml::SequenceMessage::Enum sequenceMessageType, - Uml::ID::Type id /* = Uml::id_None */) - : UMLWidget(scene, WidgetBase::wt_Message, id) -{ - init(); - m_pOw[Uml::RoleType::A] = a; - m_pOw[Uml::RoleType::B] = b; - m_sequenceMessageType = sequenceMessageType; - if (m_sequenceMessageType == Uml::SequenceMessage::Creation) { - y -= m_pOw[Uml::RoleType::B]->height() / 2; - m_pOw[Uml::RoleType::B]->setY(y); - } - updateResizability(); - calculateWidget(); - y = y < getMinY() ? getMinY() : y; - y = y > getMaxY() ? getMaxY() : y; - setY(y); - - this->activate(); -} - -/** - * Constructs a MessageWidget. - * - * @param scene The parent to this class. - * @param seqMsgType The Uml::SequenceMessage::Enum of this message widget - * @param id The ID to assign (-1 will prompt a new ID.) - */ -MessageWidget::MessageWidget(UMLScene * scene, Uml::SequenceMessage::Enum seqMsgType, - Uml::ID::Type id) - : UMLWidget(scene, WidgetBase::wt_Message, id) -{ - init(); - m_sequenceMessageType = seqMsgType; -} - -/** - * Constructs a Lost or Found MessageWidget. - * - * @param scene The parent to this class. - * @param a The role A widget for this message. - * @param xclick The horizontal position clicked by the user - * @param yclick The vertical position clicked by the user - * @param sequenceMessageType Whether lost or found - * @param id The ID to assign (-1 will prompt a new ID.) - */ -MessageWidget::MessageWidget(UMLScene * scene, ObjectWidget* a, int xclick, int yclick, - Uml::SequenceMessage::Enum sequenceMessageType, - Uml::ID::Type id /*= Uml::id_None*/) - : UMLWidget(scene, WidgetBase::wt_Message, id) -{ - init(); - m_pOw[Uml::RoleType::A] = a; - m_pOw[Uml::RoleType::B] = a; - - m_sequenceMessageType = sequenceMessageType; - - m_xclicked = xclick; - m_yclicked = yclick; - - updateResizability(); - calculateWidget(); - yclick = yclick < getMinY() ? getMinY() : yclick; - yclick = yclick > getMaxY() ? getMaxY() : yclick; - setY(yclick); - m_yclicked = yclick; - - this->activate(); -} - -/** - * Initializes key variables of the class. - */ -void MessageWidget::init() -{ - m_xclicked = -1; - m_yclicked = -1; - m_ignoreSnapToGrid = true; - m_ignoreSnapComponentSizeToGrid = true; - m_pOw[Uml::RoleType::A] = m_pOw[Uml::RoleType::B] = NULL; - m_pFText = NULL; -} - -/** - * Standard destructor. - */ -MessageWidget::~MessageWidget() -{ -} - -/** - * Sets the y-coordinate. - * Reimplemented from UMLWidget. - * - * @param y The y-coordinate to be set. - */ -void MessageWidget::setY(qreal y) -{ - if (y < getMinY()) { - DEBUG(DBG_SRC) << "got out of bounds y position, check the reason" << this->y() << getMinY(); - return; - } - - UMLWidget::setY(y); - if (m_sequenceMessageType == Uml::SequenceMessage::Creation) { - const qreal objWidgetHalfHeight = m_pOw[Uml::RoleType::B]->height() / 2; - m_pOw[Uml::RoleType::B]->setY(y - objWidgetHalfHeight); - } - - if (m_pFText && !UMLApp::app()->document()->loading()) { - setTextPosition(); - emit sigMessageMoved(); - } -} - -/** - * Update the UMLWidget::m_resizable flag according to the - * charactersitics of this message. - */ -void MessageWidget::updateResizability() -{ - if (m_sequenceMessageType == Uml::SequenceMessage::Synchronous) - UMLWidget::m_resizable = true; - else - UMLWidget::m_resizable = false; -} - -/** - * Overridden from UMLWidget. - * Returns the cursor to be shown when resizing the widget. - * The cursor shown is KCursor::sizeVerCursor(). - * - * @return The cursor to be shown when resizing the widget. - */ -QCursor MessageWidget::resizeCursor() const -{ - return Qt::SizeVerCursor; -} - -/** - * Overridden from UMLWidget. - * Resizes the height of the message widget and emits the message moved signal. - * Message widgets can only be resized vertically, so width isn't modified. - * - * @param newW The new width for the widget (isn't used). - * @param newH The new height for the widget. - */ -void MessageWidget::resizeWidget(qreal newW, qreal newH) -{ - if (sequenceMessageType() == Uml::SequenceMessage::Creation) - setSize(width(), newH); - else { - qreal x1 = m_pOw[Uml::RoleType::A]->x(); - qreal x2 = getxclicked(); - qreal diffX = 0; - if (x1 < x2) { - diffX = x2 + (newW - width()); - } - else { - diffX = x2 - (newW - width()); - } - if (diffX <= 0 ) - diffX = 10; - setxclicked (diffX); - setSize(newW, newH); - calculateWidget(); - - } - emit sigMessageMoved(); -} - -/** - * Constrains the vertical position of the message widget so it doesn't go - * upper than the bottom side of the lower object. - * The height of the floating text widget in the message is taken in account - * if there is any and isn't empty. - * - * @param diffY The difference between current Y position and new Y position. - * @return The new Y position, constrained. - */ -qreal MessageWidget::constrainPositionY(qreal diffY) -{ - qreal newY = y() + diffY; - - qreal minY = getMinY(); - if (m_pFText && !m_pFText->displayText().isEmpty()) { - minY += m_pFText->height(); - } - - if (newY < minY) { - newY = minY; - } - - return newY; -} - -/** - * Overridden from UMLWidget. - * Moves the widget to a new position using the difference between the - * current position and the new position. X position is ignored, and widget - * is only moved along Y axis. If message goes upper than the object, it's - * kept at this position until it should be lowered again (the unconstrained - * Y position is saved to know when it's the time to lower it again). - * If the message is a creation message, the object created is also moved to - * the new vertical position. - * @see constrainPositionY - * - * @param diffX The difference between current X position and new X position - * (isn't used). - * @param diffY The difference between current Y position and new Y position. - */ -void MessageWidget::moveWidgetBy(qreal diffX, qreal diffY) -{ - Q_UNUSED(diffX); - qreal newY = constrainPositionY(diffY); - setY(newY); -} - -/** - * Overridden from UMLWidget. - * Modifies the value of the diffX and diffY variables used to move the widgets. - * All the widgets are constrained to be moved only in Y axis (diffX is set to 0). - * @see constrainPositionY - * - * @param diffX The difference between current X position and new X position. - * @param diffY The difference between current Y position and new Y position. - */ -void MessageWidget::constrainMovementForAllWidgets(qreal &diffX, qreal &diffY) -{ - diffX = 0; - diffY = constrainPositionY(diffY) - y(); -} - -/** - * Reimplemented from UMLWidget and calls other paint...() methods - * depending on the message type. - */ -void MessageWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - Q_UNUSED(option); - Q_UNUSED(widget); - - if(!m_pOw[Uml::RoleType::A] || !m_pOw[Uml::RoleType::B]) { - return; - } - setPenFromSettings(painter); - if (m_sequenceMessageType == Uml::SequenceMessage::Synchronous) { - paintSynchronous(painter, option); - } else if (m_sequenceMessageType == Uml::SequenceMessage::Asynchronous) { - paintAsynchronous(painter, option); - } else if (m_sequenceMessageType == Uml::SequenceMessage::Creation) { - paintCreation(painter, option); - } else if (m_sequenceMessageType == Uml::SequenceMessage::Lost) { - paintLost(painter, option); - } else if (m_sequenceMessageType == Uml::SequenceMessage::Found) { - paintFound(painter, option); - } else { - uWarning() << "Unknown message type"; - } -} - -/** - * Draw a solid-kf6 (triangular) arrowhead pointing in the given direction. - * The direction can be either Qt::LeftArrow or Qt::RightArrow. - */ -void MessageWidget::paintsolid-kf6Arrowhead(QPainter *p, int x, int y, Qt::ArrowType direction) -{ - int arrowheadExtentX = 4; - if (direction == Qt::RightArrow) { - arrowheadExtentX = -arrowheadExtentX; - } - QPolygon points; - points.putPoints(0, 3, x, y, x + arrowheadExtentX, y - 3, x + arrowheadExtentX, y + 3); - p->setBrush(QBrush(p->pen().color())); - p->drawPolygon(points); -} - -/** - * Draw an arrow pointing in the given direction. - * The arrow head is not solid-kf6, i.e. it is made up of two lines - * like so: ---> - * The direction can be either Qt::LeftArrow or Qt::RightArrow. - */ -void MessageWidget::paintArrow(QPainter *p, int x, int y, int w, - Qt::ArrowType direction, bool useDottedLine /* = false */) -{ - if (w > 3) { - int arrowheadStartX = x; - int arrowheadExtentX = 4; - if (direction == Qt::RightArrow) { - arrowheadStartX += w; - arrowheadExtentX = -arrowheadExtentX; - } - // draw upper half of arrowhead - p->drawLine(arrowheadStartX, y, arrowheadStartX + arrowheadExtentX, y - 3); - // draw lower half of arrowhead - p->drawLine(arrowheadStartX, y, arrowheadStartX + arrowheadExtentX, y + 3); - } - // draw arrow line - if (useDottedLine) { - QPen pen = p->pen(); - pen.setStyle(Qt::DotLine); - p->setPen(pen); - } - p->drawLine(x, y, x + w, y); -} - -/** - * Draws the calling arrow with filled in arrowhead, the - * timeline box and the returning arrow with a dashed line and - * stick arrowhead. - */ -void MessageWidget::paintSynchronous(QPainter *painter, const QStyleOptionGraphicsItem *option) -{ - int x1 = m_pOw[Uml::RoleType::A]->x(); - int x2 = m_pOw[Uml::RoleType::B]->x(); - int w = width() - 1; - int h = height(); - int offsetX = 0; - int offsetY = 0; - - bool messageOverlaps = m_pOw[Uml::RoleType::A]->messageOverlap(y(), this); - const int boxWidth = 17; - const int wr = w < boxWidth ? w : boxWidth; - const int arrowWidth = 4; - - if(isSelf()) { - painter->fillRect(offsetX, offsetY, wr, h, QBrush(Qt::white)); //box - painter->drawRect(offsetX, offsetY, wr, h); //box - offsetX += wr; - w -= wr; - offsetY += 3; - const int lowerLineY = offsetY + h - 6; - // draw upper line segment (leaving the life line) - painter->drawLine(offsetX, offsetY, offsetX + w, offsetY); - // draw line segment parallel to (and at the right of) the life line - painter->drawLine(offsetX + w, offsetY, offsetX + w, lowerLineY); - // draw lower line segment (back to the life line) - paintArrow(painter, offsetX, lowerLineY, w, Qt::LeftArrow); - offsetX -= wr; - offsetY -= 3; - } else if(x1 < x2) { - if (messageOverlaps) { - offsetX += 8; - w -= 8; - } - QPen pen = painter->pen(); - int startX = offsetX + w - wr + 1; - painter->fillRect(startX, offsetY, wr, h, QBrush(Qt::white)); //box - painter->drawRect(startX, offsetY, wr, h); //box - painter->drawLine(offsetX, offsetY + arrowWidth, startX, offsetY + arrowWidth); //arrow line - if (w > boxWidth + arrowWidth) - paintsolid-kf6Arrowhead(painter, startX - 1, offsetY + arrowWidth, Qt::RightArrow); - paintArrow(painter, offsetX, offsetY + h - arrowWidth + 1, w - wr + 1, Qt::LeftArrow, true); // return arrow - if (messageOverlaps) { - offsetX -= 8; //reset for drawSelected() - } - } else { - if (messageOverlaps) { - w -=8; - } - QPen pen = painter->pen(); - painter->fillRect(offsetX, offsetY, wr, h, QBrush(Qt::white)); //box - painter->drawRect(offsetX, offsetY, wr, h); //box - painter->drawLine(offsetX + wr + 1, offsetY + arrowWidth, offsetX + w, offsetY + arrowWidth); //arrow line - if (w > boxWidth + arrowWidth) - paintsolid-kf6Arrowhead(painter, offsetX + wr, offsetY + arrowWidth, Qt::LeftArrow); - paintArrow(painter, offsetX + wr + 1, offsetY + h - arrowWidth + 1, w - wr - 1, Qt::RightArrow, true); // return arrow - } - - UMLWidget::paint(painter, option); -} - -/** - * Draws a solid-kf6 arrow line and a stick arrow head. - */ -void MessageWidget::paintAsynchronous(QPainter *painter, const QStyleOptionGraphicsItem *option) -{ - int x1 = m_pOw[Uml::RoleType::A]->x(); - int x2 = m_pOw[Uml::RoleType::B]->x(); - int w = width() - 1; - int h = height() - 1; - int offsetX = 0; - int offsetY = 0; - bool messageOverlapsA = m_pOw[Uml::RoleType::A]->messageOverlap(y(), this); - //bool messageOverlapsB = m_pOw[Uml::RoleType::B]->messageOverlap(y(), this); - - if(isSelf()) { - if (messageOverlapsA) { - offsetX += 7; - w -= 7; - } - const int lowerLineY = offsetY + h - 3; - // draw upper line segment (leaving the life line) - painter->drawLine(offsetX, offsetY, offsetX + w, offsetY); - // draw line segment parallel to (and at the right of) the life line - painter->drawLine(offsetX + w, offsetY, offsetX + w, lowerLineY); - // draw lower line segment (back to the life line) - paintArrow(painter, offsetX, lowerLineY, w, Qt::LeftArrow); - if (messageOverlapsA) { - offsetX -= 7; //reset for drawSelected() - } - } else if(x1 < x2) { - if (messageOverlapsA) { - offsetX += 7; - w -= 7; - } - paintArrow(painter, offsetX, offsetY + 4, w, Qt::RightArrow); - if (messageOverlapsA) { - offsetX -= 7; - } - } else { - if (messageOverlapsA) { - w -= 7; - } - paintArrow(painter, offsetX, offsetY + 4, w, Qt::LeftArrow); - } - - UMLWidget::paint(painter, option); -} - -/** - * Draws a solid-kf6 arrow line and a stick arrow head to the - * edge of the target object widget instead of to the - * sequence line. - */ -void MessageWidget::paintCreation(QPainter *painter, const QStyleOptionGraphicsItem *option) -{ - int x1 = m_pOw[Uml::RoleType::A]->x(); - int x2 = m_pOw[Uml::RoleType::B]->x(); - int w = width(); - //int h = height() - 1; - int offsetX = 0; - int offsetY = 0; - bool messageOverlapsA = m_pOw[Uml::RoleType::A]->messageOverlap(y(), this); - //bool messageOverlapsB = m_pOw[Uml::RoleType::B]->messageOverlap(y(), this); - - const int lineY = offsetY + 4; - if (x1 < x2) { - if (messageOverlapsA) { - offsetX += 7; - w -= 7; - } - paintArrow(painter, offsetX, lineY, w, Qt::RightArrow); - if (messageOverlapsA) { - offsetX -= 7; - } - } else { - if (messageOverlapsA) { - w -= 7; - } - paintArrow(painter, offsetX, lineY, w, Qt::LeftArrow); - } - - UMLWidget::paint(painter, option); -} - - -/** - * Draws a solid-kf6 arrow line and a stick arrow head - * and a circle - */ -void MessageWidget::paintLost(QPainter *painter, const QStyleOptionGraphicsItem *option) -{ - int x1 = m_pOw[Uml::RoleType::A]->centerX(); - int x2 = m_xclicked; - int w = width(); - int h = height(); - int offsetX = 0; - int offsetY = 0; - bool messageOverlapsA = m_pOw[Uml::RoleType::A]->messageOverlap(y(), this); - //bool messageOverlapsB = m_pOw[Uml::RoleType::B]->messageOverlap(y(), this); - - if(x1 < x2) { - if (messageOverlapsA) { - offsetX += 7; - w -= 7; - } - - setPenFromSettings(painter); - painter->setBrush(WidgetBase::lineColor()); - painter->drawEllipse(offsetX + w - h, offsetY, h, h); - paintArrow(painter, offsetX, offsetY + h/2, w - h, Qt::RightArrow); - - if (messageOverlapsA) { - offsetX -= 7; - } - } else { - setPenFromSettings(painter); - painter->setBrush(WidgetBase::lineColor()); - painter->drawEllipse(offsetX, offsetY, h, h); - paintArrow(painter, offsetX + h, offsetY + h/2, w - h, Qt::LeftArrow); - } - - UMLWidget::paint(painter, option); -} - -/** - * Draws a circle and a solid-kf6 arrow line and a stick arrow head. - */ -void MessageWidget::paintFound(QPainter *painter, const QStyleOptionGraphicsItem *option) -{ - int x1 = m_pOw[Uml::RoleType::A]->centerX(); - int x2 = m_xclicked; - int w = width(); - int h = height(); - int offsetX = 0; - int offsetY = 0; - bool messageOverlapsA = m_pOw[Uml::RoleType::A]->messageOverlap(y(), this); - //bool messageOverlapsB = m_pOw[Uml::RoleType::B]->messageOverlap(y(), this); - - if(x1 < x2) { - if (messageOverlapsA) { - offsetX += 7; - w -= 7; - } - setPenFromSettings(painter); - painter->setBrush(WidgetBase::lineColor()); - painter->drawEllipse(offsetX + w - h, offsetY, h, h); - paintArrow(painter, offsetX, offsetY + h/2, w, Qt::LeftArrow); - if (messageOverlapsA) { - offsetX -= 7; - } - } else { - if (messageOverlapsA) { - w -= 7; - } - setPenFromSettings(painter); - painter->setBrush(WidgetBase::lineColor()); - painter->drawEllipse(offsetX, offsetY, h, h); - paintArrow(painter, offsetX, offsetY + h/2, w, Qt::RightArrow); - } - - UMLWidget::paint(painter, option); -} - -/** - * Overrides operation from UMLWidget. - * - * @param p Point to be checked. - * - * @return 'this' if the point is on a part of the MessageWidget. - * NB In case of a synchronous message, the empty space - * between call line and return line does not count, i.e. if - * the point is located in that space the function returns NULL. - */ -UMLWidget* MessageWidget::onWidget(const QPointF& p) -{ - if (m_sequenceMessageType != Uml::SequenceMessage::Synchronous) { - return UMLWidget::onWidget(p); - } - // Synchronous message: - // Consists of top arrow (call) and bottom arrow (return.) - if (p.x() < x() || p.x() > x() + width()) - return NULL; - const int tolerance = 5; // pixels - const int pY = p.y(); - const int topArrowY = y() + 3; - const int bottomArrowY = y() + height() - 3; - if (pY < topArrowY - tolerance || pY > bottomArrowY + tolerance) - return NULL; - if (height() <= 2 * tolerance) - return this; - if (pY > topArrowY + tolerance && pY < bottomArrowY - tolerance) - return NULL; - return this; -} - -/** - * Sets the text position relative to the sequence message. - */ -void MessageWidget::setTextPosition() -{ - if (m_pFText == NULL) { - DEBUG(DBG_SRC) << "m_pFText is NULL"; - return; - } - if (m_pFText->displayText().isEmpty()) { - return; - } - m_pFText->updateGeometry(); - int ftX = constrainX(m_pFText->x(), m_pFText->width(), m_pFText->textRole()); - int ftY = y() - m_pFText->height(); - m_pFText->setX(ftX); - m_pFText->setY(ftY); -} - -/** - * Returns the textX arg with constraints applied. - * Auxiliary to setTextPosition() and constrainTextPos(). - */ -int MessageWidget::constrainX(int textX, int textWidth, Uml::TextRole::Enum tr) -{ - int result = textX; - const int minTextX = x() + 5; - if (textX < minTextX || tr == Uml::TextRole::Seq_Message_Self) { - result = minTextX; - } else { - ObjectWidget *objectAtRight = NULL; - if (m_pOw[Uml::RoleType::B]->x() > m_pOw[Uml::RoleType::A]->x()) - objectAtRight = m_pOw[Uml::RoleType::B]; - else - objectAtRight = m_pOw[Uml::RoleType::A]; - const int objRight_seqLineX = objectAtRight->centerX(); - const int maxTextX = objRight_seqLineX - textWidth - 5; - if (maxTextX <= minTextX) - result = minTextX; - else if (textX > maxTextX) - result = maxTextX; - } - return result; -} - -/** - * Constrains the FloatingTextWidget X and Y values supplied. - * Overrides operation from LinkWidget. - * - * @param textX candidate X value (may be modified by the constraint) - * @param textY candidate Y value (may be modified by the constraint) - * @param textWidth width of the text - * @param textHeight height of the text - * @param tr Uml::TextRole::Enum of the text - */ -void MessageWidget::constrainTextPos(qreal &textX, qreal &textY, qreal textWidth, qreal textHeight, - Uml::TextRole::Enum tr) -{ - textX = constrainX(textX, textWidth, tr); - // Constrain Y. - const qreal minTextY = getMinY(); - const qreal maxTextY = getMaxY() - textHeight - 5; - if (textY < minTextY) - textY = minTextY; - else if (textY > maxTextY) - textY = maxTextY; -// setY(textY + textHeight); // NB: side effect -} - -/** - * Shortcut for calling m_pFText->setLink() followed by - * this->setTextPosition(). - */ -void MessageWidget::setLinkAndTextPos() -{ - if (m_pFText) { - m_pFText->setLink(this); - setTextPosition(); - } -} - -void MessageWidget::resizeEvent(QResizeEvent* /*re*/) -{ -} - -/** - * Calculate the geometry of the widget. - */ -void MessageWidget::calculateWidget() -{ - setMessageText(m_pFText); - calculateDimensions(); - setVisible(true); -} - -void MessageWidget::slotWidgetMoved(Uml::ID::Type id) -{ - const Uml::ID::Type idA = m_pOw[Uml::RoleType::A]->localID(); - const Uml::ID::Type idB = m_pOw[Uml::RoleType::B]->localID(); - if (idA != id && idB != id) { - DEBUG(DBG_SRC) << "id=" << Uml::ID::toString(id) << ": ignoring for idA=" << Uml::ID::toString(idA) - << ", idB=" << Uml::ID::toString(idB); - return; - } - qreal y = this->y(); - if (y < getMinY()) - y = getMinY(); - if (y > getMaxY()) - y = getMaxY(); - setPos(x(), y); - calculateWidget(); - if(!m_pFText) - return; - if (m_scene->selectedCount(true) > 1) - return; - setTextPosition(); -} - -/** - * Check to see if the given ObjectWidget is involved in the message. - * - * @param w The ObjectWidget to check for. - * @return true - if is contained, false - not contained. - */ -bool MessageWidget::hasObjectWidget(ObjectWidget * w) -{ - if(m_pOw[Uml::RoleType::A] == w || m_pOw[Uml::RoleType::B] == w) - return true; - else - return false; -} - -/** - * This method determines whether the message is for "Self" for - * an ObjectWidget. - * - * @retval True If both ObjectWidgets for this widget exists and - * are same. - */ -bool MessageWidget::isSelf() const -{ - return (m_pOw[Uml::RoleType::A] && m_pOw[Uml::RoleType::B] && - m_pOw[Uml::RoleType::A] == m_pOw[Uml::RoleType::B]); -} - -void MessageWidget::slotMenuSelection(QAction* action) -{ - ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); - if (sel == ListPopupMenu::mt_Delete) { - // This will clean up this widget and the text widget: - m_scene->removeWidget(this); - } else { - - UMLWidget::slotMenuSelection(action); - } -} - -/** - * Activates a MessageWidget. Connects its m_pOw[] pointers - * to UMLObjects and also send signals about its FloatingTextWidget. - */ -bool MessageWidget::activate(IDChangeLog * /*Log = 0*/) -{ - m_scene->resetPastep-kf6oint(); - // UMLWidget::activate(Log); CHECK: I don't think we need this ? - if (m_pOw[Uml::RoleType::A] == NULL) { - UMLWidget *pWA = m_scene->findWidget(m_widgetAId); - if (pWA == NULL) { - DEBUG(DBG_SRC) << "role A object " << Uml::ID::toString(m_widgetAId) << " not found"; - return false; - } - m_pOw[Uml::RoleType::A] = dynamic_cast(pWA); - if (m_pOw[Uml::RoleType::A] == NULL) { - DEBUG(DBG_SRC) << "role A widget " << Uml::ID::toString(m_widgetAId) - << " is not an ObjectWidget"; - return false; - } - } - if (m_pOw[Uml::RoleType::B] == NULL) { - UMLWidget *pWB = m_scene->findWidget(m_widgetBId); - if (pWB == NULL) { - DEBUG(DBG_SRC) << "role B object " << Uml::ID::toString(m_widgetBId) << " not found"; - return false; - } - m_pOw[Uml::RoleType::B] = dynamic_cast(pWB); - if (m_pOw[Uml::RoleType::B] == NULL) { - DEBUG(DBG_SRC) << "role B widget " << Uml::ID::toString(m_widgetBId) - << " is not an ObjectWidget"; - return false; - } - } - updateResizability(); - - UMLClassifier *c = dynamic_cast(m_pOw[Uml::RoleType::B]->umlObject()); - UMLOperation *op = NULL; - if (c && !m_CustomOp.isEmpty()) { - Uml::ID::Type opId = Uml::ID::fromString(m_CustomOp); - op = dynamic_cast(c->findChildObjectById(opId, true)); - if (op) { - // If the UMLOperation is set, m_CustomOp isn't used anyway. - // Just setting it empty for the sake of sanity. - m_CustomOp.clear(); - } - } - - if(!m_pFText) { - Uml::TextRole::Enum tr = Uml::TextRole::Seq_Message; - if (isSelf()) - tr = Uml::TextRole::Seq_Message_Self; - m_pFText = new FloatingTextWidget(m_scene, tr, operationText(m_scene)); - m_scene->addFloatingTextWidget(m_pFText); - m_pFText->setFontCmd(UMLWidget::font()); - } - if (op) - setOperation(op); // This requires a valid m_pFText. - setLinkAndTextPos(); - m_pFText->setText(QString()); - m_pFText->setActivated(); - QString messageText = m_pFText->text(); - m_pFText->setVisible(messageText.length() > 1); - - connect(m_pOw[Uml::RoleType::A], SIGNAL(sigWidgetMoved(Uml::ID::Type)), this, SLOT(slotWidgetMoved(Uml::ID::Type))); - connect(m_pOw[Uml::RoleType::B], SIGNAL(sigWidgetMoved(Uml::ID::Type)), this, SLOT(slotWidgetMoved(Uml::ID::Type))); - - connect(this, SIGNAL(sigMessageMoved()), m_pOw[Uml::RoleType::A], SLOT(slotMessageMoved())); - connect(this, SIGNAL(sigMessageMoved()), m_pOw[Uml::RoleType::B], SLOT(slotMessageMoved())); - m_pOw[Uml::RoleType::A]->messageAdded(this); - if (!isSelf()) - m_pOw[Uml::RoleType::B]->messageAdded(this); - - // Calculate the size and position of the message widget - calculateDimensions(); - - // Position the floating text accordingly - setTextPosition(); - - emit sigMessageMoved(); - return true; -} - -/** - * Resolve references of this message so they reference the correct - * new object widgets after paste. - */ -void MessageWidget::resolveObjectWidget(IDChangeLog* log) { - m_widgetAId = log->findNewID(m_widgetAId); - m_widgetBId = log->findNewID(m_widgetBId); -} - -/** - * Overrides operation from LinkWidget. - * Required by FloatingTextWidget. - * - * @param ft The text widget which to update. - */ -void MessageWidget::setMessageText(FloatingTextWidget *ft) -{ - if (ft == NULL) - return; - ft->setSequenceNumber(m_SequenceNumber); - ft->setText(operationText(m_scene)); - setTextPosition(); -} - -/** - * Overrides operation from LinkWidget. - * Required by FloatingTextWidget. - * - * @param ft The text widget which to update. - * @param newText The new text to set. - */ -void MessageWidget::setText(FloatingTextWidget *ft, const QString &newText) -{ - ft->setText(newText); - UMLApp::app()->document()->setModified(true); -} - -/** - * Overrides operation from LinkWidget. - * Required by FloatingTextWidget. - * - * @param op The new operation string to set. - */ -void MessageWidget::setOperationText(const QString &op) -{ - m_CustomOp = op; ///FIXME m_pOperation -} - -/** - * Implements operation from LinkWidget. - * Required by FloatingTextWidget. - */ -void MessageWidget::lwSetFont (QFont font) -{ - UMLWidget::setFont(font); -} - -/** - * Overrides operation from LinkWidget. - * Required by FloatingTextWidget. - * @todo Move to LinkWidget. - */ -UMLClassifier *MessageWidget::operationOwner() -{ - UMLObject *pObject = m_pOw[Uml::RoleType::B]->umlObject(); - if (pObject == NULL) - return NULL; - UMLClassifier *c = dynamic_cast(pObject); - return c; -} - -/** - * Implements operation from LinkWidget. - * Motivated by FloatingTextWidget. - */ -UMLOperation *MessageWidget::operation() -{ - return static_cast(m_umlObject); -} - -/** - * Implements operation from LinkWidget. - * Motivated by FloatingTextWidget. - */ -void MessageWidget::setOperation(UMLOperation *op) -{ - if (m_umlObject && m_pFText) - disconnect(m_umlObject, SIGNAL(modified()), m_pFText, SLOT(setMessageText())); - m_umlObject = op; - if (m_umlObject && m_pFText) { - connect(m_umlObject, SIGNAL(modified()), m_pFText, SLOT(setMessageText())); - m_pFText->setMessageText(); - } -} - -/** - * Overrides operation from LinkWidget. - * Required by FloatingTextWidget. - */ -QString MessageWidget::customOpText() -{ - return m_CustomOp; -} - -/** - * Overrides operation from LinkWidget. - * Required by FloatingTextWidget. - */ -void MessageWidget::setCustomOpText(const QString &opText) -{ - m_CustomOp = opText; - m_pFText->setMessageText(); -} - -/** - * Overrides operation from LinkWidget. - * Required by FloatingTextWidget. - */ -QString MessageWidget::lwOperationText() -{ - UMLOperation *pOperation = operation(); - if (pOperation != NULL) { - return pOperation->toString(Uml::SignatureType::SigNoVis); - } else { - return customOpText(); - } -} - -/** - * Overrides operation from LinkWidget. - * Required by FloatingTextWidget. - */ -UMLClassifier *MessageWidget::lwClassifier() -{ - UMLObject *o = m_pOw[Uml::RoleType::B]->umlObject(); - UMLClassifier *c = dynamic_cast(o); - return c; -} - -/** - * Calculates the size of the widget by calling - * calculateDimensionsSynchronous(), - * calculateDimensionsAsynchronous(), or - * calculateDimensionsCreation() - */ -void MessageWidget::calculateDimensions() -{ - if (m_sequenceMessageType == Uml::SequenceMessage::Synchronous) { - calculateDimensionsSynchronous(); - } else if (m_sequenceMessageType == Uml::SequenceMessage::Asynchronous) { - calculateDimensionsAsynchronous(); - } else if (m_sequenceMessageType == Uml::SequenceMessage::Creation) { - calculateDimensionsCreation(); - } else if (m_sequenceMessageType == Uml::SequenceMessage::Lost) { - calculateDimensionsLost(); - } else if (m_sequenceMessageType == Uml::SequenceMessage::Found) { - calculateDimensionsFound(); - } else { - uWarning() << "Unknown message type"; - } - if (! UMLApp::app()->document()->loading()) { - adjustAssocs(x(), y()); // adjust assoc lines - } -} - -/** - * Calculates and sets the size of the widget for a synchronous message. - */ -void MessageWidget::calculateDimensionsSynchronous() -{ - int x = 0; - - int x1 = m_pOw[Uml::RoleType::A]->centerX(); - int x2 = m_pOw[Uml::RoleType::B]->centerX(); - - int widgetWidth = 0; - int widgetHeight = 0; - if(isSelf()) { - widgetWidth = 50; - x = x1 - 2; - } else if(x1 < x2) { - x = x1; - widgetWidth = x2 - x1 + 8; - } else { - x = x2 - 8; - widgetWidth = x1 - x2 + 8; - } - - if (height() < 20) { - widgetHeight = 20; - } else { - widgetHeight = height(); - } - - setX(x); - setSize(widgetWidth, widgetHeight); -} - -/** - * Calculates and sets the size of the widget for an asynchronous message. - */ -void MessageWidget::calculateDimensionsAsynchronous() -{ - int x = 0; - - int x1 = m_pOw[Uml::RoleType::A]->centerX(); - int x2 = m_pOw[Uml::RoleType::B]->centerX(); - - int widgetWidth = 0; - int widgetHeight = 8; - if(isSelf()) { - widgetWidth = 50; - x = x1; - if(height() < 20) { - widgetHeight = 20; - } else { - widgetHeight = height(); - } - } else if(x1 < x2) { - x = x1; - widgetWidth = x2 - x1; - } else { - x = x2; - widgetWidth = x1 - x2; - } - x += 1; - widgetWidth -= 2; - setX(x); - setSize(widgetWidth, widgetHeight); -} - -/** - * Calculates and sets the size of the widget for a creation message. - */ -void MessageWidget::calculateDimensionsCreation() -{ - int x = 0; - - int x1 = m_pOw[Uml::RoleType::A]->centerX(); - int x2 = m_pOw[Uml::RoleType::B]->x(); - int w2 = m_pOw[Uml::RoleType::B]->width(); - - if (x1 > x2) - x2 += w2; - - int widgetWidth = 0; - int widgetHeight = 8; - if (x1 < x2) { - x = x1; - widgetWidth = x2 - x1; - } else { - x = x2; - widgetWidth = x1 - x2; - } - x += 1; - widgetWidth -= 2; - setPos(x, m_pOw[Uml::RoleType::B]->y() + m_pOw[Uml::RoleType::B]->height() / 2); - setSize(widgetWidth, widgetHeight); -} - -/** - * Calculates and sets the size of the widget for a lost message. - */ -void MessageWidget::calculateDimensionsLost() -{ - int x = 0; - - int x1 = m_pOw[Uml::RoleType::A]->centerX(); - int x2 = m_xclicked; - - int widgetWidth = 0; - int widgetHeight = 10; - if(x1 < x2) { - x = x1; - widgetWidth = x2 - x1 + circleWidth/2; - } else { - x = x2 - circleWidth/2; - widgetWidth = x1 - x2 + circleWidth/2; - } - setX(x); - setSize(widgetWidth, widgetHeight); -} - -/** - * Calculates and sets the size of the widget for a found message. - */ -void MessageWidget::calculateDimensionsFound() -{ - int x = 0; - - int x1 = m_pOw[Uml::RoleType::A]->centerX(); - int x2 = m_xclicked; - - int widgetWidth = 0; - int widgetHeight = 10; - if(x1 < x2) { - x = x1; - widgetWidth = x2 - x1 + circleWidth/2; - } else { - x = x2 - circleWidth/2; - widgetWidth = x1 - x2 + circleWidth/2; - } - - setX(x); - setSize(widgetWidth, widgetHeight); -} - -/** - * Used to cleanup any other widget it may need to delete. - */ -void MessageWidget::cleanup() -{ - if (m_pOw[Uml::RoleType::A]) { - disconnect(this, SIGNAL(sigMessageMoved()), m_pOw[Uml::RoleType::A], SLOT(slotMessageMoved())); - m_pOw[Uml::RoleType::A]->messageRemoved(this); - } - if (m_pOw[Uml::RoleType::B]) { - disconnect(this, SIGNAL(sigMessageMoved()), m_pOw[Uml::RoleType::B], SLOT(slotMessageMoved())); - m_pOw[Uml::RoleType::B]->messageRemoved(this); - } - - UMLWidget::cleanup(); - if (m_pFText) { - m_scene->removeWidgetCmd(m_pFText); - m_pFText = NULL; - } -} - -/** - * Sets the state of whether the widget is selected. - * - * @param _select True if the widget is selected. - */ -void MessageWidget::setSelected(bool _select) -{ - UMLWidget::setSelected(_select); - if(!m_pFText || m_pFText->displayText().isEmpty()) - return; - if(isSelected() && m_pFText->isSelected()) - return; - if(!isSelected() && !m_pFText->isSelected()) - return; - - m_pFText->setSelected(isSelected()); -} - -/** - * Returns the minimum height this widget should be set at on - * a sequence diagrams. Takes into account the widget positions - * it is related to. - */ -int MessageWidget::getMinY() -{ - if (!m_pOw[Uml::RoleType::A] || !m_pOw[Uml::RoleType::B]) { - return 0; - } - if (m_sequenceMessageType == Uml::SequenceMessage::Creation) { - return m_pOw[Uml::RoleType::A]->y() + m_pOw[Uml::RoleType::A]->height(); - } - int heightA = m_pOw[Uml::RoleType::A]->y() + m_pOw[Uml::RoleType::A]->height(); - int heightB = m_pOw[Uml::RoleType::B]->y() + m_pOw[Uml::RoleType::B]->height(); - int height = heightA; - if(heightA < heightB) { - height = heightB; - } - return height; -} - -/** - * Returns the maximum height this widget should be set at on - * a sequence diagrams. Takes into account the widget positions - * it is related to. - */ -int MessageWidget::getMaxY() -{ - if(!m_pOw[Uml::RoleType::A] || !m_pOw[Uml::RoleType::B]) { - return 0; - } - int heightA = (int)((ObjectWidget*)m_pOw[Uml::RoleType::A])->getEndLineY(); - int heightB = (int)((ObjectWidget*)m_pOw[Uml::RoleType::B])->getEndLineY(); - int height = heightA; - if(heightA > heightB) { - height = heightB; - } - return (height - this->height()); -} - -/** - * Sets the related widget on the given side. - * - * @param ow The ObjectWidget we are related to. - * @param role The Uml::RoleType::Enum to be set for the ObjectWidget - */ -void MessageWidget::setObjectWidget(ObjectWidget * ow, Uml::RoleType::Enum role) -{ - m_pOw[role] = ow; - updateResizability(); -} - -/** - * Returns the related widget on the given side. - * - * @return The ObjectWidget we are related to. - */ -ObjectWidget* MessageWidget::objectWidget(Uml::RoleType::Enum role) -{ - return m_pOw[role]; -} - -/** - * Set the xclicked - */ -void MessageWidget::setxclicked(int xclick) -{ - m_xclicked = xclick; -} - -/** - * Set the yclicked - */ -void MessageWidget::setyclicked(int yclick) -{ - m_yclicked = yclick; -} - -/** - * Event handler for mouse double click events. - * @param event QGraphicsSceneMouseEvent which triggered the double click event - */ -void MessageWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) -{ - Q_UNUSED(event) - DEBUG(DBG_SRC) << "NOT IMPLEMENTED YET!"; - if (m_pFText != NULL) { - DEBUG(DBG_SRC) << "NOT IMPLEMENTED YET - on floating text widget!"; -// QAction* action = m_pMenu->getAction(ListPopupMenu::mt_Select_Operation); -// m_pFText->slotMenuSelection(action); - } -} - -/** - * Saves to the "messagewidget" XMI element. - */ -void MessageWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) -{ - QDomElement messageElement = qDoc.createElement(QLatin1String("messagewidget")); - UMLWidget::saveToXMI(qDoc, messageElement); - LinkWidget::saveToXMI(qDoc, messageElement); - if (m_pOw[Uml::RoleType::A]) - messageElement.setAttribute(QLatin1String("widgetaid"), Uml::ID::toString(m_pOw[Uml::RoleType::A]->localID())); - if (m_pOw[Uml::RoleType::B]) - messageElement.setAttribute(QLatin1String("widgetbid"), Uml::ID::toString(m_pOw[Uml::RoleType::B]->localID())); - UMLOperation *pOperation = operation(); - if (pOperation) - messageElement.setAttribute(QLatin1String("operation"), Uml::ID::toString(pOperation->id())); - else - messageElement.setAttribute(QLatin1String("operation"), m_CustomOp); - messageElement.setAttribute(QLatin1String("sequencemessagetype"), m_sequenceMessageType); - if (m_sequenceMessageType == Uml::SequenceMessage::Lost || m_sequenceMessageType == Uml::SequenceMessage::Found) { - messageElement.setAttribute(QLatin1String("xclicked"), m_xclicked); - messageElement.setAttribute(QLatin1String("yclicked"), m_yclicked); - } - - // save the corresponding message text - if (m_pFText && !m_pFText->text().isEmpty()) { - messageElement.setAttribute(QLatin1String("textid"), Uml::ID::toString(m_pFText->id())); - m_pFText->saveToXMI(qDoc, messageElement); - } - - qElement.appendChild(messageElement); -} - -/** - * Loads from the "messagewidget" XMI element. - */ -bool MessageWidget::loadFromXMI(QDomElement& qElement) -{ - if (!UMLWidget::loadFromXMI(qElement)) { - return false; - } - if (!LinkWidget::loadFromXMI(qElement)) { - return false; - } - QString textid = qElement.attribute(QLatin1String("textid"), QLatin1String("-1")); - QString widgetaid = qElement.attribute(QLatin1String("widgetaid"), QLatin1String("-1")); - QString widgetbid = qElement.attribute(QLatin1String("widgetbid"), QLatin1String("-1")); - m_CustomOp = qElement.attribute(QLatin1String("operation")); - QString sequenceMessageType = qElement.attribute(QLatin1String("sequencemessagetype"), QLatin1String("1001")); - m_sequenceMessageType = Uml::SequenceMessage::fromInt(sequenceMessageType.toInt()); - if (m_sequenceMessageType == Uml::SequenceMessage::Lost || m_sequenceMessageType == Uml::SequenceMessage::Found) { - m_xclicked = qElement.attribute(QLatin1String("xclicked"), QLatin1String("-1")).toFloat(); - m_yclicked = qElement.attribute(QLatin1String("yclicked"), QLatin1String("-1")).toFloat(); - } - - m_widgetAId = Uml::ID::fromString(widgetaid); - m_widgetBId = Uml::ID::fromString(widgetbid); - m_textId = Uml::ID::fromString(textid); - - Uml::TextRole::Enum tr = Uml::TextRole::Seq_Message; - if (m_widgetAId == m_widgetBId) - tr = Uml::TextRole::Seq_Message_Self; - - //now load child elements - QDomNode node = qElement.firstChild(); - QDomElement element = node.toElement(); - if (!element.isNull()) { - QString tag = element.tagName(); - if (tag == QLatin1String("floatingtext") || tag == QLatin1String("UML::FloatingTextWidget")) { - m_pFText = new FloatingTextWidget(m_scene, tr, operationText(m_scene), m_textId); - m_scene->addFloatingTextWidget(m_pFText); - if(! m_pFText->loadFromXMI(element)) { - // Most likely cause: The FloatingTextWidget is empty. - delete m_pFText; - m_pFText = NULL; - } - else - m_pFText->setSequenceNumber(m_SequenceNumber); - } else { - uError() << "unknown tag " << tag; - } - } - return true; -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/messagewidget.h umbrello-kf6-15.08.1/umbrello/widgets/messagewidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/messagewidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/messagewidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,212 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef MESSAGEWIDGET_H -#define MESSAGEWIDGET_H - -#include "umlwidget.h" -#include "linkwidget.h" - -// forward declarations -class FloatingTextWidget; -class ObjectWidget; -class QResizeEvent; -class UMLOperation; - -/** - * Used to display a message on a sequence diagram. The message - * could be between two objects or a message that calls itself on - * an object. This class will only display the line that is - * required and the text will be setup by the @ref FloatingTextWidget - * widget that is passed in the constructor. A message can be - * synchronous (calls a method and gains control back on return, - * as happens in most programming languages) or asynchronous - * (calls a method and gains back control immediately). - * - * @short Displays a message. - * @author Paul Hensgen - * @see UMLWidget - * @see ObjectWidget - * @see FloatingTextWidget - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class MessageWidget : public UMLWidget, public LinkWidget -{ - Q_OBJECT -public: - MessageWidget(UMLScene * scene, ObjectWidget* a, ObjectWidget* b, - int y, Uml::SequenceMessage::Enum sequenceMessageType, - Uml::ID::Type id = Uml::ID::None); - MessageWidget(UMLScene * scene, Uml::SequenceMessage::Enum sequenceMessageType, - Uml::ID::Type id = Uml::ID::None); - MessageWidget(UMLScene * scene, ObjectWidget* a, int xclick, int yclick, - Uml::SequenceMessage::Enum sequenceMessageType, - Uml::ID::Type id = Uml::ID::None); - virtual ~MessageWidget(); - - virtual void setY(qreal y); - - //---------- LinkWidget Interface methods implemementation from now on. - - virtual void lwSetFont (QFont font); - virtual UMLClassifier *operationOwner(); - - virtual UMLOperation *operation(); - virtual void setOperation(UMLOperation *op); - - virtual QString customOpText(); - virtual void setCustomOpText(const QString &opText); - - virtual void setMessageText(FloatingTextWidget *ft); - virtual void setText(FloatingTextWidget *ft, const QString &newText); - - virtual QString lwOperationText(); - virtual UMLClassifier *lwClassifier(); - virtual void setOperationText(const QString &op); - - virtual void constrainTextPos(qreal &textX, qreal &textY, qreal textWidth, qreal textHeight, - Uml::TextRole::Enum tr); - - //---------- End LinkWidget Interface methods implemementation. - - /// @return Whether the message is synchronous or asynchronous - Uml::SequenceMessage::Enum sequenceMessageType() const { - return m_sequenceMessageType; - } - - bool hasObjectWidget(ObjectWidget * w); - - ObjectWidget* objectWidget(Uml::RoleType::Enum role); - void setObjectWidget(ObjectWidget * ow, Uml::RoleType::Enum role) ; - - bool isSelf() const; - - /** - * Returns the text widget it is related to. - * - * @return The text widget we are related to. - */ - FloatingTextWidget * floatingTextWidget() { - return m_pFText; - } - - /** - * Sets the text widget it is related to. - * - * @param f The text widget we are related to. - */ - void setFloatingTextWidget(FloatingTextWidget * f) { - m_pFText = f; - } - - void calculateWidget(); - - virtual bool activate(IDChangeLog * Log = 0); - void resolveObjectWidget(IDChangeLog* log); - - void calculateDimensions(); - void calculateDimensionsSynchronous(); - void calculateDimensionsAsynchronous(); - void calculateDimensionsCreation(); - void calculateDimensionsLost(); - void calculateDimensionsFound(); - - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - - void setTextPosition(); - - void cleanup(); - - void setSelected(bool _select); - - int getMinY(); - int getMaxY(); - - UMLWidget* onWidget(const QPointF& p); - - virtual void resizeWidget(qreal newW, qreal newH); - - virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); - virtual bool loadFromXMI(QDomElement & qElement); - - void setxclicked(int xclick); - void setyclicked(int yclick); - - /** - * Return the xclicked - */ - int getxclicked() const { - return m_xclicked; - } - -protected: - virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); - - virtual void moveWidgetBy(qreal diffX, qreal diffY); - virtual void constrainMovementForAllWidgets(qreal &diffX, qreal &diffY); - - virtual QCursor resizeCursor() const; - - void setLinkAndTextPos(); - - int constrainX(int textX, int textWidth, Uml::TextRole::Enum tr); - - static void paintArrow(QPainter *p, int x, int y, int w, - Qt::ArrowType direction, bool useDottedLine = false); - static void paintsolid-kf6Arrowhead(QPainter *p, int x, int y, Qt::ArrowType direction); - - void updateResizability(); - - void paintSynchronous(QPainter *painter, const QStyleOptionGraphicsItem *option); - void paintAsynchronous(QPainter *painter, const QStyleOptionGraphicsItem *option); - void paintCreation(QPainter *painter, const QStyleOptionGraphicsItem *option); - void paintLost(QPainter *painter, const QStyleOptionGraphicsItem *option); - void paintFound(QPainter *painter, const QStyleOptionGraphicsItem *option); - - // Data loaded/saved - QString m_CustomOp; - /** - * Whether the message is synchronous or asynchronous - */ - Uml::SequenceMessage::Enum m_sequenceMessageType; - -private: - void resizeEvent(QResizeEvent *re); - - qreal constrainPositionY(qreal diffY); - - void init(); - - ObjectWidget * m_pOw[2]; - FloatingTextWidget * m_pFText; - - int m_xclicked; - int m_yclicked; - - /** - * The following variables are used by loadFromXMI() as an intermediate - * store. activate() resolves the IDs, i.e. after activate() the variables - * m_pOw[] and m_pFText can be used. - */ - Uml::ID::Type m_widgetAId, m_widgetBId, m_textId; - -public slots: - void slotWidgetMoved(Uml::ID::Type id); - void slotMenuSelection(QAction* action); - -signals: - /** - * emitted when the message widget is moved up or down - * slots into ObjectWidget::slotMessageMoved() - */ - void sigMessageMoved(); -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/nodewidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/nodewidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/nodewidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/nodewidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,156 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "nodewidget.h" - -// app includes -#include "debug_utils.h" -#include "node.h" -#include "umlscene.h" -#include "umlview.h" - -// qt includes -#include -#include - -DEBUG_REGISTER_DISABLED(NodeWidget) - -/** - * Constructs a NodeWidget. - * - * @param scene The parent of this NodeWidget. - * @param n The UMLNode this will be representing. - */ -NodeWidget::NodeWidget(UMLScene * scene, UMLNode *n) - : UMLWidget(scene, WidgetBase::wt_Node, n) -{ - setSize(100, 30); - setZValue(1); // above box but below UMLWidget because may embed widgets -} - -/** - * Destructor. - */ -NodeWidget::~NodeWidget() -{ -} - -/** - * Overrides standard method. - */ -void NodeWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - Q_UNUSED(option); - Q_UNUSED(widget); - - setPenFromSettings(painter); - if (UMLWidget::useFillColor()) { - painter->setBrush(UMLWidget::fillColor()); - } else { - painter->setBrush(m_scene->backgroundColor()); - } - const int w = width(); - const int h = height(); - const int wDepth = (w/3 > DEPTH ? DEPTH : w/3); - const int hDepth = (h/3 > DEPTH ? DEPTH : h/3); - const int bodyOffsetY = hDepth; - const int bodyWidth = w - wDepth; - const int bodyHeight = h - hDepth; - QFont font = UMLWidget::font(); - font.setBold(true); - const QFontMetrics &fm = getFontMetrics(FT_BOLD); - const int fontHeight = fm.lineSpacing(); - QString nameStr = name(); - - QPolygon pointArray(5); - pointArray.setPoint(0, 0, bodyOffsetY); - pointArray.setPoint(1, wDepth, 0); - pointArray.setPoint(2, w, 0); - pointArray.setPoint(3, w, bodyHeight); - pointArray.setPoint(4, bodyWidth, h); - painter->drawPolygon(pointArray); - painter->drawRect(0, bodyOffsetY, bodyWidth, bodyHeight); - painter->drawLine(w, 0, bodyWidth, bodyOffsetY); - - painter->setPen(textColor()); - painter->setFont(font); - - int lines = 1; - if (m_umlObject) { - QString stereotype = m_umlObject->stereotype(); - if (!stereotype.isEmpty()) { - painter->drawText(0, bodyOffsetY + (bodyHeight/2) - fontHeight, - bodyWidth, fontHeight, Qt::AlignCenter, m_umlObject->stereotype(true)); - lines = 2; - } - } - - if (UMLWidget::isInstance()) { - font.setUnderline(true); - painter->setFont(font); - nameStr = UMLWidget::instanceName() + QLatin1String(" : ") + nameStr; - } - - if (lines == 1) { - painter->drawText(0, bodyOffsetY + (bodyHeight/2) - (fontHeight/2), - bodyWidth, fontHeight, Qt::AlignCenter, nameStr); - } else { - painter->drawText(0, bodyOffsetY + (bodyHeight/2), - bodyWidth, fontHeight, Qt::AlignCenter, nameStr); - } - - UMLWidget::paint(painter, option, widget); -} - -/** - * Overrides method from UMLWidget. - */ -QSizeF NodeWidget::minimumSize() const -{ - if (m_umlObject == NULL) { - DEBUG(DBG_SRC) << "m_umlObject is NULL"; - return UMLWidget::minimumSize(); - } - - const QFontMetrics &fm = getFontMetrics(FT_BOLD_ITALIC); - const int fontHeight = fm.lineSpacing(); - - QString name = m_umlObject->name(); - if (UMLWidget::isInstance()) { - name = UMLWidget::instanceName() + QLatin1String(" : ") + name; - } - - int width = fm.width(name) + 2 * defaultMargin; - - int tempWidth = 0; - if (!m_umlObject->stereotype().isEmpty()) { - tempWidth = fm.width(m_umlObject->stereotype(true)); - } - if (tempWidth > width) - width = tempWidth; - width += DEPTH; - - int height = (2*fontHeight) + DEPTH; - - return QSizeF(width, height); -} - -/** - * Saves to the "nodewidget" XMI element. - * Note: For loading we use the method inherited from UMLWidget. - */ -void NodeWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) -{ - QDomElement conceptElement = qDoc.createElement(QLatin1String("nodewidget")); - UMLWidget::saveToXMI(qDoc, conceptElement); - qElement.appendChild(conceptElement); -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/nodewidget.h umbrello-kf6-15.08.1/umbrello/widgets/nodewidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/nodewidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/nodewidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,44 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef NODEWIDGET_H -#define NODEWIDGET_H - -#include "umlwidget.h" - -class UMLNode; - -/** - * Defines a graphical version of the Node. Most of the functionality - * will come from the @ref UMLNode class. - * - * @short A graphical version of a Node. - * @author Jonathan Riddell - * @see UMLWidget - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class NodeWidget : public UMLWidget -{ -public: - - NodeWidget(UMLScene * scene, UMLNode *n); - virtual ~NodeWidget(); - - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - - void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); - -protected: - QSizeF minimumSize() const; - - static const int DEPTH = 30; ///< pixels on Z axis -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/notewidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/notewidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/notewidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/notewidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,517 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "notewidget.h" - -// app includes -#include "debug_utils.h" -#include "docwindow.h" -#include "listpopupmenu.h" -#include "notedialog.h" -#include "uml.h" -#include "umldoc.h" -#include "umlscene.h" -#include "umlview.h" - -// kde includes -#include -#if QT_VERSION < 0x050000 -#include -#include -#endif - -// qt includes -#include -#if QT_VERSION >= 0x050000 -#include -#include -#endif - -NoteWidget * NoteWidget::s_pCurrentNote; - -/** - * Constructs a NoteWidget. - * - * @param scene The parent to this widget. - * @param noteType The NoteWidget::NoteType of this NoteWidget - * @param id The unique id of the widget. - * The default (-1) will prompt a new ID. - */ -NoteWidget::NoteWidget(UMLScene * scene, NoteType noteType , Uml::ID::Type id) - : UMLWidget(scene, WidgetBase::wt_Note, id), - m_diagramLink(Uml::ID::None), - m_noteType(noteType) -{ - setZValue(20); //make sure always on top. -} - -/** - * Destructor. - */ -NoteWidget::~NoteWidget() -{ -} - -/** - * Override default method. - */ -void NoteWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - Q_UNUSED(option); - Q_UNUSED(widget); - - const int margin = 10; - int w = width(); - int h = height(); - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - QPolygon poly(6); - poly.setPoint(0, 0, 0); - poly.setPoint(1, 0, h); - poly.setPoint(2, w, h); - poly.setPoint(3, w, margin); - poly.setPoint(4, w - margin, 0); - poly.setPoint(5, 0, 0); - - setPenFromSettings(painter); - if (UMLWidget::useFillColor()) { - QBrush brush(UMLWidget::fillColor()); - painter->setBrush(brush); - painter->drawPolygon(poly); - } else - painter->drawPolyline(poly); - painter->drawLine(w - margin, 0, w - margin, margin); - painter->drawLine(w - margin, margin, w, margin); - painter->setPen(textColor()); - switch(m_noteType) { - case NoteWidget::PreCondition : - painter->drawText(0, margin, w, fontHeight, Qt::AlignCenter, QLatin1String("<< precondition >>")); - break; - case NoteWidget::PostCondition : - painter->drawText(0, margin, w, fontHeight, Qt::AlignCenter, QLatin1String("<< postcondition >>")); - break; - case NoteWidget::Transformation : - painter->drawText(0, margin, w, fontHeight, Qt::AlignCenter, QLatin1String("<< transformation >>")); - break; - case NoteWidget::Normal : - default : - break; - } - - UMLWidget::paint(painter, option, widget); - -// paintText(&p, 0, 0); - paintTextWordWrap(painter); -} - -/** - * Returns the type of note. - */ -NoteWidget::NoteType NoteWidget::noteType() const -{ - return m_noteType; -} - -/** - * Converts a string to NoteWidget::NoteType. - */ -NoteWidget::NoteType NoteWidget::stringToNoteType(const QString& noteType) -{ - if (noteType == QLatin1String("Precondition")) - return NoteWidget::PreCondition; - else if (noteType == QLatin1String("Postcondition")) - return NoteWidget::PostCondition; - else if (noteType == QLatin1String("Transformation")) - return NoteWidget::Transformation; - else - return NoteWidget::Normal; -} - -/** - * Sets the type of note. - */ -void NoteWidget::setNoteType(NoteType noteType) -{ - m_noteType = noteType; -} - -/** - * Sets the type of note. - */ -void NoteWidget::setNoteType(const QString& noteType) -{ - setNoteType(stringToNoteType(noteType)); -} - -/** - * Return the ID of the diagram hyperlinked to this note. - * - * @return ID of an UMLView, or Uml::ID::None if no - * hyperlink is set. - */ -Uml::ID::Type NoteWidget::diagramLink() const -{ - return m_diagramLink; -} - -/** - * Set the ID of the diagram hyperlinked to this note. - * To switch off the hyperlink, set this to Uml::id_None. - * - * @param viewID ID of an UMLScene. - */ -void NoteWidget::setDiagramLink(Uml::ID::Type viewID) -{ - UMLDoc *umldoc = UMLApp::app()->document(); - UMLView *view = umldoc->findView(viewID); - if (view == NULL) { - uError() << "no view found for viewID " << Uml::ID::toString(viewID); - return; - } - QString linkText(QLatin1String("Diagram: ") + view->umlScene()->name()); - setDocumentation(linkText); - m_diagramLink = viewID; - update(); -} - -/** - * Display a dialog box to allow the user to choose the note's type. - */ -void NoteWidget::askForNoteType(UMLWidget* &targetWidget) -{ - static const QStringList list = QStringList() << i18n("Precondition") - << i18n("Postcondition") - << i18n("Transformation"); - bool pressedOK = false; - -#if QT_VERSION >= 0x050000 - QString type = QInputDialog::getItem (UMLApp::app(), - i18n("Note Type"), i18n("Select the Note Type"), list, - 0, false, &pressedOK); -#else - QString type = KInputDialog::getItem (i18n("Note Type"), i18n("Select the Note Type"), list, - 0, false, &pressedOK, UMLApp::app()); -#endif - - if (pressedOK) { - dynamic_cast(targetWidget)->setNoteType(type); - } else { - targetWidget->cleanup(); - delete targetWidget; - targetWidget = 0; - } -} - -/** - * Loads a "notewidget" XMI element. - */ -bool NoteWidget::loadFromXMI(QDomElement & qElement) -{ - if (!UMLWidget::loadFromXMI(qElement)) - return false; - setZValue(20); //make sure always on top. - setDocumentation(qElement.attribute(QLatin1String("text"))); - QString diagramlink = qElement.attribute(QLatin1String("diagramlink")); - if (!diagramlink.isEmpty()) - m_diagramLink = Uml::ID::fromString(diagramlink); - QString type = qElement.attribute(QLatin1String("noteType")); - setNoteType((NoteType)type.toInt()); - return true; -} - -/** - * Saves to the "notewidget" XMI element. - */ -void NoteWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) -{ - QDomElement noteElement = qDoc.createElement(QLatin1String("notewidget")); - UMLWidget::saveToXMI(qDoc, noteElement); - noteElement.setAttribute(QLatin1String("text"), documentation()); - if (m_diagramLink != Uml::ID::None) - noteElement.setAttribute(QLatin1String("diagramlink"), Uml::ID::toString(m_diagramLink)); - noteElement.setAttribute(QLatin1String("noteType"), m_noteType); - qElement.appendChild(noteElement); -} - -/** - * Show a properties dialog for a NoteWidget. - */ -void NoteWidget::showPropertiesDialog() -{ - NoteDialog * dlg = 0; - UMLApp::app()->docWindow()->updateDocumentation(false); - dlg = new NoteDialog(umlScene()->activeView(), this); - if (dlg->exec()) { - UMLApp::app()->docWindow()->showDocumentation(this, true); - UMLApp::app()->document()->setModified(true); - update(); - } - delete dlg; -} - -/** - * Will be called when a menu selection has been made from the popup - * menu. - * - * @param action The action that has been selected. - */ -void NoteWidget::slotMenuSelection(QAction* action) -{ - ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); - switch(sel) { - case ListPopupMenu::mt_Rename: - showPropertiesDialog(); - break; - - default: - UMLWidget::slotMenuSelection(action); - break; - } -} - -/** - * Overrides method from UMLWidget. - */ -QSizeF NoteWidget::minimumSize() const -{ - int width = 60; - int height = 30; - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int textWidth = fm.width(documentation()); - if (m_noteType == PreCondition) { - const int widthtemp = fm.width(QLatin1String("<< precondition >>")); - width = textWidth > widthtemp ? textWidth : widthtemp; - width += 10; - } - else if (m_noteType == PostCondition) { - const int widthtemp = fm.width(QLatin1String("<< postcondition >>")); - width = textWidth > widthtemp ? textWidth : widthtemp; - width += 10; - } - else if (m_noteType == Transformation) { - const int widthtemp = fm.width(QLatin1String("<< transformation >>")); - width = textWidth > widthtemp ? textWidth : widthtemp; - width += 10; - } - return QSizeF(width, height); -} - -/** - * Calculate content related size of widget. - * Overrides method from UMLWidget. - */ -QSizeF NoteWidget::calculateSize(bool withExtensions /* = true */) const -{ - Q_UNUSED(withExtensions) - int width = this->width(); - int height = this->height(); - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int margin = fm.width(QLatin1String("W")); - QSize size = fm.size (0, documentation()); - const int textWidth = size.width(); - if (m_noteType == PreCondition) { - const int widthtemp = fm.width(QLatin1String("<< precondition >>")); - width = textWidth > widthtemp ? textWidth : widthtemp; - width += 2 * margin; - } - else if (m_noteType == PostCondition) { - const int widthtemp = fm.width(QLatin1String("<< postcondition >>")); - width = textWidth > widthtemp ? textWidth : widthtemp; - width += 2 * margin; - } - else if (m_noteType == Transformation) { - const int widthtemp = fm.width(QLatin1String("<< transformation >>")); - width = textWidth > widthtemp ? textWidth : widthtemp; - width += 2 * margin; - } - return QSizeF(width, height); -} - -/** - * Paints the text. Auxiliary to paint(). - * Implemented without word wrap. - */ -void NoteWidget::paintText(QPainter *painter) -{ - if (painter == 0) { - return; - } - - QString text = documentation(); - if (text.length() == 0) { - return; - } - - painter->setPen(Qt::black); - QFont font = UMLWidget::font(); - painter->setFont(font); - - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - const int margin = fm.width(QLatin1String("W")); - const QSize textSize = fm.size(Qt::TextExpandTabs, text); - - const int width = this->width() - margin * 2; - const int height = this->height() - fontHeight; - int textY = fontHeight / 2; - int textX = margin; - - if ((textSize.width() < width) && (textSize.height() < height)) { - // the entire text is small enough - draw it - painter->drawText(textX, textY, - textSize.width(), textSize.height(), - Qt::AlignLeft, text); - } - else { - // not all text can be drawn - QStringList lines = text.split(QLatin1Char('\n')); - foreach(const QString& line, lines) { - int lineWidth = fm.width(line); - if (lineWidth < width) { - // line is small enough - draw it - painter->drawText(textX, textY, - textSize.width(), fontHeight, - Qt::AlignLeft, line); - } - else { - // draw a smaller line - for(int len = line.length(); len > 0; --len) { - QString smallerLine = line.left(len); - int smallerLineWidth = fm.width(smallerLine); - if (smallerLineWidth < width) { - // line is small enough - draw it - painter->drawText(textX, textY, - width, fontHeight, - Qt::AlignLeft, smallerLine); - } - } - } - textY += fontHeight; - if (textY > height) { - // skip the next lines - size is not enough - break; - } - } - } -} - -/** - * Paints the text. Auxiliary to paint(). - * Implemented with word wrap. - */ -void NoteWidget::paintTextWordWrap(QPainter *painter) -{ - if (painter == 0) { - return; - } - QString text = documentation(); - if (text.length() == 0) { - return; - } - // Implement word wrap for text as follows: - // wrap at width on whole words. - // if word is wider than width then clip word - // if reach height exit and don't print anymore - // start new line on \n character - painter->setPen(Qt::black); - QFont font = UMLWidget::font(); - painter->setFont(font); - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - QString word; - QString fullLine; - QString testCombineLine; - const int margin = fm.width(QLatin1String("W")); - int textY = fontHeight / 2; - int textX = margin; - const int width = this -> width() - margin * 2; - const int height = this -> height() - fontHeight; - QChar returnChar = QChar::fromLatin1('\n'); - QChar c; - - for (int i = 0; i <= text.length(); ++i) { - if (i < text.length()) { - c = text[i]; - } else { - // all chars of text have been handled already -> - // perform this last run to spool current content of "word" - c = returnChar; - } - if (c == returnChar || c.isSpace()) { - // new word delimiter found -> it is time to decide on word wrap - testCombineLine = fullLine + QLatin1Char(' ') + word; - int textWidth = fm.width(testCombineLine); - if (textX + textWidth > width) { - // combination of "fullLine" and "word" doesn't fit into one line -> - // print "fullLine" in current line, update write position to next line - // and decide then on following actions - painter->drawText(textX, textY, - textWidth, fontHeight, Qt::AlignLeft, fullLine); - fullLine = word; - word = QString(); - // update write position - textX = margin; - textY += fontHeight; - if (textY > height) - return; - // in case of c==newline -> - // print "word" and set write position one additional line lower - if (c == returnChar) { - // print "word" - which is now "fullLine" and set to next line - painter->drawText(textX, textY, - textWidth, fontHeight, Qt::AlignLeft, fullLine); - fullLine = QString(); - textX = margin; - textY += fontHeight; - if(textY > height) return; - } - } - else if (c == returnChar) { - // newline found and combination of "fullLine" and "word" fits - // in one line - painter->drawText(textX, textY, - textWidth, fontHeight, Qt::AlignLeft, testCombineLine); - fullLine = word = QString(); - textX = margin; - textY += fontHeight; - if (textY > height) - return; - } else { - // word delimiter found, and combination of "fullLine", space and "word" fits into one line - fullLine = testCombineLine; - word = QString(); - } - } else { - // no word delimiter found --> add current char to "word" - if (c != QLatin1Char('\0')) - word += c; - } - }//end for -} - -/** - * Event handler for moude double click events. - * - * @param event The QGraphicsSceneMouseEvent event. - */ -void NoteWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) -{ - if (event->button() == Qt::LeftButton) { - if (m_diagramLink == Uml::ID::None) { - showPropertiesDialog(); - } else { - UMLDoc *umldoc = UMLApp::app()->document(); - umldoc->changeCurrentView(m_diagramLink); - } - event->accept(); - } -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/notewidget.h umbrello-kf6-15.08.1/umbrello/widgets/notewidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/notewidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/notewidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,83 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef NOTEWIDGET_H -#define NOTEWIDGET_H - -//app includes -#include "umlwidget.h" - -// Qt forward declarations -class QPainter; - -/** - * Displays a note box to allow multiple lines of text to be displayed. - * These widgets are diagram specific. They will still need a unique id - * from the @ref UMLDoc class for deletion and other purpose-kf6s. - * - * @short Displays a note box. - * @author Paul Hensgen - * @see UMLWidget - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class NoteWidget : public UMLWidget -{ - Q_OBJECT -public: - - /// This enum type is used to specify the type of note. - enum NoteType - { - Normal, - PreCondition, - PostCondition, - Transformation - }; - - explicit NoteWidget(UMLScene * scene, NoteWidget::NoteType noteType = Normal, - Uml::ID::Type id = Uml::ID::None); - virtual ~NoteWidget(); - - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - - static NoteType stringToNoteType(const QString& noteType); - - NoteType noteType() const; - void setNoteType(NoteType noteType); - void setNoteType(const QString& noteType); - - Uml::ID::Type diagramLink() const; - void setDiagramLink(Uml::ID::Type viewID); - - void askForNoteType(UMLWidget* &targetWidget); - - virtual void showPropertiesDialog(); - - virtual bool loadFromXMI(QDomElement & qElement); - virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); - - static NoteWidget *s_pCurrentNote; - -public Q_SLOTS: - void slotMenuSelection(QAction* action); - -protected: - virtual QSizeF minimumSize() const; - virtual QSizeF calculateSize(bool withExtensions = true) const; - void paintText(QPainter *painter); - void paintTextWordWrap(QPainter *painter); - virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); - -private: - Uml::ID::Type m_diagramLink; ///< The diagram/scene this note links to. - NoteType m_noteType; ///< The type of note. @see NoteWidget::NoteType -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/objectnodewidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/objectnodewidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/objectnodewidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/objectnodewidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,377 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "objectnodewidget.h" - -// app includes -#include "debug_utils.h" -#include "docwindow.h" -#include "dialog_utils.h" -#include "listpopupmenu.h" -#include "objectnodedialog.h" -#include "uml.h" -#include "umldoc.h" -#include "umlscene.h" -#include "umlview.h" - -// kde includes -#include -#if QT_VERSION < 0x050000 -#include -#endif - -// qt includes -#if QT_VERSION >= 0x050000 -#include -#endif -#include -#include - -#define OBJECTNODE_MARGIN 5 -#define OBJECTNODE_WIDTH 30 -#define OBJECTNODE_HEIGHT 10 - -/** - * Creates a Object Node widget. - * - * @param scene The parent of the widget. - * @param objectNodeType The type of object node - * @param id The ID to assign (-1 will prompt a new ID.) - */ -ObjectNodeWidget::ObjectNodeWidget(UMLScene * scene, ObjectNodeType objectNodeType, Uml::ID::Type id) - : UMLWidget(scene, WidgetBase::wt_ObjectNode, id) -{ - setObjectNodeType(objectNodeType); - setState(QString()); -} - -/** - * Destructor. - */ -ObjectNodeWidget::~ObjectNodeWidget() -{ -} - -/** - * Overrides the standard paint event. - */ -void ObjectNodeWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - Q_UNUSED(option); - Q_UNUSED(widget); - - int w = width(); - int h = height(); - - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - int textStartY = (h / 2) - (fontHeight / 2); - - setPenFromSettings(painter); - - if (UMLWidget::useFillColor()) { - painter->setBrush(UMLWidget::fillColor()); - } - - painter->drawRect(0, 0, w, h); - painter->setFont(UMLWidget::font()); - - switch (m_objectNodeType) - { - case Normal : break; - case Buffer : - { - painter->setPen(textColor()); - painter->drawText(OBJECTNODE_MARGIN, (textStartY/2), w - OBJECTNODE_MARGIN * 2, fontHeight, Qt::AlignHCenter, QLatin1String("<< centralBuffer >>")); - painter->drawText(OBJECTNODE_MARGIN, (textStartY/2) + fontHeight + 5, w - OBJECTNODE_MARGIN * 2, fontHeight, Qt::AlignHCenter, name()); - } - break; - case Data : - { - painter->setPen(textColor()); - painter->drawText(OBJECTNODE_MARGIN, (textStartY/2), w - OBJECTNODE_MARGIN * 2, fontHeight, Qt::AlignHCenter, QLatin1String("<< datastore >>")); - painter->drawText(OBJECTNODE_MARGIN, (textStartY/2) + fontHeight + 5, w - OBJECTNODE_MARGIN * 2, fontHeight, Qt::AlignHCenter, name()); - } - break; - case Flow : - { - QString objectflow_value; - if (state() == QLatin1String("-") || state().isEmpty()) - { - objectflow_value = QLatin1Char(' '); - } - else - { - objectflow_value = QLatin1Char('[') + state() + QLatin1Char(']'); - } - - painter->drawLine(10, h/2, w-10, h/2); - painter->setPen(textColor()); - painter->setFont(UMLWidget::font()); - painter->drawText(OBJECTNODE_MARGIN, textStartY/2 - OBJECTNODE_MARGIN, w - OBJECTNODE_MARGIN * 2, fontHeight, Qt::AlignHCenter, name()); - painter->drawText(OBJECTNODE_MARGIN, textStartY/2 + textStartY + OBJECTNODE_MARGIN, w - OBJECTNODE_MARGIN * 2, fontHeight, Qt::AlignHCenter, objectflow_value); - } - break; - } - - UMLWidget::paint(painter, option, widget); -} - -/** - * Overrides method from UMLWidget. - */ -QSizeF ObjectNodeWidget::minimumSize() const -{ - int widthtmp = 10, height = 10, width=10; - if (m_objectNodeType == Buffer) { - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - const int textWidth = fm.width(QLatin1String("<< centralBuffer >>")); - const int namewidth = fm.width(name()); - height = fontHeight * 2; - widthtmp = textWidth > OBJECTNODE_WIDTH ? textWidth : OBJECTNODE_WIDTH; - width = namewidth > widthtmp ? namewidth : widthtmp; - height = height > OBJECTNODE_HEIGHT ? height : OBJECTNODE_HEIGHT; - width += OBJECTNODE_MARGIN * 2; - height += OBJECTNODE_MARGIN * 2 + 5; - } else if (m_objectNodeType == Data) { - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - const int textWidth = fm.width(QLatin1String("<< datastore >>")); - const int namewidth = fm.width(name()); - height = fontHeight * 2; - widthtmp = textWidth > OBJECTNODE_WIDTH ? textWidth : OBJECTNODE_WIDTH; - width = namewidth > widthtmp ? namewidth : widthtmp; - height = height > OBJECTNODE_HEIGHT ? height : OBJECTNODE_HEIGHT; - width += OBJECTNODE_MARGIN * 2; - height += OBJECTNODE_MARGIN * 2 + 5; - } else if (m_objectNodeType == Flow) { - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - const int textWidth = fm.width(QLatin1Char('[') + state() + QLatin1Char(']')); - const int namewidth = fm.width(name()); - height = fontHeight * 2; - widthtmp = textWidth > OBJECTNODE_WIDTH ? textWidth : OBJECTNODE_WIDTH; - width = namewidth > widthtmp ? namewidth : widthtmp; - height = height > OBJECTNODE_HEIGHT ? height : OBJECTNODE_HEIGHT; - width += OBJECTNODE_MARGIN * 2; - height += OBJECTNODE_MARGIN * 4; - } - - return QSizeF(width, height); -} - -/** - * Returns the type of object node. - */ -ObjectNodeWidget::ObjectNodeType ObjectNodeWidget::objectNodeType() const -{ - return m_objectNodeType; -} - -/** - * Returns the type of object node. - */ -ObjectNodeWidget::ObjectNodeType ObjectNodeWidget::toObjectNodeType(const QString& type) -{ - if (type == QLatin1String("Central buffer")) - return ObjectNodeWidget::Buffer; - if (type == QLatin1String("Data store")) - return ObjectNodeWidget::Data; - if (type == QLatin1String("Object Flow")) - return ObjectNodeWidget::Flow; - // Shouldn't happen - Q_ASSERT(0); - return ObjectNodeWidget::Flow; -} - -/** - * Sets the type of object node. - */ -void ObjectNodeWidget::setObjectNodeType(ObjectNodeType objectNodeType) -{ - m_objectNodeType = objectNodeType; - UMLWidget::m_resizable = true; -} - -/** - * Sets the type of object node. - */ -void ObjectNodeWidget::setObjectNodeType(const QString& type) -{ - setObjectNodeType(ObjectNodeWidget::toObjectNodeType(type)); -} - -/** - * Sets the state of an object node when it's an objectflow. - */ -void ObjectNodeWidget::setState(const QString& state) -{ - m_state = state; - updateGeometry(); -} - -/** - * Returns the state of object node. - */ -QString ObjectNodeWidget::state() const -{ - return m_state; -} - -/** - * Captures any popup menu signals for menus it created. - */ -void ObjectNodeWidget::slotMenuSelection(QAction* action) -{ - ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); - switch(sel) { - case ListPopupMenu::mt_Rename: - { - bool ok = false; - QString text = name(); -#if QT_VERSION >= 0x050000 - text = QInputDialog::getText(Q_NULLPTR, - i18n("Enter Object Node Name"), - i18n("Enter the name of the object node :"), - QLineEdit::Normal, - name(), &ok); -#else - text = KInputDialog::getText(i18n("Enter Object Node Name"), - i18n("Enter the name of the object node :"), - name(), &ok); -#endif - if (ok && !text.isEmpty()) { - setName(text); - } - } - break; - - case ListPopupMenu::mt_Properties: - showPropertiesDialog(); - break; - - default: - UMLWidget::slotMenuSelection(action); - } -} - -/** - * Show a properties dialog for an ObjectNodeWidget. - */ -void ObjectNodeWidget::showPropertiesDialog() -{ - UMLApp::app()->docWindow()->updateDocumentation(false); - - QPointer dialog = new ObjectNodeDialog(UMLApp::app()->currentView(), this); - if (dialog->exec() && dialog->getChangesMade()) { - UMLApp::app()->docWindow()->showDocumentation(this, true); - UMLApp::app()->document()->setModified(true); - } - delete dialog; -} - -/** - * Saves the widget to the "objectnodewidget" XMI element. - */ -void ObjectNodeWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) -{ - QDomElement objectNodeElement = qDoc.createElement(QLatin1String("objectnodewidget")); - UMLWidget::saveToXMI(qDoc, objectNodeElement); - objectNodeElement.setAttribute(QLatin1String("objectnodename"), m_Text); - objectNodeElement.setAttribute(QLatin1String("documentation"), m_Doc); - objectNodeElement.setAttribute(QLatin1String("objectnodetype"), m_objectNodeType); - objectNodeElement.setAttribute(QLatin1String("objectnodestate"), m_state); - qElement.appendChild(objectNodeElement); -} - -/** - * Loads the widget from the "objectnodewidget" XMI element. - */ -bool ObjectNodeWidget::loadFromXMI(QDomElement& qElement) -{ - if(!UMLWidget::loadFromXMI(qElement) ) - return false; - m_Text = qElement.attribute(QLatin1String("objectnodename")); - m_Doc = qElement.attribute(QLatin1String("documentation")); - QString type = qElement.attribute(QLatin1String("objectnodetype"), QLatin1String("1")); - m_state = qElement.attribute(QLatin1String("objectnodestate")); - setObjectNodeType((ObjectNodeType)type.toInt()); - return true; -} - -/** - * Open a dialog box to select the objectNode type (Data, Buffer or Flow). - */ -void ObjectNodeWidget::askForObjectNodeType(UMLWidget* &targetWidget) -{ - bool pressedOK = false; - int current = 0; - const QStringList list = QStringList() - << QLatin1String("Central buffer") - << QLatin1String("Data store") - << QLatin1String("Object Flow"); - -#if QT_VERSION >= 0x050000 - QString type = QInputDialog::getItem (UMLApp::app(), - i18n("Select Object node type"), i18n("Select the object node type"), - list, current, false, &pressedOK); - -#else - QString type = KInputDialog::getItem (i18n("Select Object node type"), i18n("Select the object node type"), list, current, false, &pressedOK, UMLApp::app()); -#endif - - if (pressedOK) { - dynamic_cast(targetWidget)->setObjectNodeType(type); - if (type == QLatin1String("Data store")) - Dialog_Utils::askNameForWidget(targetWidget, i18n("Enter the name of the data store node"), i18n("Enter the name of the data store node"), i18n("data store name")); - if (type == QLatin1String("Central buffer")) - Dialog_Utils::askNameForWidget(targetWidget, i18n("Enter the name of the buffer node"), i18n("Enter the name of the buffer"), i18n("centralBuffer")); - if (type == QLatin1String("Object Flow")) { - Dialog_Utils::askNameForWidget(targetWidget, i18n("Enter the name of the object flow"), i18n("Enter the name of the object flow"), i18n("object flow")); - askStateForWidget(); - } - } else { - targetWidget->cleanup(); - delete targetWidget; - targetWidget = NULL; - } -} - -/** - * Open a dialog box to input the state of the widget. - * This box is shown only if m_objectNodeType = Flow. - */ -void ObjectNodeWidget::askStateForWidget() -{ - bool pressedOK = false; -#if QT_VERSION >= 0x050000 - QString state = QInputDialog::getText(UMLApp::app(), - i18n("Enter Object Flow State"), i18n("Enter State (keep '-' if there is no state for the object) "), - QLineEdit::Normal, - i18n("-"), &pressedOK); -#else - QString state = KInputDialog::getText(i18n("Enter Object Flow State"), i18n("Enter State (keep '-' if there is no state for the object) "), i18n("-"), &pressedOK, UMLApp::app()); -#endif - - if (pressedOK) { - setState(state); - } else { - cleanup(); - } -} - -void ObjectNodeWidget::slotOk() -{ - // kdialog-kf6::accept(); -} - - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/objectnodewidget.h umbrello-kf6-15.08.1/umbrello/widgets/objectnodewidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/objectnodewidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/objectnodewidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,76 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef OBJECTNODEWIDGET_H -#define OBJECTNODEWIDGET_H - -#include "umlwidget.h" - -/** - * This class is the graphical version of a UML Object Node. A ObjectNodeWidget is created - * by a @ref UMLView. An ObjectNodeWidget belongs to only one @ref UMLView instance. - * When the @ref UMLView instance that this class belongs to, it will be automatically deleted. - * - * The ObjectNodeWidget class inherits from the @ref UMLWidget class which adds most of the functionality - * to this class. - * - * @short A graphical version of a UML Activity. - * @author Florence Mattler - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class ObjectNodeWidget : public UMLWidget -{ - Q_OBJECT - -public: - enum ObjectNodeType - { - Normal, - Data, - Buffer, - Flow - }; - - explicit ObjectNodeWidget(UMLScene * scene, ObjectNodeType objectNodeType = Normal, Uml::ID::Type id = Uml::ID::None); - virtual ~ObjectNodeWidget(); - - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - - ObjectNodeType objectNodeType() const; - static ObjectNodeType toObjectNodeType(const QString& type); - - void setObjectNodeType(ObjectNodeType objectNodeType); - void setObjectNodeType(const QString& type) ; - - void setState(const QString& state); - QString state() const; - - virtual void showPropertiesDialog(); - - void askStateForWidget(); - void askForObjectNodeType(UMLWidget* &targetWidget); - - virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); - virtual bool loadFromXMI(QDomElement& qElement); - -protected: - QSizeF minimumSize() const; - -public slots: - void slotMenuSelection(QAction* action); - void slotOk(); - -private: - ObjectNodeType m_objectNodeType; ///< type of object node - QString m_state; ///< state of object node when it's an objectFlow - -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/objectwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/objectwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/objectwidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/objectwidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,710 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header file -#include "objectwidget.h" - -// local includes -#include "classpropertiesdialog.h" -#include "debug_utils.h" -#include "docwindow.h" -#include "listpopupmenu.h" -#include "messagewidget.h" -#include "seqlinewidget.h" -#include "uml.h" -#include "umldoc.h" -#include "umlobject.h" -#include "umlscene.h" -#include "umlview.h" - -// kde includes -#include -#if QT_VERSION < 0x050000 -#include -#endif - -// qt includes -#if QT_VERSION >= 0x050000 -#include -#endif -#include -#include -#include - -#define O_MARGIN 5 -#define O_WIDTH 40 -#define A_WIDTH 20 -#define A_HEIGHT 40 -#define A_MARGIN 5 - -DEBUG_REGISTER_DISABLED(ObjectWidget) - -/** - * The number of pixels margin between the lowest message - * and the bottom of the vertical line - */ -static const int sequenceLineMargin = 20; - -/** - * Creates an ObjectWidget. - * - * @param scene The parent to this object. - * @param o The object it will be representing. - */ -ObjectWidget::ObjectWidget(UMLScene * scene, UMLObject *o) - : UMLWidget(scene, WidgetBase::wt_Object, o), - m_multipleInstance(false), - m_drawAsActor(false), - m_showDestruction(false), - m_isOnDestructionBox(false) -{ - if (m_scene && (m_scene->type() == Uml::DiagramType::Sequence)) { - m_pLine = new SeqLineWidget( m_scene, this ); - m_pLine->setStartPoint(x() + width() / 2, y() + height()); - } else { - m_pLine = 0; - } -} - -/** - * Destructor. - */ -ObjectWidget::~ObjectWidget() -{ - cleanup(); -} - -/** - * Sets whether representing a multi-instance object. - * - * @param multiple Object state. true- multi, false - single. - */ -void ObjectWidget::setMultipleInstance(bool multiple) -{ - //make sure only calling this in relation to an object on a collab. diagram - if (m_scene && (m_scene->type() == Uml::DiagramType::Collaboration)) { - m_multipleInstance = multiple; - updateGeometry(); - update(); - } -} - -/** - * Returns whether object is representing a multi-object. - * - * @return True if object is representing a multi-object. - */ -bool ObjectWidget::multipleInstance() const -{ - return m_multipleInstance; -} - -/** - * Overridden from UMLWidget. - * Moves the widget to a new position using the difference between the - * current position and the new position. - * Y position is ignored, and widget is only moved along X axis. - * - * @param diffX The difference between current X position and new X position. - * @param diffY The difference between current Y position and new Y position - * (isn't used). - */ -void ObjectWidget::moveWidgetBy(qreal diffX, qreal diffY) -{ - setX(x() + diffX); - if (m_scene && (m_scene->type() != Uml::DiagramType::Sequence)) { - setY(y() + diffY); - } -} - -/** - * Overridden from UMLWidget. - * Modifies the value of the diffX and diffY variables used to move the widgets. - * All the widgets are constrained to be moved only in X axis (diffY is set to 0). - * - * @param diffX The difference between current X position and new X position. - * @param diffY The difference between current Y position and new Y position. - */ -void ObjectWidget::constrainMovementForAllWidgets(qreal &diffX, qreal &diffY) -{ - Q_UNUSED(diffX); - if (m_scene && (m_scene->type() == Uml::DiagramType::Sequence)) { - diffY = 0; - } -} - -/** - * Override default method. - */ -void ObjectWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - Q_UNUSED(option); - Q_UNUSED(widget); - - if (m_drawAsActor) - paintActor(painter); - else - paintObject(painter); - - setPenFromSettings(painter); - - UMLWidget::paint(painter, option, widget); -} - -/** - * Handles a popup menu selection. - */ -void ObjectWidget::slotMenuSelection(QAction* action) -{ - ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); - switch(sel) { - case ListPopupMenu::mt_Rename_Object: - { - bool ok; - QRegExpValidator* validator = new QRegExpValidator(QRegExp(QLatin1String(".*")), 0); -#if QT_VERSION >= 0x050000 - QString name = QInputDialog::getText(m_scene->activeView(), - i18n("Rename Object"), - i18n("Enter object name:"), - QLineEdit::Normal, - m_instanceName, - &ok); -#else - QString name = KInputDialog::getText - (i18n("Rename Object"), - i18n("Enter object name:"), - m_instanceName, - &ok, - m_scene->activeView(), - validator); -#endif - if (ok) { - m_instanceName = name; - updateGeometry(); - moveEvent(0); - update(); - UMLApp::app()->document()->setModified(true); - } - delete validator; - break; - } - case ListPopupMenu::mt_Properties: - showPropertiesDialog(); - updateGeometry(); - moveEvent(0); - update(); - break; - - case ListPopupMenu::mt_Up: - tabUp(); - break; - - case ListPopupMenu::mt_Down: - tabDown(); - break; - - default: - UMLWidget::slotMenuSelection(action); - break; - } -} - -/** - * Overrides method from UMLWidget - */ -QSizeF ObjectWidget::minimumSize() const -{ - int width, height; - const QFontMetrics &fm = getFontMetrics(FT_UNDERLINE); - const int fontHeight = fm.lineSpacing(); - const QString t = m_instanceName + QLatin1String(" : ") + name(); - const int textWidth = fm.width(t); - if (m_drawAsActor) { - width = textWidth > A_WIDTH?textWidth:A_WIDTH; - height = A_HEIGHT + fontHeight + A_MARGIN; - width += A_MARGIN * 2; - } else { - width = textWidth > O_WIDTH?textWidth:O_WIDTH; - height = fontHeight + O_MARGIN * 2; - width += O_MARGIN * 2; - if (m_multipleInstance) { - width += 10; - height += 10; - } - }//end else drawasactor - - return QSizeF(width, height); -} - -/** - * Sets whether to draw as an Actor. - * - * @param drawAsActor True if widget shall be drawn as an actor. - */ -void ObjectWidget::setDrawAsActor(bool drawAsActor) -{ - m_drawAsActor = drawAsActor; - updateGeometry(); -} - -/** - * Returns whether to draw as an Actor or not. - * - * @return True if widget is drawn as an actor. - */ -bool ObjectWidget::drawAsActor() const -{ - return m_drawAsActor; -} - -/** - * Activate the object after serializing it from a QDataStream - */ -bool ObjectWidget::activate(IDChangeLog* ChangeLog /*= 0*/) -{ - if (! UMLWidget::activate(ChangeLog)) - return false; - if (m_showDestruction && m_pLine) - m_pLine->setupDestructionBox(); - moveEvent(0); - return true; -} - -/** - * Sets the x-coordinate. - * Reimplements the method from UMLWidget. - * - * @param x The x-coordinate to be set. - */ -void ObjectWidget::setX(qreal x) -{ - UMLWidget::setX(x); - moveEvent(0); -} - -/** - * Sets the y-coordinate. - * Reimplements the method from UMLWidget. - * - * @param y The y-coordinate to be set. - */ -void ObjectWidget::setY(qreal y) -{ - UMLWidget::setY(y); - if (!UMLApp::app()->document()->loading()) - moveEvent(0); -} - -/** - * Return the x coordinate of the widgets center. - * @return The x-coordinate of the widget center. - */ -qreal ObjectWidget::centerX() -{ - return x() + width()/2; -} - -/** - * Overrides the standard operation. - */ -void ObjectWidget::moveEvent(QGraphicsSceneMouseEvent *event) -{ - Q_UNUSED(event) - emit sigWidgetMoved(m_nLocalID); - if (m_pLine) { - m_pLine->setStartPoint(x() + width() / 2, y() + height()); - } -} - -/** - * Overrides the standard operation. - */ -void ObjectWidget::mousePressEvent(QGraphicsSceneMouseEvent *me) -{ - UMLWidget::mousePressEvent(me); - m_isOnDestructionBox = false; - if (m_pLine && m_pLine->onDestructionBox(me->scenePos())) { - m_isOnDestructionBox = true; - qreal oldX = x() + width() / 2; - qreal oldY = getEndLineY() - 10; - m_oldPos = QPointF(oldX, oldY); - } -} - -/** - * Overrides the standard operation. - */ -void ObjectWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* me) -{ - if (m_inResizeArea) { - DEBUG(DBG_SRC) << "resizing..."; - resize(me); - moveEvent(0); - return; - } - - if (m_isOnDestructionBox) { - qreal diffY = me->scenePos().y() - m_oldPos.y(); - moveDestructionBy(diffY); - } - else { - UMLWidget::mouseMoveEvent(me); - } -} - -/** - * Moves the destruction Box to a new position using the difference between the - * current position and the new position. - * The destruction box is only moved along Y axis. - * - * @param diffY The difference between current Y position and new Y position - */ -void ObjectWidget::moveDestructionBy(qreal diffY) -{ - // endLine = length of the life line + diffY - 10 to center on the destruction box - qreal endLine = getEndLineY() + diffY - 10; - SeqLineWidget *pLine = sequentialLine(); - pLine->setEndOfLine(endLine); - m_oldPos.setY(endLine); -} - -/** - * Handles a color change signal. - */ -void ObjectWidget::slotFillColorChanged(Uml::ID::Type /*viewID*/) -{ - UMLWidget::setFillColor(m_scene->fillColor()); - UMLWidget::setLineColor(m_scene->lineColor()); - - if(m_pLine) - m_pLine->setPen(QPen(UMLWidget::lineColor(), UMLWidget::lineWidth(), Qt::DashLine)); -} - -/** - * Used to cleanup any other widget it may need to delete. - */ -void ObjectWidget::cleanup() -{ - UMLWidget::cleanup(); - if(m_pLine) { - m_pLine->cleanup(); - delete m_pLine; - m_pLine = 0; - } -} - -/** - * Show a properties dialog for an ObjectWidget. - */ -void ObjectWidget::showPropertiesDialog() -{ - UMLApp::app()->docWindow()->updateDocumentation(false); - QPointer dlg = new ClassPropertiesDialog((QWidget*)UMLApp::app(), this); - if (dlg->exec()) { - UMLApp::app()->docWindow()->showDocumentation(this, true); - UMLApp::app()->document()->setModified(true); - } - dlg->close(); - delete dlg; -} - -/** - * Draw the object as an object (default). - */ -void ObjectWidget::paintObject(QPainter *painter) -{ - QFont oldFont = painter->font(); - QFont font = UMLWidget::font(); - font.setUnderline(true); - painter->setFont(font); - - setPenFromSettings(painter); - if(UMLWidget::useFillColor()) - painter->setBrush(UMLWidget::fillColor()); - else - painter->setBrush(m_scene->backgroundColor()); - const int w = width(); - const int h = height(); - - const QString t = m_instanceName + QLatin1String(" : ") + name(); - int multiInstOfst = 0; - if (m_multipleInstance) { - painter->drawRect(10, 10, w - 10, h - 10); - painter->drawRect(5, 5, w - 10, h - 10); - multiInstOfst = 10; - } - painter->drawRect(0, 0, w - multiInstOfst, h - multiInstOfst); - painter->setPen(textColor()); - painter->drawText(O_MARGIN, O_MARGIN, - w - O_MARGIN * 2 - multiInstOfst, h - O_MARGIN * 2 - multiInstOfst, - Qt::AlignCenter, t); - - painter->setFont(oldFont); -} - -/** - * Draw the object as an actor. - */ -void ObjectWidget::paintActor(QPainter *painter) -{ - const QFontMetrics &fm = getFontMetrics(FT_UNDERLINE); - - setPenFromSettings(painter); - if (UMLWidget::useFillColor()) - painter->setBrush(UMLWidget::fillColor()); - const int w = width(); - const int textStartY = A_HEIGHT + A_MARGIN; - const int fontHeight = fm.lineSpacing(); - - const int middleX = w / 2; - const int thirdH = A_HEIGHT / 3; - - //draw actor - painter->drawEllipse(middleX - A_WIDTH / 2, 0, A_WIDTH, thirdH);//head - painter->drawLine(middleX, thirdH, middleX, thirdH * 2);//body - painter->drawLine(middleX, 2 * thirdH, - middleX - A_WIDTH / 2, A_HEIGHT);//left leg - painter->drawLine(middleX, 2 * thirdH, - middleX + A_WIDTH / 2, A_HEIGHT);//right leg - painter->drawLine(middleX - A_WIDTH / 2, thirdH + thirdH / 2, - middleX + A_WIDTH / 2, thirdH + thirdH / 2);//arms - //draw text - painter->setPen(textColor()); - QString t = m_instanceName + QLatin1String(" : ") + name(); - painter->drawText(A_MARGIN, textStartY, - w - A_MARGIN * 2, fontHeight, Qt::AlignCenter, t); -} - -/** - * Move the object up on a sequence diagram. - */ -void ObjectWidget::tabUp() -{ - int newY = y() - height(); - if (newY < topMargin()) - newY = topMargin(); - setY(newY); - adjustAssocs(x(), newY); -} - -/** - * Move the object down on a sequence diagram. - */ -void ObjectWidget::tabDown() -{ - int newY = y() + height(); - setY(newY); - adjustAssocs(x(), newY); -} - -/** - * Returns the top margin constant (Y axis value) - * - * @return Y coordinate of the space between the diagram top - * and the upper edge of the ObjectWidget. - */ -int ObjectWidget::topMargin() -{ - return 80 - height(); -} - -/** - * Returns whether or not the widget can be moved vertically up. - * - * @return True if widget can be moved upwards vertically. - */ -bool ObjectWidget::canTabUp() -{ - return (y() > topMargin()); -} - -/** - * Sets whether to show deconstruction on sequence line. - * - * @param bShow True if destruction on line shall be shown. - */ -void ObjectWidget::setShowDestruction(bool bShow) -{ - m_showDestruction = bShow; - if(m_pLine) - m_pLine->setupDestructionBox(); -} - -/** - * Returns whether to show deconstruction on sequence line. - * - * @return True if destruction on sequence line is shown. - */ -bool ObjectWidget::showDestruction() const -{ - return m_showDestruction; -} - -/** - * Sets the y position of the bottom of the vertical line. - * - * @param yPosition The y coordinate for the bottom of the line. - */ -void ObjectWidget::setEndLine(int yPosition) -{ - if (m_pLine) { - m_pLine->setEndOfLine(yPosition); - } -} - -/** - * Returns the end Y co-ord of the sequence line. - * - * @return Y coordinate of the endpoint of the sequence line. - */ -int ObjectWidget::getEndLineY() -{ - int y = this->y() + height(); - if(m_pLine) - y += m_pLine->getLineLength(); - if (m_showDestruction) - y += 10; - return y; -} - -/** - * Add a message widget to the list. - * - * @param message Pointer to the MessageWidget to add. - */ -void ObjectWidget::messageAdded(MessageWidget* message) -{ - if (m_messages.count(message)) { - uError() << message->name() << ": duplicate entry !"; - return ; - } - m_messages.append(message); -} - -/** - * Remove a message widget from the list. - * - * @param message Pointer to the MessageWidget to remove. - */ -void ObjectWidget::messageRemoved(MessageWidget* message) -{ - if (m_messages.removeAll(message) == false) { - uError() << message->name() << ": missing entry !"; - return ; - } -} - -/** - * Called when a message widget with an end on this object has - * moved up or down. - * Sets the bottom of the line to a nice position. - */ -void ObjectWidget::slotMessageMoved() -{ - if (m_pLine) { - int lowestMessage = 0; - foreach (MessageWidget* message, m_messages) { - int messageHeight = message->y() + message->height(); - if (lowestMessage < messageHeight) { - lowestMessage = messageHeight; - } - } - m_pLine->setEndOfLine(lowestMessage + sequenceLineMargin); - } -} - -/** - * Returns whether a message is overlapping with another message. - * Used by MessageWidget::paint() methods. - * - * @param y top of your message - * @param messageWidget pointer to your message so it doesn't check against itself - */ -bool ObjectWidget::messageOverlap(qreal y, MessageWidget* messageWidget) -{ - foreach (MessageWidget* message, m_messages) { - if (message == messageWidget) { - continue; - } - const qreal msgY = message->y(); - const qreal msgHeight = msgY + message->height(); - if (y >= msgY && y <= msgHeight) { - return true; - } - } - return false; -} - -/** - * Return the SeqLineWidget. - * Returns a non NULL pointer if this ObjectWidget is part of a - * sequence diagram. - */ -SeqLineWidget *ObjectWidget::sequentialLine() const -{ - return m_pLine; -} - -/** - * Overridden from UMLWidget. - * Returns the cursor to be shown when resizing the widget. - * The cursor shown is KCursor::sizeHorCursor(). - * - * @return The cursor to be shown when resizing the widget. - */ -QCursor ObjectWidget::resizeCursor() const -{ - return Qt::SizeHorCursor; -} - -/** - * Overridden from UMLWidget. - * Resizes the width of the object widget. - * Object widgets can only be resized horizontally, so height isn't modified. - * - * @param newW The new width for the widget. - * @param newH The new height for the widget (isn't used). - */ -void ObjectWidget::resizeWidget(qreal newW, qreal newH) -{ - Q_UNUSED(newH); - setSize(newW, height()); -} - -/** - * Saves to the "objectwidget" XMI element. - */ -void ObjectWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) -{ - QDomElement objectElement = qDoc.createElement(QLatin1String("objectwidget")); - UMLWidget::saveToXMI(qDoc, objectElement); - objectElement.setAttribute(QLatin1String("drawasactor"), m_drawAsActor); - objectElement.setAttribute(QLatin1String("multipleinstance"), m_multipleInstance); - objectElement.setAttribute(QLatin1String("decon"), m_showDestruction); - qElement.appendChild(objectElement); -} - -/** - * Loads from a "objectwidget" XMI element. - */ -bool ObjectWidget::loadFromXMI(QDomElement& qElement) -{ - if(!UMLWidget::loadFromXMI(qElement)) - return false; - QString draw = qElement.attribute(QLatin1String("drawasactor"), QLatin1String("0")); - QString multi = qElement.attribute(QLatin1String("multipleinstance"), QLatin1String("0")); - QString decon = qElement.attribute(QLatin1String("decon"), QLatin1String("0")); - - m_drawAsActor = (bool)draw.toInt(); - m_multipleInstance = (bool)multi.toInt(); - m_showDestruction = (bool)decon.toInt(); - return true; -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/objectwidget.h umbrello-kf6-15.08.1/umbrello/widgets/objectwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/objectwidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/objectwidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,115 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef OBJECTWIDGET_H -#define OBJECTWIDGET_H - -#include "messagewidgetlist.h" -#include "umlwidget.h" - -class MessageWidget; -class SeqLineWidget; -class UMLScene; - -/** - * Displays an instance UMLObject of a concept. - * - * The local ID is needed as a it can represent a class - * that has many objects representing it. - * - * @short Displays an instance of a Concept. - * @author Paul Hensgen - * @see UMLWidget - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class ObjectWidget : public UMLWidget -{ - Q_OBJECT -public: - ObjectWidget(UMLScene *scene, UMLObject *o); - virtual ~ObjectWidget(); - - virtual void setX(qreal x); - virtual void setY(qreal y); - - qreal centerX(); - - void setMultipleInstance(bool multiple); - bool multipleInstance() const; - - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - - bool activate(IDChangeLog* ChangeLog = 0); - - void cleanup(); - - void showPropertiesDialog(); - - void setDrawAsActor(bool drawAsActor); - bool drawAsActor() const; - - void setShowDestruction(bool bShow); - bool showDestruction() const; - - int topMargin(); - - void setEndLine(int yPosition); - int getEndLineY(); - - void messageAdded(MessageWidget* message); - void messageRemoved(MessageWidget* message); - - bool canTabUp(); - - bool messageOverlap(qreal y, MessageWidget* messageWidget); - - SeqLineWidget *sequentialLine() const; - - virtual void resizeWidget(qreal newW, qreal newH); - - virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); - virtual bool loadFromXMI(QDomElement& qElement); - -public slots: - void slotMenuSelection(QAction* action); - virtual void slotFillColorChanged(Uml::ID::Type viewID); - void slotMessageMoved(); - -protected: - virtual void mousePressEvent(QGraphicsSceneMouseEvent *me); - virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *me); - - QSizeF minimumSize() const; - - virtual void moveEvent(QGraphicsSceneMouseEvent *event); - virtual void moveWidgetBy(qreal diffX, qreal diffY); - virtual void constrainMovementForAllWidgets(qreal &diffX, qreal &diffY); - - virtual QCursor resizeCursor() const; - - void paintActor(QPainter *p); - void paintObject(QPainter *p); - -private: - void tabUp(); - void tabDown(); - - void moveDestructionBy(qreal diffY); - - SeqLineWidget* m_pLine; - bool m_multipleInstance; ///< draw an object as a multiple object - bool m_drawAsActor; ///< object should be drawn as an Actor or an Object - bool m_showDestruction; ///< show object destruction on sequence diagram line - bool m_isOnDestructionBox; ///< true when a click occurred on the destruction box - MessageWidgetList m_messages; ///< message widgets with an end on this widget - -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/packagewidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/packagewidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/packagewidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/packagewidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,149 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "packagewidget.h" - -// app includes -#include "debug_utils.h" -#include "package.h" -#include "uml.h" -#include "umldoc.h" -#include "umlobject.h" -#include "umlscene.h" -#include "umlview.h" - -// qt includes -#include - -/** - * Constructs a PackageWidget. - * - * @param scene The parent of this PackageWidget. - * @param o The UMLObject this will be representing. - */ -PackageWidget::PackageWidget(UMLScene * scene, UMLPackage *o) - : UMLWidget(scene, WidgetBase::wt_Package, o), - m_pMenu(0) -{ - setSize(100, 30); - setZValue(1); // above box but below UMLWidget because may embed widgets - //set defaults from m_scene - if (m_scene) { - //check to see if correct - const Settings::OptionState& ops = m_scene->optionState(); - m_showStereotype = ops.classState.showStereoType; - } -} - -/** - * Destructor. - */ -PackageWidget::~PackageWidget() -{ -} - -/** - * Overrides standard method. - */ -void PackageWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - Q_UNUSED(option); - Q_UNUSED(widget); - - setPenFromSettings(painter); - if (UMLWidget::useFillColor()) - painter->setBrush(UMLWidget::fillColor()); - else - painter->setBrush(m_scene->backgroundColor()); - - int w = width(); - int h = height(); - QFont font = UMLWidget::font(); - font.setBold(true); - //FIXME italic is true when a package is first created until you click elsewhere, not sure why - font.setItalic(false); - const QFontMetrics &fm = getFontMetrics(FT_BOLD); - const int fontHeight = fm.lineSpacing(); - - painter->drawRect(0, 0, 50, fontHeight); - if (m_umlObject != NULL - && m_umlObject->stereotype() == QLatin1String("subsystem")) { - - const int fHalf = fontHeight / 2; - const int symY = fHalf; - const int symX = 38; - painter->drawLine(symX, symY, symX, symY + fHalf - 2); // left leg - painter->drawLine(symX + 8, symY, symX + 8, symY + fHalf - 2); // right leg - painter->drawLine(symX, symY, symX + 8, symY); // waist - painter->drawLine(symX + 4, symY, symX + 4, symY - fHalf + 2); // head - } - painter->drawRect(0, fontHeight - 1, w, h - fontHeight); - - painter->setPen(textColor()); - painter->setFont(font); - - int lines = 1; - if (m_umlObject != NULL) { - QString stereotype = m_umlObject->stereotype(); - if (!stereotype.isEmpty()) { - painter->drawText(0, fontHeight + PACKAGE_MARGIN, - w, fontHeight, Qt::AlignCenter, m_umlObject->stereotype(true)); - lines = 2; - } - } - - painter->drawText(0, (fontHeight*lines) + PACKAGE_MARGIN, - w, fontHeight, Qt::AlignCenter, name()); - - UMLWidget::paint(painter, option, widget); -} - -/** - * Overrides method from UMLWidget - */ -QSizeF PackageWidget::minimumSize() const -{ - if (!m_umlObject) { - return UMLWidget::minimumSize(); - } - - const QFontMetrics &fm = getFontMetrics(FT_BOLD_ITALIC); - const int fontHeight = fm.lineSpacing(); - - int lines = 1; - - int width = fm.width(m_umlObject->name()); - - int tempWidth = 0; - if (!m_umlObject->stereotype().isEmpty()) { - tempWidth = fm.width(m_umlObject->stereotype(true)); - lines = 2; - } - if (tempWidth > width) - width = tempWidth; - width += PACKAGE_MARGIN * 2; - if (width < 70) - width = 70; // minumin width of 70 - - int height = (lines*fontHeight) + fontHeight + (PACKAGE_MARGIN * 2); - - return QSizeF(width, height); -} - -/** - * Saves to the "packagewidget" XMI element. - */ -void PackageWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) -{ - QDomElement conceptElement = qDoc.createElement(QLatin1String("packagewidget")); - UMLWidget::saveToXMI(qDoc, conceptElement); - qElement.appendChild(conceptElement); -} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/packagewidget.h umbrello-kf6-15.08.1/umbrello/widgets/packagewidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/packagewidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/packagewidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,47 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef PACKAGEWIDGET_H -#define PACKAGEWIDGET_H - -#include "umlwidget.h" - -class UMLPackage; -class ListPopupMenu; - -#define PACKAGE_MARGIN 5 - -/** - * Defines a graphical version of the Package. Most of the - * functionality will come from the @ref UMLPackage class. - * - * @short A graphical version of a Package. - * @author Jonathan Riddell - * @see UMLWidget - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class PackageWidget : public UMLWidget -{ -public: - explicit PackageWidget(UMLScene * scene, UMLPackage * o); - virtual ~PackageWidget(); - - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - - void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); - -protected: - QSizeF minimumSize() const; - -private: - ListPopupMenu* m_pMenu; ///< the right mouse button menu -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/pinportbase.cpp umbrello-kf6-15.08.1/umbrello/widgets/pinportbase.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/pinportbase.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/pinportbase.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,378 +0,0 @@ -/*************************************************************************** - * 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) 2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "pinportbase.h" - -// app includes -#include "port.h" -#include "package.h" -#include "debug_utils.h" -#include "umldoc.h" -#include "umlscene.h" -#include "umlview.h" -#include "floatingtextwidget.h" - -// qt includes -#include -#include - -// sys includes -#include - -PinPortBase::PinPortBase(UMLScene *scene, WidgetType type, UMLObject *o) - : UMLWidget(scene, type, o) -{ - init(); -} - -PinPortBase::PinPortBase(UMLScene *scene, WidgetType type, UMLWidget *a, Uml::ID::Type id) - : UMLWidget(scene, type, id) -{ - init(a); -} - -/** - * Standard destructor. - */ -PinPortBase::~PinPortBase() -{ -} - -/** - * Performs initializations which are common to PinWidget and PortWidget. - */ -void PinPortBase::init(UMLWidget *owner) -{ - m_ignoreSnapToGrid = true; - m_ignoreSnapComponentSizeToGrid = true; - m_resizable = false; - m_pOw = owner; - m_pName = NULL; - m_motionConnected = false; - const int edgeLength = 15; // old: (m_baseType == wt_Pin ? 10 : 15); - const QSizeF FixedSize(edgeLength, edgeLength); - setMinimumSize(FixedSize); - setMaximumSize(FixedSize); - setSize(FixedSize); -} - -UMLWidget* PinPortBase::ownerWidget() -{ - return m_pOw; -} - -/** - * Overrides method from UMLWidget in order to set a tooltip. - * The tooltip is set to the name(). - * The reason for using a tooltip for the name is that the size of this - * widget is not large enough to accommodate the average name. - */ -void PinPortBase::updateWidget() -{ - QString strName = name(); - uDebug() << " port name is " << strName; - if (m_pName) { - m_pName->setText(strName); - } else { - setToolTip(strName); - } -} - -/** - * Overrides method from UMLWidget to set the name. - */ -void PinPortBase::setName(const QString &strName) -{ - UMLWidget::setName(strName); - updateGeometry(); - if (m_pName) { - m_pName->setText(strName); - } -} - -/** - * Overridden from UMLWidget. - * Moves the widget to a new position using the difference between the - * current position and the new position. - * Movement is constrained such that the port is always attached to its - * owner widget. - * - * @param diffX The difference between current X position and new X position. - * @param diffY The difference between current Y position and new Y position. - */ -void PinPortBase::moveWidgetBy(qreal diffX, qreal diffY) -{ - UMLWidget* owner = ownerWidget(); - qreal newX = x() + diffX; - qreal newY = y() + diffY; - uDebug() << "PinPortBase::moveWidgetBy " << diffX << "," << diffY; - if (owner == NULL) { - uError() << "PinPortBase::moveWidgetBy: ownerWidget() returns NULL"; - setX(newX); - setY(newY); - return; - } - const qreal deltaTop = fabs(y() + height() - owner->y()); - const qreal deltaBottom = fabs(owner->y() + owner->height() - y()); - const qreal deltaLeft = fabs(x() + width() - owner->x()); - const qreal deltaRight = fabs(owner->x() + owner->width() - x()); - bool didAnyMovement = false; - if (deltaTop < 1.0 || deltaBottom < 1.0) { - if (newX < owner->x() - width()) - newX = owner->x() - width(); - else if (newX > owner->x() + owner->width()) - newX = owner->x() + owner->width(); - setX(newX); - didAnyMovement = true; - } - if (deltaLeft < 1.0 || deltaRight < 1.0) { - if (newY < owner->y() - height()) - newY = owner->y() - height(); - else if (newY > owner->y() + owner->height()) - newY = owner->y() + owner->height(); - setY(newY); - didAnyMovement = true; - } - if (!didAnyMovement) { - uDebug() << "constraint failed for (" << diffX << ", " << diffY << ")"; - setX(newX); - setY(newY); - } -} - -/** - * Align this widget's position such that it is attached at one of the - * sides of its owner's widget. - */ -void PinPortBase::attachToOwner() { - UMLWidget *owner = ownerWidget(); - const QPointF scenePos = m_scene->pos(); - if (owner == NULL) { - uError() << "PinPortBase::attachToOwner: ownerWidget() returns NULL"; - setX(scenePos.x()); - setY(scenePos.y()); - return; - } - bool xIsWithinOwner = false; - if (scenePos.x() < owner->x() - width()) { - setX(owner->x() - width()); - } else if (scenePos.x() <= owner->x() + owner->width()) { - setX(scenePos.x()); - xIsWithinOwner = true; - } else { - setX(owner->x() + owner->width()); - } - if (scenePos.y() < owner->y() - height()) { - setY(owner->y() - height()); - } else if (scenePos.y() <= owner->y() + owner->height()) { - if (xIsWithinOwner) { - if (scenePos.y() <= owner->y() + owner->height() / 2.0) - setY(owner->y() - height()); - else - setY(owner->y() + owner->height()); - } else { - setY(scenePos.y()); - } - } else { - setY(owner->y() + owner->height()); - } - - if (m_motionConnected) { - uDebug() << "connectOwnerMotion was already done"; - } else { - connectOwnerMotion(); - m_motionConnected = true; - } -} - -/** - * Overrides standard method. - */ -void PinPortBase::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - setPenFromSettings(painter); - if (UMLWidget::useFillColor()) { - painter->setBrush(UMLWidget::fillColor()); - } else { - painter->setBrush(m_scene->backgroundColor()); - } - - int w = width(); - int h = height(); - - painter->drawRect(0, 0, w, h); - - UMLWidget::paint(painter, option, widget); -} - -void PinPortBase::slotOwnerMoved(qreal diffX, qreal diffY) -{ - setX(x() + diffX); - setY(y() + diffY); -} - -/** - * Captures any popup menu signals for menus it created. - */ -void PinPortBase::slotMenuSelection(QAction* action) -{ - ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); - switch(sel) { - case ListPopupMenu::mt_NameAsTooltip: - if (m_pName) { - action->setChecked(true); - delete m_pName; - m_pName = NULL; - setToolTip(name()); - } else { - action->setChecked(false); - m_pName = new FloatingTextWidget(m_scene, Uml::TextRole::Floating, name()); - m_pName->setParentItem(this); - m_pName->setText(name()); // to get geometry update - m_pName->activate(); - UMLWidget* owner = ownerWidget(); - if (owner == NULL) { - uError() << "PinPortBase::slotMenuSelection: ownerWidget() returns NULL"; - setX(x()); - setY(y()); - } else { - const qreal w = width(); - const qreal h = height(); - if (x() < owner->x()) - m_pName->setX(-m_pName->width()); - else if (x() >= owner->x() + owner->width()) - m_pName->setX(w); - else - m_pName->setX(-m_pName->width() / 2.0 + w / 2.0); - if (y() < owner->y()) - m_pName->setY(-m_pName->height() - 2); - else if (y() >= owner->y() + owner->height()) - m_pName->setY(h); - else - m_pName->setY(-m_pName->height() / 2.0 + h / 2.0); - } - m_pName->update(); - setToolTip(QString()); - QToolTip::hideText(); - } - break; - - default: - UMLWidget::slotMenuSelection(action); - } -} - -FloatingTextWidget *PinPortBase::floatingTextWidget() { - return m_pName; -} - -void PinPortBase::setFloatingTextWidget(FloatingTextWidget *ft) { - m_pName = ft; - if (m_pName) - m_pName->setParentItem(this); -} - -/** - * Override method from UMLWidget in order to additionally check m_pName. - * - * @param p Point to be checked. - * - * @return 'this' if UMLWidget::onWidget(p) returns non NULL; - * m_pName if m_pName is non NULL and m_pName->onWidget(p) returns non NULL; - * else NULL. - */ -UMLWidget* PinPortBase::onWidget(const QPointF &p) -{ - if (UMLWidget::onWidget(p) != NULL) - return this; - if (m_pName) { - uDebug() << "floatingtext: " << m_pName->text(); - return m_pName->onWidget(p); - } - return NULL; -} - -/** - * Reimplement function from UMLWidget - */ -UMLWidget* PinPortBase::widgetWithID(Uml::ID::Type id) -{ - if (UMLWidget::widgetWithID(id)) - return this; - if (m_pName && m_pName->widgetWithID(id)) - return m_pName; - return NULL; -} - - -/** - * Saves the widget to the "pinwidget" or "portwidget" XMI element. - */ -void PinPortBase::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) -{ - QDomElement element = qDoc.createElement(m_baseType == wt_Pin ? QLatin1String("pinwidget") - : QLatin1String("portwidget")); - element.setAttribute(QLatin1String("widgetaid"), Uml::ID::toString(ownerWidget()->id())); - UMLWidget::saveToXMI(qDoc, element); - if (m_pName && !m_pName->text().isEmpty()) { - m_pName->saveToXMI(qDoc, element); - } - qElement.appendChild(element); -} - -/** - * Loads from a "pinwidget" or from a "portwidget" XMI element. - */ -bool PinPortBase::loadFromXMI(QDomElement & qElement) -{ - if (!UMLWidget::loadFromXMI(qElement)) - return false; - - QString widgetaid = qElement.attribute(QLatin1String("widgetaid"), QLatin1String("-1")); - Uml::ID::Type aId = Uml::ID::fromString(widgetaid); - UMLWidget *owner = m_scene->findWidget(aId); - if (owner == NULL) { - DEBUG(DBG_SRC) << "owner object " << Uml::ID::toString(aId) << " not found"; - return false; - } - m_pOw = owner; - - // Optional child element: floatingtext - QDomNode node = qElement.firstChild(); - QDomElement element = node.toElement(); - if (!element.isNull()) { - QString tag = element.tagName(); - if (tag == QLatin1String("floatingtext")) { - m_pName = new FloatingTextWidget(m_scene, Uml::TextRole::Floating, - name(), Uml::ID::Reserved); - if (!m_pName->loadFromXMI(element)) { - // Most likely cause: The FloatingTextWidget is empty. - delete m_pName; - m_pName = NULL; - } else { - m_pName->setParentItem(this); - m_pName->activate(); - m_pName->update(); - } - } else { - uError() << "unknown tag " << tag; - } - } - - if (m_motionConnected) { - uDebug() << "connectOwnerMotion was already done"; - } else { - connectOwnerMotion(); - m_motionConnected = true; - } - return true; -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/pinportbase.h umbrello-kf6-15.08.1/umbrello/widgets/pinportbase.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/pinportbase.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/pinportbase.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,63 +0,0 @@ -/*************************************************************************** - * 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) 2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef PINPORTBASE_H -#define PINPORTBASE_H - -#include "umlwidget.h" - -class FloatingTextWidget; - -/** - * @short Abstract base class for PinWidget and PortWidget - * @author Oliver Kellogg - * @see UMLWidget - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class PinPortBase : public UMLWidget -{ - Q_OBJECT -public: - PinPortBase(UMLScene *scene, WidgetType type, UMLObject *o); - PinPortBase(UMLScene *scene, WidgetType type, UMLWidget *a, Uml::ID::Type id = Uml::ID::None); - virtual ~PinPortBase(); - - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - - virtual UMLWidget* ownerWidget(); - virtual void connectOwnerMotion() = 0; - - void setName(const QString &strName); - void updateWidget(); - void moveWidgetBy(qreal diffX, qreal diffY); - void attachToOwner(); - - UMLWidget* onWidget(const QPointF& p); - UMLWidget* widgetWithID(Uml::ID::Type id); - - FloatingTextWidget *floatingTextWidget(); - void setFloatingTextWidget(FloatingTextWidget *ft); - - void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); - bool loadFromXMI(QDomElement& qElement); - -public slots: - void slotOwnerMoved(qreal diffX, qreal diffY); - virtual void slotMenuSelection(QAction* action); - -protected: - void init(UMLWidget *owner = 0); - - UMLWidget* m_pOw; - FloatingTextWidget *m_pName; - bool m_motionConnected; -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/pinwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/pinwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/pinwidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/pinwidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,103 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "pinwidget.h" - -// app includes -#include "debug_utils.h" -#include "floatingtextwidget.h" -#include "listpopupmenu.h" -#include "umlscene.h" -#include "activitywidget.h" - -// kde includes -#if QT_VERSION < 0x050000 -#include -#endif -#include - -// qt includes -#if QT_VERSION >= 0x050000 -#include -#endif -#include - -DEBUG_REGISTER_DISABLED(PinWidget) - -/** - * Creates a Pin widget. - * - * @param scene The parent of the widget. - * @param a The widget to which this pin is attached. - * @param id The ID to assign (-1 will prompt a new ID). - */ -PinWidget::PinWidget(UMLScene* scene, UMLWidget* a, Uml::ID::Type id) - : PinPortBase(scene, WidgetBase::wt_Pin, a, id) -{ - // setParent(a); - // m_nY = y() < getMinY() ? getMinY() : y(); - - m_pName = new FloatingTextWidget(m_scene, Uml::TextRole::Floating, name()); - m_pName->setParentItem(this); - m_pName->setText(name()); // to get geometry update - m_pName->activate(); - setVisible(true); -} - -/** - * Destructor. - */ -PinWidget::~PinWidget() -{ -} - -/** - * Implement abstract function from PinPortWidget. - */ -void PinWidget::connectOwnerMotion() -{ - ActivityWidget *owner = static_cast(ownerWidget()); - connect(owner, SIGNAL(sigActMoved(qreal,qreal)), this, SLOT(slotOwnerMoved(qreal,qreal))); -} - -/** - * Captures any popup menu signals for menus it created. - */ -void PinWidget::slotMenuSelection(QAction* action) -{ - ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); - switch(sel) { - case ListPopupMenu::mt_Rename: - { - bool ok = false; - QString name = m_Text; -#if QT_VERSION >= 0x050000 - name = QInputDialog::getText(Q_NULLPTR, - i18n("Enter Pin Name"), - i18n("Enter the pin name :"), - QLineEdit::Normal, - m_Text, &ok); -#else - name = KInputDialog::getText(i18n("Enter Pin Name"), - i18n("Enter the pin name :"), - m_Text, &ok); -#endif - if (ok) { - setName(name); - } - } - break; - - default: - PinPortBase::slotMenuSelection(action); - } -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/pinwidget.h umbrello-kf6-15.08.1/umbrello/widgets/pinwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/pinwidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/pinwidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,46 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef PINWIDGET_H -#define PINWIDGET_H - -#include "pinportbase.h" - -/** - * This class is the graphical version of a UML Pin. A pinWidget is created - * by a @ref UMLView. An pinWidget belongs to only one @ref UMLView instance. - * When the @ref UMLView instance that this class belongs to, it will be automatically deleted. - * - * The pinWidget class inherits from the @ref UMLWidget class which adds most of the functionality - * to this class. - * - * @short A graphical version of a UML pin. - * @author Hassan KOUCH - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class PinWidget : public PinPortBase -{ - Q_OBJECT -public: - - PinWidget(UMLScene* scene, UMLWidget* a, Uml::ID::Type id = Uml::ID::None); - virtual ~PinWidget(); - - void connectOwnerMotion(); - // int getMinY(); - -public slots: - void slotMenuSelection(QAction* action); - -// private: - // int m_nY; -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/portwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/portwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/portwidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/portwidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,106 +0,0 @@ -/*************************************************************************** - * 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) 2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "portwidget.h" - -// app includes -#include "port.h" -#include "package.h" -#include "debug_utils.h" -#include "umldoc.h" -#include "umlscene.h" -#include "componentwidget.h" -#include "floatingtextwidget.h" - -// kde includes -#if QT_VERSION < 0x050000 -#include -#endif -#include - -// qt includes -#if QT_VERSION >= 0x050000 -#include -#endif -#include -#include - -/** - * Constructs a PortWidget. - * - * @param scene The parent of this PortWidget. - * @param d The UMLPort this will be representing. - */ -PortWidget::PortWidget(UMLScene *scene, UMLPort *d) - : PinPortBase(scene, WidgetBase::wt_Port, d) -{ - setToolTip(d->name()); -} - -/** - * Standard deconstructor. - */ -PortWidget::~PortWidget() -{ -} - -/** - * Override function from PinPortWidget. - */ -UMLWidget* PortWidget::ownerWidget() -{ - if (m_pOw == NULL) { - const Uml::ID::Type compWidgetId = m_umlObject->umlPackage()->id(); - m_pOw = m_scene->widgetOnDiagram(compWidgetId); - } - return m_pOw; -} - -/** - * Implement abstract function from PinPortWidget. - */ -void PortWidget::connectOwnerMotion() -{ - ComponentWidget *owner = static_cast(ownerWidget()); - connect(owner, SIGNAL(sigCompMoved(qreal,qreal)), this, SLOT(slotOwnerMoved(qreal,qreal))); -} - -/** - * Captures any popup menu signals for menus it created. - */ -void PortWidget::slotMenuSelection(QAction* action) -{ - ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); - switch(sel) { - case ListPopupMenu::mt_Rename: - { - bool ok = false; - QString newName; -#if QT_VERSION >= 0x050000 - newName = QInputDialog::getText(Q_NULLPTR, - i18n("Enter Port Name"), i18n("Enter the port name :"), - QLineEdit::Normal, - name(), &ok); -#else - newName = KInputDialog::getText(i18n("Enter Port Name"), i18n("Enter the port name :"), - name(), &ok); -#endif - if (ok) { - setName(newName); - } - } - break; - - default: - PinPortBase::slotMenuSelection(action); - } -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/portwidget.h umbrello-kf6-15.08.1/umbrello/widgets/portwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/portwidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/portwidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,42 +0,0 @@ -/*************************************************************************** - * 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) 2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef PORTWIDGET_H -#define PORTWIDGET_H - -#include "pinportbase.h" - -class UMLPort; - -/** - * Defines a graphical version of the UML2 port. Most of the functionality - * comes from the @ref PinPortBase class from which this class inherits. - * - * @short A graphical version of a port on a component. - * @author Oliver Kellogg - * @see PinPortBase, UMLWidget - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class PortWidget : public PinPortBase -{ - Q_OBJECT -public: - PortWidget(UMLScene *scene, UMLPort *d); - virtual ~PortWidget(); - - UMLWidget* ownerWidget(); - void connectOwnerMotion(); - -public slots: - void slotMenuSelection(QAction* action); - -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/preconditionwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/preconditionwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/preconditionwidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/preconditionwidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,335 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "preconditionwidget.h" - -// app includes -#include "debug_utils.h" -#include "listpopupmenu.h" -#include "objectwidget.h" -#include "uml.h" -#include "umlscene.h" -#include "uniqueid.h" -#include "idchangelog.h" - -// kde includes -#if QT_VERSION < 0x050000 -#include -#endif -#include - -// qt includes -#if QT_VERSION >= 0x050000 -#include -#endif -#include - -DEBUG_REGISTER_DISABLED(PreconditionWidget) - -#define PRECONDITION_MARGIN 5 -#define PRECONDITION_WIDTH 30 -#define PRECONDITION_HEIGHT 10 - -/** - * Creates a Precondition widget. - * - * @param scene The parent of the widget. - * @param a The role A widget for this precondition. - * @param id The ID to assign (-1 will prompt a new ID). - */ -PreconditionWidget::PreconditionWidget(UMLScene* scene, ObjectWidget* a, Uml::ID::Type id) - : UMLWidget(scene, WidgetBase::wt_Precondition, id), - m_objectWidget(a) -{ - m_ignoreSnapToGrid = true; - m_ignoreSnapComponentSizeToGrid = true; - m_resizable = true ; - setVisible(true); - //updateResizability(); - // calculateWidget(); - if (y() < minY()) - m_nY = minY(); - else if (y() > maxY()) - m_nY = maxY(); - else - m_nY = y(); - - activate(); -} - -/** - * Destructor. - */ -PreconditionWidget::~PreconditionWidget() -{ -} - -/** - * Overrides the standard paint event. - */ -void PreconditionWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - Q_UNUSED(option); - Q_UNUSED(widget); - - int w = width(); - int h = height(); - - int x = m_objectWidget->x() + m_objectWidget->width() / 2; - x -= w/2; - setX(x); - int y = this->y(); - - //test if y isn't above the object - if (y <= m_objectWidget->y() + m_objectWidget->height()) { - y = m_objectWidget->y() + m_objectWidget->height() + 15; - } - if (y + h >= m_objectWidget->getEndLineY()) { - y = m_objectWidget->getEndLineY() - h; - } - setY(y); - setPenFromSettings(painter); - if (UMLWidget::useFillColor()) { - painter->setBrush(UMLWidget::fillColor()); - } - { - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - const QString precondition_value = QLatin1String("{ ") + name() + QLatin1String(" }"); - //int middleX = w / 2; - int textStartY = (h / 2) - (fontHeight / 2); - painter->drawRoundRect(0, 0, w, h, (h * 60) / w, 60); - painter->setPen(textColor()); - painter->setFont(UMLWidget::font()); - painter->drawText(PRECONDITION_MARGIN, textStartY, - w - PRECONDITION_MARGIN * 2, fontHeight, Qt::AlignCenter, precondition_value); - } - - UMLWidget::paint(painter, option, widget); -} - -/** - * Overrides method from UMLWidget. - */ -QSizeF PreconditionWidget::minimumSize() const -{ - int width = 10, height = 10; - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - const int textWidth = fm.width(name()) + 25; - height = fontHeight; - width = textWidth > PRECONDITION_WIDTH ? textWidth : PRECONDITION_WIDTH; - height = height > PRECONDITION_HEIGHT ? height : PRECONDITION_HEIGHT; - width += PRECONDITION_MARGIN * 2; - height += PRECONDITION_MARGIN * 2; - - return QSizeF(width, height); -} - -/** - * Calculate the geometry of the widget. - */ -void PreconditionWidget::calculateWidget() -{ - calculateDimensions(); - - setVisible(true); - - setX(m_nPosX); - setY(m_nY); -} - -/** - * Activates a PreconditionWidget. Connects the WidgetMoved signal from - * its m_objectWidget pointer so that PreconditionWidget can adjust to the move of - * the object widget. - */ -bool PreconditionWidget::activate(IDChangeLog * Log /*= 0*/) -{ - m_scene->resetPastep-kf6oint(); - UMLWidget::activate(Log); - - loadObjectWidget(); - - if (!m_objectWidget) { - DEBUG(DBG_SRC) << "role A widget " << Uml::ID::toString(m_widgetAId) - << " could not be found"; - return false; - } - - connect(m_objectWidget, SIGNAL(sigWidgetMoved(Uml::ID::Type)), this, SLOT(slotWidgetMoved(Uml::ID::Type))); - - calculateDimensions(); - return true; -} - -/** - * Resolve references of this precondition so it references the correct - * new object widget after paste. - */ -void PreconditionWidget::resolveObjectWidget(IDChangeLog* log) { - m_widgetAId = log->findNewID(m_widgetAId); -} - -/** - * Calculates the size of the widget. - */ -void PreconditionWidget::calculateDimensions() -{ - int x = 0; - int w = 0; - int h = 0; - int x1 = m_objectWidget->x(); - int w1 = m_objectWidget->width() / 2; - - x1 += w1; - - QSizeF q = minimumSize(); - w = q.width() > width() ? q.width() : width(); - h = q.height() > height() ? q.height() : height(); - - x = x1 - w/2; - - m_nPosX = x; - - setSize(w, h); -} - -/** - * Slot when widget is moved. - */ -void PreconditionWidget::slotWidgetMoved(Uml::ID::Type id) -{ - const Uml::ID::Type idA = m_objectWidget->localID(); - if (idA != id) { - DEBUG(DBG_SRC) << "id=" << Uml::ID::toString(id) << ": ignoring for idA=" << Uml::ID::toString(idA); - return; - } - m_nY = y(); - if (m_nY < minY()) - m_nY = minY(); - if (m_nY > maxY()) - m_nY = maxY(); - - calculateDimensions(); - if (m_scene->selectedCount(true) > 1) - return; -} - -/** - * Returns the minimum height this widget should be set at on - * a sequence diagrams. Takes into account the widget positions - * it is related to. - */ -int PreconditionWidget::minY() const -{ - if (m_objectWidget) { - return m_objectWidget->y() + m_objectWidget->height(); - } - return 0; -} - -/** - * Returns the maximum height this widget should be set at on - * a sequence diagrams. Takes into account the widget positions - * it is related to. - */ -int PreconditionWidget::maxY() const -{ - if (m_objectWidget) { - return ((int)m_objectWidget->getEndLineY() - height()); - } - return 0; -} - -/** - * Captures any popup menu signals for menus it created. - */ -void PreconditionWidget::slotMenuSelection(QAction* action) -{ - ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); - switch(sel) { - case ListPopupMenu::mt_Rename: - { - bool ok = false; - QString text = name(); -#if QT_VERSION >= 0x050000 - text = QInputDialog::getText(Q_NULLPTR, - i18n("Enter Precondition Name"), - i18n("Enter the precondition :"), - QLineEdit::Normal, - text, &ok); -#else - text = KInputDialog::getText(i18n("Enter Precondition Name"), - i18n("Enter the precondition :"), - text, &ok); -#endif - if (ok && !text.isEmpty()) { - setName(text); - } - calculateWidget(); - } - break; - - default: - UMLWidget::slotMenuSelection(action); - } -} - -/** - * Saves the widget to the "preconditionwidget" XMI element. - */ -void PreconditionWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) -{ - QDomElement preconditionElement = qDoc.createElement(QLatin1String("preconditionwidget")); - UMLWidget::saveToXMI(qDoc, preconditionElement); - - preconditionElement.setAttribute(QLatin1String("widgetaid"), Uml::ID::toString(m_objectWidget->localID())); - preconditionElement.setAttribute(QLatin1String("preconditionname"), name()); - preconditionElement.setAttribute(QLatin1String("documentation"), documentation()); - qElement.appendChild(preconditionElement); -} - -/** - * Loads the widget from the "preconditionwidget" XMI element. - */ -bool PreconditionWidget::loadFromXMI(QDomElement& qElement) -{ - if(!UMLWidget::loadFromXMI(qElement)) - return false; - QString widgetaid = qElement.attribute(QLatin1String("widgetaid"), QLatin1String("-1")); - setName(qElement.attribute(QLatin1String("preconditionname"))); - setDocumentation(qElement.attribute(QLatin1String("documentation"))); - - m_widgetAId = Uml::ID::fromString(widgetaid); - - // Lookup the ObjectWidget, if it can't be found, assume it will be - // resolved later - loadObjectWidget(); - - return true; -} - -/** - * Load the object widget from m_widgetAId - * - * This method is called in loadFromXMI() when loading an XMI file, and called - * from activate() when activating a widget after pasting. - */ -void PreconditionWidget::loadObjectWidget() -{ - if (m_objectWidget == 0) { - m_objectWidget = dynamic_cast( - umlScene()->findWidget(m_widgetAId) - ); - } -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/preconditionwidget.h umbrello-kf6-15.08.1/umbrello/widgets/preconditionwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/preconditionwidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/preconditionwidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,70 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef PRECONDITIONWIDGET_H -#define PRECONDITIONWIDGET_H - -#include "umlwidget.h" - -class ObjectWidget; - -/** - * @short A graphical version of a UML Precondition (new in UML 2.0). - * - * This class is the graphical version of a UML Precondition. A PreconditionWidget is created - * by a @ref UMLView. An PreconditionWidget belongs to only one @ref UMLView instance. - * When the @ref UMLView instance that this class belongs to, it will be automatically deleted. - * - * The PreconditionWidget class inherits from the @ref UMLWidget class which adds most of the functionality - * to this class. - * - * @author Florence Mattler - * - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class PreconditionWidget : public UMLWidget -{ - Q_OBJECT -public: - PreconditionWidget(UMLScene* scene, ObjectWidget* a, Uml::ID::Type id = Uml::ID::None); - virtual ~PreconditionWidget(); - - void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - - int minY() const; - int maxY() const; - - bool activate(IDChangeLog* Log = 0); - void resolveObjectWidget(IDChangeLog* log); - - virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); - virtual bool loadFromXMI(QDomElement& qElement); - - void setObjectWidget(ObjectWidget* widget); - -public slots: - void slotMenuSelection(QAction* action); - void slotWidgetMoved(Uml::ID::Type id); - -protected: - QSizeF minimumSize() const; - -private: - void calculateWidget(); - void calculateDimensions(); - - ObjectWidget* m_objectWidget; - int m_nY; - - Uml::ID::Type m_widgetAId; - void loadObjectWidget(); -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/regionwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/regionwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/regionwidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/regionwidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,108 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "regionwidget.h" - -// app includes -#include "basictypes.h" -#include "debug_utils.h" - -// kde includes -#include - -#define REGION_MARGIN 5 -#define REGION_WIDTH 90 -#define REGION_HEIGHT 45 - -/** - * Creates a Region widget. - * - * @param scene The parent of the widget. - * @param id The ID to assign (-1 will prompt a new ID.) - */ -RegionWidget::RegionWidget(UMLScene* scene, Uml::ID::Type id) - : UMLWidget(scene, WidgetBase::wt_Region, id) -{ -} - -/** - * Destructor. - */ -RegionWidget::~RegionWidget() -{ -} - -/** - * Overrides the standard paint event. - */ -void RegionWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - Q_UNUSED(option); - Q_UNUSED(widget); - - const int w = width(); - const int h = height(); - - setPenFromSettings(painter); - QPen pen = painter->pen(); - pen.setColor(Qt::red); - pen.setStyle(Qt::DashLine); - painter->setPen(pen); - painter->drawRoundRect(0, 0, w, h, (h * 60) / w, 60); - - UMLWidget::paint(painter, option, widget); -} - -/** - * Overrides method from UMLWidget - */ -QSizeF RegionWidget::minimumSize() const -{ - int width = 10, height = 10; - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - int textWidth = fm.width(name()); - - height = fontHeight; - width = textWidth > REGION_WIDTH?textWidth:REGION_WIDTH; - height = height > REGION_HEIGHT ? height : REGION_HEIGHT; - width += REGION_MARGIN * 2; - height += REGION_MARGIN * 2; - - return QSizeF(width, height); -} - -/** - * Saves region widget to XMI element. - */ -void RegionWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) -{ - QDomElement regionElement = qDoc.createElement(QLatin1String("regionwidget")); - UMLWidget::saveToXMI(qDoc, regionElement); - regionElement.setAttribute(QLatin1String("regionname"), name()); - regionElement.setAttribute(QLatin1String("documentation"), documentation()); - - qElement.appendChild(regionElement); -} - -/** - * Loads region widget from XMI element. - */ -bool RegionWidget::loadFromXMI(QDomElement& qElement) -{ - if (!UMLWidget::loadFromXMI(qElement)) { - return false; - } - setName(qElement.attribute(QLatin1String("regionname"))); - setDocumentation(qElement.attribute(QLatin1String("documentation"))); - return true; -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/regionwidget.h umbrello-kf6-15.08.1/umbrello/widgets/regionwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/regionwidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/regionwidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,36 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * -***************************************************************************/ - -#ifndef REGIONWIDGET_H -#define REGIONWIDGET_H - -#include "umlwidget.h" - -/** - * Represents a rectangular region on Activity diagram. - */ -class RegionWidget: public UMLWidget -{ - Q_OBJECT -public: - explicit RegionWidget(UMLScene* scene, Uml::ID::Type id = Uml::ID::None); - virtual ~RegionWidget(); - - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - - void saveToXMI(QDomDocument& qDoc, QDomElement& qElement); - bool loadFromXMI(QDomElement& qElement); - -protected: - QSizeF minimumSize() const; - -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/seqlinewidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/seqlinewidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/seqlinewidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/seqlinewidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,197 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "seqlinewidget.h" - -//app includes -#include "messagewidget.h" -#include "objectwidget.h" -#include "umlscene.h" -#include "umlview.h" - -//qt includes -#include - -// class members -int const SeqLineWidget::m_nMouseDownEpsilonX = 20; - -/** - * Constructor. - */ -SeqLineWidget::SeqLineWidget(UMLScene *scene, ObjectWidget * pObject) - : QGraphicsLineItem(), - m_scene(scene) -{ - scene->addItem(this); - m_pObject = pObject; - setPen(QPen(m_pObject->lineColor(), 0, Qt::DashLine)); - setZValue(0); - setVisible(true); - m_DestructionBox.line1 = 0; - m_nLengthY = 250; - setupDestructionBox(); -} - -/** - * Destructor. - */ -SeqLineWidget::~SeqLineWidget() -{ -} - -/** - * Return whether point is on sequence line. - * Takes into account destruction box if shown. - * - * @param p The point to investigate. - * @return True if point is on this sequence line. - */ -bool SeqLineWidget::onWidget(const QPointF & p) -{ - bool isOnWidget = false; - QPointF sp = line().p1(); - QPointF ep = line().p2(); - //see if on widget (for message creation) - if (sp.x() - m_nMouseDownEpsilonX < p.x() - && ep.x() + m_nMouseDownEpsilonX > p.x() - && sp.y() < p.y() && ep.y() + 3 > p.y()) - { - isOnWidget = true; - } - return isOnWidget; -} - -/** - * Return whether point is on the destruction box. - * - * @param p The point to investigate. - * @return True if point is on the destruction box of this sequence line. - */ -bool SeqLineWidget::onDestructionBox(const QPointF & p) -{ - bool isOnDestructionBox = false; - int x = m_pObject->x() + m_pObject->width() / 2; - int y = m_pObject->y() + m_pObject->height() + m_nLengthY; - - //see if on destruction box - if (!m_pObject->showDestruction()) { - return false; - } - if (x - 10 < p.x() && x + 10 > p.x() - && y - 10 < p.y() && y + 10 > p.y()) - { - isOnDestructionBox = true; - } - return isOnDestructionBox; -} - -/** - * Clean up anything before deletion. - */ -void SeqLineWidget::cleanup() -{ - cleanupDestructionBox(); -} - -/** - * Set the start point of the line. - * - * @param startX X coordinate of the start point. - * @param startY Y coordinate of the start point. - */ -void SeqLineWidget::setStartPoint(int startX, int startY) -{ - int endX = startX; - int endY = startY + m_nLengthY; - QGraphicsLineItem::setLine(startX, startY, endX, endY); - moveDestructionBox(); -} - -/** - * Clean up destruction box. - */ -void SeqLineWidget::cleanupDestructionBox() -{ - if (m_DestructionBox.line1) { - delete m_DestructionBox.line1; - m_DestructionBox.line1 = 0; - delete m_DestructionBox.line2; - m_DestructionBox.line2 = 0; - } -} - -/** - * Set up destruction box. - */ -void SeqLineWidget::setupDestructionBox() -{ - cleanupDestructionBox(); - if(!m_pObject->showDestruction()) { - return; - } - QRect rect; - rect.setX(m_pObject->x() + m_pObject->width() / 2 - 10); - rect.setY(m_pObject->y() + m_pObject->height() + m_nLengthY); - rect.setWidth(14); - rect.setHeight(14); - - m_DestructionBox.line1 = new QGraphicsLineItem; - m_scene->addItem(m_DestructionBox.line1); - m_DestructionBox.setLine1Points(rect); - m_DestructionBox.line1->setVisible(true); - m_DestructionBox.line1->setPen(QPen(m_pObject->lineColor(), 2)); - m_DestructionBox.line1->setZValue(3); - - m_DestructionBox.line2 = new QGraphicsLineItem; - m_scene->addItem(m_DestructionBox.line2); - m_DestructionBox.setLine2Points(rect); - m_DestructionBox.line2->setVisible(true); - m_DestructionBox.line2->setPen(QPen(m_pObject->lineColor(), 2)); - m_DestructionBox.line2->setZValue(3); -} - -/** - * Move destruction box. - */ -void SeqLineWidget::moveDestructionBox() -{ - if(!m_DestructionBox.line1) { - return; - } - QRect rect; - rect.setX(m_pObject->x() + m_pObject->width() / 2 - 7); - rect.setY(m_pObject->y() + m_pObject->height() + m_nLengthY - 7); - rect.setWidth(14); - rect.setHeight(14); - m_DestructionBox.setLine1Points(rect); - m_DestructionBox.setLine2Points(rect); -} - -/** - * Sets the y position of the bottom of the vertical line. - * - * @param yPosition The y coordinate for the bottom of the line. - */ -void SeqLineWidget::setEndOfLine(int yPosition) -{ - QPointF sp = line().p1(); - int newY = yPosition; - m_nLengthY = yPosition - m_pObject->y() - m_pObject->height(); - // normally the managing Objectwidget is responsible for the call of this function - // but to be sure - make a double check _against current position_ - if (m_nLengthY < 0) { - m_nLengthY = 0; - newY = m_pObject->y() + m_pObject->height(); - } - setLine(sp.x(), sp.y(), sp.x(), newY); - moveDestructionBox(); - m_scene->resizeSceneToItems(); -} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/seqlinewidget.h umbrello-kf6-15.08.1/umbrello/widgets/seqlinewidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/seqlinewidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/seqlinewidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,86 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef SEQLINEWIDGET_H -#define SEQLINEWIDGET_H - -#include - -class ObjectWidget; -class UMLScene; - -/** - * @short Widget class for graphical representation of sequence lines - * @author Paul Hensgen - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class SeqLineWidget : public QGraphicsLineItem -{ -public: - SeqLineWidget(UMLScene *scene, ObjectWidget * pObject); - virtual ~SeqLineWidget(); - - bool onWidget(const QPointF& p); - - bool onDestructionBox(const QPointF& p); - - void cleanup(); - - void setupDestructionBox(); - - void setStartPoint(int startX, int startY); - - /** - * Gets the length of the line. - * - * @return Length of the line. - */ - int getLineLength() { - return m_nLengthY; - } - - /** - * Returns the @ref ObjectWidget associated with this sequence line. - * - * @return Pointer to the associated ObjectWidget. - */ - ObjectWidget * getObjectWidget() { - return m_pObject; - } - - void setEndOfLine(int yPosition); - -protected: - void cleanupDestructionBox(); - - void moveDestructionBox(); - - ObjectWidget* m_pObject; ///< ObjectWidget associated with this sequence line - UMLScene* m_scene; ///< scene displayed on - - struct DestructionBox { - QGraphicsLineItem * line1; - QGraphicsLineItem * line2; - void setLine1Points(QRect rect) { - line1->setLine(rect.x(), rect.y(), - rect.x() + rect.width(), rect.y() + rect.height()); - } - void setLine2Points(QRect rect) { - line2->setLine(rect.x(), rect.y() + rect.height(), - rect.x() + rect.width(), rect.y()); - } - } m_DestructionBox; ///< the destruction box - - int m_nLengthY; ///< the length of the line - - static int const m_nMouseDownEpsilonX; ///< margin used for mouse clicks -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/signalwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/signalwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/signalwidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/signalwidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,386 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "signalwidget.h" - -// app includes -#include "basictypes.h" -#include "debug_utils.h" -#include "floatingtextwidget.h" -#include "linkwidget.h" -#include "listpopupmenu.h" -#include "uml.h" -#include "umldoc.h" -#include "uniqueid.h" -#include "umlview.h" -#include "umlwidget.h" - -// kde includes -#include -#if QT_VERSION < 0x050000 -#include -#endif - -// qt includes -#include -#if QT_VERSION >= 0x050000 -#include -#endif -#include - -/** - * Creates a Signal widget. - * - * @param scene The parent of the widget. - * @param signalType The type of Signal. - * @param id The ID to assign (-1 will prompt a new ID.) - */ -SignalWidget::SignalWidget(UMLScene *scene, SignalType signalType, Uml::ID::Type id) - : UMLWidget(scene, WidgetBase::wt_Signal, id), - m_oldX(0), - m_oldY(0) -{ - m_signalType = signalType; - m_pName = NULL; - if (signalType == SignalWidget::Time) { - m_pName = new FloatingTextWidget(scene, Uml::TextRole::Floating, QString()); - scene->setupNewWidget(m_pName); - m_pName->setX(0); - m_pName->setY(0); - connect(m_pName, SIGNAL(destroyed()), this, SLOT(slotTextDestroyed())); - } -} - -/** - * Destructor. - */ -SignalWidget::~SignalWidget() -{ -} - -/** - * Overrides the standard paint event. - */ -void SignalWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - Q_UNUSED(option); - Q_UNUSED(widget); - - setPenFromSettings(painter); - const int w = width(); - const int h = height(); - QPolygon a; - switch (m_signalType) - { - case Send : - if(UMLWidget::useFillColor()) - painter->setBrush(UMLWidget::fillColor()); - { - a.setPoints(5, 0, 0, - (w*2)/3, 0, - w, h/2, - (w*2)/3, h, - 0, h); - painter->drawPolygon(a); - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - int textStartY = (h / 2) - (fontHeight / 2); - - painter->setPen(textColor()); - QFont font = UMLWidget::font(); - font.setBold(false); - painter->setFont(font); - painter->drawText(SIGNAL_MARGIN, textStartY, - w - SIGNAL_MARGIN * 2, fontHeight, - Qt::AlignCenter, name()); - setPenFromSettings(painter); - } - break; - case Accept : - if(UMLWidget::useFillColor()) - painter->setBrush(UMLWidget::fillColor()); - { - a.setPoints(5, 0, 0, - w/3, h/2, - 0, h, - w, h, - w, 0); - - painter->drawPolygon(a); - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - int textStartY = (h / 2) - (fontHeight / 2); - - painter->setPen(textColor()); - QFont font = UMLWidget::font(); - font.setBold(false); - painter->setFont(font); - painter->drawText(SIGNAL_MARGIN, textStartY, - w - SIGNAL_MARGIN * 2 + (w/3), fontHeight, - Qt::AlignCenter, name()); - setPenFromSettings(painter); - } - break; - case Time : - if(UMLWidget::useFillColor()) - painter->setBrush(UMLWidget::fillColor()); - { - a.setPoints(4, 0, 0, - w, h, - 0, h, - w, 0); - - painter->drawPolygon(a); - //const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - //const int fontHeight = fm.lineSpacing(); - //int textStartY = (h / 2) - (fontHeight / 2); - painter->setPen(textColor()); - QFont font = UMLWidget::font(); - font.setBold(false); - painter->setFont(font); - - setPenFromSettings(painter); - } - if (m_pName) { - if (m_pName->x() == 0 && m_pName->y() == 0) { - //the floating text has not been linked with the signal - m_pName->setX(w/2 - m_pName->width()/2); - m_pName->setY(h); - } - m_pName->setVisible((m_pName->text().length() > 0)); - m_pName->updateGeometry(); - } - - break; - default: - uWarning() << "Unknown signal type:" << m_signalType; - break; - } - - UMLWidget::paint(painter, option, widget); -} - -/** - * Overrides the UMLWidget method. - */ -void SignalWidget::setX(qreal newX) -{ - m_oldX = x(); - UMLWidget::setX(newX); -} - -/** - * Overrides the UMLWidget method. - */ -void SignalWidget::setY(qreal newY) -{ - m_oldY = y(); - UMLWidget::setY(newY); -} - -/** - * Sets the name of the signal. - */ -void SignalWidget::setName(const QString &strName) -{ - UMLWidget::setName(strName); - updateGeometry(); - if (signalType() == SignalWidget::Time) { - if (!m_pName) { - m_pName = new FloatingTextWidget(umlScene(), Uml::TextRole::Floating, m_Text); - umlScene()->setupNewWidget(m_pName); - m_pName->setX(0); - m_pName->setY(0); - connect(m_pName, SIGNAL(destroyed()), this, SLOT(slotTextDestroyed())); - } - else - m_pName->setText(m_Text); - } -} - -/** - * Returns the type of Signal. - */ -SignalWidget::SignalType SignalWidget::signalType() const -{ - return m_signalType; -} - -/** - * Returns the type string of Signal. - */ -QString SignalWidget::signalTypeStr() const -{ - return QLatin1String(ENUM_NAME(SignalWidget, SignalType, m_signalType)); -} - -/** - * Sets the type of Signal. - */ -void SignalWidget::setSignalType(SignalType signalType) -{ - m_signalType = signalType; -} - -/** - * Show a properties dialog for a UMLWidget. - */ -void SignalWidget::showPropertiesDialog() -{ -} - -/** - * Overrides mouseMoveEvent. - */ -void SignalWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* me) -{ - UMLWidget::mouseMoveEvent(me); - int diffX = m_oldX - x(); - int diffY = m_oldY - y(); - if (m_pName!=NULL) { - m_pName->setX(m_pName->x() - diffX); - m_pName->setY(m_pName->y() - diffY); - } -} - -/** - * Loads a "signalwidget" XMI element. - */ -bool SignalWidget::loadFromXMI(QDomElement & qElement) -{ - if(!UMLWidget::loadFromXMI(qElement)) - return false; - m_Text = qElement.attribute(QLatin1String("signalname")); - m_Doc = qElement.attribute(QLatin1String("documentation")); - QString type = qElement.attribute(QLatin1String("signaltype")); - QString textid = qElement.attribute(QLatin1String("textid"), QLatin1String("-1")); - Uml::ID::Type textId = Uml::ID::fromString(textid); - - setSignalType((SignalType)type.toInt()); - if (signalType() == Time) { - - if (textId != Uml::ID::None) { - UMLWidget *flotext = m_scene -> findWidget(textId); - if (flotext != NULL) { - // This only happens when loading files produced by - // umbrello-kf6-1.3-beta2. - m_pName = static_cast(flotext); - return true; - } - } else { - // no textid stored -> get unique new one - textId = UniqueID::gen(); - } - } - //now load child elements - QDomNode node = qElement.firstChild(); - QDomElement element = node.toElement(); - if (!element.isNull()) { - QString tag = element.tagName(); - if (tag == QLatin1String("floatingtext") || tag == QLatin1String("UML::FloatingTextWidget")) { - m_pName = new FloatingTextWidget(m_scene, Uml::TextRole::Floating, m_Text, textId); - if(! m_pName->loadFromXMI(element)) { - // Most likely cause: The FloatingTextWidget is empty. - delete m_pName; - m_pName = NULL; - } - else - connect(m_pName, SIGNAL(destroyed()), this, SLOT(slotTextDestroyed())); - } else { - uError() << "unknown tag " << tag; - } - } - return true; -} - -/** - * Creates the "signalwidget" XMI element. - */ -void SignalWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) -{ - QDomElement signalElement = qDoc.createElement(QLatin1String("signalwidget")); - UMLWidget::saveToXMI(qDoc, signalElement); - signalElement.setAttribute(QLatin1String("signalname"), m_Text); - signalElement.setAttribute(QLatin1String("documentation"), m_Doc); - signalElement.setAttribute(QLatin1String("signaltype"), m_signalType); - if (m_pName && !m_pName->text().isEmpty()) { - signalElement.setAttribute(QLatin1String("textid"), Uml::ID::toString(m_pName->id())); - m_pName -> saveToXMI(qDoc, signalElement); - } - qElement.appendChild(signalElement); -} - -/** - * Show a properties dialog for a SignalWidget. - * - */ -void SignalWidget::slotMenuSelection(QAction* action) -{ - ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); - switch(sel) { - case ListPopupMenu::mt_Rename: - { - bool ok = false; - QString name = m_Text; -#if QT_VERSION >= 0x050000 - name = QInputDialog::getText(Q_NULLPTR, - i18n("Enter signal name"), - i18n("Enter the signal name :"), - QLineEdit::Normal, - m_Text, &ok); -#else - name = KInputDialog::getText(i18n("Enter signal name"), - i18n("Enter the signal name :"), - m_Text, &ok); -#endif - if (ok && name.length() > 0) { - setName(name); - } - } - break; - - default: - UMLWidget::slotMenuSelection(action); - } -} - -/** - * Overrides method from UMLWidget - */ -QSizeF SignalWidget::minimumSize() const -{ - int width = SIGNAL_WIDTH, height = SIGNAL_HEIGHT; - const QFontMetrics &fm = getFontMetrics(FT_BOLD); - const int fontHeight = fm.lineSpacing(); - int textWidth = fm.width(name()); - - if (m_signalType == Accept) - textWidth = int((float)textWidth * 1.3f); - height = fontHeight; - if (m_signalType != Time) - { - width = textWidth > SIGNAL_WIDTH?textWidth:SIGNAL_WIDTH; - height = height > SIGNAL_HEIGHT?height:SIGNAL_HEIGHT; - } - width += SIGNAL_MARGIN * 2; - height += SIGNAL_MARGIN * 2; - - return QSizeF(width, height); -} - -/** - * Called if user deletes text widget - */ -void SignalWidget::slotTextDestroyed() -{ - m_pName = 0; -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/signalwidget.h umbrello-kf6-15.08.1/umbrello/widgets/signalwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/signalwidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/signalwidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,86 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * -***************************************************************************/ - -#ifndef SIGNALWIDGET_H -#define SIGNALWIDGET_H - -#include "floatingtextwidget.h" -#include "linkwidget.h" -#include "umlwidget.h" -#include "worktoolbar.h" - -#define SIGNAL_MARGIN 5 -#define SIGNAL_WIDTH 45 -#define SIGNAL_HEIGHT 15 - -/** - * Represents a Send signal, Accept signal or Time event on an - * Activity diagram. - */ -class SignalWidget : public UMLWidget -{ - Q_OBJECT - Q_ENUMS(SignalType) -public: - /// Enumeration that codes the different types of signal. - enum SignalType - { - Send = 0, - Accept, - Time - }; - - explicit SignalWidget(UMLScene * scene, SignalType signalType = Send, Uml::ID::Type id = Uml::ID::None); - virtual ~SignalWidget(); - - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - - void setX(qreal newX); - void setY(qreal newY); - - virtual void setName(const QString &strName); - - SignalType signalType() const; - QString signalTypeStr() const; - void setSignalType(SignalType signalType); - - virtual void showPropertiesDialog(); - - void mouseMoveEvent(QGraphicsSceneMouseEvent *me); - - virtual bool loadFromXMI(QDomElement & qElement); - virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); - -public Q_SLOTS: - virtual void slotMenuSelection(QAction* action); - -protected: - QSizeF minimumSize() const; - - /** - * Save the value of the widget to know how to move the floatingtext - */ - int m_oldX; - int m_oldY; - - // Only for the time event - /** - * This is a pointer to the Floating Text widget which displays the - * name of the signal widget. - */ - FloatingTextWidget* m_pName; - - SignalType m_signalType; ///< Type of signal - -protected Q_SLOTS: - void slotTextDestroyed(); -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/statewidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/statewidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/statewidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/statewidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,534 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "statewidget.h" - -// app includes -#include "debug_utils.h" -#include "docwindow.h" -#include "listpopupmenu.h" -#include "statedialog.h" -#include "uml.h" -#include "umldoc.h" -#include "umlscene.h" -#include "umlview.h" -#include "umlwidget.h" - -// kde includes -#include -#if QT_VERSION < 0x050000 -#include -#endif - -// qt includes -#if QT_VERSION >= 0x050000 -#include -#endif -#include - -/** - * Creates a State widget. - * - * @param scene The parent of the widget. - * @param stateType The type of state. - * @param id The ID to assign (-1 will prompt a new ID.) - */ -StateWidget::StateWidget(UMLScene * scene, StateType stateType, Uml::ID::Type id) - : UMLWidget(scene, WidgetBase::wt_State, id) -{ - m_stateType = stateType; - m_drawVertical = true; - setAspectRatioMode(); - m_Text = QLatin1String("State"); - QSizeF size = minimumSize(); - setSize(size.width(), size.height()); -} - -/** - * Destructor. - */ -StateWidget::~StateWidget() -{ -} - -/** - * Overrides the standard paint event. - */ -void StateWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - Q_UNUSED(option); - Q_UNUSED(widget); - - const qreal w = width(); - const qreal h = height(); - if (w == 0 || h == 0) - return; - - setPenFromSettings(painter); - switch (m_stateType) { - case StateWidget::Normal: - { - if (UMLWidget::useFillColor()) { - painter->setBrush(UMLWidget::fillColor()); - } - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - int textStartY = (h / 2) - (fontHeight / 2); - const int count = m_Activities.count(); - if (count == 0) { - painter->drawRoundRect(0, 0, w, h, (h*40)/w, (w*40)/h); - painter->setPen(textColor()); - QFont font = UMLWidget::font(); - font.setBold(false); - painter->setFont(font); - painter->drawText(STATE_MARGIN, textStartY, - w - STATE_MARGIN * 2, fontHeight, - Qt::AlignCenter, name()); - setPenFromSettings(painter); - } else { - painter->drawRoundRect(0, 0, w, h, (h*40)/w, (w*40)/h); - textStartY = STATE_MARGIN; - painter->setPen(textColor()); - QFont font = UMLWidget::font(); - font.setBold(true); - painter->setFont(font); - painter->drawText(STATE_MARGIN, textStartY, w - STATE_MARGIN * 2, - fontHeight, Qt::AlignCenter, name()); - font.setBold(false); - painter->setFont(font); - setPenFromSettings(painter); - int linePosY = textStartY + fontHeight; - - QStringList::Iterator end(m_Activities.end()); - for(QStringList::Iterator it(m_Activities.begin()); it != end; ++it) { - textStartY += fontHeight; - painter->drawLine(0, linePosY, w, linePosY); - painter->setPen(textColor()); - painter->drawText(STATE_MARGIN, textStartY, w - STATE_MARGIN * 2, - fontHeight, Qt::AlignCenter, *it); - setPenFromSettings(painter); - linePosY += fontHeight; - }//end for - }//end else - } - break; - case StateWidget::Initial : - painter->setBrush(WidgetBase::lineColor()); - painter->drawEllipse(0, 0, w, h); - break; - case StateWidget::End : - painter->setBrush(WidgetBase::lineColor()); - painter->drawEllipse(0, 0, w, h); - painter->setBrush(Qt::white); - painter->drawEllipse(1, 1, w - 2, h - 2); - painter->setBrush(WidgetBase::lineColor()); - painter->drawEllipse(3, 3, w - 6, h - 6); - break; - case StateWidget::Fork: - case StateWidget::Join: - { - painter->setPen(Qt::black); - painter->setBrush(Qt::black); - painter->drawRect(rect()); - } - break; - case StateWidget::Junction: - { - painter->setPen(Qt::black); - painter->setBrush(Qt::black); - painter->drawEllipse(rect()); - } - break; - case StateWidget::DeepHistory: - { - painter->setBrush(Qt::white); - painter->drawEllipse(rect()); - painter->setPen(Qt::black); - painter->setFont(UMLWidget::font()); - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing() / 2; - const int xStar = fm.boundingRect(QLatin1String("H")).width(); - const int yStar = fontHeight / 4; - painter->drawText((w / 6), - (h / 4) + fontHeight, QLatin1String("H")); - painter->drawText((w / 6) + xStar, - (h / 4) + fontHeight - yStar, QLatin1String("*")); - } - break; - case StateWidget::ShallowHistory: - { - painter->setBrush(Qt::white); - painter->drawEllipse(rect()); - painter->setPen(Qt::black); - painter->setFont(UMLWidget::font()); - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing() / 2; - painter->drawText((w / 6), - (h / 4) + fontHeight, QLatin1String("H")); - } - break; - case StateWidget::Choice: - { - const qreal x = w / 2; - const qreal y = h / 2; - QPolygonF polygon; - polygon << QPointF(x, 0) << QPointF(w, y) - << QPointF(x, h) << QPointF(0, y); - painter->setBrush(UMLWidget::fillColor()); - painter->drawPolygon(polygon); - } - break; - default: - uWarning() << "Unknown state type: " << stateTypeStr(); - break; - } - - UMLWidget::paint(painter, option, widget); -} - -/** - * Overrides method from UMLWidget - */ -QSizeF StateWidget::minimumSize() const -{ - int width = 10, height = 10; - switch (m_stateType) { - case StateWidget::Normal: - { - const QFontMetrics &fm = getFontMetrics(FT_BOLD); - const int fontHeight = fm.lineSpacing(); - int textWidth = fm.width(name()); - const int count = m_Activities.count(); - height = fontHeight; - if(count > 0) { - height = fontHeight * (count + 1); - - QStringList::ConstIterator end(m_Activities.end()); - for(QStringList::ConstIterator it(m_Activities.begin()); it != end; ++it) { - int w = fm.width(*it); - if(w > textWidth) - textWidth = w; - }//end for - }//end if - width = textWidth > STATE_WIDTH?textWidth:STATE_WIDTH; - height = height > STATE_HEIGHT?height:STATE_HEIGHT; - width += STATE_MARGIN * 2; - height += STATE_MARGIN * 2; - break; - } - case StateWidget::Fork: - case StateWidget::Join: - if (m_drawVertical) { - width = 8; - height = 60; - } else { - width = 60; - height = 8; - } - break; - case StateWidget::Junction: - width = 18; - height = 18; - break; - case StateWidget::DeepHistory: - case StateWidget::ShallowHistory: - { - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - width = height = fm.lineSpacing(); - } - break; - case StateWidget::Choice: - width = 25; - height = 25; - break; - default: - break; - } - - return QSizeF(width, height); -} - -/** - * Overrides method from UMLWidget - */ -QSizeF StateWidget::maximumSize() -{ - switch (m_stateType) { - case StateWidget::Initial: - case StateWidget::End: - case StateWidget::Junction: - case StateWidget::Choice: - return QSizeF(35, 35); - break; - case StateWidget::DeepHistory: - case StateWidget::ShallowHistory: - { - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - return QSizeF(fontHeight + 10, fontHeight + 10); - } - break; - default: - break; - } - return UMLWidget::maximumSize(); -} - -/** - * Set the aspect ratio mode. - * Some state types have a fixed aspect ratio - */ -void StateWidget::setAspectRatioMode() -{ - switch (m_stateType) { - case StateWidget::Initial: - case StateWidget::End: - case StateWidget::Choice: - case StateWidget::DeepHistory: - case StateWidget::ShallowHistory: - case StateWidget::Fork: - case StateWidget::Join: - case StateWidget::Junction: - setFixedAspectRatio(true); - break; - default: - setFixedAspectRatio(false); - break; - } -} - -/** - * Returns the type of state. - * @return StateType - */ -StateWidget::StateType StateWidget::stateType() const -{ - return m_stateType; -} - -/** - * Returns the type string of state. - */ -QString StateWidget::stateTypeStr() const -{ - return QLatin1String(ENUM_NAME(StateWidget, StateType, m_stateType)); -} - -/** - * Sets the type of state. - */ -void StateWidget::setStateType(StateType stateType) -{ - m_stateType = stateType; - setAspectRatioMode(); -} - -/** - * Adds an activity to this widget. - * @return true on success - */ -bool StateWidget::addActivity(const QString &activity) -{ - m_Activities.append(activity); - updateGeometry(); - return true; -} - -/** - * Removes the given activity from the state. - */ -bool StateWidget::removeActivity(const QString &activity) -{ - if(m_Activities.removeAll(activity) == 0) - return false; - updateGeometry(); - return true; -} - -/** - * Renames the given activity. - */ -bool StateWidget::renameActivity(const QString &activity, const QString &newName) -{ - int index = - 1; - if((index = m_Activities.indexOf(activity)) == -1) - return false; - m_Activities[ index ] = newName; - return true; -} - -/** - * Sets the states activities to the ones given. - */ -void StateWidget::setActivities(const QStringList &list) -{ - m_Activities = list; - updateGeometry(); -} - -/** - * Returns the list of activities. - */ -QStringList StateWidget::activities() const -{ - return m_Activities; -} - -/** - * Get whether to draw a fork or join vertically. - */ -bool StateWidget::drawVertical() const -{ - return m_drawVertical; -} - -/** - * Set whether to draw a fork or join vertically. - */ -void StateWidget::setDrawVertical(bool to) -{ - m_drawVertical = to; - setSize(height(), width()); - updateGeometry(); - UMLWidget::adjustAssocs(x(), y()); -} - -/** - * Show a properties dialog for a StateWidget. - */ -void StateWidget::showPropertiesDialog() -{ - UMLApp::app()->docWindow()->updateDocumentation(false); - - QPointer dialog = new StateDialog(m_scene->activeView(), this); - if (dialog->exec() && dialog->getChangesMade()) { - UMLApp::app()->docWindow()->showDocumentation(this, true); - UMLApp::app()->document()->setModified(true); - } - delete dialog; -} - -/** - * Creates the "statewidget" XMI element. - */ -void StateWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) -{ - QDomElement stateElement = qDoc.createElement(QLatin1String("statewidget")); - UMLWidget::saveToXMI(qDoc, stateElement); - stateElement.setAttribute(QLatin1String("statename"), m_Text); - stateElement.setAttribute(QLatin1String("documentation"), m_Doc); - stateElement.setAttribute(QLatin1String("statetype"), m_stateType); - if (m_stateType == Fork || m_stateType == Join) - stateElement.setAttribute(QLatin1String("drawvertical"), m_drawVertical); - //save states activities - QDomElement activitiesElement = qDoc.createElement(QLatin1String("Activities")); - - QStringList::Iterator end(m_Activities.end()); - for(QStringList::Iterator it(m_Activities.begin()); it != end; ++it) { - QDomElement tempElement = qDoc.createElement(QLatin1String("Activity")); - tempElement.setAttribute(QLatin1String("name"), *it); - activitiesElement.appendChild(tempElement); - }//end for - stateElement.appendChild(activitiesElement); - qElement.appendChild(stateElement); -} - -/** - * Loads a "statewidget" XMI element. - */ -bool StateWidget::loadFromXMI(QDomElement & qElement) -{ - if(!UMLWidget::loadFromXMI(qElement)) - return false; - m_Text = qElement.attribute(QLatin1String("statename")); - m_Doc = qElement.attribute(QLatin1String("documentation")); - QString type = qElement.attribute(QLatin1String("statetype"), QLatin1String("1")); - m_stateType = (StateType)type.toInt(); - setAspectRatioMode(); - QString drawVertical = qElement.attribute(QLatin1String("drawvertical"), QLatin1String("1")); - m_drawVertical = (bool)drawVertical.toInt(); - //load states activities - QDomNode node = qElement.firstChild(); - QDomElement tempElement = node.toElement(); - if(!tempElement.isNull() && tempElement.tagName() == QLatin1String("Activities")) { - QDomNode node = tempElement.firstChild(); - QDomElement activityElement = node.toElement(); - while(!activityElement.isNull()) { - if(activityElement.tagName() == QLatin1String("Activity")) { - QString name = activityElement.attribute(QLatin1String("name")); - if(!name.isEmpty()) - m_Activities.append(name); - }//end if - node = node.nextSibling(); - activityElement = node.toElement(); - }//end while - }//end if - return true; -} - -/** - * Captures any popup menu signals for menus it created. - */ -void StateWidget::slotMenuSelection(QAction* action) -{ - bool ok = false; - QString nameNew = name(); - - ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); - switch(sel) { - case ListPopupMenu::mt_Rename: -#if QT_VERSION >= 0x050000 - nameNew = QInputDialog::getText(Q_NULLPTR, - i18n("Enter State Name"), - i18n("Enter the name of the new state:"), - QLineEdit::Normal, - name(), &ok); -#else - nameNew = KInputDialog::getText(i18n("Enter State Name"), - i18n("Enter the name of the new state:"), - name(), &ok); -#endif - if (ok && nameNew.length() > 0) { - setName(nameNew); - } - break; - - case ListPopupMenu::mt_Properties: - showPropertiesDialog(); - break; - - case ListPopupMenu::mt_New_Activity: -#if QT_VERSION >= 0x050000 - nameNew = QInputDialog::getText(Q_NULLPTR, - i18n("Enter Activity"), - i18n("Enter the name of the new activity:"), - QLineEdit::Normal, - i18n("new activity"), &ok); -#else - nameNew = KInputDialog::getText(i18n("Enter Activity"), - i18n("Enter the name of the new activity:"), - i18n("new activity"), &ok); -#endif - if (ok && nameNew.length() > 0) { - addActivity(nameNew); - } - break; - - case ListPopupMenu::mt_Flip: - setDrawVertical(!m_drawVertical); - break; - - default: - UMLWidget::slotMenuSelection(action); - break; - } -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/statewidget.h umbrello-kf6-15.08.1/umbrello/widgets/statewidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/statewidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/statewidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,99 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * -***************************************************************************/ - -#ifndef STATEWIDGET_H -#define STATEWIDGET_H - -#include "umlwidget.h" - -#include -#include - -#define STATE_MARGIN 5 -#define STATE_WIDTH 30 -#define STATE_HEIGHT 10 - -/** - * This class is the graphical version of a UML State. - * - * A StateWidget is created by a @ref UMLView. A StateWidget belongs to - * only one @ref UMLView instance. - * When the @ref UMLView instance that this class belongs to is destroyed, - * it will be automatically deleted. - * - * The StateWidget class inherits from the @ref UMLWidget class - * which adds most of the functionality to this class. - * - * @short A graphical version of a UML State. - * @author Paul Hensgen - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class StateWidget : public UMLWidget -{ - Q_OBJECT - Q_ENUMS(StateType) -public: - /// Enumeration that codes the different types of state. - enum StateType - { - Initial = 0, // Pseudostate - Normal, - End, - Fork, // Pseudostate - Join, // Pseudostate - Junction, // Pseudostate - DeepHistory, // Pseudostate - ShallowHistory, // Pseudostate - Choice // Pseudostate - //Terminate // Pseudostate - //EntryPoint // Pseudostate - //ExitPoint // Pseudostate - }; - - explicit StateWidget(UMLScene * scene, StateType stateType = Normal, Uml::ID::Type id = Uml::ID::None); - virtual ~StateWidget(); - - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - - StateType stateType() const; - QString stateTypeStr() const; - void setStateType(StateType stateType); - - bool addActivity(const QString &activity); - bool removeActivity(const QString &activity); - bool renameActivity(const QString &activity, const QString &newName); - - QStringList activities() const; - void setActivities(const QStringList &list); - - bool drawVertical() const; - void setDrawVertical(bool to = true); - - virtual void showPropertiesDialog(); - - virtual bool loadFromXMI(QDomElement & qElement); - virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); - -protected: - QSizeF minimumSize() const; - QSizeF maximumSize(); - void setAspectRatioMode(); - -public Q_SLOTS: - virtual void slotMenuSelection(QAction* action); - -private: - StateType m_stateType; ///< Type of state. - bool m_drawVertical; ///< whether to draw the fork/join horizontally or vertically - QStringList m_Activities; ///< List of activities for the state. - -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/statusbartoolbutton.cpp umbrello-kf6-15.08.1/umbrello/widgets/statusbartoolbutton.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/statusbartoolbutton.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/statusbartoolbutton.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,122 +0,0 @@ -// vim: set tabstop=4 shiftwidth=4 noexpandtab: -/* -Widget taken from gwenview-kf6 -Copyright 2007 Aurélien Gâteau - -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. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR purpose-kf6. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -*/ -// Self -#include "statusbartoolbutton.h" - -// Qt -#include -#include -#include -#include - -// KDE -#include - -StatusBarToolButton::StatusBarToolButton(QWidget* parent) - : QToolButton(parent), - mGroupPosition(NotGrouped) -{ - setToolButtonStyle(Qt::ToolButtonTextOnly); - setFocusPolicy(Qt::NoFocus); - setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); -} - - -QSize StatusBarToolButton::minimumSizeHint() const -{ - return sizeHint(); -} - - -QSize StatusBarToolButton::sizeHint() const -{ - QSize sh = QToolButton::sizeHint(); - sh.setHeight(fontMetrics().height()); - return sh; -} - - -void StatusBarToolButton::setGroupPosition(StatusBarToolButton::GroupPosition groupPosition) -{ - mGroupPosition = groupPosition; -} - - -void StatusBarToolButton::paintEvent(QPaintEvent* event) -{ - if (mGroupPosition == NotGrouped) { - QToolButton::paintEvent(event); - return; - } - QStylePainter painter(this); - QStyleOptionToolButton opt; - initStyleOption(&opt); - QStyleOptionToolButton panelOpt = opt; - - // Panel - QRect& panelRect = panelOpt.rect; - switch (mGroupPosition) { - case GroupLeft: - panelRect.setWidth(panelRect.width() * 2); - break; - case GroupCenter: - panelRect.setLeft(panelRect.left() - panelRect.width()); - panelRect.setWidth(panelRect.width() * 3); - break; - case GroupRight: - panelRect.setLeft(panelRect.left() - panelRect.width()); - break; - case NotGrouped: - Q_ASSERT(0); - } - painter.drawPrimitive(QStyle::PE_PanelButtonTool, panelOpt); - - // Separator - const int y1 = opt.rect.top() + 6; - const int y2 = opt.rect.bottom() - 6; - if (mGroupPosition & GroupRight) { - const int x = opt.rect.left(); - painter.setPen(opt.palette.color(QPalette::Light)); - painter.drawLine(x, y1, x, y2); - } - if (mGroupPosition & GroupLeft) { - const int x = opt.rect.right(); - painter.setPen(opt.palette.color(QPalette::Mid)); - painter.drawLine(x, y1, x, y2); - } - - // Text - painter.drawControl(QStyle::CE_ToolButtonLabel, opt); - - // Filtering message on tooltip text for CJK to remove accelerators. - // Quoting ktoolbar.cpp: - // """ - // CJK languages use more verbose accelerator marker: they add a Latin - // letter in parenthesis, and put accelerator on that. Hence, the default - // removal of ampersand only may not be enough there, instead the whole - // parenthesis construct should be removed. Provide these filtering i18n - // messages so that translators can use Transcript for custom removal. - // """ - if (!actions().isEmpty()) { - QAction* action = actions().first(); - setToolTip(i18nc("@info:tooltip of custom toolbar button", "%1", action->toolTip())); - } -} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/statusbartoolbutton.h umbrello-kf6-15.08.1/umbrello/widgets/statusbartoolbutton.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/statusbartoolbutton.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/statusbartoolbutton.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,58 +0,0 @@ -// vim: set tabstop=4 shiftwidth=4 noexpandtab: -/* -gwenview-kf6: an image viewer -Copyright 2007 Aurélien Gâteau - -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. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR purpose-kf6. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -*/ -#ifndef STATUSBARTOOLBUTTON_H -#define STATUSBARTOOLBUTTON_H - -// Qt -#include - -/** - * A thin tool button which can be grouped with another and look like one solid-kf6 - * bar: - * - * (button1 | button2) - */ -class StatusBarToolButton : public QToolButton -{ - Q_OBJECT -public: - enum GroupPosition { - NotGrouped = 0, - GroupLeft = 1, - GroupRight = 2, - GroupCenter = 3 - }; - - explicit StatusBarToolButton(QWidget* parent = 0); - - virtual QSize minimumSizeHint() const; - virtual QSize sizeHint() const; - - void setGroupPosition(StatusBarToolButton::GroupPosition groupPosition); - -protected: - virtual void paintEvent(QPaintEvent* event); - -private: - GroupPosition mGroupPosition; -}; - -#endif /* STATUSBARTOOLBUTTON_H */ diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/toolbarstateonewidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/toolbarstateonewidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/toolbarstateonewidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/toolbarstateonewidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,249 +0,0 @@ -/*************************************************************************** - * 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) 2004-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "toolbarstateonewidget.h" - -// app includes -#include "activitywidget.h" -#include "dialog_utils.h" -#include "floatingtextwidget.h" -#include "messagewidget.h" -#include "objectwidget.h" -#include "pinwidget.h" -#include "portwidget.h" -#include "preconditionwidget.h" -#include "regionwidget.h" -#include "uml.h" -#include "umldoc.h" -#include "umlscene.h" -#include "umlwidget.h" -#include "object_factory.h" -#include "package.h" -#include "widget_factory.h" - -// kde includes -#include -#include -#if QT_VERSION < 0x050000 -#include -#endif - -// qt includes -#if QT_VERSION >= 0x050000 -#include -#endif - -// using namespace Uml; - -/** - * Creates a new ToolBarStateOneWidget. - * - * @param umlScene The UMLScene to use. - */ -ToolBarStateOneWidget::ToolBarStateOneWidget(UMLScene *umlScene) - : ToolBarStatePool(umlScene), - m_firstObject(0), - m_isObjectWidgetLine(false) -{ -} - -/** - * Destroys this ToolBarStateOneWidget. - */ -ToolBarStateOneWidget::~ToolBarStateOneWidget() -{ -} - -/** - * Called when the current tool is changed to use another tool. - * Executes base method and cleans the message. - */ -void ToolBarStateOneWidget::cleanBeforeChange() -{ - ToolBarStatePool::cleanBeforeChange(); -} - -/** - * Called when a mouse event happened. - * It executes the base method and then updates the position of the - * message line, if any. - */ -void ToolBarStateOneWidget::mouseMove(QGraphicsSceneMouseEvent* ome) -{ - ToolBarStatePool::mouseMove(ome); -} - -/** - * A widget was removed from the UMLView. - * If the widget removed was the current widget, the current widget is set - * to 0. - * Also, if it was the first object, the message is cleaned. - */ -void ToolBarStateOneWidget::slotWidgetRemoved(UMLWidget* widget) -{ - ToolBarState::slotWidgetRemoved(widget); -} - -/** - * Selects only widgets, but no associations. - * Overrides base class method. - * If the press event happened on the line of an object, the object is set - * as current widget. If the press event happened on a widget, the widget is - * set as current widget. - */ -void ToolBarStateOneWidget::setCurrentElement() -{ - m_isObjectWidgetLine = false; - ObjectWidget* objectWidgetLine = m_pUMLScene->onWidgetLine(m_pMouseEvent->scenePos()); - if (objectWidgetLine) { - setCurrentWidget(objectWidgetLine); - m_isObjectWidgetLine = true; - return; - } - - UMLWidget *widget = m_pUMLScene->widgetAt(m_pMouseEvent->scenePos()); - if (widget) { - setCurrentWidget(widget); - return; - } -} - -/** - * Called when the release event happened on a widget. - * If the button pressed isn't left button or the widget isn't an object - * widget, the message is cleaned. - * If the release event didn't happen on the line of an object and the first - * object wasn't selected, nothing is done. If the first object was already - * selected, a creation message is made. - * If the event happened on the line of an object, the first object or the - * second are set, depending on whether the first object was already set or - * not. - */ -void ToolBarStateOneWidget::mouseReleaseWidget() -{ - WidgetBase::WidgetType type = widgetType(); - - if (type == WidgetBase::wt_Precondition) { - m_firstObject = 0; - } - if (type == WidgetBase::wt_Pin) { - m_firstObject = 0; - } - - if (m_pMouseEvent->button() != Qt::LeftButton || - (currentWidget()->baseType() != WidgetBase::wt_Object && - currentWidget()->baseType() != WidgetBase::wt_Activity && - currentWidget()->baseType() != WidgetBase::wt_Component && - currentWidget()->baseType() != WidgetBase::wt_Region)) { - return; - } - - if (!m_firstObject && type == WidgetBase::wt_Pin) { - setWidget(currentWidget()); - return ; - } - - if (!m_isObjectWidgetLine && !m_firstObject) { - return; - } - - if (!m_firstObject) { - setWidget(currentWidget()); - } - -} - -/** - * Called when the release event happened on an empty space. - * Cleans the message. - * Empty spaces are not only actual empty spaces, but also associations. - */ -void ToolBarStateOneWidget::mouseReleaseEmpty() -{ -} - -/** - * Sets the first object of the message using the specified object. - * The temporal visual message is created and mouse tracking enabled, so - * mouse events will be delivered. - * - * @param firstObject The first object of the message. - */ -void ToolBarStateOneWidget::setWidget(UMLWidget* firstObject) -{ - m_firstObject = firstObject; - - UMLWidget * umlwidget = 0; - //m_pUMLScene->viewport()->setMouseTracking(true); - if (widgetType() == WidgetBase::wt_Precondition) { - umlwidget = new PreconditionWidget(m_pUMLScene, static_cast(m_firstObject)); - - Dialog_Utils::askNameForWidget(umlwidget, i18n("Enter Precondition Name"), i18n("Enter the precondition"), i18n("new precondition")); - // Create the widget. Some setup functions can remove the widget. - } - - if (widgetType() == WidgetBase::wt_Pin) { - if (m_firstObject->baseType() == WidgetBase::wt_Activity) { - umlwidget = new PinWidget(m_pUMLScene, m_firstObject); - // Create the widget. Some setup functions can remove the widget. - } else if (m_firstObject->baseType() == WidgetBase::wt_Component) { - bool pressedOK = false; -#if QT_VERSION >= 0x050000 - QString name = QInputDialog::getText(UMLApp::app(), - i18n("Enter Port Name"), i18n("Enter the port"), - QLineEdit::Normal, - i18n("new port"), - &pressedOK); -#else - QString name = KInputDialog::getText(i18n("Enter Port Name"), i18n("Enter the port"), i18n("new port"), - &pressedOK, UMLApp::app()); -#endif - if (pressedOK) { - UMLPackage* component = static_cast(m_firstObject->umlObject()); - UMLObject *port = Object_Factory::createUMLObject(UMLObject::ot_Port, name, component); - umlwidget = Widget_Factory::createWidget(m_pUMLScene, port); - } - } - } - - if (umlwidget) { - m_pUMLScene->setupNewWidget(umlwidget); - } - -} - -/** - * Returns the widget type of this tool. - * - * @return The widget type of this tool. - */ -WidgetBase::WidgetType ToolBarStateOneWidget::widgetType() -{ - if (getButton() == WorkToolBar::tbb_Seq_Precondition) { - return WidgetBase::wt_Precondition; - } - - if (getButton() == WorkToolBar::tbb_Pin) { - return WidgetBase::wt_Pin; - } - // Shouldn't happen - Q_ASSERT(0); - return WidgetBase::wt_Pin; -} - -/** - * Goes back to the initial state. - */ -void ToolBarStateOneWidget::init() -{ - ToolBarStatePool::init(); -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/toolbarstateonewidget.h umbrello-kf6-15.08.1/umbrello/widgets/toolbarstateonewidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/toolbarstateonewidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/toolbarstateonewidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,59 +0,0 @@ -/*************************************************************************** - * 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) 2004-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef TOOLBARSTATEONEWIDGET_H -#define TOOLBARSTATEONEWIDGET_H - -#include "toolbarstatepool.h" -#include "widgetbase.h" - -/** - * Sequence tool to create components linked with one object in sequence diagram - * like precondition. - * With sequence tool, one objects is selected clicking with left button on - * it - */ -class ToolBarStateOneWidget : public ToolBarStatePool -{ - Q_OBJECT -public: - explicit ToolBarStateOneWidget(UMLScene *umlScene); - virtual ~ToolBarStateOneWidget(); - - virtual void cleanBeforeChange(); - - // FIXME: obsolete - virtual void mouseMove(QGraphicsSceneMouseEvent* ome); - -public Q_SLOTS: - virtual void slotWidgetRemoved(UMLWidget* widget); - -protected: - virtual void setCurrentElement(); - - virtual void mouseReleaseWidget(); - virtual void mouseReleaseEmpty(); - - void setWidget(UMLWidget* firstObject); - WidgetBase::WidgetType widgetType(); - - UMLWidget* m_firstObject; ///< The first object in the message. - - /** - * If there is a current widget, it is true if the press event happened on - * the line of an object, or false if it happened on a normal UMLWidget. - */ - bool m_isObjectWidgetLine; - -private: - virtual void init(); -}; - -#endif //TOOLBARSTATEONEWIDGET_H diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/umlwidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/umlwidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/umlwidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/umlwidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,1859 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#include "umlwidget.h" - -// local includes -#include "associationwidget.h" -#include "classifier.h" -#include "classpropertiesdialog.h" -#include "cmds.h" -#include "debug_utils.h" -#include "docwindow.h" -#include "floatingtextwidget.h" -#include "idchangelog.h" -#include "listpopupmenu.h" -#include "settingsdialog.h" -#include "uml.h" -#include "umldoc.h" -#include "umllistview.h" -#include "umlobject.h" -#include "umlscene.h" -#include "umlview.h" -#include "uniqueid.h" - -// kde includes -#include -#include - -// qt includes -#include -#include -#include -#include - -using namespace Uml; - -DEBUG_REGISTER_DISABLED(UMLWidget) - -const QSizeF UMLWidget::DefaultMinimumSize(50, 20); -const QSizeF UMLWidget::DefaultMaximumSize(1000, 5000); -const qreal UMLWidget::defaultMargin = 5; - -/** - * Creates a UMLWidget object. - * - * @param scene The view to be displayed on. - * @param type The WidgetType to construct. - * This must be set to the appropriate value by the constructors of inheriting classes. - * @param o The UMLObject to represent. - */ -UMLWidget::UMLWidget(UMLScene * scene, WidgetType type, UMLObject * o) - : WidgetBase(scene, type) -{ - init(); - m_umlObject = o; - if (m_umlObject) { - connect(m_umlObject, SIGNAL(modified()), this, SLOT(updateWidget())); - m_nId = m_umlObject->id(); - } -} - -/** - * Creates a UMLWidget object. - * - * @param scene The view to be displayed on. - * @param type The WidgetType to construct. - * This must be set to the appropriate value by the constructors of inheriting classes. - * @param id The id of the widget. - * The default value (id_None) will prompt generation of a new ID. - */ -UMLWidget::UMLWidget(UMLScene *scene, WidgetType type, Uml::ID::Type id) - : WidgetBase(scene, type) -{ - init(); - if (id == Uml::ID::None) - m_nId = UniqueID::gen(); - else - m_nId = id; -} - -/** - * Destructor. - */ -UMLWidget::~UMLWidget() -{ - cleanup(); -} - -/** - * Assignment operator - */ -UMLWidget& UMLWidget::operator=(const UMLWidget & other) -{ - if (this == &other) - return *this; - - WidgetBase::operator=(other); - - // assign members loaded/saved - m_useFillColor = other.m_useFillColor; - m_usesDiagramFillColor = other.m_usesDiagramFillColor; - m_usesDiagramUseFillColor = other.m_usesDiagramUseFillColor; - m_fillColor = other.m_fillColor; - m_Assocs = other.m_Assocs; - m_isInstance = other.m_isInstance; - m_instanceName = other.m_instanceName; - m_instanceName = other.m_instanceName; - m_showStereotype = other.m_showStereotype; - setX(other.x()); - setY(other.y()); - setRect(rect().x(), rect().y(), other.width(), other.height()); - - // assign volatile (non-saved) members - m_startMove = other.m_startMove; - m_nPosX = other.m_nPosX; - m_doc = other.m_doc; //new - m_resizable = other.m_resizable; - for (unsigned i = 0; i < FT_INVALID; ++i) - m_pFontMetrics[i] = other.m_pFontMetrics[i]; - m_activated = other.m_activated; - m_ignoreSnapToGrid = other.m_ignoreSnapToGrid; - m_ignoreSnapComponentSizeToGrid = other.m_ignoreSnapComponentSizeToGrid; - return *this; -} - -/** - * Overload '==' operator - */ -bool UMLWidget::operator==(const UMLWidget& other) const -{ - if (this == &other) - return true; - - if (m_baseType != other.m_baseType) { - return false; - } - - if (id() != other.id()) - return false; - - /* Testing the associations is already an exaggeration, no? - The type and ID should uniquely identify an UMLWidget. - */ - if (m_Assocs.count() != other.m_Assocs.count()) { - return false; - } - - // if(getBaseType() != wt_Text) // DON'T do this for floatingtext widgets, an infinite loop will result - // { - AssociationWidgetListIt assoc_it(m_Assocs); - AssociationWidgetListIt assoc_it2(other.m_Assocs); - AssociationWidget * assoc = 0, *assoc2 = 0; - while (assoc_it.hasNext() && assoc_it2.hasNext()) { - assoc = assoc_it.next(); - assoc2 = assoc_it2.next(); - - if (!(*assoc == *assoc2)) { - return false; - } - } - // } - return true; - // NOTE: In the comparison tests we are going to do, we don't need these values. - // They will actually stop things functioning correctly so if you change these, be aware of that. - /* - if(m_useFillColor != other.m_useFillColor) - return false; - if(m_nId != other.m_nId) - return false; - if(m_nX != other.m_nX) - return false; - if(m_nY != other.m_nY) - return false; - */ -} - -/** - * Sets the local id of the object. - * - * @param id The local id of the object. - */ -void UMLWidget::setLocalID(Uml::ID::Type id) -{ - m_nLocalID = id; -} - -/** - * Returns the local ID for this object. This ID is used so that - * many objects of the same @ref UMLObject instance can be on the - * same diagram. - * - * @return The local ID. - */ -Uml::ID::Type UMLWidget::localID() const -{ - return m_nLocalID; -} - -/** - * Returns the widget with the given ID. - * The default implementation tests the following IDs: - * - m_nLocalID - * - if m_umlObject is non NULL: m_umlObject->id() - * - m_nID - * Composite widgets override this function to test further owned widgets. - * - * @param id The ID to test this widget against. - * @return 'this' if id is either of m_nLocalID, m_umlObject->id(), or m_nId; - * else NULL. - */ -UMLWidget* UMLWidget::widgetWithID(Uml::ID::Type id) -{ - if (id == m_nLocalID || - (m_umlObject != NULL && id == m_umlObject->id()) || - id == m_nId) - return this; - return NULL; -} - -/** - * Compute the minimum possible width and height. - * - * @return QSizeF(mininum_width, minimum_height) - */ -QSizeF UMLWidget::minimumSize() const -{ - return m_minimumSize; -} - -/** - * This method is used to set the minimum size variable for this - * widget. - * - * @param newSize The size being set as minimum. - */ -void UMLWidget::setMinimumSize(const QSizeF& newSize) -{ - m_minimumSize = newSize; -} - -/** - * Compute the maximum possible width and height. - * - * @return maximum size - */ -QSizeF UMLWidget::maximumSize() -{ - return m_maximumSize; -} - -/** - * This method is used to set the maximum size variable for this - * widget. - * - * @param newSize The size being set as maximum. - */ -void UMLWidget::setMaximumSize(const QSizeF& newSize) -{ - m_maximumSize = newSize; -} - -/** - * Event handler for context menu events. - */ -void UMLWidget::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) -{ - WidgetBase::contextMenuEvent(event); -} - -/** - * Moves the widget to a new position using the difference between the - * current position and the new position. - * This method doesn't adjust associations. It only moves the widget. - * - * It can be overridden to constrain movement only in one axis even when - * the user isn't constraining the movement with shift or control buttons, for example. - * The movement policy set here is applied whenever the widget is moved, being it - * moving it explicitly, or as a part of a selection but not receiving directly the - * mouse events. - * - * Default behaviour is move the widget to the new position using the diffs. - * @see constrainMovementForAllWidgets - * - * @param diffX The difference between current X position and new X position. - * @param diffY The difference between current Y position and new Y position. - */ -void UMLWidget::moveWidgetBy(qreal diffX, qreal diffY) -{ - setX(x() + diffX); - setY(y() + diffY); -} - -/** - * Modifies the value of the diffX and diffY variables used to move the widgets. - * - * It can be overridden to constrain movement of all the selected widgets only in one - * axis even when the user isn't constraining the movement with shift or control - * buttons, for example. - * The difference with moveWidgetBy is that the diff positions used here are - * applied to all the selected widgets instead of only to m_widget, and that - * moveWidgetBy, in fact, moves the widget, and here simply the diff positions - * are modified. - * - * Default behaviour is do nothing. - * @see moveWidgetBy - * - * @param diffX The difference between current X position and new X position. - * @param diffY The difference between current Y position and new Y position. - */ -void UMLWidget::constrainMovementForAllWidgets(qreal &diffX, qreal &diffY) -{ - Q_UNUSED(diffX) Q_UNUSED(diffY) -} - -/** - * Bring the widget at the pressed position to the foreground. - */ -void UMLWidget::toForeground() -{ - QRectF rect = QRectF(scenePos(), QSizeF(width(), height())); - QList items = scene()->items(rect, Qt::IntersectsItemShape, Qt::DescendingOrder); - DEBUG(DBG_SRC) << "items at " << rect << " = " << items.count(); - if (items.count() > 1) { - foreach(QGraphicsItem* i, items) { - UMLWidget* w = dynamic_cast(i); - if (w) { - DEBUG(DBG_SRC) << "item=" << w->name() << " with zValue=" << w->zValue(); - if (w->name() != name()) { - if (w->zValue() >= zValue()) { - setZValue(w->zValue() + 1.0); - DEBUG(DBG_SRC) << "bring to foreground with zValue: " << zValue(); - } - } - } - } - } - else { - setZValue(0.0); - } - DEBUG(DBG_SRC) << "zValue is " << zValue(); -} - -/** - * Handles a mouse press event. - * It'll select the widget (or mark it to be deselected) and prepare it to - * be moved or resized. Go on reading for more info about this. - * - * Widget values and message bar status are saved. - * - * If shift or control buttons are pressed, we're in move area no matter - * where the button was pressed in the widget. Moreover, if the widget - * wasn't already selected, it's added to the selection. If already selected, - * it's marked to be deselected when releasing the button (provided it isn't - * moved). - * Also, if the widget is already selected with other widgets but shift nor - * control buttons are pressed, we're in move area. If finally we don't move - * the widget, it's selected and the other widgets deselected when releasing - * the left button. - * - * If shift nor control buttons are pressed, we're facing a single selection. - * Depending on the position of the cursor, we're in move or in resize area. - * If the widget wasn't selected (both when there are no widgets selected, or - * when there're other widgets selected but not the one receiving the press - * event) it's selected and the others deselected, if any. If already selected, - * it's marked to be deselected when releasing the button (provided it wasn't - * moved or resized). - * - * @param event The QGraphicsSceneMouseEvent event. - */ -void UMLWidget::mousePressEvent(QGraphicsSceneMouseEvent *event) -{ - if (event->button() != Qt::LeftButton) { - event->ignore(); - return; - } - event->accept(); - DEBUG(DBG_SRC) << "widget = " << name() << " / type = " << baseTypeStr(); - - toForeground(); - - m_startMovePostion = pos(); - m_startResizeSize = QSizeF(width(), height()); - - // saving the values of the widget - m_pressOffset = event->scenePos() - pos(); - DEBUG(DBG_SRC) << "press offset=" << m_pressOffset; - - m_oldStatusBarMsg = UMLApp::app()->statusBarMsg(); - - if (event->modifiers() == Qt::ShiftModifier || event->modifiers() == Qt::ControlModifier) { - m_shiftPressed = true; - - if (event->button() == Qt::LeftButton) { - m_inMoveArea = true; - } - - if (!isSelected()) { - selectMultiple(event); - } - return; - } - - m_shiftPressed = false; - - int count = m_scene->selectedCount(true); - if (event->button() == Qt::LeftButton) { - if (isSelected() && count > 1) { - // single selection is made in release event if the widget wasn't moved - m_inMoveArea = true; - m_oldPos = pos(); - return; - } - - if (isInResizeArea(event)) { - m_inResizeArea = true; - m_oldW = width(); - m_oldH = height(); - } else { - m_inMoveArea = true; - } - } - - // if widget wasn't selected, or it was selected but with other widgets also selected - if (!isSelected() || count > 1) { - selectSingle(event); - } -} - -/** - * Handles a mouse move event. - * It resizes or moves the widget, depending on where the cursor is pressed - * on the widget. Go on reading for more info about this. - * - * If resizing, the widget is resized using UMLWidget::resizeWidget (where specific - * widget resize constraint can be applied), and then the associations are - * adjusted. - * The resizing can be constrained also to a specific axis using control - * and shift buttons. If on or another is pressed, it's constrained to X axis. - * If both are pressed, it's constrained to Y axis. - * - * If not resizing, the widget is being moved. If the move is being started, - * the selection bounds are set (which includes updating the list of selected - * widgets). - * The difference between the previous position of the selection and the new - * one is got (taking in account the selection bounds so widgets don't go - * beyond the scene limits). Then, it's constrained to X or Y axis depending - * on shift and control buttons. - * A further constraint is made using constrainMovementForAllWidgets (for example, - * if the widget that receives the event can only be moved in Y axis, with this - * method the movement of all the widgets in the selection can be constrained to - * be moved only in Y axis). - * Then, all the selected widgets are moved using moveWidgetBy (where specific - * widget movement constraint can be applied) and, if a certain amount of time - * passed from the last move event, the associations are also updated (they're - * not updated always to be easy on the CPU). Finally, the scene is resized, - * and selection bounds updated. - * - * @param event The QGraphicsSceneMouseEvent event. - */ -void UMLWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* event) -{ - if (m_inResizeArea) { - resize(event); - return; - } - - if (!m_moved) { - UMLApp::app()->document()->writeToStatusBar(i18n("Hold shift or ctrl to move in X axis. Hold shift and control to move in Y axis. Right button click to cancel move.")); - - m_moved = true; - //Maybe needed by AssociationWidget - m_startMove = true; - - setSelectionBounds(); - } - - QPointF position = event->scenePos() - m_pressOffset; - qreal diffX = position.x() - x(); - qreal diffY = position.y() - y(); - - if ((event->modifiers() & Qt::ShiftModifier) && (event->modifiers() & Qt::ControlModifier)) { - // move only in Y axis - diffX = 0; - } else if ((event->modifiers() & Qt::ShiftModifier) || (event->modifiers() & Qt::ControlModifier)) { - // move only in X axis - diffY = 0; - } - - constrainMovementForAllWidgets(diffX, diffY); - - // nothing to move - if (diffX == 0 && diffY == 0) { - return; - } - - QPointF delta = event->scenePos() - event->lastScenePos(); - adjustUnselectedAssocs(delta.x(), delta.y()); - - DEBUG(DBG_SRC) << "diffX=" << diffX << " / diffY=" << diffY; - foreach(UMLWidget* widget, umlScene()->selectedWidgets()) { - widget->moveWidgetBy(diffX, diffY); - widget->slotSnapToGrid(); - } - - // Move any selected associations. - foreach(AssociationWidget* aw, m_scene->selectedAssocs()) { - if (aw->isSelected()) { - aw->moveEntireAssoc(diffX, diffY); - } - } - - umlScene()->resizeSceneToItems(); -} - -/** - * Handles a mouse release event. - * It selects or deselects the widget and cancels or confirms the move or - * resize. Go on reading for more info about this. - * No matter which tool is selected, Z position of widget is updated. - * - * Middle button release resets the selection. - * Left button release, if it wasn't moved nor resized, selects the widget - * and deselect the others if it wasn't selected and there were other widgets - * selected. If the widget was marked to be deselected, deselects it. - * If it was moved or resized, the document is set to modified if position - * or size changed. Also, if moved, all the associations are adjusted because - * the timer could have prevented the adjustment in the last move event before - * the release. - * If mouse was pressed in resize area, cursor is set again to normal cursor - * Right button release if right button was pressed shows the pop up menu for - * the widget. - * If left button was pressed, it cancels the move or resize with a mouse move - * event at the same position than the cursor was when pressed. Another left - * button release is also sent. - * - * @param event The QGraphicsSceneMouseEvent event. - */ -void UMLWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) -{ - if (!m_moved && !m_resized) { - if (!m_shiftPressed && (m_scene->selectedCount(true) > 1)) { - selectSingle(event); - } else if (!isSelected()) { - deselect(event); - } - } else { - // Commands - if (m_moved) { - int selectionCount = umlScene()->selectedWidgets().count(); - if (selectionCount > 1) { - UMLApp::app()->beginMacro(i18n("Move widgets")); - } - foreach(UMLWidget* widget, umlScene()->selectedWidgets()) { - UMLApp::app()->executeCommand(new Uml::CmdMoveWidget(widget)); - } - if (selectionCount > 1) { - UMLApp::app()->endMacro(); - } - m_moved = false; - } else { - UMLApp::app()->executeCommand(new Uml::CmdResizeWidget(this)); - m_resized = false; - } - - if ((m_inMoveArea && wasPositionChanged()) || - (m_inResizeArea && wasSizeChanged())) { - umlDoc()->setModified(true); - } - - UMLApp::app()->document()->writeToStatusBar(m_oldStatusBarMsg); - } - - if (m_inResizeArea) { - m_inResizeArea = false; - m_scene->activeView()->setCursor(Qt::ArrowCursor); - } else { - m_inMoveArea = false; - } -} - -/** - * Event handler for mouse double click events. - * @param event the QGraphicsSceneMouseEvent event. - */ -void UMLWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) -{ - if (event->button() == Qt::LeftButton) { - DEBUG(DBG_SRC) << "widget = " << name() << " / type = " << baseTypeStr(); - switch(baseType()) { - case WidgetBase::wt_Message: // will be handled in its class - QGraphicsItem::mouseDoubleClickEvent(event); - break; - default: - showPropertiesDialog(); - event->accept(); - break; - } - } -} - -/** - * Return the start position of the move action. - * @return point where the move began - */ -QPointF UMLWidget::startMovePosition() const -{ - return m_startMovePostion; -} - -/** - * Set the start position of the move action. - * @param position point where the move began - */ -void UMLWidget::setStartMovePosition(const QPointF &position) -{ - m_startMovePostion = position; -} - -/** - * Return the start size of the resize action. - * @return size where the resize began - */ -QSizeF UMLWidget::startResizeSize() const -{ - return m_startResizeSize; -} - -/** - * Resizes the widget. - * It's called from resize, after the values are constrained and before - * the associations are adjusted. - * - * Default behaviour is resize the widget using the new size values. - * @see resize - * - * @param newW The new width for the widget. - * @param newH The new height for the widget. - */ -void UMLWidget::resizeWidget(qreal newW, qreal newH) -{ - setSize(newW, newH); -} - -/** - * When a widget changes this slot captures that signal. - */ -void UMLWidget::updateWidget() -{ - updateGeometry(); - switch (m_baseType) { - case WidgetBase::wt_Class: - m_scene->createAutoAttributeAssociations(this); - break; - case WidgetBase::wt_Entity: - m_scene->createAutoConstraintAssociations(this); - break; - default: - break; - } - - if (isVisible()) - update(); -} - -/** - * Apply possible constraints to the given candidate width and height. - * The default implementation limits input values to the bounds returned - * by minimumSize()/maximumSize(). - * - * @param width input value, may be modified by the constraint - * @param height input value, may be modified by the constraint - */ -void UMLWidget::constrain(qreal& width, qreal& height) -{ - QSizeF minSize = minimumSize(); - if (width < minSize.width()) - width = minSize.width(); - if (height < minSize.height()) - height = minSize.height(); - QSizeF maxSize = maximumSize(); - if (width > maxSize.width()) - width = maxSize.width(); - if (height > maxSize.height()) - height = maxSize.height(); - - if (fixedAspectRatio()) { - QSizeF size = rect().size(); - float aspectRatio = size.width() > 0 ? (float)size.height()/size.width() : 1; - height = width * aspectRatio; - } -} - -/** - * Initializes key attributes of the class. - */ -void UMLWidget::init() -{ - m_nId = Uml::ID::None; - m_nLocalID = UniqueID::gen(); - m_isInstance = false; - setMinimumSize(DefaultMinimumSize); - setMaximumSize(DefaultMaximumSize); - - m_font = QApplication::font(); - for (int i = (int)FT_INVALID - 1; i >= 0; --i) { - FontType fontType = (FontType)i; - setupFontType(m_font, fontType); - m_pFontMetrics[fontType] = new QFontMetrics(m_font); - } - - if (m_scene) { - m_useFillColor = true; - m_usesDiagramFillColor = true; - m_usesDiagramUseFillColor = true; - const Settings::OptionState& optionState = m_scene->optionState(); - m_fillColor = optionState.uiState.fillColor; - m_showStereotype = optionState.classState.showStereoType; - } else { - uError() << "SERIOUS PROBLEM - m_scene is NULL"; - m_useFillColor = false; - m_usesDiagramFillColor = false; - m_usesDiagramUseFillColor = false; - m_showStereotype = false; - } - - m_resizable = true; - m_fixedAspectRatio = false; - - m_startMove = false; - m_activated = false; - m_ignoreSnapToGrid = false; - m_ignoreSnapComponentSizeToGrid = false; - m_doc = UMLApp::app()->document(); - m_nPosX = 0; - connect(m_scene, SIGNAL(sigFillColorChanged(Uml::ID::Type)), this, SLOT(slotFillColorChanged(Uml::ID::Type))); - connect(m_scene, SIGNAL(sigLineColorChanged(Uml::ID::Type)), this, SLOT(slotLineColorChanged(Uml::ID::Type))); - connect(m_scene, SIGNAL(sigTextColorChanged(Uml::ID::Type)), this, SLOT(slotTextColorChanged(Uml::ID::Type))); - connect(m_scene, SIGNAL(sigLineWidthChanged(Uml::ID::Type)), this, SLOT(slotLineWidthChanged(Uml::ID::Type))); - - m_umlObject = 0; - - m_oldPos = QPointF(); - m_pressOffset = QPointF(); - m_oldW = 0; - m_oldH = 0; - - m_shiftPressed = false; - m_inMoveArea = false; - m_inResizeArea = false; - m_moved = false; - m_resized = false; - - setZValue(2.0); // default for most widgets -} - -/** - * This is usually called synchronously after menu.exec() and \a - * trigger's parent is always the ListPopupMenu which can be used to - * get the type of action of \a trigger. - * - * @note Subclasses can reimplement to handle specific actions and - * leave the rest to WidgetBase::slotMenuSelection. - */ -void UMLWidget::slotMenuSelection(QAction *trigger) -{ - if (!trigger) { - return; - } - - ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(trigger); - switch (sel) { - case ListPopupMenu::mt_Resize: - umlScene()->resizeSelection(); - break; - - default: - WidgetBase::slotMenuSelection(trigger); - break; - } -} - -/** - * Captures when another widget moves if this widget is linked to it. - * @see sigWidgetMoved - * - * @param id The id of object behind the widget. - */ -void UMLWidget::slotWidgetMoved(Uml::ID::Type /*id*/) -{ -} - -/** - * Captures a color change signal. - * - * @param viewID The id of the UMLScene behind the widget. - */ -void UMLWidget::slotFillColorChanged(Uml::ID::Type viewID) -{ - //only change if on the diagram concerned - if (m_scene->ID() != viewID) { - return; - } - if (m_usesDiagramFillColor) { - WidgetBase::setFillColor(m_scene->fillColor()); - } - if (m_usesDiagramUseFillColor) { - WidgetBase::setUseFillColor(m_scene->useFillColor()); - } - update(); -} - -/** - * Captures a text color change signal. - * - * @param viewID The id of the UMLScene behind the widget. - */ -void UMLWidget::slotTextColorChanged(Uml::ID::Type viewID) -{ - //only change if on the diagram concerned - if (m_scene->ID() != viewID) - return; - WidgetBase::setTextColor(m_scene->textColor()); - update(); -} - - -/** - * Captures a line color change signal. - * - * @param viewID The id of the UMLScene behind the widget. - */ -void UMLWidget::slotLineColorChanged(Uml::ID::Type viewID) -{ - //only change if on the diagram concerned - if (m_scene->ID() != viewID) - return; - - if (m_usesDiagramLineColor) { - WidgetBase::setLineColor(m_scene->lineColor()); - } - update(); -} - -/** - * Captures a linewidth change signal. - * - * @param viewID The id of the UMLScene behind the widget. - */ -void UMLWidget::slotLineWidthChanged(Uml::ID::Type viewID) -{ - //only change if on the diagram concerned - if (m_scene->ID() != viewID) { - return; - } - if (m_usesDiagramLineWidth) { - WidgetBase::setLineWidth(m_scene->lineWidth()); - } - update(); -} - -/** - * Set the status of using fill color (undo action) - * - * @param fc the status of using fill color. - */ -void UMLWidget::setUseFillColor(bool fc) -{ - if (useFillColor() != fc) { - UMLApp::app()->executeCommand(new CmdChangeUseFillColor(this, fc)); - } -} - -/** - * Set the status of using fill color. - * - * @param fc the status of using fill color. - */ -void UMLWidget::setUseFillColorCmd(bool fc) -{ - WidgetBase::setUseFillColor(fc); - update(); -} - -/** - * Overrides the method from WidgetBase. - */ -void UMLWidget::setTextColorCmd(const QColor &color) -{ - WidgetBase::setTextColor(color); - update(); -} - -/** - * Overrides the method from WidgetBase. - */ -void UMLWidget::setTextColor(const QColor &color) -{ - if (textColor() != color) { - UMLApp::app()->executeCommand(new CmdChangeTextColor(this, color)); - update(); - } -} - -/** - * Overrides the method from WidgetBase. - */ -void UMLWidget::setLineColorCmd(const QColor &color) -{ - WidgetBase::setLineColor(color); - update(); -} - -/** - * Overrides the method from WidgetBase. - */ -void UMLWidget::setLineColor(const QColor &color) -{ - if (lineColor() != color) { - UMLApp::app()->executeCommand(new CmdChangeLineColor(this, color)); - } -} - -/** - * Overrides the method from WidgetBase, execute CmdChangeLineWidth - */ -void UMLWidget::setLineWidth(uint width) -{ - if (lineWidth() != width) { - UMLApp::app()->executeCommand(new CmdChangeLineWidth(this, width)); - } -} - -/** - * Overrides the method from WidgetBase. - */ -void UMLWidget::setLineWidthCmd(uint width) -{ - WidgetBase::setLineWidth(width); - update(); -} - -/** - * Sets the background fill color - * - * @param color the new fill color - */ -void UMLWidget::setFillColor(const QColor &color) -{ - if (fillColor() != color) { - UMLApp::app()->executeCommand(new CmdChangeFillColor(this, color)); - } -} - -/** - * Sets the background fill color - * - * @param color the new fill color - */ -void UMLWidget::setFillColorCmd(const QColor &color) -{ - WidgetBase::setFillColor(color); - update(); -} - -/** - * Activate the object after serializing it from a QDataStream - * - * @param ChangeLog - * @return true for success - */ -bool UMLWidget::activate(IDChangeLog* /*ChangeLog = 0 */) -{ - if (widgetHasUMLObject(m_baseType) && m_umlObject == NULL) { - m_umlObject = m_doc->findObjectById(m_nId); - if (m_umlObject == NULL) { - uError() << "cannot find UMLObject with id=" << Uml::ID::toString(m_nId); - return false; - } - } - setFontCmd(m_font); - setSize(width(), height()); - m_activated = true; - updateGeometry(); - if (m_scene->getPaste()) { - FloatingTextWidget * ft = 0; - QPointF point = m_scene->getPastep-kf6oint(); - int x = point.x() + this->x(); - int y = point.y() + this->y(); - if (m_scene->type() == Uml::DiagramType::Sequence) { - switch (baseType()) { - case WidgetBase::wt_Object: - case WidgetBase::wt_Precondition : - setY(this->y()); - setX(x); - break; - - case WidgetBase::wt_Message: - setY(this->y()); - setX(x); - break; - - case WidgetBase::wt_Text: - ft = static_cast(this); - if (ft->textRole() == Uml::TextRole::Seq_Message) { - setX(x); - setY(this->y()); - } else { - setX(this->x()); - setY(this->y()); - } - break; - - default: - setY(y); - break; - }//end switch base type - }//end if sequence - else { - setX(x); - setY(y); - } - }//end if pastep-kf6oint - else { - setX(this->x()); - setY(this->y()); - } - if (m_scene->getPaste()) - m_scene->createAutoAssociations(this); - updateGeometry(); - return true; -} - -/** - * Returns true if the Activate method has been called for this instance - * - * @return The activate status. - */ -bool UMLWidget::isActivated() const -{ - return m_activated; -} - -/** - * Set the m_activated flag of a widget but does not perform the Activate method - * - * @param active Status of activation is to be set. - */ -void UMLWidget::setActivated(bool active /*=true*/) -{ - m_activated = active; -} - -/** - * Adds an already created association to the list of - * associations that include this UMLWidget - */ -void UMLWidget::addAssoc(AssociationWidget* pAssoc) -{ - if (pAssoc && !m_Assocs.contains(pAssoc)) { - m_Assocs.append(pAssoc); - } -} - -/** - * Removes an already created association from the list of - * associations that include this UMLWidget - */ -void UMLWidget::removeAssoc(AssociationWidget* pAssoc) -{ - if (pAssoc) { - m_Assocs.removeAll(pAssoc); - } -} - -/** - * Adjusts associations with the given co-ordinates - * - * @param dx The amount by which the widget moved in X direction. - * @param dy The amount by which the widget moved in Y direction. - */ -void UMLWidget::adjustAssocs(qreal dx, qreal dy) -{ - // don't adjust Assocs on file load, as - // the original positions, which are stored in XMI - // should be reproduced exactly - // (don't try to reposition assocs as long - // as file is only partly loaded -> reposition - // could be misguided) - /// @todo avoid trigger of this event during load - if (m_doc->loading()) { - // don't recalculate the assocs during load of XMI - // -> return immediately without action - return; - } - - foreach(AssociationWidget* assocwidget, m_Assocs) { - assocwidget->saveIdealTextPositions(); - } - - foreach(AssociationWidget* assocwidget, m_Assocs) { - assocwidget->widgetMoved(this, dx, dy); - } -} - -/** - * Adjusts all unselected associations with the given co-ordinates - * - * @param dx The amount by which the widget moved in X direction. - * @param dy The amount by which the widget moved in Y direction. - */ -void UMLWidget::adjustUnselectedAssocs(qreal dx, qreal dy) -{ - foreach(AssociationWidget* assocwidget, m_Assocs) { - if (!assocwidget->isSelected()) - assocwidget->saveIdealTextPositions(); - } - - foreach(AssociationWidget* assocwidget, m_Assocs) { - if (!assocwidget->isSelected()) { - assocwidget->widgetMoved(this, dx, dy); - } - } -} - -/** - * Show a properties dialog for a UMLWidget. - */ -void UMLWidget::showPropertiesDialog() -{ - // will already be selected so make sure docWindow updates the doc - // back it the widget - UMLApp::app()->docWindow()->updateDocumentation(false); - QPointer dlg = new ClassPropertiesDialog((QWidget*)UMLApp::app(), this); - - if (dlg->exec()) { - UMLApp::app()->docWindow()->showDocumentation(umlObject(), true); - m_doc->setModified(true); - } - dlg->close(); //wipe from memory - delete dlg; -} - -/** - * Move the widget by an X and Y offset relative to - * the current position. - */ -void UMLWidget::moveByLocal(qreal dx, qreal dy) -{ - qreal newX = x() + dx; - qreal newY = y() + dy; - setX(newX); - setY(newY); - adjustAssocs(dx, dy); -} - -/** - * Set the pen. - */ -void UMLWidget::setPenFromSettings(QPainter & p) -{ - p.setPen(QPen(m_lineColor, m_lineWidth)); -} - -/** - * Set the pen. - */ -void UMLWidget::setPenFromSettings(QPainter *p) -{ - p->setPen(QPen(m_lineColor, m_lineWidth)); -} - -/** - * Returns the cursor to be shown when resizing the widget. - * Default cursor is KCursor::sizeFDiagCursor(). - * - * @return The cursor to be shown when resizing the widget. - */ -QCursor UMLWidget::resizeCursor() const -{ - return Qt::SizeFDiagCursor; -} - -/** - * Checks if the mouse is in resize area (right bottom corner), and sets - * the cursor depending on that. - * The cursor used when resizing is gotten from resizeCursor(). - * - * @param me The QMouseEVent to check. - * @return true if the mouse is in resize area, false otherwise. - */ -bool UMLWidget::isInResizeArea(QGraphicsSceneMouseEvent *me) -{ - qreal m = 10.0; - const qreal w = width(); - const qreal h = height(); - - // If the widget itself is very small then make the resize area small, too. - // Reason: Else it becomes impossible to do a move instead of resize. - if (w - m < m || h - m < m) { - m = 2.0; - } - - if (m_resizable && - me->scenePos().x() >= (x() + w - m) && - me->scenePos().y() >= (y() + h - m)) { - m_scene->activeView()->setCursor(resizeCursor()); - return true; - } else { - m_scene->activeView()->setCursor(Qt::ArrowCursor); - return false; - } -} - -/** - * calculate content related size of widget. - * - * @return calculated widget size - */ -QSizeF UMLWidget::calculateSize(bool withExtensions /* = true */) const -{ - Q_UNUSED(withExtensions) - return QSizeF(width(), height()); -} - -/** - * Resize widget to minimum size. - */ -void UMLWidget::resize() -{ - qreal oldW = width(); - qreal oldH = height(); - // @TODO minimumSize() do not work in all cases, we need a dedicated autoResize() method - QSizeF size = minimumSize(); - setSize(size.width(), size.height()); - DEBUG(DBG_SRC) << "size=" << size; - adjustAssocs(size.width()-oldW, size.height()-oldH); -} - -/** - * Resizes the widget and adjusts the associations. - * It's called when a mouse move event happens and the cursor was - * in resize area when pressed. - * Resizing can be constrained to an specific axis using control and shift buttons. - * - * @param me The QGraphicsSceneMouseEvent to get the values from. - */ -void UMLWidget::resize(QGraphicsSceneMouseEvent *me) -{ - // TODO the status message lies for at least MessageWidget which could only be resized vertical - UMLApp::app()->document()->writeToStatusBar(i18n("Hold shift or ctrl to move in X axis. Hold shift and control to move in Y axis. Right button click to cancel resize.")); - - m_resized = true; - - qreal newW = m_oldW + me->scenePos().x() - x() - m_pressOffset.x(); - qreal newH = m_oldH + me->scenePos().y() - y() - m_pressOffset.y(); - - if ((me->modifiers() & Qt::ShiftModifier) && (me->modifiers() & Qt::ControlModifier)) { - //Move in Y axis - newW = m_oldW; - } else if ((me->modifiers() & Qt::ShiftModifier) || (me->modifiers() & Qt::ControlModifier)) { - //Move in X axis - newH = m_oldH; - } - - constrain(newW, newH); - resizeWidget(newW, newH); - DEBUG(DBG_SRC) << "event=" << me->scenePos() << "/ pos=" << pos() << " / newW=" << newW << " / newH=" << newH; - QPointF delta = me->scenePos() - me->lastScenePos(); - adjustAssocs(delta.x(), delta.y()); - - m_scene->resizeSceneToItems(); -} - -/** - * Checks if the size of the widget changed respect to the size that - * it had when press event was fired. - * - * @return true if was resized, false otherwise. - */ -bool UMLWidget::wasSizeChanged() -{ - return m_oldW != width() || m_oldH != height(); -} - -/** - * Checks if the position of the widget changed respect to the position that - * it had when press event was fired. - * - * @return true if was moved, false otherwise. - */ -bool UMLWidget::wasPositionChanged() -{ - return m_oldPos != pos(); -} - -/** - * Fills m_selectedWidgetsList and sets the selection bounds ((m_min/m_max)X/Y attributes). - */ -void UMLWidget::setSelectionBounds() -{ -} - -void UMLWidget::setSelectedFlag(bool _select) -{ - WidgetBase::setSelected(_select); -} - -/** - * Sets the state of whether the widget is selected. - * - * @param _select The state of whether the widget is selected. - */ -void UMLWidget::setSelected(bool _select) -{ - WidgetBase::setSelected(_select); - const WidgetBase::WidgetType wt = m_baseType; - if (_select) { - if (m_scene->selectedCount() == 0) { - if (widgetHasUMLObject(wt)) { - UMLApp::app()->docWindow()->showDocumentation(m_umlObject, false); - } else { - UMLApp::app()->docWindow()->showDocumentation(this, false); - } - }//end if - /* if (wt != wt_Text && wt != wt_Box) { - setZ(9);//keep text on top and boxes behind so don't touch Z value - } */ - } else { - /* if (wt != wt_Text && wt != wt_Box) { - setZ(m_origZ); - } */ - if (isSelected()) - UMLApp::app()->docWindow()->updateDocumentation(true); - } - - // TODO: isn't this handled by toForeground() ? - const QPoint pos(x(), y()); - UMLWidget *bkgnd = m_scene->widgetAt(pos); - if (bkgnd && bkgnd != this && _select) { - DEBUG(DBG_SRC) << "setting Z to " << bkgnd->zValue() + 1.0 << ", SelectState: " << _select; - setZValue(bkgnd->zValue() + 1.0); - } - - update(); - - // selection changed, we have to make sure the copy and paste items - // are correctly enabled/disabled - UMLApp::app()->slotCopyChanged(); - - // select in tree view as done for diagrams - if (_select) { - UMLListViewItem * item = UMLApp::app()->listView()->findItem(id()); - if (item) - UMLApp::app()->listView()->setCurrentItem(item); - else - UMLApp::app()->listView()->clearSelection(); - } -} - -/** - * Selects the widget and clears the other selected widgets, if any. - * - * @param me The QGraphicsSceneMouseEvent which made the selection. - */ -void UMLWidget::selectSingle(QGraphicsSceneMouseEvent *me) -{ - m_scene->clearSelected(); - - // Adds the widget to the selected widgets list, but as it has been cleared - // only the current widget is selected. - selectMultiple(me); -} - -/** - * Selects the widget and adds it to the list of selected widgets. - * - * @param me The QGraphicsSceneMouseEvent which made the selection. - */ -void UMLWidget::selectMultiple(QGraphicsSceneMouseEvent *me) -{ - Q_UNUSED(me); - - setSelected(true); -} - -/** - * Deselects the widget and removes it from the list of selected widgets. - * - * @param me The QGraphicsSceneMouseEvent which made the selection. - */ -void UMLWidget::deselect(QGraphicsSceneMouseEvent *me) -{ - Q_UNUSED(me); - - setSelected(false); -} - -/** - * Clears the selection, resets the toolbar and deselects the widget. - */ -//void UMLWidget::resetSelection() -//{ -// m_scene->clearSelected(); -// m_scene->resetToolbar(); -// setSelected(false); -//} - -/** - * Sets the view the widget is on. - * - * @param scene The UMLScene the widget is on. - */ -void UMLWidget::setScene(UMLScene *scene) -{ - //remove signals from old view - was probably 0 anyway - disconnect(m_scene, SIGNAL(sigFillColorChanged(Uml::ID::Type)), this, SLOT(slotFillColorChanged(Uml::ID::Type))); - disconnect(m_scene, SIGNAL(sigTextColorChanged(Uml::ID::Type)), this, SLOT(slotTextColorChanged(Uml::ID::Type))); - disconnect(m_scene, SIGNAL(sigLineWidthChanged(Uml::ID::Type)), this, SLOT(slotLineWidthChanged(Uml::ID::Type))); - m_scene = scene; - connect(m_scene, SIGNAL(sigFillColorChanged(Uml::ID::Type)), this, SLOT(slotFillColorChanged(Uml::ID::Type))); - connect(m_scene, SIGNAL(sigTextColorChanged(Uml::ID::Type)), this, SLOT(slotTextColorChanged(Uml::ID::Type))); - connect(m_scene, SIGNAL(sigLineWidthChanged(Uml::ID::Type)), this, SLOT(slotLineWidthChanged(Uml::ID::Type))); -} - -/** - * Sets the x-coordinate. - * Currently, the only class that reimplements this method is - * ObjectWidget. - * - * @param x The x-coordinate to be set. - */ -void UMLWidget::setX(qreal x) -{ - QGraphicsObject::setX(x); -} - -/** - * Sets the y-coordinate. - * Currently, the only class that reimplements this method is - * ObjectWidget. - * - * @param y The y-coordinate to be set. - */ -void UMLWidget::setY(qreal y) -{ - QGraphicsObject::setY(y); -} - -/** - * Used to cleanup any other widget it may need to delete. - * Used by child classes. This should be called before deleting a widget of a diagram. - */ -void UMLWidget::cleanup() -{ -} - -/** - * Tells the widget to snap to grid. - * Will use the grid settings of the @ref UMLView it belongs to. - */ -void UMLWidget::slotSnapToGrid() -{ - if (!m_ignoreSnapToGrid) { - qreal newX = m_scene->snappedX(x()); - setX(newX); - qreal newY = m_scene->snappedY(y()); - setY(newY); - } -} - -/** - * Returns whether the widget type has an associated UMLObject - */ -bool UMLWidget::widgetHasUMLObject(WidgetBase::WidgetType type) -{ - if (type == WidgetBase::wt_Actor || - type == WidgetBase::wt_UseCase || - type == WidgetBase::wt_Class || - type == WidgetBase::wt_Interface || - type == WidgetBase::wt_Enum || - type == WidgetBase::wt_Datatype || - type == WidgetBase::wt_Package || - type == WidgetBase::wt_Component || - type == WidgetBase::wt_Port || - type == WidgetBase::wt_Node || - type == WidgetBase::wt_Artifact || - type == WidgetBase::wt_Object) { - return true; - } else { - return false; - } -} - -/** - * Set m_ignoreSnapToGrid. - */ -void UMLWidget::setIgnoreSnapToGrid(bool to) -{ - m_ignoreSnapToGrid = to; -} - -/** - * Return the value of m_ignoreSnapToGrid. - */ -bool UMLWidget::getIgnoreSnapToGrid() const -{ - return m_ignoreSnapToGrid; -} - -/** - * Sets the size. - * If m_scene->snapComponentSizeToGrid() is true, then - * set the next larger size that snaps to the grid. - */ -void UMLWidget::setSize(qreal width, qreal height) -{ - // snap to the next larger size that is a multiple of the grid - if (!m_ignoreSnapComponentSizeToGrid - && m_scene->snapComponentSizeToGrid()) { - // integer divisions - int numX = width / m_scene->snapX(); - int numY = height / m_scene->snapY(); - // snap to the next larger valid value - if (width > numX * m_scene->snapX()) - width = (numX + 1) * m_scene->snapX(); - if (height > numY * m_scene->snapY()) - height = (numY + 1) * m_scene->snapY(); - } - - setRect(rect().x(), rect().y(), width, height); -} - -/** - * Sets the size with another size. - */ -void UMLWidget::setSize(const QSizeF& size) -{ - setSize(size.width(), size.height()); -} - -/** - * Update the size of this widget. - */ -void UMLWidget::updateGeometry() -{ - if (m_doc->loading()) { - return; - } - qreal oldW = width(); - qreal oldH = height(); - QSizeF size = calculateSize(); - qreal clipWidth = size.width(); - qreal clipHeight = size.height(); - constrain(clipWidth, clipHeight); - setSize(clipWidth, clipHeight); - slotSnapToGrid(); - adjustAssocs(size.width()-oldW, size.height()-oldH); -} - -/** - * clip the size of this widget against the - * minimal and maximal limits. - */ -void UMLWidget::clipSize() -{ - qreal clipWidth = width(); - qreal clipHeight = height(); - constrain(clipWidth, clipHeight); - setSize(clipWidth, clipHeight); -} - -/** - * Template Method, override this to set the default font metric. - */ -void UMLWidget::setDefaultFontMetrics(QFont &font, UMLWidget::FontType fontType) -{ - setupFontType(font, fontType); - setFontMetrics(fontType, QFontMetrics(font)); -} - -void UMLWidget::setupFontType(QFont &font, UMLWidget::FontType fontType) -{ - switch (fontType) { - case FT_NORMAL: - font.setBold(false); - font.setItalic(false); - font.setUnderline(false); - break; - case FT_BOLD: - font.setBold(true); - font.setItalic(false); - font.setUnderline(false); - break; - case FT_ITALIC: - font.setBold(false); - font.setItalic(true); - font.setUnderline(false); - break; - case FT_UNDERLINE: - font.setBold(false); - font.setItalic(false); - font.setUnderline(true); - break; - case FT_BOLD_ITALIC: - font.setBold(true); - font.setItalic(true); - font.setUnderline(false); - break; - case FT_BOLD_UNDERLINE: - font.setBold(true); - font.setItalic(false); - font.setUnderline(true); - break; - case FT_ITALIC_UNDERLINE: - font.setBold(false); - font.setItalic(true); - font.setUnderline(true); - break; - case FT_BOLD_ITALIC_UNDERLINE: - font.setBold(true); - font.setItalic(true); - font.setUnderline(true); - break; - default: return; - } -} - -void UMLWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - Q_UNUSED(option); - Q_UNUSED(widget); - - if (option->state & QStyle::State_Selected) { - const qreal w = width(); - const qreal h = height(); - const qreal s = 4; - QBrush brush(Qt::blue); - painter->fillRect(0, 0, s, s, brush); - painter->fillRect(0, 0 + h - s, s, s, brush); - painter->fillRect(0 + w - s, 0, s, s, brush); - - // Draw the resize anchor in the lower right corner. - // Don't draw it if the widget is so small that the - // resize anchor would cover up most of the widget. - if (m_resizable && w >= s+8 && h >= s+8) { - brush.setColor(Qt::red); - const int right = 0 + w; - const int bottom = 0 + h; - painter->drawLine(right - s, 0 + h - 1, 0 + w - 1, 0 + h - s); - painter->drawLine(right - (s*2), bottom - 1, right - 1, bottom - (s*2)); - painter->drawLine(right - (s*3), bottom - 1, right - 1, bottom - (s*3)); - } else { - painter->fillRect(0 + w - s, 0 + h - s, s, s, brush); - } - // debug info - if (Tracer::instance()->isEnabled(QLatin1String(metaObject()->className()))) { - painter->setPen(Qt::green); - painter->setBrush(Qt::NoBrush); - painter->drawPath(shape()); - painter->setPen(Qt::red); - painter->drawRect(boundingRect()); - // origin - painter->drawLine(-10, 0, 10, 0); - painter->drawLine(0, -10, 0, 10); - } - } - - if (umlScene()->isShowDocumentationIndicator() && hasDocumentation()) { - const qreal h = height(); - const qreal d = 8; - QPolygonF p; - p << QPointF(0, h - d) << QPointF(d, h) << QPointF(0, h); - painter->setPen(Qt::blue); - painter->setBrush(Qt::red); - painter->drawPolygon(p); - } -} - -/** - * Template Method, override this to set the default font metric. - */ -void UMLWidget::setDefaultFontMetrics(QFont &font, UMLWidget::FontType fontType, QPainter &painter) -{ - setupFontType(font, fontType); - painter.setFont(font); - setFontMetrics(fontType, painter.fontMetrics()); -} - -/** - * Returns the font metric used by this object for Text - * which uses bold/italic fonts. - */ -QFontMetrics &UMLWidget::getFontMetrics(UMLWidget::FontType fontType) const -{ - return *m_pFontMetrics[fontType]; -} - -/** - * Set the font metric to use. - */ -void UMLWidget::setFontMetrics(UMLWidget::FontType fontType, QFontMetrics fm) -{ - delete m_pFontMetrics[fontType]; - m_pFontMetrics[fontType] = new QFontMetrics(fm); -} - -/** - * Sets the font the widget is to use. - * - * @param font Font to be set. - */ -void UMLWidget::setFont(const QFont &font) -{ - QFont newFont = font; - forceUpdateFontMetrics(newFont, 0); - - if (m_font != newFont) { - UMLApp::app()->executeCommand(new CmdChangeFont(this, font)); - } -} - -/** - * Sets the font the widget is to use. - * - * @param font Font to be set. - */ -void UMLWidget::setFontCmd(const QFont &font) -{ - WidgetBase::setFont(font); - forceUpdateFontMetrics(0); - if (m_doc->loading()) - return; - update(); -} - -/** - * Updates font metrics for widgets current m_font - */ -void UMLWidget::forceUpdateFontMetrics(QPainter *painter) -{ - forceUpdateFontMetrics(m_font, painter); -} - -/** - * @note For performance Reasons, only FontMetrics for already used - * font types are updated. Not yet used font types will not get a font metric - * and will get the same font metric as if painter was zero. - * This behaviour is acceptable, because diagrams will always be shown on Display - * first before a special painter like a printer device is used. - */ -void UMLWidget::forceUpdateFontMetrics(QFont& font, QPainter *painter) -{ - if (painter == 0) { - for (int i = (int)FT_INVALID - 1; i >= 0; --i) { - if (m_pFontMetrics[(UMLWidget::FontType)i] != 0) - setDefaultFontMetrics(font, (UMLWidget::FontType)i); - } - } else { - for (int i2 = (int)FT_INVALID - 1; i2 >= 0; --i2) { - if (m_pFontMetrics[(UMLWidget::FontType)i2] != 0) - setDefaultFontMetrics(font, (UMLWidget::FontType)i2, *painter); - } - } - if (m_doc->loading()) - return; - // calculate the size, based on the new font metric - updateGeometry(); -} - -/** - * Set the status of whether to show Stereotype. - * - * @param flag True if stereotype shall be shown. - */ -void UMLWidget::setShowStereotype(bool flag) -{ - m_showStereotype = flag; - updateGeometry(); - update(); -} - -/** - * Returns the status of whether to show Stereotype. - * - * @return True if stereotype is shown. - */ -bool UMLWidget::showStereotype() const -{ - return m_showStereotype; -} - -/** - * Overrides the standard operation. - * - * @param me The move event. - */ -void UMLWidget::moveEvent(QGraphicsSceneMouseEvent* me) -{ - Q_UNUSED(me) -} - -void UMLWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) -{ - /* - Call after required actions in child class. - Type must be set in the child class. - */ - WidgetBase::saveToXMI(qDoc, qElement); - qElement.setAttribute(QLatin1String("xmi.id"), Uml::ID::toString(id())); - qElement.setAttribute(QLatin1String("x"), x()); - qElement.setAttribute(QLatin1String("y"), y()); - qElement.setAttribute(QLatin1String("width"), width()); - qElement.setAttribute(QLatin1String("height"), height()); - qElement.setAttribute(QLatin1String("isinstance"), m_isInstance); - if (!m_instanceName.isEmpty()) - qElement.setAttribute(QLatin1String("instancename"), m_instanceName); - if (m_showStereotype) - qElement.setAttribute(QLatin1String("showstereotype"), m_showStereotype); - - // Unique identifier for widget (todo: id() should be unique, new attribute - // should indicate the UMLObject's ID it belongs to) - qElement.setAttribute(QLatin1String("localid"), Uml::ID::toString(m_nLocalID)); -} - -bool UMLWidget::loadFromXMI(QDomElement & qElement) -{ - QString id = qElement.attribute(QLatin1String("xmi.id"), QLatin1String("-1")); - m_nId = Uml::ID::fromString(id); - - WidgetBase::loadFromXMI(qElement); - QString x = qElement.attribute(QLatin1String("x"), QLatin1String("0")); - QString y = qElement.attribute(QLatin1String("y"), QLatin1String("0")); - QString h = qElement.attribute(QLatin1String("height"), QLatin1String("0")); - QString w = qElement.attribute(QLatin1String("width"), QLatin1String("0")); - - setSize(w.toFloat(), h.toFloat()); - setX(x.toFloat()); - setY(y.toFloat()); - QString isinstance = qElement.attribute(QLatin1String("isinstance"), QLatin1String("0")); - m_isInstance = (bool)isinstance.toInt(); - m_instanceName = qElement.attribute(QLatin1String("instancename")); - QString showstereo = qElement.attribute(QLatin1String("showstereotype"), QLatin1String("0")); - m_showStereotype = (bool)showstereo.toInt(); - - QString localid = qElement.attribute(QLatin1String("localid"), QLatin1String("0")); - if (localid != QLatin1String("0")) { - m_nLocalID = Uml::ID::fromString(localid); - } - - return true; -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/umlwidget.h umbrello-kf6-15.08.1/umbrello/widgets/umlwidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/umlwidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/umlwidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,347 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef UMLWIDGET_H -#define UMLWIDGET_H - -#include "associationwidgetlist.h" -#include "basictypes.h" -#include "optionstate.h" -#include "umlwidgetlist.h" -#include "widgetbase.h" - -#include -#include - -class IDChangeLog; -class UMLDoc; -class UMLObject; -class UMLScene; - -class QPainter; -class QFontMetrics; - -/** - * This is the base class for nearly all graphical widgets. - * - * @short The base class for graphical UML objects. - * @author Paul Hensgen - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class UMLWidget : public WidgetBase -{ - Q_OBJECT -public: - - friend class ToolBarStateArrow; // for calling the mouse*Event handlers - - static const QSizeF DefaultMinimumSize; - static const QSizeF DefaultMaximumSize; - static const qreal defaultMargin; - - explicit UMLWidget(UMLScene *scene, WidgetType type = wt_UMLWidget, UMLObject *o = 0); - explicit UMLWidget(UMLScene *scene, WidgetType type = wt_UMLWidget, Uml::ID::Type id = Uml::ID::None); - virtual ~UMLWidget(); - - // Copy constructor - not implemented. - // UMLWidget(const UMLWidget& other); - - UMLWidget& operator=(const UMLWidget& other); - - bool operator==(const UMLWidget& other) const; - - void setLocalID(Uml::ID::Type id); - Uml::ID::Type localID() const; - - virtual UMLWidget* widgetWithID(Uml::ID::Type id); - - virtual QSizeF minimumSize() const; - void setMinimumSize(const QSizeF &size); - - virtual QSizeF maximumSize(); - void setMaximumSize(const QSizeF &size); - - virtual void setUseFillColor(bool fc); - void setUseFillColorCmd(bool fc); - - virtual void setTextColor(const QColor &color); - void setTextColorCmd(const QColor &color); - - virtual void setLineColor(const QColor &color); - void setLineColorCmd(const QColor &color); - - virtual void setLineWidth(uint width); - void setLineWidthCmd(uint width); - - virtual void setFillColor(const QColor &color); - void setFillColorCmd(const QColor &color); - - void setSelectedFlag(bool _select); - virtual void setSelected(bool _select); - - void setScene(UMLScene *scene); - - virtual bool activate(IDChangeLog* ChangeLog = 0); - - void setPenFromSettings(QPainter &p); - void setPenFromSettings(QPainter *p); - - virtual void setFont(const QFont &font); - void setFontCmd(const QFont &font); - - /** - * Returns whether we triggered the update of position movement. - * If so, you probably don't want to move it. - * - * @return The moving state. - */ - bool getStartMove() const { - return m_startMove; - } - - virtual void setX(qreal x); - virtual void setY(qreal y); - - /** - * Returns the height of widget. - */ - qreal height() const { - return rect().height(); - } - - /** - * Returns the width of the widget. - */ - qreal width() const { - return rect().width(); - } - - void setSize(qreal width, qreal height); - void setSize(const QSizeF& size); - - virtual void resizeWidget(qreal newW, qreal newH); - - bool getIgnoreSnapToGrid() const; - void setIgnoreSnapToGrid(bool to); - - void moveByLocal(qreal dx, qreal dy); - - void removeAssoc(AssociationWidget* pAssoc); - void addAssoc(AssociationWidget* pAssoc); - - /** - * Returns the list of associations connected to this widget. - */ - AssociationWidgetList & associationWidgetList() { - return m_Assocs; - } - - /** - * Read property of bool m_isInstance - */ - bool isInstance() const { - return m_isInstance; - } - - /** - * Write property of bool m_isInstance - */ - void setIsInstance(bool isInstance) { - m_isInstance = isInstance; - } - - /** - * Write property of m_instanceName - */ - void setInstanceName(const QString &instanceName) { - m_instanceName = instanceName; - } - - /** - * Read property of m_instanceName - */ - QString instanceName() const { - return m_instanceName; - } - - bool showStereotype() const; - virtual void setShowStereotype(bool flag); - - virtual void showPropertiesDialog(); - - virtual void adjustAssocs(qreal dx, qreal dy); - void adjustUnselectedAssocs(qreal dx, qreal dy); - - bool isActivated() const; - void setActivated(bool active = true); - - virtual void cleanup(); - - static bool widgetHasUMLObject(WidgetBase::WidgetType type); - - void updateGeometry(); - - void clipSize(); - - void forceUpdateFontMetrics(QPainter *painter); - void forceUpdateFontMetrics(QFont &font, QPainter *painter); - - virtual bool loadFromXMI(QDomElement &qElement); - virtual void saveToXMI(QDomDocument &qDoc, QDomElement &qElement); - - QPointF startMovePosition() const; - void setStartMovePosition(const QPointF &position); - - QSizeF startResizeSize() const; - - virtual QSizeF calculateSize(bool withExtensions = true) const; - void resize(); - - bool fixedAspectRatio() const { - return m_fixedAspectRatio; - } - - void setFixedAspectRatio(bool state) { - m_fixedAspectRatio = state; - } - - typedef enum { - FT_NORMAL = 0, - FT_BOLD = 1, - FT_ITALIC = 2, - FT_UNDERLINE = 3, - FT_BOLD_ITALIC = 4, - FT_BOLD_UNDERLINE = 5, - FT_ITALIC_UNDERLINE = 6, - FT_BOLD_ITALIC_UNDERLINE = 7, - FT_INVALID = 8 - } FontType; - - virtual void setDefaultFontMetrics(QFont &font, UMLWidget::FontType fontType); - virtual void setDefaultFontMetrics(QFont &font, UMLWidget::FontType fontType, QPainter &painter); - - QFontMetrics &getFontMetrics(UMLWidget::FontType fontType) const; - void setFontMetrics(UMLWidget::FontType fontType, QFontMetrics fm); - void setupFontType(QFont &font, UMLWidget::FontType fontType); - - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - -public Q_SLOTS: - virtual void updateWidget(); - virtual void slotMenuSelection(QAction* action); - virtual void slotWidgetMoved(Uml::ID::Type id); - virtual void slotFillColorChanged(Uml::ID::Type viewID); - virtual void slotLineColorChanged(Uml::ID::Type viewID); - virtual void slotTextColorChanged(Uml::ID::Type viewID); - virtual void slotLineWidthChanged(Uml::ID::Type viewID); - - void slotSnapToGrid(); - -signals: - /** - * Emit when the widget moves its' position. - * @param id The id of the object behind the widget. - */ - void sigWidgetMoved(Uml::ID::Type id); - -protected: - virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent* event); - virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); - virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); - virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event); - virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); - - virtual void moveEvent(QGraphicsSceneMouseEvent *event); - virtual void moveWidgetBy(qreal diffX, qreal diffY); - virtual void constrainMovementForAllWidgets(qreal &diffX, qreal &diffY); - virtual void constrain(qreal& width, qreal& height); - - virtual bool isInResizeArea(QGraphicsSceneMouseEvent *me); - virtual QCursor resizeCursor() const; - - void selectSingle(QGraphicsSceneMouseEvent *me); - void selectMultiple(QGraphicsSceneMouseEvent *me); - void deselect(QGraphicsSceneMouseEvent *me); - // void resetSelection(); - - void setSelectionBounds(); - - void resize(QGraphicsSceneMouseEvent *me); - - bool wasSizeChanged(); - bool wasPositionChanged(); - - ///////////////// Data Loaded/Saved ///////////////////////////////// - - /// A list of AssociationWidgets between the UMLWidget and other UMLWidgets in the diagram - AssociationWidgetList m_Assocs; - - QString m_instanceName; ///< instance name (used if on a deployment diagram) - bool m_isInstance; ///< holds whether this widget is a component instance (i.e. on a deployment diagram) - bool m_showStereotype; ///< should the stereotype be displayed - - ///////////////// End of Data Loaded/Saved ////////////////////////// - - Uml::ID::Type m_nLocalID; - bool m_startMove; - QPointF m_startMovePostion; - QSizeF m_startResizeSize; - int m_nPosX; - UMLDoc *m_doc; ///< shortcut for UMLApp::app()->getDocument() - bool m_resizable; - QFontMetrics *m_pFontMetrics[FT_INVALID]; - QSizeF m_minimumSize; - QSizeF m_maximumSize; - - /// true if the activate function has been called for this class instance - bool m_activated; - - /** - * Change Widget Behaviour - */ - bool m_ignoreSnapToGrid; - bool m_ignoreSnapComponentSizeToGrid; - bool m_fixedAspectRatio; - - /// The text in the status bar when the cursor was pressed. - QString m_oldStatusBarMsg; - - /// The X/Y offset from the position of the cursor when it was pressed to the - /// upper left corner of the widget. - QPointF m_pressOffset; - - /// The X/Y position the widget had when the movement started. - QPointF m_oldPos; - - /// The width/height the widget had when the resize started. - qreal m_oldW, m_oldH; - - /// If shift or control button were pressed in mouse press event. - bool m_shiftPressed; - - /** - * If cursor was in move/resize area when left button was pressed (and no - * other widgets were selected). - */ - bool m_inMoveArea, m_inResizeArea; - - /** - * If the widget was selected/moved/resized in the press and release cycle. - * Moved/resized is true if the widget was moved/resized even if the final - * position/size is the same as the starting one. - */ - bool m_moved, m_resized; - -private: - void init(); - void toForeground(); - -}; -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/usecasewidget.cpp umbrello-kf6-15.08.1/umbrello/widgets/usecasewidget.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/usecasewidget.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/usecasewidget.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,96 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header file -#include "usecasewidget.h" - -// app includes -#include "usecase.h" -#include "umlview.h" - -/** - * Creates a UseCase widget. - * @param scene The parent of the widget. - * @param o The UMLUseCase to represent. - */ -UseCaseWidget::UseCaseWidget(UMLScene * scene, UMLUseCase *o) - : UMLWidget(scene, WidgetBase::wt_UseCase, o) -{ -} - -/** - * Destructor. - */ -UseCaseWidget::~UseCaseWidget() -{ -} - -/** - * Overrides the standard paint event. - */ -void UseCaseWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - Q_UNUSED(option); - Q_UNUSED(widget); - - setPenFromSettings(painter); - if (UMLWidget::useFillColor()) - painter->setBrush(UMLWidget::fillColor()); - QFont font = UMLWidget::font(); - font.setUnderline(false); - font.setBold(false); - font.setItalic(m_umlObject->isAbstract()); - painter->setFont(font); - const QFontMetrics &fm = getFontMetrics(FT_NORMAL); - const int fontHeight = fm.lineSpacing(); - const int w = width(); - const int h = height(); - //int middleX = w / 2; - bool drawStereotype = umlObject() && !umlObject()->stereotype().isEmpty(); - const int textStartY = (h / 2) - (drawStereotype ? fontHeight / 4 : fontHeight / 2); - - painter->drawEllipse(0, 0, w, h); - painter->setPen(textColor()); - if (drawStereotype) - painter->drawText(UC_MARGIN, textStartY-fontHeight, w - UC_MARGIN * 2, fontHeight, Qt::AlignCenter, umlObject()->stereotype(true)); - - painter->drawText(UC_MARGIN, textStartY, w - UC_MARGIN * 2, fontHeight, Qt::AlignCenter, name()); - setPenFromSettings(painter); - - UMLWidget::paint(painter, option, widget); -} - -/** - * Saves this UseCase to file. - */ -void UseCaseWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) -{ - QDomElement usecaseElement = qDoc.createElement(QLatin1String("usecasewidget")); - UMLWidget::saveToXMI(qDoc, usecaseElement); - qElement.appendChild(usecaseElement); -} - -/** - * Overrides method from UMLWidget - */ -QSizeF UseCaseWidget::minimumSize() const -{ - const UMLWidget::FontType ft = (m_umlObject->isAbstract() ? FT_BOLD_ITALIC : FT_BOLD); - const QFontMetrics &fm = UMLWidget::getFontMetrics(ft); - const int fontHeight = fm.lineSpacing(); - const int textWidth = fm.width(name()); - bool drawStereotype = umlObject() && !umlObject()->stereotype().isEmpty(); - int width = textWidth > UC_WIDTH?textWidth:UC_WIDTH; - int height = UC_HEIGHT + (drawStereotype ? 2 * fontHeight : fontHeight) + UC_MARGIN; - - width += UC_MARGIN * 2; - - return QSizeF(width, height); -} diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/usecasewidget.h umbrello-kf6-15.08.1/umbrello/widgets/usecasewidget.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/usecasewidget.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/usecasewidget.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,58 +0,0 @@ -/*************************************************************************** - * 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-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef USECASEWIDGET_H -#define USECASEWIDGET_H - -#include "umlwidget.h" - -class UMLUseCase; - -#define UC_MARGIN 5 -#define UC_WIDTH 60 -#define UC_HEIGHT 30 - - -/** - * This class is the graphical version of a UMLUseCase. The - * UseCaseWidget class inherits from the @ref UMLWidget class - * which adds most of the functionality to this class. - - * A UseCaseWidget is created by a @ref UMLView. An UseCaseWidget belongs to only one - * @ref UMLView instance. When the @ref UMLView instance that this class belongs to, - * it will be automatically deleted. - * - * If the @ref UMLUseCase class that this UseCaseWidget is displaying is deleted, the @ref UMLView will - * make sure that this instance is also deleted. - * - * The UseCaseWidget class inherits from the @ref UMLWidget class which adds most of the functionality - * to this class. - * - * @short A graphical version of a UMLUseCase. - * @author Paul Hensgen - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class UseCaseWidget : public UMLWidget -{ -public: - UseCaseWidget(UMLScene * scene, UMLUseCase *o); - virtual ~UseCaseWidget(); - - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - - // For loading we can use the loadFromXMI() inherited from - // UMLWidget. - virtual void saveToXMI(QDomDocument & qDoc, QDomElement & qElement); - -protected: - QSizeF minimumSize() const; -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/widgetbase.cpp umbrello-kf6-15.08.1/umbrello/widgets/widgetbase.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/widgetbase.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/widgetbase.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,1119 +0,0 @@ -/*************************************************************************** - * 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) 2004-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#include "widgetbase.h" - -#include "classifier.h" -#include "debug_utils.h" -#include "floatingtextwidget.h" -#include "optionstate.h" -#include "uml.h" -#include "umldoc.h" -#include "umlobject.h" -#include "umlscene.h" - -#if QT_VERSION < 0x050000 -#include -#include -#endif -#include - -#include -#if QT_VERSION >= 0x050000 -#include -#include -#endif -#include - -/** - * Creates a WidgetBase object. - * - * @param scene The view to be displayed on. - * @param type The WidgetType to construct. This must be set to the appropriate - * value by the constructors of inheriting classes. - */ -WidgetBase::WidgetBase(UMLScene *scene, WidgetType type) - : QGraphicsObject(), - m_baseType(type), - m_scene(scene), - m_umlObject(0), - m_textColor(QColor("black")), - m_lineColor(QColor("black")), - m_fillColor(QColor("yellow")), - m_brush(m_fillColor), - m_lineWidth(0), // initialize with 0 to have valid start condition - m_useFillColor(true), - m_usesDiagramTextColor(true), - m_usesDiagramLineColor(true), - m_usesDiagramLineWidth(true) -{ - setSelected(false); - scene->addItem(this); - - // TODO 310283 - setFlags(ItemIsSelectable); - //setFlags(ItemIsSelectable | ItemIsMovable |ItemSendsGeometryChanges); - if (m_scene) { - m_usesDiagramLineColor = true; - m_usesDiagramLineWidth = true; - m_usesDiagramTextColor = true; - const Settings::OptionState& optionState = m_scene->optionState(); - m_textColor = optionState.uiState.textColor; - m_lineColor = optionState.uiState.lineColor; - m_lineWidth = optionState.uiState.lineWidth; - m_font = optionState.uiState.font; - } else { - uError() << "WidgetBase constructor: SERIOUS PROBLEM - m_scene is NULL"; - } -} - -/** - * Destructor. - */ -WidgetBase::~WidgetBase() -{ -} - -/** - * Read property of m_baseType. - */ -WidgetBase::WidgetType WidgetBase::baseType() const -{ - return m_baseType; -} - -/** - * @return The type used for rtti as string. - */ -QLatin1String WidgetBase::baseTypeStr() const -{ - return QLatin1String(ENUM_NAME(WidgetBase, WidgetType, m_baseType)); -} - -/* - * Sets the state of whether the widget is selected. - * - * @param select The state of whether the widget is selected. - */ -void WidgetBase::setSelected(bool select) -{ - QGraphicsObject::setSelected(select); -} - -/** - * Deliver a pointer to the connected UMLView - * (needed esp. by event handling of AssociationLine). - */ -UMLScene* WidgetBase::umlScene() const -{ - return m_scene; -} - -/** - * This is shortcut method for UMLApp::app()->document(). - * - * @return Pointer to the UMLDoc object. - */ -UMLDoc* WidgetBase::umlDoc() const -{ - return UMLApp::app()->document(); -} - -/** - * Returns the @ref UMLObject set to represent. - * - * @return the UMLObject to represent. - */ -UMLObject* WidgetBase::umlObject() const -{ - return m_umlObject; -} - -/** - * Sets the @ref UMLObject to represent. - * - * @param obj The object to represent. - */ -void WidgetBase::setUMLObject(UMLObject *obj) -{ - m_umlObject = obj; -} - -/** - * Write property of m_nId. - */ -void WidgetBase::setID(Uml::ID::Type id) -{ - if (m_umlObject) { - if (m_umlObject->id() != Uml::ID::None) - uWarning() << "changing old UMLObject " << Uml::ID::toString(m_umlObject->id()) - << " to " << Uml::ID::toString(id); - m_umlObject->setID(id); - } - m_nId = id; -} - -/** - * Read property of m_nId. - */ -Uml::ID::Type WidgetBase::id() const -{ - if (m_umlObject) - return m_umlObject->id(); - return m_nId; -} - -/** - * Used by some child classes to get documentation. - * - * @return The documentation from the UMLObject (if m_umlObject is set.) - */ -QString WidgetBase::documentation() const -{ - if (m_umlObject) - return m_umlObject->doc(); - return m_Doc; -} - -/** - * Returns state of documentation for the widget. - * - * @return false if documentation is empty - */ -bool WidgetBase::hasDocumentation() -{ - if (m_umlObject) - return m_umlObject->hasDoc(); - return !m_Doc.isEmpty(); -} - -/** - * Used by some child classes to set documentation. - * - * @param doc The documentation to be set in the UMLObject - * (if m_umlObject is set.) - */ -void WidgetBase::setDocumentation(const QString& doc) -{ - if (m_umlObject) - m_umlObject->setDoc(doc); - else - m_Doc = doc; -} - -/** - * Gets the name from the corresponding UMLObject if this widget has an - * underlying UMLObject; if it does not, then it returns the local - * m_Text (notably the case for FloatingTextWidget.) - * - * @return the currently set name - */ -QString WidgetBase::name() const -{ - if (m_umlObject) - return m_umlObject->name(); - return m_Text; -} - -/** - * Sets the name in the corresponding UMLObject. - * Sets the local m_Text if m_umlObject is NULL. - * - * @param strName The name to be set. - */ -void WidgetBase::setName(const QString &strName) -{ - if (m_umlObject) - m_umlObject->setName(strName); - else - m_Text = strName; -} - -/** - * Returns text color - * - * @return currently used text color - */ -QColor WidgetBase::textColor() const -{ - return m_textColor; -} - -/** - * Sets the text color - * - * @param color the new text color - */ -void WidgetBase::setTextColor(const QColor &color) -{ - m_textColor = color; - m_usesDiagramTextColor = false; -} - -/** - * Returns line color - * - * @return currently used line color - */ -QColor WidgetBase::lineColor() const -{ - return m_lineColor; -} - -/** - * Sets the line color - * - * @param color The new line color - */ -void WidgetBase::setLineColor(const QColor &color) -{ - m_lineColor = color; - m_usesDiagramLineColor = false; -} - -/** - * Returns fill color - * - * @return currently used fill color - */ -QColor WidgetBase::fillColor() const -{ - return m_fillColor; -} - -/** - * Sets the fill color - * - * @param color The new fill color - */ -void WidgetBase::setFillColor(const QColor &color) -{ - m_fillColor = color; - m_usesDiagramFillColor = false; -} - -/** - * Returns line width - * - * @return currently used line with - */ -uint WidgetBase::lineWidth() const -{ - return m_lineWidth; -} - -/** - * Sets the line width - * - * @param width The new line width - */ -void WidgetBase::setLineWidth(uint width) -{ - m_lineWidth = width; - m_usesDiagramLineWidth = false; -} - -/** - * Return state of fill color usage - * - * @return True if fill color is used - */ -bool WidgetBase::useFillColor() -{ - return m_useFillColor; -} - -/** - * Set state if fill color is used - * - * @param state The state to set - */ -void WidgetBase::setUseFillColor(bool state) -{ - m_useFillColor = state; - m_usesDiagramUseFillColor = false; -} - -/** - * Returns state if diagram text color is used - * - * @return True means diagram text color is used - */ -bool WidgetBase::usesDiagramTextColor() const -{ - return m_usesDiagramTextColor; -} - -/** - * Set state if diagram text color is used - * - * @param state The state to set - */ -void WidgetBase::setUsesDiagramTextColor(bool state) -{ - if (m_usesDiagramTextColor == state) { - return; - } - m_usesDiagramTextColor = state; - setTextColor(m_textColor); -} - -/** - * Returns state of diagram line color is used - * - * @return True means diagrams line color is used -*/ -bool WidgetBase::usesDiagramLineColor() const -{ - return m_usesDiagramLineColor; -} - -/** - * Set state of diagram line color is used - * - * @param state The state to set - */ -void WidgetBase::setUsesDiagramLineColor(bool state) -{ - m_usesDiagramLineColor = state; -} - -/** - * Returns state of diagram fill color is used - * - * @return True means diagrams fill color is used -*/ -bool WidgetBase::usesDiagramFillColor() const -{ - return m_usesDiagramFillColor; -} - -/** - * Set state if diagram fill color is used - * - * @param state The state to set - */ -void WidgetBase::setUsesDiagramFillColor(bool state) -{ - m_usesDiagramFillColor = state; -} - -/** - * Returns state of diagram use fill color is used - * - * @return True means diagrams fill color is used -*/ -bool WidgetBase::usesDiagramUseFillColor() const -{ - return m_usesDiagramUseFillColor; -} - -/** - * Set state of diagram use fill color is used - * - * @param state The state to set - */ -void WidgetBase::setUsesDiagramUseFillColor(bool state) -{ - m_usesDiagramUseFillColor = state; -} - -/** - * Returns state of diagram line width is used - * - * @return True means diagrams line width is used - */ -bool WidgetBase::usesDiagramLineWidth() const -{ - return m_usesDiagramLineWidth; -} - -/** - * Set state of diagram line width is used - * - * @param state The state to set - */ -void WidgetBase::setUsesDiagramLineWidth(bool state) -{ - m_usesDiagramLineWidth = state; -} - -/** - * Returns the font used for diaplaying any text. - * @return the font - */ -QFont WidgetBase::font() const -{ - return m_font; -} - -/** - * Set the font used to display text inside this widget. - */ -void WidgetBase::setFont(const QFont& font) -{ - m_font = font; -} - -/** - * A virtual method for the widget to display a property dialog box. - * Subclasses should reimplment this appropriately. - */ -void WidgetBase::showPropertiesDialog() -{ -} - -/** - * A virtual method to save the properties of this widget into a - * QDomElement i.e xml. - * - * Subclasses should first create a new dedicated element as the child - * of \a qElement parameter passed. Then this base method should be - * called to save basic widget properties. - * - * @param qDoc A QDomDocument object representing the xml document. - * @param qElement A QDomElement representing xml element data. - */ -void WidgetBase::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) - { - Q_UNUSED(qDoc) - - qElement.setAttribute(QLatin1String("textcolor"), m_usesDiagramTextColor ? QLatin1String("none") - : m_textColor.name()); - if (m_usesDiagramLineColor) { - qElement.setAttribute(QLatin1String("linecolor"), QLatin1String("none")); - } else { - qElement.setAttribute(QLatin1String("linecolor"), m_lineColor.name()); - } - if (m_usesDiagramLineWidth) { - qElement.setAttribute(QLatin1String("linewidth"), QLatin1String("none")); - } else { - qElement.setAttribute(QLatin1String("linewidth"), m_lineWidth); - } - qElement.setAttribute(QLatin1String("usefillcolor"), m_useFillColor); - // for consistency the following attributes now use american spelling for "color" - qElement.setAttribute(QLatin1String("usesdiagramfillcolor"), m_usesDiagramFillColor); - qElement.setAttribute(QLatin1String("usesdiagramusefillcolor"), m_usesDiagramUseFillColor); - if (m_usesDiagramFillColor) { - qElement.setAttribute(QLatin1String("fillcolor"), QLatin1String("none")); - } else { - qElement.setAttribute(QLatin1String("fillcolor"), m_fillColor.name()); - } - qElement.setAttribute(QLatin1String("font"), m_font.toString()); -} - -/** - * A virtual method to load the properties of this widget from a - * QDomElement into this widget. - * - * Subclasses should reimplement this to load addtional properties - * required, calling this base method to load the basic properties of - * the widget. - * - * @param qElement A QDomElement which contains xml info for this widget. - * - * @todo Add support to load older version. - */ -bool WidgetBase::loadFromXMI(QDomElement& qElement) -{ - // first load from "linecolour" and then overwrite with the "linecolor" - // attribute if that one is present. The "linecolour" name was a "typo" in - // earlier versions of umbrello-kf6 - QString lineColor = qElement.attribute(QLatin1String("linecolour"), QLatin1String("none")); - lineColor = qElement.attribute(QLatin1String("linecolor"), lineColor); - if (lineColor != QLatin1String("none")) { - m_lineColor = QColor(lineColor); - m_usesDiagramLineColor = false; - } else if (m_baseType != WidgetBase::wt_Box && m_scene != NULL) { - m_lineColor = m_scene->lineColor(); - m_usesDiagramLineColor = true; - } - QString lineWidth = qElement.attribute(QLatin1String("linewidth"), QLatin1String("none")); - if (lineWidth != QLatin1String("none")) { - m_lineWidth = lineWidth.toInt(); - m_usesDiagramLineWidth = false; - } else if (m_scene) { - m_lineWidth = m_scene->lineWidth(); - m_usesDiagramLineWidth = true; - } - QString textColor = qElement.attribute(QLatin1String("textcolor"), QLatin1String("none")); - if (textColor != QLatin1String("none")) { - m_textColor = QColor(textColor); - m_usesDiagramTextColor = false; - } else if (m_scene) { - m_textColor = m_scene->textColor(); - m_usesDiagramTextColor = true; - } - QString usefillcolor = qElement.attribute(QLatin1String("usefillcolor"), QLatin1String("1")); - m_useFillColor = (bool)usefillcolor.toInt(); - /* - For the next three *color attributes, there was a mixup of american and english spelling for "color". - So first we need to keep backward compatibility and try to retrieve the *colour attribute. - Next we overwrite this value if we find a *color, otherwise the former *colour is kept. - */ - QString fillColor = qElement.attribute(QLatin1String("fillcolour"), QLatin1String("none")); - fillColor = qElement.attribute(QLatin1String("fillcolor"), fillColor); - if (fillColor != QLatin1String("none")) { - m_fillColor = QColor(fillColor); - } - - QString usesDiagramFillColor = qElement.attribute(QLatin1String("usesdiagramfillcolour"), QLatin1String("1")); - usesDiagramFillColor = qElement.attribute(QLatin1String("usesdiagramfillcolor"), usesDiagramFillColor); - m_usesDiagramFillColor = (bool)usesDiagramFillColor.toInt(); - - QString usesDiagramUseFillColor = qElement.attribute(QLatin1String("usesdiagramusefillcolour"), QLatin1String("1")); - usesDiagramUseFillColor = qElement.attribute(QLatin1String("usesdiagramusefillcolor"), usesDiagramUseFillColor); - m_usesDiagramUseFillColor = (bool)usesDiagramUseFillColor.toInt(); - - QString font = qElement.attribute(QLatin1String("font")); - if (!font.isEmpty()) { - QFont newFont; - newFont.fromString(font); - m_font = newFont; - } else { - uWarning() << "Using default font " << m_font.toString() - << " for widget with xmi.id " << Uml::ID::toString(m_nId); - } - - return true; -} - -/** - * Assignment operator - */ -WidgetBase& WidgetBase::operator=(const WidgetBase& other) -{ - m_baseType = other.m_baseType; - m_scene = other.m_scene; - m_umlObject = other.m_umlObject; - m_Doc = other.m_Doc; - m_Text = other.m_Text; - m_nId = other.m_nId; - m_textColor = other.m_textColor; - m_lineColor = other.m_lineColor; - m_fillColor = other.m_fillColor; - m_brush = other.m_brush; - m_font = other.m_font; - m_lineWidth = other.m_lineWidth; - m_useFillColor = other.m_useFillColor; - m_usesDiagramTextColor = other.m_usesDiagramTextColor; - m_usesDiagramLineColor = other.m_usesDiagramLineColor; - m_usesDiagramFillColor = other.m_usesDiagramFillColor; - m_usesDiagramLineWidth = other.m_usesDiagramLineWidth; - setSelected(other.isSelected()); - - return *this; -} - -/** - * return drawing rectangle of widget in local coordinates - */ -QRectF WidgetBase::rect() const -{ - return m_rect; -} - -/** - * set widget rectangle in item coordinates - */ -void WidgetBase::setRect(const QRectF& rect) -{ - if (m_rect == rect) - return; - prepareGeometryChange(); - m_rect = rect; - update(); -} - -/** - * set widget rectangle in item coordinates - */ -void WidgetBase::setRect(qreal x, qreal y, qreal width, qreal height) -{ - setRect(QRectF(x, y, width, height)); -} - -/** - * @return The bounding rectangle for this widget. - * @see setRect - */ -QRectF WidgetBase::boundingRect() const -{ - int halfWidth = lineWidth()/2; - return m_rect.adjusted(-halfWidth, -halfWidth, halfWidth, halfWidth); -} - -/** - * Test if point is inside the bounding rectangle of the widget. - * Inheriting classes may reimplement this to test possible child widgets. - * - * @param p Point to be checked. - * - * @return 'this' if the given point is in the boundaries of the widget; - * else NULL. - */ -UMLWidget* WidgetBase::onWidget(const QPointF &p) -{ - UMLWidget *uw = dynamic_cast(this); - if (uw == NULL) - return NULL; - const qreal w = m_rect.width(); - const qreal h = m_rect.height(); - const qreal left = x(); // don't use m_rect.x() for this, it is always 0 - const qreal right = left + w; - const qreal top = y(); // don't use m_rect.y() for this, it is always 0 - const qreal bottom = top + h; - // uDebug() << "p=(" << p.x() << "," << p.y() - // << "), x=" << left << ", y=" << top << ", w=" << w << ", h=" << h - // << "; right=" << right << ", bottom=" << bottom; - if (p.x() < left || p.x() > right || - p.y() < top || p.y() > bottom) { // Qt coord.sys. origin in top left corner - // uDebug() << "returning NULL"; - return NULL; - } - // uDebug() << "returning this"; - return uw; -} - -/** - * Draws the UMLWidget on the given paint device - * - * @param painter The painter for the drawing device - * @param option Painting related options - * @param widget Background widget on which to paint (optional) - * - */ -void WidgetBase::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - Q_UNUSED(painter); Q_UNUSED(option); Q_UNUSED(widget); -} - -/** - * Reimplemented to show appropriate context menu. - */ -void WidgetBase::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) -{ - event->accept(); - uDebug() << "widget = " << name() << " / type = " << baseTypeStr(); - - UMLScene *scene = umlScene(); - - // If right-click was done on a widget that was not selected, clear the - // current selection and select the new widget. The context menu is shown - // with actions for that single widget. - // If a keyboard modifier was used, add the widget to the current selection - // and show the menu with actions for the whole selection. - if (!isSelected()) { - Qt::KeyboardModifiers forSelection = (Qt::ControlModifier | Qt::ShiftModifier); - if ((event->modifiers() & forSelection) == 0) { - scene->clearSelected(); - } - - if (umlObject() != 0) { - scene->selectWidget(dynamic_cast(this)); - } else { - setSelected(true); - } - } - - int count = scene->selectedCount(true); - - // Determine multi state - bool multi = (isSelected() && count > 1); - - ListPopupMenu popup(0, this, multi, scene->getUniqueSelectionType()); - - // Disable the "view code" menu for simple code generators - if (UMLApp::app()->isSimpleCodeGeneratorActive()) { - popup.setActionEnabled(ListPopupMenu::mt_ViewCode, false); - } - - QAction *triggered = popup.exec(event->screenPos()); - ListPopupMenu *parentMenu = ListPopupMenu::menuFromAction(triggered); - - if (!parentMenu) { - uDebug() << "Action's data field does not contain ListPopupMenu pointer"; - return; - } - - WidgetBase *ownerWidget = parentMenu->ownerWidget(); - // assert because logic is based on only WidgetBase being the owner of - // ListPopupMenu actions executed in this context menu. - Q_ASSERT_X(ownerWidget != 0, "WidgetBase::contextMenuEvent", - "ownerWidget is null which means action belonging to UMLView, UMLScene" - " or UMLObject is the one triggered in ListPopupMenu"); - - ownerWidget->slotMenuSelection(triggered); -} - -/** - * This is usually called synchronously after menu.exec() and \a - * trigger's parent is always the ListPopupMenu which can be used to - * get the type of action of \a trigger. - * - * @note Subclasses can reimplement to handle specific actions and - * leave the rest to WidgetBase::slotMenuSelection. - */ -void WidgetBase::slotMenuSelection(QAction *trigger) -{ - if (!trigger) { - return; - } - QColor newColor; - - const WidgetType wt = m_baseType; // short hand name - - ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(trigger); - switch (sel) { - case ListPopupMenu::mt_Rename: - umlDoc()->renameUMLObject(umlObject()); - break; - - case ListPopupMenu::mt_Properties: - if (wt == WidgetBase::wt_Actor || wt == WidgetBase::wt_UseCase || - wt == WidgetBase::wt_Package || wt == WidgetBase::wt_Interface || - wt == WidgetBase::wt_Datatype || wt == WidgetBase::wt_Node || - wt == WidgetBase::wt_Component || wt == WidgetBase::wt_Artifact || - wt == WidgetBase::wt_Enum || wt == WidgetBase::wt_Entity || - wt == WidgetBase::wt_Port || - (wt == WidgetBase::wt_Class && umlScene()->type() == Uml::DiagramType::Class)) { - - showPropertiesDialog(); - - } else if (wt == WidgetBase::wt_Object) { - m_umlObject->showPropertiesDialog(); - } else { - uWarning() << "making properties dialog for unknown widget type"; - } - break; - - case ListPopupMenu::mt_Line_Color: - case ListPopupMenu::mt_Line_Color_Selection: -#if QT_VERSION >= 0x050000 - newColor = QColorDialog::getColor(lineColor()); - if (newColor != lineColor()) { -#else - newColor = lineColor(); - if (KColorDialog::getColor(newColor)) { -#endif - if (sel == ListPopupMenu::mt_Line_Color_Selection) { - umlScene()->selectionSetLineColor(newColor); - } else { - setLineColor(newColor); - } - setUsesDiagramLineColor(false); - umlDoc()->setModified(true); - } - break; - - case ListPopupMenu::mt_Fill_Color: - case ListPopupMenu::mt_Fill_Color_Selection: -#if QT_VERSION >= 0x050000 - newColor = QColorDialog::getColor(fillColor()); - if (newColor != fillColor()) { -#else - newColor = fillColor(); - if (KColorDialog::getColor(newColor)) { -#endif - if (sel == ListPopupMenu::mt_Fill_Color_Selection) { - umlScene()->selectionSetFillColor(newColor); - } else { - setFillColor(newColor); - } - umlDoc()->setModified(true); - } - break; - - case ListPopupMenu::mt_Use_Fill_Color: - setUseFillColor(!m_useFillColor); - break; - - case ListPopupMenu::mt_Set_Use_Fill_Color_Selection: - umlScene()->selectionUseFillColor(true); - break; - - case ListPopupMenu::mt_Unset_Use_Fill_Color_Selection: - umlScene()->selectionUseFillColor(false); - break; - - case ListPopupMenu::mt_Show_Attributes_Selection: - case ListPopupMenu::mt_Hide_Attributes_Selection: - umlScene()->selectionSetVisualProperty( - ClassifierWidget::ShowAttributes, sel != ListPopupMenu::mt_Hide_Attributes_Selection - ); - break; - - case ListPopupMenu::mt_Show_Operations_Selection: - case ListPopupMenu::mt_Hide_Operations_Selection: - umlScene()->selectionSetVisualProperty( - ClassifierWidget::ShowOperations, sel != ListPopupMenu::mt_Hide_Operations_Selection - ); - break; - - case ListPopupMenu::mt_Show_Visibility_Selection: - case ListPopupMenu::mt_Hide_Visibility_Selection: - umlScene()->selectionSetVisualProperty( - ClassifierWidget::ShowVisibility, sel != ListPopupMenu::mt_Hide_Visibility_Selection - ); - break; - - case ListPopupMenu::mt_Show_Operation_Signature_Selection: - case ListPopupMenu::mt_Hide_Operation_Signature_Selection: - umlScene()->selectionSetVisualProperty( - ClassifierWidget::ShowOperationSignature, sel != ListPopupMenu::mt_Hide_Operation_Signature_Selection - ); - break; - - case ListPopupMenu::mt_Show_Attribute_Signature_Selection: - case ListPopupMenu::mt_Hide_Attribute_Signature_Selection: - umlScene()->selectionSetVisualProperty( - ClassifierWidget::ShowAttributeSignature, sel != ListPopupMenu::mt_Hide_Attribute_Signature_Selection - ); - break; - - case ListPopupMenu::mt_Show_Packages_Selection: - case ListPopupMenu::mt_Hide_Packages_Selection: - umlScene()->selectionSetVisualProperty( - ClassifierWidget::ShowPackage, sel != ListPopupMenu::mt_Hide_Packages_Selection - ); - break; - - case ListPopupMenu::mt_Show_Stereotypes_Selection: - case ListPopupMenu::mt_Hide_Stereotypes_Selection: - umlScene()->selectionSetVisualProperty( - ClassifierWidget::ShowStereotype, sel != ListPopupMenu::mt_Hide_Stereotypes_Selection - ); - break; - - case ListPopupMenu::mt_Hide_NonPublic_Selection: - case ListPopupMenu::mt_Show_NonPublic_Selection: - umlScene()->selectionSetVisualProperty( - ClassifierWidget::ShowPublicOnly, sel != ListPopupMenu::mt_Show_NonPublic_Selection - ); - break; - - - case ListPopupMenu::mt_ViewCode: { - UMLClassifier *c = dynamic_cast(umlObject()); - if (c) { - UMLApp::app()->viewCodeDocument(c); - } - break; - } - - case ListPopupMenu::mt_Delete: - umlScene()->deleteSelection(); - break; - - case ListPopupMenu::mt_Change_Font: - case ListPopupMenu::mt_Change_Font_Selection: { -#if QT_VERSION >= 0x050000 - bool ok = false; - QFont newFont = QFontDialog::getFont(&ok, font()); - if (ok) { -#else - QFont newFont = font(); - if (KFontDialog::getFont(newFont, KFontChooser::NoDisplayFlags, 0) == KFontDialog::Accepted) { -#endif - if (sel == ListPopupMenu::mt_Change_Font_Selection) { - m_scene->selectionSetFont(newFont); - } else { - setFont(newFont); - } - } - } - break; - - case ListPopupMenu::mt_Cut: - umlScene()->setStartedCut(); - UMLApp::app()->slotEditCut(); - break; - - case ListPopupMenu::mt_Copy: - UMLApp::app()->slotEditCopy(); - break; - - case ListPopupMenu::mt_Paste: - UMLApp::app()->slotEditPaste(); - break; - - case ListPopupMenu::mt_Refactoring: - //check if we are operating on a classifier, or some other kind of UMLObject - if (dynamic_cast(umlObject())) { - UMLApp::app()->refactor(static_cast(umlObject())); - } - break; - - case ListPopupMenu::mt_Clone: - { - foreach (UMLWidget* widget, umlScene()->selectedWidgets()) { - if (Model_Utils::isCloneable(widget->baseType())) { - UMLObject *clone = widget->umlObject()->clone(); - umlScene()->addObject(clone); - } - } - } - break; - - case ListPopupMenu::mt_Rename_MultiA: - case ListPopupMenu::mt_Rename_MultiB: - case ListPopupMenu::mt_Rename_Name: - case ListPopupMenu::mt_Rename_RoleAName: - case ListPopupMenu::mt_Rename_RoleBName: { - FloatingTextWidget *ft = static_cast(this); - ft->handleRename(); - break; - } - case ListPopupMenu::mt_Align_Right: - umlScene()->alignRight(); - break; - case ListPopupMenu::mt_Align_Left: - umlScene()->alignLeft(); - break; - case ListPopupMenu::mt_Align_Top: - umlScene()->alignTop(); - break; - case ListPopupMenu::mt_Align_Bottom: - umlScene()->alignBottom(); - break; - case ListPopupMenu::mt_Align_VerticalMiddle: - umlScene()->alignVerticalMiddle(); - break; - case ListPopupMenu::mt_Align_HorizontalMiddle: - umlScene()->alignHorizontalMiddle(); - break; - case ListPopupMenu::mt_Align_VerticalDistribute: - umlScene()->alignVerticalDistribute(); - break; - case ListPopupMenu::mt_Align_HorizontalDistribute: - umlScene()->alignHorizontalDistribute(); - break; - default: - uDebug() << "MenuType " << ListPopupMenu::toString(sel) << " not implemented"; - break; - } -} - -/** - * Helper function for debug output. - * Returns the given enum value as string. - * @param wt WidgetType of which a string representation is wanted - * @return the WidgetType as string - */ -QString WidgetBase::toString(WidgetType wt) -{ - return QLatin1String(ENUM_NAME(WidgetBase, WidgetType, wt)); -} - -/** - * Returns the given enum value as localized string. - * @param wt WidgetType of which a string representation is wanted - * @return the WidgetType as localized string - */ -QString WidgetBase::toI18nString(WidgetType wt) -{ - QString name; - - switch (wt) { - case wt_Activity: - name = i18n("Activity"); - break; - case wt_Actor: - name = i18n("Actor"); - break; - case wt_Artifact: - name = i18n("Artifact"); - break; - case wt_Association: - name = i18n("Association"); - break; - case wt_Box: - name = i18n("Box"); - break; - case wt_Category: - name = i18n("Category"); - break; - case wt_CombinedFragment: - name = i18n("CombinedFragment"); - break; - case wt_Component: - name = i18n("Component"); - break; - case wt_Class: - name = i18n("Class"); - break; - case wt_Datatype: - name = i18n("Datatype"); - break; - case wt_Entity: - name = i18n("Entity"); - break; - case wt_Enum: - name = i18n("Enum"); - break; - case wt_FloatingDashLine: - name = i18n("FloatingDashLine"); - break; - case wt_ForkJoin: - name = i18n("ForkJoin"); - break; - case wt_Interface: - name = i18n("Interface"); - break; - case wt_Message: - name = i18n("Message"); - break; - case wt_Node: - name = i18n("Node"); - break; - case wt_Note: - name = i18n("Note"); - break; - case wt_Object: - name = i18n("Object"); - break; - case wt_ObjectNode: - name = i18n("ObjectNode"); - break; - case wt_Package: - name = i18n("Package"); - break; - case wt_Pin: - name = i18n("Pin"); - break; - case wt_Port: - name = i18n("Port"); - break; - case wt_Precondition: - name = i18n("Precondition"); - break; - case wt_Region: - name = i18n("Region"); - break; - case wt_Signal: - name = i18n("Signal"); - break; - case wt_State: - name = i18n("State"); - break; - case wt_Text: - name = i18n("Text"); - break; - case wt_UseCase: - name = i18n("UseCase"); - break; - default: - name = QLatin1String(" &name:"); - uWarning() << "unknown widget type"; - break; - } - return name; -} - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/widgetbase.h umbrello-kf6-15.08.1/umbrello/widgets/widgetbase.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/widgetbase.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/widgetbase.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,192 +0,0 @@ -/*************************************************************************** - * 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) 2004-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef WIDGETBASE_H -#define WIDGETBASE_H - -#include "basictypes.h" - -#include -#include -#include -#include -#include -#include - -// forward declarations -class QAction; -class UMLDoc; -class UMLObject; -class UMLScene; -class UMLWidget; // required by function onWidget() - -/** - * @short Common base class for UMLWidget and AssociationWidget - * @author Oliver Kellogg - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -class WidgetBase : public QGraphicsObject -{ - Q_OBJECT - Q_ENUMS(WidgetType) - -public: - enum WidgetType - { - wt_UMLWidget = 300, // does not have UMLObject representation - wt_Actor, // has UMLObject representation - wt_UseCase, // has UMLObject representation - wt_Class, // has UMLObject representation - wt_Interface, // has UMLObject representation - wt_Datatype, // has UMLObject representation - wt_Enum, // has UMLObject representation - wt_Entity, // has UMLObject representation - wt_Package, // has UMLObject representation - wt_Object, // has UMLObject representation - wt_Note, // does not have UMLObject representation - wt_Box, // does not have UMLObject representation - wt_Message, // does not have UMLObject representation - wt_Text, // does not have UMLObject representation - wt_State, // does not have UMLObject representation - wt_Activity, // does not have UMLObject representation - wt_Component, // has UMLObject representation - wt_Artifact, // has UMLObject representation - wt_Node, // has UMLObject representation - wt_Association, // has UMLObject representation - wt_ForkJoin, // does not have UMLObject representation - wt_Precondition, // does not have UMLObject representation - wt_CombinedFragment, // does not have UMLObject representation - wt_FloatingDashLine, // does not have UMLObject representation - wt_Signal, // does not have UMLObject representation - wt_Pin, - wt_ObjectNode, - wt_Region, - wt_Category, // has UMLObject representation - wt_Port // has UMLObject representation - }; - - static QString toString(WidgetType wt); - static QString toI18nString(WidgetType wt); - - explicit WidgetBase(UMLScene * scene, WidgetType type= wt_UMLWidget); - virtual ~WidgetBase(); - - UMLObject* umlObject() const; - virtual void setUMLObject(UMLObject *obj); - - Uml::ID::Type id() const; - void setID(Uml::ID::Type id); - - WidgetType baseType() const; - QLatin1String baseTypeStr() const; - - virtual void setSelected(bool select); - - UMLScene* umlScene() const; - UMLDoc* umlDoc() const; - - QString documentation() const; - bool hasDocumentation(); - virtual void setDocumentation(const QString& doc); - - QString name() const; - virtual void setName(const QString &strName); - - QColor lineColor() const; - virtual void setLineColor(const QColor& color); - - uint lineWidth() const; - virtual void setLineWidth(uint width); - - QColor textColor() const; - virtual void setTextColor(const QColor& color); - - QColor fillColor() const; - virtual void setFillColor(const QColor& color); - - bool usesDiagramLineColor() const; - void setUsesDiagramLineColor(bool state); - - bool usesDiagramLineWidth() const; - void setUsesDiagramLineWidth(bool state); - - bool useFillColor(); - virtual void setUseFillColor(bool state); - - bool usesDiagramTextColor() const; - void setUsesDiagramTextColor(bool state); - - bool usesDiagramFillColor() const; - void setUsesDiagramFillColor(bool state); - - bool usesDiagramUseFillColor() const; - void setUsesDiagramUseFillColor(bool state); - - virtual QFont font() const; - virtual void setFont(const QFont& font); - - virtual void showPropertiesDialog(); - - virtual bool loadFromXMI(QDomElement &qElement); - virtual void saveToXMI(QDomDocument &qDoc, QDomElement &qElement); - - WidgetBase& operator=(const WidgetBase& other); - - QRectF rect() const; - void setRect(const QRectF& rect); - void setRect(qreal x, qreal y, qreal width, qreal height); - - virtual QRectF boundingRect() const; - - virtual UMLWidget* onWidget(const QPointF &p); - - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - -public Q_SLOTS: - virtual void slotMenuSelection(QAction *trigger); - -protected: - virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *event); - - WidgetType m_baseType; ///< Type of widget. - UMLScene *m_scene; - UMLObject *m_umlObject; - QString m_Doc; ///< Only used if m_umlObject is not set. - QString m_Text; - QRectF m_rect; ///< widget size - - /** - * This ID is only used when the widget does not have a - * corresponding UMLObject (i.e. the m_umlObject pointer is NULL.) - * For UMLObjects, the ID from the UMLObject is used. - */ - Uml::ID::Type m_nId; - - QColor m_textColor; ///< Color of the text of the widget. Is saved to XMI. - QColor m_lineColor; ///< Color of the lines of the widget. Is saved to XMI. - QColor m_fillColor; ///< color of the background of the widget - QBrush m_brush; - QFont m_font; - uint m_lineWidth; ///< Width of the lines of the widget. Is saved to XMI. - bool m_useFillColor; ///< flag indicates if the UMLWidget uses the Diagram FillColour - - /** - * true by default, false if the colors have - * been explicitly set for this widget. - * These are saved to XMI. - */ - bool m_usesDiagramTextColor; - bool m_usesDiagramLineColor; - bool m_usesDiagramFillColor; - bool m_usesDiagramUseFillColor; - bool m_usesDiagramLineWidth; -}; - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/widget_factory.cpp umbrello-kf6-15.08.1/umbrello/widgets/widget_factory.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/widget_factory.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/widget_factory.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,296 +0,0 @@ -/*************************************************************************** - * 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) 2006-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "widget_factory.h" - -// app includes -#include "activitywidget.h" -#include "actor.h" -#include "actorwidget.h" -#include "artifact.h" -#include "artifactwidget.h" -#include "associationwidget.h" -#include "boxwidget.h" -#include "category.h" -#include "categorywidget.h" -#include "classifier.h" -#include "classifierwidget.h" -#include "cmds.h" -#include "combinedfragmentwidget.h" -#include "component.h" -#include "componentwidget.h" -#include "datatypewidget.h" -#include "debug_utils.h" -#include "entity.h" -#include "entitywidget.h" -#include "enum.h" -#include "enumwidget.h" -#include "floatingdashlinewidget.h" -#include "floatingtextwidget.h" -#include "folder.h" -#include "forkjoinwidget.h" -#include "messagewidget.h" -#include "node.h" -#include "nodewidget.h" -#include "notewidget.h" -#include "object_factory.h" -#include "objectnodewidget.h" -#include "objectwidget.h" -#include "package.h" -#include "packagewidget.h" -#include "pinwidget.h" -#include "port.h" -#include "portwidget.h" -#include "preconditionwidget.h" -#include "regionwidget.h" -#include "signalwidget.h" -#include "statewidget.h" -#include "uml.h" -#include "umldoc.h" -#include "umlscene.h" -#include "umlview.h" -#include "usecase.h" -#include "usecasewidget.h" - -namespace Widget_Factory { - -/** - * Create a UMLWidget in the given view and representing the given document object. - */ -UMLWidget *createWidget(UMLScene *scene, UMLObject *o) -{ - QPointF pos = scene->pos(); - int y = pos.y(); - Uml::DiagramType::Enum diagramType = scene->type(); - UMLObject::ObjectType type = o->baseType(); - UMLWidget *newWidget = NULL; - switch (type) { - case UMLObject::ot_Actor: - if (diagramType == Uml::DiagramType::Sequence) { - ObjectWidget *ow = new ObjectWidget(scene, o); - ow->setDrawAsActor(true); - y = ow->topMargin(); - newWidget = ow; - } else - newWidget = new ActorWidget(scene, static_cast(o)); - break; - case UMLObject::ot_UseCase: - newWidget = new UseCaseWidget(scene, static_cast(o)); - break; - case UMLObject::ot_Folder: - case UMLObject::ot_Package: - newWidget = new ClassifierWidget(scene, static_cast(o)); - break; - case UMLObject::ot_Component: - newWidget = new ComponentWidget(scene, static_cast(o)); - if (diagramType == Uml::DiagramType::Deployment) { - newWidget->setIsInstance(true); - } - break; - case UMLObject::ot_Port: - { - PinPortBase *pw = new PortWidget(scene, static_cast(o)); - pw->attachToOwner(); - newWidget = pw; - } - break; - case UMLObject::ot_Node: - newWidget = new NodeWidget(scene, static_cast(o)); - break; - case UMLObject::ot_Artifact: - newWidget = new ArtifactWidget(scene, static_cast(o)); - break; - case UMLObject::ot_Datatype: - newWidget = new DatatypeWidget(scene, static_cast(o)); - break; - case UMLObject::ot_Enum: - newWidget = new EnumWidget(scene, static_cast(o)); - break; - case UMLObject::ot_Entity: - newWidget = new EntityWidget(scene, static_cast(o)); - break; - case UMLObject::ot_Interface: - if (diagramType == Uml::DiagramType::Sequence || diagramType == Uml::DiagramType::Collaboration) { - ObjectWidget *ow = new ObjectWidget(scene, o); - if (diagramType == Uml::DiagramType::Sequence) { - y = ow->topMargin(); - } - newWidget = ow; - } else { - UMLClassifier *c = static_cast(o); - ClassifierWidget* interfaceWidget = new ClassifierWidget(scene, c); - if (diagramType == Uml::DiagramType::Component || diagramType == Uml::DiagramType::Deployment) { - interfaceWidget->setDrawAsCircle(true); - } - newWidget = interfaceWidget; - } - break; - case UMLObject::ot_Class: - //see if we really want an object widget or class widget - if (diagramType == Uml::DiagramType::Class || diagramType == Uml::DiagramType::Component) { - UMLClassifier *c = static_cast(o); - ClassifierWidget *cw = new ClassifierWidget(scene, c); - if (diagramType == Uml::DiagramType::Component) - cw->setDrawAsCircle(true); - newWidget = cw; - } else { - ObjectWidget *ow = new ObjectWidget(scene, o); - if (diagramType == Uml::DiagramType::Sequence) { - y = ow->topMargin(); - } - newWidget = ow; - } - break; - case UMLObject::ot_Category: - newWidget = new CategoryWidget(scene, static_cast(o)); - break; - default: - uWarning() << "trying to create an invalid widget (" << UMLObject::toString(type) << ")"; - } - - if (newWidget) { - newWidget->setX(pos.x()); - newWidget->setY(y); - } - - return newWidget; -} - -bool validateObjType(UMLObject::ObjectType expected, UMLObject* &o, Uml::ID::Type id) -{ - if (o == NULL) { - uDebug() << "Widget_Factory::validateObjType: creating new object of type " - << expected; - QString artificialName = QLatin1String("LOST_") + Uml::ID::toString(id); - o = Object_Factory::createUMLObject(expected, artificialName, NULL, false); - if (o == NULL) - return false; - o->setID(id); - UMLPackage *parentPkg = o->umlPackage(); - parentPkg->addObject(o); - return true; - } - UMLObject::ObjectType actual = o->baseType(); - if (actual == expected) - return true; - uError() << "validateObjType(" << o->name() - << "): expected type " << UMLObject::toString(expected) << ", actual type " - << UMLObject::toString(actual); - return false; -} - -/** - * Create a UMLWidget according to the given XMI tag. - */ -UMLWidget* makeWidgetFromXMI(const QString& tag, - const QString& idStr, UMLScene *scene) -{ - UMLWidget *widget = NULL; - - // Loading of widgets which do NOT represent any UMLObject, - // just graphic stuff with no real model information - //FIXME while boxes and texts are just diagram objects, activities and - // states should be UMLObjects - if (tag == QLatin1String("statewidget") || tag == QLatin1String("UML:StateWidget")) { - widget = new StateWidget(scene, StateWidget::Normal, Uml::ID::Reserved); - } else if (tag == QLatin1String("notewidget") || tag == QLatin1String("UML:NoteWidget")) { - widget = new NoteWidget(scene, NoteWidget::Normal, Uml::ID::Reserved); - } else if (tag == QLatin1String("boxwidget")) { - widget = new BoxWidget(scene, Uml::ID::Reserved); - } else if (tag == QLatin1String("floatingtext") || tag == QLatin1String("UML:FloatingTextWidget")) { - widget = new FloatingTextWidget(scene, Uml::TextRole::Floating, QString(), Uml::ID::Reserved); - } else if (tag == QLatin1String("activitywidget") || tag == QLatin1String("UML:ActivityWidget")) { - widget = new ActivityWidget(scene, ActivityWidget::Initial, Uml::ID::Reserved); - } else if (tag == QLatin1String("messagewidget")) { - widget = new MessageWidget(scene, Uml::SequenceMessage::Asynchronous, Uml::ID::Reserved); - } else if (tag == QLatin1String("forkjoin")) { - widget = new ForkJoinWidget(scene, Qt::Vertical, Uml::ID::Reserved); - } else if (tag == QLatin1String("preconditionwidget")) { - widget = new PreconditionWidget(scene, NULL, Uml::ID::Reserved); - } else if (tag == QLatin1String("combinedFragmentwidget")) { - widget = new CombinedFragmentWidget(scene, CombinedFragmentWidget::Ref, Uml::ID::Reserved); - } else if (tag == QLatin1String("signalwidget")) { - widget = new SignalWidget(scene, SignalWidget::Send, Uml::ID::Reserved); - } else if (tag == QLatin1String("floatingdashlinewidget")) { - widget = new FloatingDashLineWidget(scene, Uml::ID::Reserved); - } else if (tag == QLatin1String("objectnodewidget")) { - widget = new ObjectNodeWidget(scene, ObjectNodeWidget::Normal, Uml::ID::Reserved); - } else if (tag == QLatin1String("regionwidget")) { - widget = new RegionWidget(scene, Uml::ID::Reserved); - } else if (tag == QLatin1String("pinwidget")) { - PinPortBase *pw = new PinWidget(scene, NULL, Uml::ID::Reserved); - pw->attachToOwner(); - widget = pw; - } - else - { - // Loading of widgets which represent an UMLObject - - // Find the UMLObject and create the Widget to represent it - Uml::ID::Type id = Uml::ID::fromString(idStr); - UMLDoc *umldoc = UMLApp::app()->document(); - UMLObject *o = umldoc->findObjectById(id); - if (o == NULL) { - uDebug() << "makeWidgetFromXMI: cannot find object with id " - << Uml::ID::toString(id); - } - - if (tag == QLatin1String("actorwidget") || tag == QLatin1String("UML:ActorWidget")) { - if (validateObjType(UMLObject::ot_Actor, o, id)) - widget = new ActorWidget(scene, static_cast(o)); - } else if (tag == QLatin1String("usecasewidget") || tag == QLatin1String("UML:UseCaseWidget")) { - if (validateObjType(UMLObject::ot_UseCase, o, id)) - widget = new UseCaseWidget(scene, static_cast(o)); - } else if (tag == QLatin1String("classwidget") || - tag == QLatin1String("UML:ClassWidget") || tag == QLatin1String("UML:ConceptWidget")) { - if (validateObjType(UMLObject::ot_Class, o, id)) - widget = new ClassifierWidget(scene, static_cast(o)); - } else if (tag == QLatin1String("packagewidget")) { - if (validateObjType(UMLObject::ot_Package, o, id)) - widget = new ClassifierWidget(scene, static_cast(o)); - } else if (tag == QLatin1String("componentwidget")) { - if (validateObjType(UMLObject::ot_Component, o, id)) - widget = new ComponentWidget(scene, static_cast(o)); - } else if (tag == QLatin1String("portwidget")) { - if (validateObjType(UMLObject::ot_Port, o, id)) - widget = new PortWidget(scene, static_cast(o)); - } else if (tag == QLatin1String("nodewidget")) { - if (validateObjType(UMLObject::ot_Node, o, id)) - widget = new NodeWidget(scene, static_cast(o)); - } else if (tag == QLatin1String("artifactwidget")) { - if (validateObjType(UMLObject::ot_Artifact, o, id)) - widget = new ArtifactWidget(scene, static_cast(o)); - } else if (tag == QLatin1String("interfacewidget")) { - if (validateObjType(UMLObject::ot_Interface, o, id)) - widget = new ClassifierWidget(scene, static_cast(o)); - } else if (tag == QLatin1String("datatypewidget")) { - if (validateObjType(UMLObject::ot_Datatype, o, id)) - widget = new DatatypeWidget(scene, static_cast(o)); - } else if (tag == QLatin1String("enumwidget")) { - if (validateObjType(UMLObject::ot_Enum, o, id)) - widget = new EnumWidget(scene, static_cast(o)); - } else if (tag == QLatin1String("entitywidget")) { - if (validateObjType(UMLObject::ot_Entity, o, id)) - widget = new EntityWidget(scene, static_cast(o)); - } else if (tag == QLatin1String("categorywidget")) { - if (validateObjType(UMLObject::ot_Category, o, id)) - widget = new CategoryWidget(scene, static_cast(o)); - } else if (tag == QLatin1String("objectwidget") || tag == QLatin1String("UML:ObjectWidget")) { - widget = new ObjectWidget(scene, o); - } else { - uWarning() << "Trying to create an unknown widget:" << tag; - } - } - return widget; -} - -} // end namespace Widget_Factory - diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/widget_factory.h umbrello-kf6-15.08.1/umbrello/widgets/widget_factory.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/widget_factory.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/widget_factory.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,34 +0,0 @@ -/*************************************************************************** - * 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) 2006-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef WIDGET_FACTORY_H -#define WIDGET_FACTORY_H - -#include - -// forward declarations -class UMLObject; -class UMLScene; -class UMLWidget; - -/** - * Widget factory methods. - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -namespace Widget_Factory { - - UMLWidget *createWidget(UMLScene *scene, UMLObject *docObj); - - UMLWidget* makeWidgetFromXMI(const QString& tag, - const QString& idStr, UMLScene *scene); - -} // end namespace Widget_Factory - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/widgetlist_utils.cpp umbrello-kf6-15.08.1/umbrello/widgets/widgetlist_utils.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/widgetlist_utils.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/widgetlist_utils.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,157 +0,0 @@ -/*************************************************************************** - * 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) 2009-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "widgetlist_utils.h" - -// app includes -#include "debug_utils.h" -#include "umlwidget.h" - -// qt/kde includes -#include - -namespace WidgetList_Utils -{ - -/** - * Looks for the smallest x-value of the given UMLWidgets. - * @param widgetList A list with UMLWidgets. - * @return The smallest X position. - */ -qreal getSmallestX(const UMLWidgetList &widgetList) -{ - qreal smallestX = 0; - - int i = 1; - foreach(UMLWidget *widget, widgetList) { - if (i == 1) { - smallestX = widget->x(); - } else { - if (smallestX > widget->x()) - smallestX = widget->x(); - } - i++; - } - - return smallestX; -} - -/** - * Looks for the smallest y-value of the given UMLWidgets. - * @param widgetList A list with UMLWidgets. - * @return The smallest Y position. - */ -qreal getSmallestY(const UMLWidgetList &widgetList) -{ - if (widgetList.isEmpty()) - return -1; - - qreal smallestY = 0; - - int i = 1; - foreach(UMLWidget *widget, widgetList) { - if (i == 1) { - smallestY = widget->y(); - } else { - if (smallestY > widget->y()) - smallestY = widget->y(); - } - i++; - } - - return smallestY; -} - -/** - * Looks for the biggest x-value of the given UMLWidgets. - * @param widgetList A list with UMLWidgets. - * @return The biggest X position. - */ -qreal getBiggestX(const UMLWidgetList &widgetList) -{ - if (widgetList.isEmpty()) - return -1; - - qreal biggestX = 0; - - int i = 1; - foreach(UMLWidget *widget, widgetList) { - if (i == 1) { - biggestX = widget->x(); - biggestX += widget->width(); - } else { - if (biggestX < widget->x() + widget->width()) - biggestX = widget->x() + widget->width(); - } - i++; - } - - return biggestX; -} - -/** - * Looks for the biggest y-value of the given UMLWidgets. - * @param widgetList A list with UMLWidgets. - * @return The biggest Y position. - */ -qreal getBiggestY(const UMLWidgetList &widgetList) -{ - if (widgetList.isEmpty()) - return -1; - - qreal biggestY = 0; - - int i = 1; - foreach(UMLWidget *widget, widgetList) { - if (i == 1) { - biggestY = widget->y(); - biggestY += widget->height(); - } else { - if (biggestY < widget->y() + widget->height()) - biggestY = widget->y() + widget->height(); - } - i++; - } - - return biggestY; -} - -/** - * Returns the sum of the heights of the given UMLWidgets - * @param widgetList A list with UMLWidgets. - */ -qreal getHeightsSum(const UMLWidgetList &widgetList) -{ - qreal heightsSum = 0; - - foreach(UMLWidget *widget, widgetList) { - heightsSum += widget->height(); - } - - return heightsSum; -} - -/** - * Returns the sum of the widths of the given UMLWidgets. - * @param widgetList A list with UMLWidgets. - */ -qreal getWidthsSum(const UMLWidgetList &widgetList) -{ - qreal widthsSum = 0; - - foreach(UMLWidget *widget, widgetList) { - widthsSum += widget->width(); - } - - return widthsSum; -} - -} // namespace WidgetList_Utils diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/widgetlist_utils.h umbrello-kf6-15.08.1/umbrello/widgets/widgetlist_utils.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/widgetlist_utils.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/widgetlist_utils.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,30 +0,0 @@ -/*************************************************************************** - * 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) 2009-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef WIDGETLIST_UTILS_H -#define WIDGETLIST_UTILS_H - -#include "umlwidgetlist.h" - -/** - * General purpose-kf6 widget list utilities. - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -namespace WidgetList_Utils -{ - qreal getSmallestX(const UMLWidgetList &widgetList); - qreal getSmallestY(const UMLWidgetList &widgetList); - qreal getBiggestX(const UMLWidgetList &widgetList); - qreal getBiggestY(const UMLWidgetList &widgetList); - qreal getHeightsSum(const UMLWidgetList &widgetList); - qreal getWidthsSum(const UMLWidgetList &widgetList); -} // namespace WidgetList_Utils - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/widget_utils.cpp umbrello-kf6-15.08.1/umbrello/widgets/widget_utils.cpp --- umbrello-kf6-15.08.1.orig/umbrello/widgets/widget_utils.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/widget_utils.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,827 +0,0 @@ -/*************************************************************************** - * 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) 2004-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -// own header -#include "widget_utils.h" - -// app includes -#include "debug_utils.h" -#include "objectwidget.h" -#include "messagewidget.h" -#include "umlwidget.h" - -// qt includes -#include -#include -#include -#include -#include - -// c++ include -#include - -namespace Widget_Utils -{ - - /** - * Find the widget identified by the given ID in the given widget - * or message list. - * - * @param id The unique ID to find. - * @param widgets The UMLWidgetList to search in. - * @param messages Optional pointer to a MessageWidgetList to search in. - */ - UMLWidget* findWidget(Uml::ID::Type id, - const UMLWidgetList& widgets, - const MessageWidgetList* messages /* = 0 */) - { - foreach (UMLWidget* obj, widgets) { - if (obj->baseType() == WidgetBase::wt_Object) { - if (static_cast(obj)->localID() == id) - return obj; - } else if (obj->id() == id) { - return obj; - } - } - - if (messages) { - foreach (UMLWidget* obj, *messages) { - if (obj->id() == id) - return obj; - } - } - return NULL; - } - - /** - * Creates the decoration point. - * @param p base point to decorate - * @param parent parent item - * @return decoration point - */ - QGraphicsRectItem* decoratePoint(const QPointF &p, QGraphicsItem* parent) - { - const qreal SIZE = 4.0; - const qreal SIZE_HALF = SIZE / 2.0; - QGraphicsRectItem *rect = new QGraphicsRectItem(p.x() - SIZE_HALF, - p.y() - SIZE_HALF, - SIZE, SIZE, - parent); - rect->setBrush(QBrush(Qt::blue)); - rect->setPen(QPen(Qt::blue)); - return rect; - } - - /** - * Calculates and draws a cross inside an ellipse - * @param p Pointer to a QPainter object. - * @param r The rectangle describing the ellipse. - */ - void drawCrossInEllipse(QPainter *p, const QRectF& r) - { - QRectF ellipse = r; - ellipse.moveCenter(QPointF(0, 0)); - qreal a = ellipse.width() * 0.5; - qreal b = ellipse.height() * .5; - qreal xc = ellipse.center().x(); - qreal yc = ellipse.center().y(); - - // The first point's x value is chosen to be center.x() + 70% of x radius. - qreal x1 = ellipse.center().x() + .7 * .5 * ellipse.width(); - // Calculate y1 corresponding to x1 using formula. - qreal y1_sqr = b*b*(1 - (x1 * x1) / (a*a)); - qreal y1 = std::sqrt(y1_sqr); - - // Mirror x1, y1 along both the axes to get 4 points for the cross. - QPointF p1(xc + x1, yc + y1); - QPointF p2(xc - x1, yc + y1); - QPointF p3(xc + x1, yc - y1); - QPointF p4(xc - x1, yc - y1); - - // Translate as we calculate for ellipse with (0, 0) as center. - p->translate(r.center().x(), r.center().y()); - - // Draw the cross now - p->drawLine(QLineF(p1, p4)); - p->drawLine(QLineF(p2, p3)); - - // Restore the translate on painter. - p->translate(-r.center().x(), -r.center().y()); - } - - /** - * Draws a polygon which is almost rectangular except for the top - * right corner. A triangle is drawn in top right corner of the - * rectangle. - * - * @param painter The painter with which this shape is to be drawn. - * @param rect The rectangle dimensions. - * @param triSize The size of the triangle in the top-right corner. - */ - void drawTriangledRect(QPainter *painter, - const QRectF &rect, const QSizeF &triSize) - { - // Draw outer boundary defined by polygon "poly". - QPolygonF poly(5); - poly[0] = rect.topLeft(); - poly[1] = rect.topRight() - QPointF(triSize.width(), 0); - poly[2] = rect.topRight() + QPointF(0, triSize.height()); - poly[3] = rect.bottomRight(); - poly[4] = rect.bottomLeft(); - painter->drawPolygon(poly); - - // Now draw the triangle base and height edges. - QLineF heightEdge(poly[1], poly[1] + QPointF(0, triSize.height())); - painter->drawLine(heightEdge); - QLineF baseEdge(heightEdge.p2(), poly[2]); - painter->drawLine(baseEdge); - } - -// /** -// * Draws an arrow head with the given painter, with the arrow -// * sharp point at \a headPos. -// * -// * param painter The painter with which this arrow should be drawn. -// * param headPos The position where the head of the arrow should lie. -// * param arrowSize This indicates the size of the arrow head. -// * param arrowType This indicates direction of arrow as in LeftArrow, RightArrow.. -// * param solid-kf6 If true, a solid-kf6 head is drawn. Otherwise 2 lines are drawn. -// */ -// void drawArrowHead(QPainter *painter, const QPointF &arrowPos, -// const QSizeF& arrowSize, Qt::ArrowType arrowType, -// bool solid-kf6) -// { -// QPolygonF poly; -// if (arrowType == Qt::LeftArrow) { -// poly << QPointF(arrowPos.x() + arrowSize.width(), arrowPos.y() - .5 * arrowSize.height()) -// << arrowPos -// << QPointF(arrowPos.x() + arrowSize.width(), arrowPos.y() + .5 * arrowSize.height()); -// } -// else if (arrowType == Qt::RightArrow) { -// poly << QPointF(arrowPos.x() - arrowSize.width(), arrowPos.y() - .5 * arrowSize.height()) -// << arrowPos -// << QPointF(arrowPos.x() - arrowSize.width(), arrowPos.y() + .5 * arrowSize.height()); -// } - -// if (solid-kf6) { -// painter->drawPolygon(poly); -// } -// else { -// painter->drawPolyline(poly); -// } -// } - -// /** -// * Draws a rounded rect rounded at specified corners. -// * -// * param painter The painter with which this round rect should be drawn. -// * param rect The rectangle to be drawn. -// * param xRadius The x radius of rounded corner. -// * param yRadius The y radius of rounded corner. -// * param corners The corners to be rounded. -// */ -// void drawRoundedRect(QPainter *painter, const QRectF& rect, qreal xRadius, -// qreal yRadius, Uml::Corners corners) -// { -// if (xRadius < 0 || yRadius < 0) { -// painter->drawRect(rect); -// return; -// } -// QRectF arcRect(0, 0, 2 * xRadius, 2 * yRadius); - -// QPainterPath path; -// path.moveTo(rect.left(), rect.top() + yRadius); -// if (corners.testFlag(Uml::Corner::TopLeft)) { -// arcRect.moveTopLeft(rect.topLeft()); -// path.arcTo(arcRect, 180, -90); -// } else { -// path.lineTo(rect.topLeft()); -// } - -// path.lineTo(rect.right() - xRadius, rect.top()); - -// if (corners.testFlag(Uml::Corner::TopRight)) { -// arcRect.moveTopRight(rect.topRight()); -// path.arcTo(arcRect, 90, -90); -// } else { -// path.lineTo(rect.topRight()); -// } - -// path.lineTo(rect.right(), rect.bottom() - yRadius); - -// if (corners.testFlag(Uml::Corner::BottomRight)) { -// arcRect.moveBottomRight(rect.bottomRight()); -// path.arcTo(arcRect, 0, -90); -// } else { -// path.lineTo(rect.bottomRight()); -// } - -// path.lineTo(rect.left() + xRadius, rect.bottom()); - -// if (corners.testFlag(Uml::Corner::BottomLeft)) { -// arcRect.moveBottomLeft(rect.bottomLeft()); -// path.arcTo(arcRect, 270, 90); -// } else { -// path.lineTo(rect.bottomLeft()); -// } - -// path.closeSubpath(); -// painter->drawPath(path); -// } - - /** - * Converts a point to a comma separated string i.e "x,y" - * @param point The QPointF to convert. - */ - QString pointToString(const QPointF& point) - { - return QString::fromLatin1("%1,%2").arg(point.x()).arg(point.y()); - } - - /** - * Converts a comma separated string to point. - */ - QPointF stringToPoint(const QString& str) - { - QPointF retVal; - QStringList list = str.split(QLatin1Char(',')); - - if(list.size() == 2) { - retVal.setX(list.first().toDouble()); - retVal.setY(list.last().toDouble()); - } - return retVal; - } - - /** - * Loads pixmap from xmi. - * - * @param pixEle The dom element from which pixmap should be loaded. - * - * @param pixmap The pixmap into which the image should be loaded. - * - * @return True or false based on success or failure of this method. - */ - bool loadPixmapFromXMI(QDomElement &pixEle, QPixmap &pixmap) - { - if (pixEle.isNull()) { - return false; - } - QDomElement xpmElement = pixEle.firstChildElement(QLatin1String("xpm")); - - QByteArray xpmData = xpmElement.text().toLatin1(); - QBuffer buffer(&xpmData); - buffer.open(QIODevice::ReadOnly); - - QImageReader reader(&buffer, "xpm"); - QImage image; - if (!reader.read(&image)) { - return false; - } - - pixmap = QPixmap::fromImage(image); - return true; - } - - /** - * Saves pixmap information into DOM element \a qElement. - * - * @param qDoc The DOM document object. - * - * @param qElement The DOM element into which the pixmap should be - * saved. - * - * @param pixmap The pixmap to be saved. - */ - void savePixmapToXMI(QDomDocument &qDoc, QDomElement &qElement, const QPixmap& pixmap) - { - QDomElement pixmapElement = qDoc.createElement(QLatin1String("pixmap")); - - QDomElement xpmElement = qDoc.createElement(QLatin1String("xpm")); - pixmapElement.appendChild(xpmElement); - - QBuffer buffer; - buffer.open(QIODevice::WriteOnly); - pixmap.save(&buffer, "xpm"); - buffer.close(); - - xpmElement.appendChild(qDoc.createTextNode(QString::fromLatin1(buffer.data()))); - - qElement.appendChild(pixmapElement); - } - - /** - * Loads gradient from xmi. The gradient pointer should be null - * and the new gradient object will be created inside this method. - * The gradient should later be deleted externally. - * - * @param gradientElement The DOM element from which gradient should be - * loaded. - * - * @param gradient The pointer to gradient into which the gradient - * should be loaded. (Allocated inside this - * method) - * - * @return True or false based on success or failure of this method. - */ - bool loadGradientFromXMI(QDomElement &gradientElement, QGradient *&gradient) - { - if(gradientElement.isNull()) { - return false; - } - - int type_as_int; - QGradient::Type type; - QGradientStops stops; - QGradient::CoordinateMode cmode = QGradient::LogicalMode; - QGradient::Spread spread = QGradient::PadSpread; - - type_as_int = gradientElement.attribute(QLatin1String("type")).toInt(); - type = QGradient::Type(type_as_int); - type_as_int = gradientElement.attribute(QLatin1String("spread")).toInt(); - spread = QGradient::Spread(type_as_int); - type_as_int = gradientElement.attribute(QLatin1String("coordinatemode")).toInt(); - cmode = QGradient::CoordinateMode(type_as_int); - - QDomElement stopElement = gradientElement.firstChildElement(QLatin1String("stops")); - if(stopElement.isNull()) { - return false; - } - for(QDomNode node = stopElement.firstChild(); !node.isNull(); node = node.nextSibling()) { - QDomElement ele = node.toElement(); - if(ele.tagName() != QLatin1String("stop")) { - continue; - } - - qreal posn = ele.attribute(QLatin1String("position")).toDouble(); - QColor color = QColor(ele.attribute(QLatin1String("color"))); - stops << QGradientStop(posn, color); - } - - if (type == QGradient::LinearGradient) { - QPointF p1 = stringToPoint(gradientElement.attribute(QLatin1String("start"))); - QPointF p2 = stringToPoint(gradientElement.attribute(QLatin1String("finalstop"))); - gradient = new QLinearGradient(p1, p2); - } - else if (type == QGradient::RadialGradient) { - QPointF center = stringToPoint(gradientElement.attribute(QLatin1String("center"))); - QPointF focal = stringToPoint(gradientElement.attribute(QLatin1String("focalpoint"))); - double radius = gradientElement.attribute(QLatin1String("radius")).toDouble(); - gradient = new QRadialGradient(center, radius, focal); - } - else { // type == QGradient::ConicalGradient - QPointF center = stringToPoint(gradientElement.attribute(QLatin1String("center"))); - double angle = gradientElement.attribute(QLatin1String("angle")).toDouble(); - gradient = new QConicalGradient(center, angle); - } - - if(gradient) { - gradient->setStops(stops); - gradient->setSpread(spread); - gradient->setCoordinateMode(cmode); - return true; - } - - return false; - } - - /** - * Saves gradient information into DOM element \a qElement. - * - * @param qDoc The DOM document object. - * - * @param qElement The DOM element into which the gradient should be - * saved. - * - * @param gradient The gradient to be saved. - */ - void saveGradientToXMI(QDomDocument &qDoc, QDomElement &qElement, const QGradient *gradient) - { - QDomElement gradientElement = qDoc.createElement(QLatin1String("gradient")); - - gradientElement.setAttribute(QLatin1String("type"), int(gradient->type())); - gradientElement.setAttribute(QLatin1String("spread"), int(gradient->spread())); - gradientElement.setAttribute(QLatin1String("coordinatemode"), int(gradient->coordinateMode())); - - QDomElement stopsElement = qDoc.createElement(QLatin1String("stops")); - gradientElement.appendChild(stopsElement); - - foreach(const QGradientStop& stop, gradient->stops()) { - QDomElement ele = qDoc.createElement(QLatin1String("stop")); - ele.setAttribute(QLatin1String("position"), stop.first); - ele.setAttribute(QLatin1String("color"), stop.second.name()); - stopsElement.appendChild(ele); - } - - QGradient::Type type = gradient->type(); - - if(type == QGradient::LinearGradient) { - const QLinearGradient *lg = static_cast(gradient); - gradientElement.setAttribute(QLatin1String("start"), pointToString(lg->start())); - gradientElement.setAttribute(QLatin1String("finalstop"), pointToString(lg->finalStop())); - } - else if(type == QGradient::RadialGradient) { - const QRadialGradient *rg = static_cast(gradient); - gradientElement.setAttribute(QLatin1String("center"), pointToString(rg->center())); - gradientElement.setAttribute(QLatin1String("focalpoint"), pointToString(rg->focalPoint())); - gradientElement.setAttribute(QLatin1String("radius"), rg->radius()); - } - else { //type == QGradient::ConicalGradient - const QConicalGradient *cg = static_cast(gradient); - gradientElement.setAttribute(QLatin1String("center"), pointToString(cg->center())); - gradientElement.setAttribute(QLatin1String("angle"), cg->angle()); - } - - qElement.appendChild(gradientElement); - } - - /** - * Extracts the QBrush properties into brush from the XMI xml - * element qElement. - * - * @param qElement The DOM element from which the xmi info should - * be extracted. - * - * @param brush The QBrush object into which brush details should - * be read into. - */ - bool loadBrushFromXMI(QDomElement &qElement, QBrush &brush) - { - if(qElement.isNull()) { - return false; - } - - quint8 style = qElement.attribute(QLatin1String("style")).toShort(); - const QString colorString = qElement.attribute(QLatin1String("color")); - QColor color; - color.setNamedColor(colorString); - - if(style == Qt::TexturePattern) { - QPixmap pixmap; - QDomElement pixElement = qElement.firstChildElement(QLatin1String("pixmap")); - if(!loadPixmapFromXMI(pixElement, pixmap)) { - return false; - } - brush = QBrush(color, pixmap); - } - - else if(style == Qt::LinearGradientPattern - || style == Qt::RadialGradientPattern - || style == Qt::ConicalGradientPattern) { - QGradient *gradient = 0; - QDomElement gradElement = qElement.firstChildElement(QLatin1String("gradient")); - - if(!loadGradientFromXMI(gradElement, gradient) || !gradient) { - delete gradient; - return false; - } - - brush = QBrush(*gradient); - delete gradient; - } - - else { - brush = QBrush(color, (Qt::BrushStyle)style); - } - - //TODO: Checks if transform needs to be loaded. - - return true; - } - - /** - * Saves the brush info as xmi into the DOM element \a qElement. - * - * @param qDoc The QDomDocument object pointing to the xmi document. - * - * @param qElement The element into which the pen, brush and font - * info should be saved. - * - * @param brush The QBrush whose details should be saved. - */ - void saveBrushToXMI(QDomDocument &qDoc, QDomElement &qElement, - const QBrush& brush) - { - QDomElement brushElement = qDoc.createElement(QLatin1String("brush")); - - brushElement.setAttribute(QLatin1String("style"), (quint8)brush.style()); - brushElement.setAttribute(QLatin1String("color"), brush.color().name()); - - if(brush.style() == Qt::TexturePattern) { - savePixmapToXMI(qDoc, brushElement, brush.texture()); - } - else if(brush.style() == Qt::LinearGradientPattern - || brush.style() == Qt::RadialGradientPattern - || brush.style() == Qt::ConicalGradientPattern) { - saveGradientToXMI(qDoc, brushElement, brush.gradient()); - } - - //TODO: Check if transform of this brush needs to be saved. - qElement.appendChild(brushElement); - } - - /** - * Returns true if the first widget's X is smaller than second's. - * Used for sorting the UMLWidgetList. - * @param widget1 The widget to compare. - * @param widget2 The widget to compare with. - */ - bool hasSmallerX(const UMLWidget* widget1, const UMLWidget* widget2) - { - return widget1->x() < widget2->x(); - } - - /** - * Returns true if the first widget's Y is smaller than second's. - * Used for sorting the UMLWidgetList. - * @param widget1 The widget to compare. - * @param widget2 The widget to compare with. - */ - bool hasSmallerY(const UMLWidget* widget1, const UMLWidget* widget2) - { - return widget1->y() < widget2->y(); - } - - /** - * Find the region in which the rectangle \a other lies with respect to - * the rectangle \a self. - * Beware that the Qt coordinate system has its origin point (0,0) in - * the upper left corner with Y values growing downwards, thus the Y - * related comparisons might look inverted if your are used to the - * natural coordinate system with (0,0) in the lower left corner. - */ - Uml::Region::Enum findRegion(const QRectF& self, const QRectF &other) - { - const qreal ownX = self.x(); - const qreal ownY = self.y(); - const qreal ownWidth = self.width(); - const qreal ownHeight = self.height(); - const qreal otherX = other.x(); - const qreal otherY = other.y(); - const qreal otherWidth = other.width(); - const qreal otherHeight = other.height(); - Uml::Region::Enum region = Uml::Region::Center; - if (otherX + otherWidth < ownX) { - if (otherY + otherHeight < ownY) - region = Uml::Region::NorthWest; - else if (otherY > ownY + ownHeight) - region = Uml::Region::SouthWest; - else - region = Uml::Region::West; - } else if (otherX > ownX + ownWidth) { - if (otherY + otherHeight < ownY) - region = Uml::Region::NorthEast; - else if (otherY > ownY + ownHeight) - region = Uml::Region::SouthEast; - else - region = Uml::Region::East; - } else { - if (otherY + otherHeight < ownY) - region = Uml::Region::North; - else if (otherY > ownY + ownHeight) - region = Uml::Region::South; - else - region = Uml::Region::Center; - } - return region; - } - - /** - * Return the point in \a poly which precedes the point at index \a index. - * If \a index is 0 then return the last (or, if \a poly.isClosed() is - * true, the second to last) point. - */ - QPointF prevPoint(int index, const QPolygonF& poly) { - if (poly.size() < 3 || index >= poly.size()) - return QPoint(); - if (index == 0) - return poly.at(poly.size() - 1 - (int)poly.isClosed()); - return poly.at(index - 1); - } - - /** - * Return the point in \a poly which follows the point at index \a index. - * If \a index is the last index then return the first (or, if - * \a poly.isClosed() is true, the second) point. - */ - QPointF nextPoint(int index, const QPolygonF& poly) { - if (poly.size() < 3 || index >= poly.size()) - return QPoint(); - if (index == poly.size() - 1) - return poly.at((int)poly.isClosed()); - return poly.at(index + 1); - } - - /** - * Return the middle value between \a a and \a b. - */ - qreal middle(qreal a, qreal b) - { - return (a + b) / 2.0; - } - - /** - * Auxiliary type for function findLine() - */ - enum Axis_Type { X , Y }; - - /** - * Auxiliary type for function findLine() - */ - enum Comparison_Type { Smallest, Largest }; - - /** - * Find the line of \a poly with the smallest or largest value (controlled by \a seek) - * along the axis controlled by \a axis. - * In case \a axis is X, do not consider lines whose Y values lie outside the Y values - * defined by \a boundingRect. - * In case \a axis is Y, do not consider lines whose X values lie outside the X values - * defined by \a boundingRect. - */ - QLineF findLine(const QPolygonF& poly, Axis_Type axis, Comparison_Type seek, const QRectF& boundingRect) - { - const int lastIndex = poly.size() - 1 - (int)poly.isClosed(); - QPointF prev = poly.at(lastIndex), curr; - QPointF p1(seek == Smallest ? QPointF(1.0e6, 1.0e6) : QPointF(-1.0e6, -1.0e6)); - QPointF p2; - for (int i = 0; i <= lastIndex; i++) { - curr = poly.at(i); - // uDebug() << " poly[" << i << "] = " << curr; - if (axis == X) { - if (fmin(prev.y(), curr.y()) > boundingRect.y() + boundingRect.height() || - fmax(prev.y(), curr.y()) < boundingRect.y()) { - // line is outside Y-axis range defined by boundingRect - } else if ((seek == Smallest && curr.x() <= p1.x()) || - (seek == Largest && curr.x() >= p1.x())) { - p1 = curr; - p2 = prev; - } - } else { - if (fmin(prev.x(), curr.x()) > boundingRect.x() + boundingRect.width() || - fmax(prev.x(), curr.x()) < boundingRect.x()) { - // line is outside X-axis range defined by boundingRect - } else if ((seek == Smallest && curr.y() <= p1.y()) || - (seek == Largest && curr.y() >= p1.y())) { - p1 = curr; - p2 = prev; - } - } - prev = curr; - } - return QLineF(p1, p2); - } - - /** - * Determine the approximate closest points of two polygons. - * @param self First QPolygonF. - * @param other Second QPolygonF. - * @return QLineF::p1() returns point of \a self; - * QLineF::p2() returns point of \a other. - */ - QLineF closestPoints(const QPolygonF& self, const QPolygonF& other) - { - const QRectF& selfRect = self.boundingRect(); - const QRectF& otherRect = other.boundingRect(); - Uml::Region::Enum region = findRegion(selfRect, otherRect); - if (region == Uml::Region::Center) - return QLineF(); - if (self.size() < 3 || other.size() < 3) - return QLineF(); - QLineF result; - const int selfLastIndex = self.size() - 1 - (int)self.isClosed(); - const int otherLastIndex = other.size() - 1 - (int)other.isClosed(); - QPointF selfPoint(self.at(selfLastIndex)); - QPointF otherPoint(other.at(otherLastIndex)); - QLineF selfLine, otherLine; - int i; - - switch (region) { - - case Uml::Region::North: - // Find other's line with largest Y values - otherLine = findLine(other, Y, Largest, selfRect); - // Find own line with smallest Y values - selfLine = findLine(self, Y, Smallest, otherRect); - // Use the middle value of the X values - result.setLine(middle(selfLine.p2().x(), selfLine.p1().x()), selfLine.p1().y(), - middle(otherLine.p2().x(), otherLine.p1().x()), otherLine.p1().y()); - break; - - case Uml::Region::South: - // Find other's line with smallest Y values - otherLine = findLine(other, Y, Smallest, selfRect); - // Find own line with largest Y values - selfLine = findLine(self, Y, Largest, otherRect); - // Use the middle value of the X values - result.setLine(middle(selfLine.p2().x(), selfLine.p1().x()), selfLine.p1().y(), - middle(otherLine.p2().x(), otherLine.p1().x()), otherLine.p1().y()); - break; - - case Uml::Region::West: - // Find other's line with largest X values - otherLine = findLine(other, X, Largest, selfRect); - // Find own line with smallest X values - selfLine = findLine(self, X, Smallest, otherRect); - // Use the middle value of the Y values - result.setLine(selfLine.p1().x(), middle(selfLine.p2().y(), selfLine.p1().y()), - otherLine.p1().x(), middle(otherLine.p2().y(), otherLine.p1().y())); - break; - - case Uml::Region::East: - // Find other's line with smallest X values - otherLine = findLine(other, X, Smallest, selfRect); - // Find own line with largest X values - selfLine = findLine(self, X, Largest, otherRect); - // Use the middle value of the Y values - result.setLine(selfLine.p1().x(), middle(selfLine.p2().y(), selfLine.p1().y()), - otherLine.p1().x(), middle(otherLine.p2().y(), otherLine.p1().y())); - break; - - case Uml::Region::NorthWest: - // Find other's point with largest X and largest Y value - for (i = 0; i < otherLastIndex; ++i) { - QPointF current(other.at(i)); - if (current.x() + current.y() >= otherPoint.x() + otherPoint.y()) { - otherPoint = current; - } - } - // Find own point with smallest X and smallest Y value - for (i = 0; i < selfLastIndex; ++i) { - QPointF current(self.at(i)); - if (current.x() + current.y() <= selfPoint.x() + selfPoint.y()) { - selfPoint = current; - } - } - result.setPoints(selfPoint, otherPoint); - break; - - case Uml::Region::SouthWest: - // Find other's point with largest X and smallest Y value - for (i = 0; i < otherLastIndex; ++i) { - QPointF current(other.at(i)); - if (current.x() >= otherPoint.x() && current.y() <= otherPoint.y()) { - otherPoint = current; - } - } - // Find own point with smallest X and largest Y value - for (i = 0; i < selfLastIndex; ++i) { - QPointF current(self.at(i)); - if (current.x() <= selfPoint.x() && current.y() >= selfPoint.y()) { - selfPoint = current; - } - } - result.setPoints(selfPoint, otherPoint); - break; - - case Uml::Region::NorthEast: - // Find other's point with smallest X and largest Y value - for (i = 0; i < otherLastIndex; ++i) { - QPointF current(other.at(i)); - if (current.x() <= otherPoint.x() && current.y() >= otherPoint.y()) { - otherPoint = current; - } - } - // Find own point with largest X and smallest Y value - for (i = 0; i < selfLastIndex; ++i) { - QPointF current(self.at(i)); - if (current.x() >= selfPoint.x() && current.y() <= selfPoint.y()) { - selfPoint = current; - } - } - result.setPoints(selfPoint, otherPoint); - break; - - case Uml::Region::SouthEast: - // Find other's point with smallest X and smallest Y value - for (i = 0; i < otherLastIndex; ++i) { - QPointF current(other.at(i)); - if (current.x() + current.y() <= otherPoint.x() + otherPoint.y()) { - otherPoint = current; - } - } - // Find own point with largest X and largest Y value - for (i = 0; i < selfLastIndex; ++i) { - QPointF current(self.at(i)); - if (current.x() + current.y() >= selfPoint.x() + selfPoint.y()) { - selfPoint = current; - } - } - result.setPoints(selfPoint, otherPoint); - break; - - default: - // Error - break; - } - - return result; - } - -} // namespace Widget_Utils diff -Nuar umbrello-kf6-15.08.1.orig/umbrello/widgets/widget_utils.h umbrello-kf6-15.08.1/umbrello/widgets/widget_utils.h --- umbrello-kf6-15.08.1.orig/umbrello/widgets/widget_utils.h 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/umbrello/widgets/widget_utils.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,66 +0,0 @@ -/*************************************************************************** - * 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) 2004-2014 * - * umbrello-kf6 UML Modeller Authors * - ***************************************************************************/ - -#ifndef WIDGET_UTILS_H -#define WIDGET_UTILS_H - -#include "basictypes.h" -#include "messagewidgetlist.h" -#include "umlwidgetlist.h" - -#include -#include -#include -#include -#include - -class QGraphicsItem; -class QGraphicsRectItem; - -/** - * General purpose-kf6 widget utilities. - * Bugs and comments to umbrello-kf6-devel@kde.org or http://bugs.kde.org - */ -namespace Widget_Utils -{ - UMLWidget* findWidget(Uml::ID::Type id, - const UMLWidgetList& widgets, - const MessageWidgetList* messages = 0); - - QGraphicsRectItem* decoratePoint(const QPointF& p, QGraphicsItem* parent = 0); - - void drawCrossInEllipse(QPainter *p, const QRectF& ellipse); - void drawTriangledRect(QPainter *painter, const QRectF& rect, const QSizeF& triSize); -// void drawArrowHead(QPainter *painter, const QPointF& arrowPos, -// const QSizeF& arrowSize, Qt::ArrowType arrowType, -// bool solid-kf6 = false); -// void drawRoundedRect(QPainter *painter, const QRectF& rect, qreal xRadius, -// qreal yRadius, Uml::Corners corners); - - QString pointToString(const QPointF& point); - QPointF stringToPoint(const QString& str); - - bool loadPixmapFromXMI(QDomElement &qElement, QPixmap &pixmap); - void savePixmapToXMI(QDomDocument &qDoc, QDomElement &qElement, const QPixmap& pixmap); - - bool loadGradientFromXMI(QDomElement &qElement, QGradient *&gradient); - void saveGradientToXMI(QDomDocument &qDoc, QDomElement &qElement, const QGradient *gradient); - - bool loadBrushFromXMI(QDomElement &qElement, QBrush &brush); - void saveBrushToXMI(QDomDocument &qDoc, QDomElement &qElement, - const QBrush& brush); - - bool hasSmallerX(const UMLWidget* widget1, const UMLWidget* widget2); - bool hasSmallerY(const UMLWidget* widget1, const UMLWidget* widget2); - - QLineF closestPoints(const QPolygonF& self, const QPolygonF& other); -} - -#endif diff -Nuar umbrello-kf6-15.08.1.orig/unittests/CMakeLists.txt umbrello-kf6-15.08.1/unittests/CMakeLists.txt --- umbrello-kf6-15.08.1.orig/unittests/CMakeLists.txt 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/unittests/CMakeLists.txt 2015-10-08 11:48:59.553089025 +0300 @@ -37,7 +37,8 @@ ${SRC_PATH}/dialogs ${SRC_PATH}/docgenerators ${SRC_PATH}/refactoring - ${SRC_PATH}/widgets + ${SRC_PATH}/umlmodel/ + ${SRC_PATH}/umlwidgets/ ${CMAKE_CURRENT_BINARY_DIR} ) diff -Nuar umbrello-kf6-15.08.1.orig/unittests/testbase.cpp umbrello-kf6-15.08.1/unittests/testbase.cpp --- umbrello-kf6-15.08.1.orig/unittests/testbase.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/unittests/testbase.cpp 2015-10-08 11:48:59.553089025 +0300 @@ -39,8 +39,6 @@ #include #endif -static UMLApp *umlApp = 0; - TestBase::TestBase(QObject *parent) : QObject(parent) { @@ -49,12 +47,12 @@ void TestBase::initTestCase() { QWidget *w = new QWidget; - umlApp = new UMLApp(w); + new UMLApp(w); } void TestBase::cleanupTestCase() { - delete umlApp; + delete UMLApp::app(); } void TestCodeGeneratorBase::initTestCase() diff -Nuar umbrello-kf6-15.08.1.orig/unittests/TEST_cppwriter.cpp umbrello-kf6-15.08.1/unittests/TEST_cppwriter.cpp --- umbrello-kf6-15.08.1.orig/unittests/TEST_cppwriter.cpp 2015-09-10 01:54:59.000000000 +0300 +++ umbrello-kf6-15.08.1/unittests/TEST_cppwriter.cpp 2015-10-08 11:48:59.553089025 +0300 @@ -51,9 +51,11 @@ UMLAttribute* attr; attr = c->createAttribute("name_"); attr = c->createAttribute("address_"); + c->addAttribute(attr); UMLOperation* op; op = c->createOperation("getName"); op = c->createOperation("getAddress"); + c->addOperation(op); cpp->writeClass(c); // does the just created file exist?