diff --git a/desktop/kde/sdk/umbrello/actions.py b/desktop/kde/sdk/umbrello/actions.py index 7889252e8a..c2fa753f3c 100755 --- a/desktop/kde/sdk/umbrello/actions.py +++ b/desktop/kde/sdk/umbrello/actions.py @@ -12,12 +12,7 @@ from pisi.actionsapi import get NoStrip=["/usr/share"] def setup(): - kde5.configure("-DCMAKE_INSTALL_PREFIX=/usr \ - -DCMAKE_BUILD_TYPE=Release \ - -DLIB_INSTALL_DIR=lib \ - -DBUILD_TESTING=OFF \ - -DBUILD_KF5=ON \ - -DKDE_INSTALL_USE_QT_SYS_PATHS=ON") + kde5.configure("-DBUILD_KF5=ON") def build(): kde5.make() diff --git a/desktop/kde/sdk/umbrello/files/upstream.patch b/desktop/kde/sdk/umbrello/files/upstream.patch new file mode 100644 index 0000000000..9aa2960641 --- /dev/null +++ b/desktop/kde/sdk/umbrello/files/upstream.patch @@ -0,0 +1,77852 @@ +diff -Nuar umbrello-15.08.1.orig/CMakeLists.txt umbrello-15.08.1/CMakeLists.txt +--- umbrello-15.08.1.orig/CMakeLists.txt 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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_VERSION_MAJOR "2") +-set(UMBRELLO_VERSION_MINOR "17") +-set(UMBRELLO_VERSION_PATCH ${KDE_APPLICATIONS_VERSION_MICRO}) ++set(UMBRELLO_VERSION_MINOR "18") ++set(UMBRELLO_VERSION_PATCH "99") + + option(BUILD_KF5 "Build for KDE Frameworks 5" OFF) + +diff -Nuar umbrello-15.08.1.orig/umbrello/actor.cpp umbrello-15.08.1/umbrello/actor.cpp +--- umbrello-15.08.1.orig/umbrello/actor.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/actor.h umbrello-15.08.1/umbrello/actor.h +--- umbrello-15.08.1.orig/umbrello/actor.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/artifact.cpp umbrello-15.08.1/umbrello/artifact.cpp +--- umbrello-15.08.1.orig/umbrello/artifact.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/artifact.h umbrello-15.08.1/umbrello/artifact.h +--- umbrello-15.08.1.orig/umbrello/artifact.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/association.cpp umbrello-15.08.1/umbrello/association.cpp +--- umbrello-15.08.1.orig/umbrello/association.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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 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-15.08.1.orig/umbrello/association.h umbrello-15.08.1/umbrello/association.h +--- umbrello-15.08.1.orig/umbrello/association.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/attribute.cpp umbrello-15.08.1/umbrello/attribute.cpp +--- umbrello-15.08.1.orig/umbrello/attribute.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/attribute.h umbrello-15.08.1/umbrello/attribute.h +--- umbrello-15.08.1.orig/umbrello/attribute.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/category.cpp umbrello-15.08.1/umbrello/category.cpp +--- umbrello-15.08.1.orig/umbrello/category.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/category.h umbrello-15.08.1/umbrello/category.h +--- umbrello-15.08.1.orig/umbrello/category.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/checkconstraint.cpp umbrello-15.08.1/umbrello/checkconstraint.cpp +--- umbrello-15.08.1.orig/umbrello/checkconstraint.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/checkconstraint.h umbrello-15.08.1/umbrello/checkconstraint.h +--- umbrello-15.08.1.orig/umbrello/checkconstraint.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/classifier.cpp umbrello-15.08.1/umbrello/classifier.cpp +--- umbrello-15.08.1.orig/umbrello/classifier.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/classifier.h umbrello-15.08.1/umbrello/classifier.h +--- umbrello-15.08.1.orig/umbrello/classifier.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/classifierlistitem.cpp umbrello-15.08.1/umbrello/classifierlistitem.cpp +--- umbrello-15.08.1.orig/umbrello/classifierlistitem.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/classifierlistitem.h umbrello-15.08.1/umbrello/classifierlistitem.h +--- umbrello-15.08.1.orig/umbrello/classifierlistitem.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/CMakeLists.txt umbrello-15.08.1/umbrello/CMakeLists.txt +--- umbrello-15.08.1.orig/umbrello/CMakeLists.txt 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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(umbrellobase_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} + ${umbrellobase_SRCS} + ) + +diff -Nuar umbrello-15.08.1.orig/umbrello/component.cpp umbrello-15.08.1/umbrello/component.cpp +--- umbrello-15.08.1.orig/umbrello/component.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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 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-15.08.1.orig/umbrello/component.h umbrello-15.08.1/umbrello/component.h +--- umbrello-15.08.1.orig/umbrello/component.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/dialogs/notedialog.cpp umbrello-15.08.1/umbrello/dialogs/notedialog.cpp +--- umbrello-15.08.1.orig/umbrello/dialogs/notedialog.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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-15.08.1.orig/umbrello/dialogs/widgets/documentationwidget.cpp umbrello-15.08.1/umbrello/dialogs/widgets/documentationwidget.cpp +--- umbrello-15.08.1.orig/umbrello/dialogs/widgets/documentationwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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-15.08.1.orig/umbrello/docwindow.cpp umbrello-15.08.1/umbrello/docwindow.cpp +--- umbrello-15.08.1.orig/umbrello/docwindow.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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-15.08.1.orig/umbrello/entityattribute.cpp umbrello-15.08.1/umbrello/entityattribute.cpp +--- umbrello-15.08.1.orig/umbrello/entityattribute.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/entityattribute.h umbrello-15.08.1/umbrello/entityattribute.h +--- umbrello-15.08.1.orig/umbrello/entityattribute.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/entityconstraint.cpp umbrello-15.08.1/umbrello/entityconstraint.cpp +--- umbrello-15.08.1.orig/umbrello/entityconstraint.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/entityconstraint.h umbrello-15.08.1/umbrello/entityconstraint.h +--- umbrello-15.08.1.orig/umbrello/entityconstraint.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/entity.cpp umbrello-15.08.1/umbrello/entity.cpp +--- umbrello-15.08.1.orig/umbrello/entity.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/entity.h umbrello-15.08.1/umbrello/entity.h +--- umbrello-15.08.1.orig/umbrello/entity.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/enum.cpp umbrello-15.08.1/umbrello/enum.cpp +--- umbrello-15.08.1.orig/umbrello/enum.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/enum.h umbrello-15.08.1/umbrello/enum.h +--- umbrello-15.08.1.orig/umbrello/enum.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/enumliteral.cpp umbrello-15.08.1/umbrello/enumliteral.cpp +--- umbrello-15.08.1.orig/umbrello/enumliteral.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/enumliteral.h umbrello-15.08.1/umbrello/enumliteral.h +--- umbrello-15.08.1.orig/umbrello/enumliteral.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/folder.cpp umbrello-15.08.1/umbrello/folder.cpp +--- umbrello-15.08.1.orig/umbrello/folder.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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")); +- 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")); +- 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 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-15.08.1.orig/umbrello/folder.h umbrello-15.08.1/umbrello/folder.h +--- umbrello-15.08.1.orig/umbrello/folder.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/foreignkeyconstraint.cpp umbrello-15.08.1/umbrello/foreignkeyconstraint.cpp +--- umbrello-15.08.1.orig/umbrello/foreignkeyconstraint.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/foreignkeyconstraint.h umbrello-15.08.1/umbrello/foreignkeyconstraint.h +--- umbrello-15.08.1.orig/umbrello/foreignkeyconstraint.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/listpopupmenu.cpp umbrello-15.08.1/umbrello/listpopupmenu.cpp +--- umbrello-15.08.1.orig/umbrello/listpopupmenu.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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-15.08.1.orig/umbrello/node.cpp umbrello-15.08.1/umbrello/node.cpp +--- umbrello-15.08.1.orig/umbrello/node.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/node.h umbrello-15.08.1/umbrello/node.h +--- umbrello-15.08.1.orig/umbrello/node.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/operation.cpp umbrello-15.08.1/umbrello/operation.cpp +--- umbrello-15.08.1.orig/umbrello/operation.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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'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'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-15.08.1.orig/umbrello/operation.h umbrello-15.08.1/umbrello/operation.h +--- umbrello-15.08.1.orig/umbrello/operation.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/org.kde.umbrello.appdata.xml umbrello-15.08.1/umbrello/org.kde.umbrello.appdata.xml +--- umbrello-15.08.1.orig/umbrello/org.kde.umbrello.appdata.xml 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-15.08.1/umbrello/org.kde.umbrello.appdata.xml 2015-10-08 11:48:59.501089026 +0300 +@@ -0,0 +1,136 @@ ++ ++ ++ org.kde.umbrello.desktop ++ CC0-1.0 ++ GPL-2.0+ ++ Umbrello ++ Umbrello ++ Umbrello ++ Umbrello ++ Umbrello ++ Umbrello ++ Umbrello ++ Umbrello ++ Umbrello ++ Umbrello ++ Umbrello ++ Umbrello ++ Umbrello ++ Umbrello ++ Umbrello ++ Umbrello ++ Umbrello ++ Umbrello ++ xxUmbrelloxx ++ 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 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 é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 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 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 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 on UML-mallinnusohjelma. Umbrellolla 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 é 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 è 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 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 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 é 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 é 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 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 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 ä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 — засіб моделювання уніфікованою мовою моделювання (UML) та інструмент для створення шаблонів коду. Програма здатна створювати діаграми систем програмного забезпечення та інших систем у стандартному форматі UML та реалізовувати діаграми UML у програмному коді багатьма мовами програмування.

++

xxUmbrello 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.kde.org ++ https://bugs.kde.org/enter_bug.cgi?format=guided&product=umbrello ++ http://docs.kde.org/stable/en/kdesdk/umbrello/index.html ++ ++ ++ http://kde.org/images/screenshots/umbrello.png ++ ++ ++ KDE ++ ++ umbrello ++ ++
+diff -Nuar umbrello-15.08.1.orig/umbrello/package.cpp umbrello-15.08.1/umbrello/package.cpp +--- umbrello-15.08.1.orig/umbrello/package.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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 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-15.08.1.orig/umbrello/package.h umbrello-15.08.1/umbrello/package.h +--- umbrello-15.08.1.orig/umbrello/package.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/port.cpp umbrello-15.08.1/umbrello/port.cpp +--- umbrello-15.08.1.orig/umbrello/port.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/port.h umbrello-15.08.1/umbrello/port.h +--- umbrello-15.08.1.orig/umbrello/port.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/stereotype.cpp umbrello-15.08.1/umbrello/stereotype.cpp +--- umbrello-15.08.1.orig/umbrello/stereotype.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/stereotype.h umbrello-15.08.1/umbrello/stereotype.h +--- umbrello-15.08.1.orig/umbrello/stereotype.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/stereotypesmodel.cpp umbrello-15.08.1/umbrello/stereotypesmodel.cpp +--- umbrello-15.08.1.orig/umbrello/stereotypesmodel.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/stereotypesmodel.h umbrello-15.08.1/umbrello/stereotypesmodel.h +--- umbrello-15.08.1.orig/umbrello/stereotypesmodel.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/stereotypeswindow.cpp umbrello-15.08.1/umbrello/stereotypeswindow.cpp +--- umbrello-15.08.1.orig/umbrello/stereotypeswindow.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/stereotypeswindow.h umbrello-15.08.1/umbrello/stereotypeswindow.h +--- umbrello-15.08.1.orig/umbrello/stereotypeswindow.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/template.cpp umbrello-15.08.1/umbrello/template.cpp +--- umbrello-15.08.1.orig/umbrello/template.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/template.h umbrello-15.08.1/umbrello/template.h +--- umbrello-15.08.1.orig/umbrello/template.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umbrelloui.rc umbrello-15.08.1/umbrello/umbrelloui.rc +--- umbrello-15.08.1.orig/umbrello/umbrelloui.rc 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-15.08.1/umbrello/umbrelloui.rc 2015-10-08 11:48:59.506089026 +0300 +@@ -85,6 +85,7 @@ + + + ++ + + + +diff -Nuar umbrello-15.08.1.orig/umbrello/umlappprivate.h umbrello-15.08.1/umbrello/umlappprivate.h +--- umbrello-15.08.1.orig/umbrello/umlappprivate.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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::Editor *editor; + KTextEditor::View *view; + KTextEditor::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-15.08.1.orig/umbrello/umlassociationlist.h umbrello-15.08.1/umbrello/umlassociationlist.h +--- umbrello-15.08.1.orig/umbrello/umlassociationlist.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef UMLASSOCIATIONLIST_H +-#define UMLASSOCIATIONLIST_H +- +-#include +- +-// forward declaration +-class UMLAssociation; +- +-typedef QList UMLAssociationList; +-typedef QListIterator UMLAssociationListIt; +- +-#endif +diff -Nuar umbrello-15.08.1.orig/umbrello/umlattributelist.cpp umbrello-15.08.1/umbrello/umlattributelist.cpp +--- umbrello-15.08.1.orig/umbrello/umlattributelist.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlattributelist.h umbrello-15.08.1/umbrello/umlattributelist.h +--- umbrello-15.08.1.orig/umbrello/umlattributelist.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlcanvasobject.cpp umbrello-15.08.1/umbrello/umlcanvasobject.cpp +--- umbrello-15.08.1.orig/umbrello/umlcanvasobject.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlcanvasobject.h umbrello-15.08.1/umbrello/umlcanvasobject.h +--- umbrello-15.08.1.orig/umbrello/umlcanvasobject.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlclassifierlist.h umbrello-15.08.1/umbrello/umlclassifierlist.h +--- umbrello-15.08.1.orig/umbrello/umlclassifierlist.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef UMLCLASSIFIERLIST_H +-#define UMLCLASSIFIERLIST_H +- +-#include +- +-// forward declaration +-class UMLClassifier; +- +-typedef QList UMLClassifierList; +-typedef QListIterator UMLClassifierListIt; +- +-#endif +diff -Nuar umbrello-15.08.1.orig/umbrello/umlclassifierlistitemlist.cpp umbrello-15.08.1/umbrello/umlclassifierlistitemlist.cpp +--- umbrello-15.08.1.orig/umbrello/umlclassifierlistitemlist.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlclassifierlistitemlist.h umbrello-15.08.1/umbrello/umlclassifierlistitemlist.h +--- umbrello-15.08.1.orig/umbrello/umlclassifierlistitemlist.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/uml.cpp umbrello-15.08.1/umbrello/uml.cpp +--- umbrello-15.08.1.orig/umbrello/uml.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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-15.08.1.orig/umbrello/umldoc.cpp umbrello-15.08.1/umbrello/umldoc.cpp +--- umbrello-15.08.1.orig/umbrello/umldoc.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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-15.08.1.orig/umbrello/umldoc.h umbrello-15.08.1/umbrello/umldoc.h +--- umbrello-15.08.1.orig/umbrello/umldoc.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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-15.08.1.orig/umbrello/umlentityattributelist.cpp umbrello-15.08.1/umbrello/umlentityattributelist.cpp +--- umbrello-15.08.1.orig/umbrello/umlentityattributelist.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlentityattributelist.h umbrello-15.08.1/umbrello/umlentityattributelist.h +--- umbrello-15.08.1.orig/umbrello/umlentityattributelist.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlentityconstraintlist.cpp umbrello-15.08.1/umbrello/umlentityconstraintlist.cpp +--- umbrello-15.08.1.orig/umbrello/umlentityconstraintlist.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlentityconstraintlist.h umbrello-15.08.1/umbrello/umlentityconstraintlist.h +--- umbrello-15.08.1.orig/umbrello/umlentityconstraintlist.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlentitylist.h umbrello-15.08.1/umbrello/umlentitylist.h +--- umbrello-15.08.1.orig/umbrello/umlentitylist.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef UMLENTITYLIST_H +-#define UMLENTITYLIST_H +- +-#include +- +-// forward declaration +-class UMLEntity; +- +-typedef QList UMLEntityList; +-typedef QListIterator UMLEntityListIt; +- +-#endif +diff -Nuar umbrello-15.08.1.orig/umbrello/umlenumliterallist.h umbrello-15.08.1/umbrello/umlenumliterallist.h +--- umbrello-15.08.1.orig/umbrello/umlenumliterallist.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef UMLENUMLITERALLIST_H +-#define UMLENUMLITERALLIST_H +- +-#include +- +-// forward declaration +-class UMLEnumLiteral; +- +-typedef QList UMLEnumLiteralList; +-typedef QListIterator UMLEnumLiteralListIt; +- +-#endif +diff -Nuar umbrello-15.08.1.orig/umbrello/umllistview.cpp umbrello-15.08.1/umbrello/umllistview.cpp +--- umbrello-15.08.1.orig/umbrello/umllistview.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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-15.08.1.orig/umbrello/umlmodel/actor.cpp umbrello-15.08.1/umbrello/umlmodel/actor.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/actor.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/actor.h umbrello-15.08.1/umbrello/umlmodel/actor.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/actor.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlmodel/artifact.cpp umbrello-15.08.1/umbrello/umlmodel/artifact.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/artifact.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/artifact.h umbrello-15.08.1/umbrello/umlmodel/artifact.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/artifact.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlmodel/association.cpp umbrello-15.08.1/umbrello/umlmodel/association.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/association.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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 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-15.08.1.orig/umbrello/umlmodel/association.h umbrello-15.08.1/umbrello/umlmodel/association.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/association.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlmodel/attribute.cpp umbrello-15.08.1/umbrello/umlmodel/attribute.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/attribute.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/attribute.h umbrello-15.08.1/umbrello/umlmodel/attribute.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/attribute.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlmodel/category.cpp umbrello-15.08.1/umbrello/umlmodel/category.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/category.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/category.h umbrello-15.08.1/umbrello/umlmodel/category.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/category.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlmodel/checkconstraint.cpp umbrello-15.08.1/umbrello/umlmodel/checkconstraint.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/checkconstraint.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/checkconstraint.h umbrello-15.08.1/umbrello/umlmodel/checkconstraint.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/checkconstraint.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlmodel/classifier.cpp umbrello-15.08.1/umbrello/umlmodel/classifier.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/classifier.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/classifier.h umbrello-15.08.1/umbrello/umlmodel/classifier.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/classifier.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlmodel/classifierlistitem.cpp umbrello-15.08.1/umbrello/umlmodel/classifierlistitem.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/classifierlistitem.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/classifierlistitem.h umbrello-15.08.1/umbrello/umlmodel/classifierlistitem.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/classifierlistitem.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlmodel/component.cpp umbrello-15.08.1/umbrello/umlmodel/component.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/component.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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 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-15.08.1.orig/umbrello/umlmodel/component.h umbrello-15.08.1/umbrello/umlmodel/component.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/component.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlmodel/entityattribute.cpp umbrello-15.08.1/umbrello/umlmodel/entityattribute.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/entityattribute.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/entityattribute.h umbrello-15.08.1/umbrello/umlmodel/entityattribute.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/entityattribute.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlmodel/entityconstraint.cpp umbrello-15.08.1/umbrello/umlmodel/entityconstraint.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/entityconstraint.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/entityconstraint.h umbrello-15.08.1/umbrello/umlmodel/entityconstraint.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/entityconstraint.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlmodel/entity.cpp umbrello-15.08.1/umbrello/umlmodel/entity.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/entity.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/entity.h umbrello-15.08.1/umbrello/umlmodel/entity.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/entity.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlmodel/enum.cpp umbrello-15.08.1/umbrello/umlmodel/enum.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/enum.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/enum.h umbrello-15.08.1/umbrello/umlmodel/enum.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/enum.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlmodel/enumliteral.cpp umbrello-15.08.1/umbrello/umlmodel/enumliteral.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/enumliteral.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/enumliteral.h umbrello-15.08.1/umbrello/umlmodel/enumliteral.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/enumliteral.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlmodel/folder.cpp umbrello-15.08.1/umbrello/umlmodel/folder.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/folder.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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")); ++ 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")); ++ 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 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-15.08.1.orig/umbrello/umlmodel/folder.h umbrello-15.08.1/umbrello/umlmodel/folder.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/folder.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlmodel/foreignkeyconstraint.cpp umbrello-15.08.1/umbrello/umlmodel/foreignkeyconstraint.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/foreignkeyconstraint.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/foreignkeyconstraint.h umbrello-15.08.1/umbrello/umlmodel/foreignkeyconstraint.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/foreignkeyconstraint.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlmodel/node.cpp umbrello-15.08.1/umbrello/umlmodel/node.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/node.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/node.h umbrello-15.08.1/umbrello/umlmodel/node.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/node.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlmodel/operation.cpp umbrello-15.08.1/umbrello/umlmodel/operation.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/operation.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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'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'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-15.08.1.orig/umbrello/umlmodel/operation.h umbrello-15.08.1/umbrello/umlmodel/operation.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/operation.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlmodel/package.cpp umbrello-15.08.1/umbrello/umlmodel/package.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/package.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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 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-15.08.1.orig/umbrello/umlmodel/package.h umbrello-15.08.1/umbrello/umlmodel/package.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/package.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlmodel/port.cpp umbrello-15.08.1/umbrello/umlmodel/port.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/port.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/port.h umbrello-15.08.1/umbrello/umlmodel/port.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/port.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlmodel/stereotype.cpp umbrello-15.08.1/umbrello/umlmodel/stereotype.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/stereotype.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/stereotype.h umbrello-15.08.1/umbrello/umlmodel/stereotype.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/stereotype.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlmodel/template.cpp umbrello-15.08.1/umbrello/umlmodel/template.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/template.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/template.h umbrello-15.08.1/umbrello/umlmodel/template.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/template.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlmodel/umlassociationlist.h umbrello-15.08.1/umbrello/umlmodel/umlassociationlist.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/umlassociationlist.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef UMLASSOCIATIONLIST_H ++#define UMLASSOCIATIONLIST_H ++ ++#include ++ ++// forward declaration ++class UMLAssociation; ++ ++typedef QList UMLAssociationList; ++typedef QListIterator UMLAssociationListIt; ++ ++#endif +diff -Nuar umbrello-15.08.1.orig/umbrello/umlmodel/umlattributelist.cpp umbrello-15.08.1/umbrello/umlmodel/umlattributelist.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/umlattributelist.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/umlattributelist.h umbrello-15.08.1/umbrello/umlmodel/umlattributelist.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/umlattributelist.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/umlcanvasobject.cpp umbrello-15.08.1/umbrello/umlmodel/umlcanvasobject.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/umlcanvasobject.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/umlcanvasobject.h umbrello-15.08.1/umbrello/umlmodel/umlcanvasobject.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/umlcanvasobject.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlmodel/umlclassifierlist.h umbrello-15.08.1/umbrello/umlmodel/umlclassifierlist.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/umlclassifierlist.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef UMLCLASSIFIERLIST_H ++#define UMLCLASSIFIERLIST_H ++ ++#include ++ ++// forward declaration ++class UMLClassifier; ++ ++typedef QList UMLClassifierList; ++typedef QListIterator UMLClassifierListIt; ++ ++#endif +diff -Nuar umbrello-15.08.1.orig/umbrello/umlmodel/umlclassifierlistitemlist.cpp umbrello-15.08.1/umbrello/umlmodel/umlclassifierlistitemlist.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/umlclassifierlistitemlist.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/umlclassifierlistitemlist.h umbrello-15.08.1/umbrello/umlmodel/umlclassifierlistitemlist.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/umlclassifierlistitemlist.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/umlentityattributelist.cpp umbrello-15.08.1/umbrello/umlmodel/umlentityattributelist.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/umlentityattributelist.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/umlentityattributelist.h umbrello-15.08.1/umbrello/umlmodel/umlentityattributelist.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/umlentityattributelist.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/umlentityconstraintlist.cpp umbrello-15.08.1/umbrello/umlmodel/umlentityconstraintlist.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/umlentityconstraintlist.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/umlentityconstraintlist.h umbrello-15.08.1/umbrello/umlmodel/umlentityconstraintlist.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/umlentityconstraintlist.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/umlentitylist.h umbrello-15.08.1/umbrello/umlmodel/umlentitylist.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/umlentitylist.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef UMLENTITYLIST_H ++#define UMLENTITYLIST_H ++ ++#include ++ ++// forward declaration ++class UMLEntity; ++ ++typedef QList UMLEntityList; ++typedef QListIterator UMLEntityListIt; ++ ++#endif +diff -Nuar umbrello-15.08.1.orig/umbrello/umlmodel/umlenumliterallist.h umbrello-15.08.1/umbrello/umlmodel/umlenumliterallist.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/umlenumliterallist.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef UMLENUMLITERALLIST_H ++#define UMLENUMLITERALLIST_H ++ ++#include ++ ++// forward declaration ++class UMLEnumLiteral; ++ ++typedef QList UMLEnumLiteralList; ++typedef QListIterator UMLEnumLiteralListIt; ++ ++#endif +diff -Nuar umbrello-15.08.1.orig/umbrello/umlmodel/umlobject.cpp umbrello-15.08.1/umbrello/umlmodel/umlobject.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/umlobject.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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 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 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 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 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-15.08.1.orig/umbrello/umlmodel/umlobject.h umbrello-15.08.1/umbrello/umlmodel/umlobject.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/umlobject.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlmodel/umlobjectlist.cpp umbrello-15.08.1/umbrello/umlmodel/umlobjectlist.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/umlobjectlist.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/umlobjectlist.h umbrello-15.08.1/umbrello/umlmodel/umlobjectlist.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/umlobjectlist.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/umloperationlist.h umbrello-15.08.1/umbrello/umlmodel/umloperationlist.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/umloperationlist.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef UMLOPERATIONLIST_H ++#define UMLOPERATIONLIST_H ++ ++#include ++ ++// forward declaration ++class UMLOperation; ++ ++typedef QList UMLOperationList; ++typedef QListIterator UMLOperationListIt; ++ ++#endif +diff -Nuar umbrello-15.08.1.orig/umbrello/umlmodel/umlpackagelist.h umbrello-15.08.1/umbrello/umlmodel/umlpackagelist.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/umlpackagelist.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef UMLPACKAGELIST_H ++#define UMLPACKAGELIST_H ++ ++#include ++ ++class UMLPackage; ++ ++typedef QList UMLPackageList; ++typedef QListIterator UMLPackageListIt; ++ ++#endif +diff -Nuar umbrello-15.08.1.orig/umbrello/umlmodel/umlrole.cpp umbrello-15.08.1/umbrello/umlmodel/umlrole.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/umlrole.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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 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-15.08.1.orig/umbrello/umlmodel/umlrole.h umbrello-15.08.1/umbrello/umlmodel/umlrole.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/umlrole.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/umlstereotypelist.h umbrello-15.08.1/umbrello/umlmodel/umlstereotypelist.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/umlstereotypelist.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef UMLSTEREOTYPELIST_H ++#define UMLSTEREOTYPELIST_H ++ ++#include ++ ++// forward declaration ++class UMLStereotype; ++ ++typedef QList UMLStereotypeList; ++typedef QListIterator UMLStereotypeListIt; ++ ++#endif +diff -Nuar umbrello-15.08.1.orig/umbrello/umlmodel/umltemplatelist.h umbrello-15.08.1/umbrello/umlmodel/umltemplatelist.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/umltemplatelist.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef UMLTEMPLATELIST_H ++#define UMLTEMPLATELIST_H ++ ++#include ++ ++// forward declaration ++class UMLTemplate; ++ ++typedef QList UMLTemplateList; ++typedef QListIterator UMLTemplateListIt; ++ ++#endif +diff -Nuar umbrello-15.08.1.orig/umbrello/umlmodel/uniqueconstraint.cpp umbrello-15.08.1/umbrello/umlmodel/uniqueconstraint.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/uniqueconstraint.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/uniqueconstraint.h umbrello-15.08.1/umbrello/umlmodel/uniqueconstraint.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/uniqueconstraint.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlmodel/usecase.cpp umbrello-15.08.1/umbrello/umlmodel/usecase.cpp +--- umbrello-15.08.1.orig/umbrello/umlmodel/usecase.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlmodel/usecase.h umbrello-15.08.1/umbrello/umlmodel/usecase.h +--- umbrello-15.08.1.orig/umbrello/umlmodel/usecase.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlobject.cpp umbrello-15.08.1/umbrello/umlobject.cpp +--- umbrello-15.08.1.orig/umbrello/umlobject.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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 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 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 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 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-15.08.1.orig/umbrello/umlobject.h umbrello-15.08.1/umbrello/umlobject.h +--- umbrello-15.08.1.orig/umbrello/umlobject.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlobjectlist.cpp umbrello-15.08.1/umbrello/umlobjectlist.cpp +--- umbrello-15.08.1.orig/umbrello/umlobjectlist.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlobjectlist.h umbrello-15.08.1/umbrello/umlobjectlist.h +--- umbrello-15.08.1.orig/umbrello/umlobjectlist.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/umloperationlist.h umbrello-15.08.1/umbrello/umloperationlist.h +--- umbrello-15.08.1.orig/umbrello/umloperationlist.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef UMLOPERATIONLIST_H +-#define UMLOPERATIONLIST_H +- +-#include +- +-// forward declaration +-class UMLOperation; +- +-typedef QList UMLOperationList; +-typedef QListIterator UMLOperationListIt; +- +-#endif +diff -Nuar umbrello-15.08.1.orig/umbrello/umlpackagelist.h umbrello-15.08.1/umbrello/umlpackagelist.h +--- umbrello-15.08.1.orig/umbrello/umlpackagelist.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef UMLPACKAGELIST_H +-#define UMLPACKAGELIST_H +- +-#include +- +-class UMLPackage; +- +-typedef QList UMLPackageList; +-typedef QListIterator UMLPackageListIt; +- +-#endif +diff -Nuar umbrello-15.08.1.orig/umbrello/umlrole.cpp umbrello-15.08.1/umbrello/umlrole.cpp +--- umbrello-15.08.1.orig/umbrello/umlrole.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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 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-15.08.1.orig/umbrello/umlrole.h umbrello-15.08.1/umbrello/umlrole.h +--- umbrello-15.08.1.orig/umbrello/umlrole.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlstereotypelist.h umbrello-15.08.1/umbrello/umlstereotypelist.h +--- umbrello-15.08.1.orig/umbrello/umlstereotypelist.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef UMLSTEREOTYPELIST_H +-#define UMLSTEREOTYPELIST_H +- +-#include +- +-// forward declaration +-class UMLStereotype; +- +-typedef QList UMLStereotypeList; +-typedef QListIterator UMLStereotypeListIt; +- +-#endif +diff -Nuar umbrello-15.08.1.orig/umbrello/umltemplatelist.h umbrello-15.08.1/umbrello/umltemplatelist.h +--- umbrello-15.08.1.orig/umbrello/umltemplatelist.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef UMLTEMPLATELIST_H +-#define UMLTEMPLATELIST_H +- +-#include +- +-// forward declaration +-class UMLTemplate; +- +-typedef QList UMLTemplateList; +-typedef QListIterator UMLTemplateListIt; +- +-#endif +diff -Nuar umbrello-15.08.1.orig/umbrello/umlwidgets/activitywidget.cpp umbrello-15.08.1/umbrello/umlwidgets/activitywidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/activitywidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/activitywidget.h umbrello-15.08.1/umbrello/umlwidgets/activitywidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/activitywidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlwidgets/actorwidget.cpp umbrello-15.08.1/umbrello/umlwidgets/actorwidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/actorwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/actorwidget.h umbrello-15.08.1/umbrello/umlwidgets/actorwidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/actorwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlwidgets/artifactwidget.cpp umbrello-15.08.1/umbrello/umlwidgets/artifactwidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/artifactwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/artifactwidget.h umbrello-15.08.1/umbrello/umlwidgets/artifactwidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/artifactwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlwidgets/associationline.cpp umbrello-15.08.1/umbrello/umlwidgets/associationline.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/associationline.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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::SolidPattern); ++ 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::SolidLine, ++ 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::SolidLine); ++} ++ ++/** ++ * @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-15.08.1.orig/umbrello/umlwidgets/associationline.h umbrello-15.08.1/umbrello/umlwidgets/associationline.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/associationline.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/associationwidget.cpp umbrello-15.08.1/umbrello/umlwidgets/associationwidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/associationwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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 purposes 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-15.08.1.orig/umbrello/umlwidgets/associationwidget.h umbrello-15.08.1/umbrello/umlwidgets/associationwidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/associationwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlwidgets/boxwidget.cpp umbrello-15.08.1/umbrello/umlwidgets/boxwidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/boxwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/boxwidget.h umbrello-15.08.1/umbrello/umlwidgets/boxwidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/boxwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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 purposes. ++ * ++ * @short Displays a box. ++ * @author Jonathan Riddell ++ * @see UMLWidget ++ * Bugs and comments to umbrello-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-15.08.1.orig/umbrello/umlwidgets/categorywidget.cpp umbrello-15.08.1/umbrello/umlwidgets/categorywidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/categorywidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/categorywidget.h umbrello-15.08.1/umbrello/umlwidgets/categorywidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/categorywidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlwidgets/classifierwidget.cpp umbrello-15.08.1/umbrello/umlwidgets/classifierwidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/classifierwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/classifierwidget.h umbrello-15.08.1/umbrello/umlwidgets/classifierwidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/classifierwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlwidgets/combinedfragmentwidget.cpp umbrello-15.08.1/umbrello/umlwidgets/combinedfragmentwidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/combinedfragmentwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/combinedfragmentwidget.h umbrello-15.08.1/umbrello/umlwidgets/combinedfragmentwidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/combinedfragmentwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlwidgets/componentwidget.cpp umbrello-15.08.1/umbrello/umlwidgets/componentwidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/componentwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/componentwidget.h umbrello-15.08.1/umbrello/umlwidgets/componentwidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/componentwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlwidgets/datatypewidget.cpp umbrello-15.08.1/umbrello/umlwidgets/datatypewidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/datatypewidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/datatypewidget.h umbrello-15.08.1/umbrello/umlwidgets/datatypewidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/datatypewidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlwidgets/entitywidget.cpp umbrello-15.08.1/umbrello/umlwidgets/entitywidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/entitywidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/entitywidget.h umbrello-15.08.1/umbrello/umlwidgets/entitywidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/entitywidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlwidgets/enumwidget.cpp umbrello-15.08.1/umbrello/umlwidgets/enumwidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/enumwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/enumwidget.h umbrello-15.08.1/umbrello/umlwidgets/enumwidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/enumwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlwidgets/floatingdashlinewidget.cpp umbrello-15.08.1/umbrello/umlwidgets/floatingdashlinewidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/floatingdashlinewidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/floatingdashlinewidget.h umbrello-15.08.1/umbrello/umlwidgets/floatingdashlinewidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/floatingdashlinewidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlwidgets/floatingtextwidget.cpp umbrello-15.08.1/umbrello/umlwidgets/floatingtextwidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/floatingtextwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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 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-15.08.1.orig/umbrello/umlwidgets/floatingtextwidget.h umbrello-15.08.1/umbrello/umlwidgets/floatingtextwidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/floatingtextwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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 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-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-15.08.1.orig/umbrello/umlwidgets/forkjoinwidget.cpp umbrello-15.08.1/umbrello/umlwidgets/forkjoinwidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/forkjoinwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/forkjoinwidget.h umbrello-15.08.1/umbrello/umlwidgets/forkjoinwidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/forkjoinwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlwidgets/layoutgrid.cpp umbrello-15.08.1/umbrello/umlwidgets/layoutgrid.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/layoutgrid.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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. 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-15.08.1.orig/umbrello/umlwidgets/layoutgrid.h umbrello-15.08.1/umbrello/umlwidgets/layoutgrid.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/layoutgrid.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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. 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-15.08.1.orig/umbrello/umlwidgets/linkwidget.cpp umbrello-15.08.1/umbrello/umlwidgets/linkwidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/linkwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/linkwidget.h umbrello-15.08.1/umbrello/umlwidgets/linkwidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/linkwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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 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-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-15.08.1.orig/umbrello/umlwidgets/messagewidget.cpp umbrello-15.08.1/umbrello/umlwidgets/messagewidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/messagewidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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 (triangular) arrowhead pointing in the given direction. ++ * The direction can be either Qt::LeftArrow or Qt::RightArrow. ++ */ ++void MessageWidget::paintSolidArrowhead(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, 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) ++ paintSolidArrowhead(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) ++ paintSolidArrowhead(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 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 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 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 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->resetPastePoint(); ++ // 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-15.08.1.orig/umbrello/umlwidgets/messagewidget.h umbrello-15.08.1/umbrello/umlwidgets/messagewidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/messagewidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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 paintSolidArrowhead(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-15.08.1.orig/umbrello/umlwidgets/nodewidget.cpp umbrello-15.08.1/umbrello/umlwidgets/nodewidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/nodewidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/nodewidget.h umbrello-15.08.1/umbrello/umlwidgets/nodewidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/nodewidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlwidgets/notewidget.cpp umbrello-15.08.1/umbrello/umlwidgets/notewidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/notewidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/notewidget.h umbrello-15.08.1/umbrello/umlwidgets/notewidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/notewidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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 purposes. ++ * ++ * @short Displays a note box. ++ * @author Paul Hensgen ++ * @see UMLWidget ++ * Bugs and comments to umbrello-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-15.08.1.orig/umbrello/umlwidgets/objectnodewidget.cpp umbrello-15.08.1/umbrello/umlwidgets/objectnodewidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/objectnodewidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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::accept(); ++} ++ ++ +diff -Nuar umbrello-15.08.1.orig/umbrello/umlwidgets/objectnodewidget.h umbrello-15.08.1/umbrello/umlwidgets/objectnodewidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/objectnodewidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlwidgets/objectwidget.cpp umbrello-15.08.1/umbrello/umlwidgets/objectwidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/objectwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/objectwidget.h umbrello-15.08.1/umbrello/umlwidgets/objectwidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/objectwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlwidgets/packagewidget.cpp umbrello-15.08.1/umbrello/umlwidgets/packagewidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/packagewidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/packagewidget.h umbrello-15.08.1/umbrello/umlwidgets/packagewidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/packagewidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlwidgets/pinportbase.cpp umbrello-15.08.1/umbrello/umlwidgets/pinportbase.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/pinportbase.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/pinportbase.h umbrello-15.08.1/umbrello/umlwidgets/pinportbase.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/pinportbase.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlwidgets/pinwidget.cpp umbrello-15.08.1/umbrello/umlwidgets/pinwidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/pinwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/pinwidget.h umbrello-15.08.1/umbrello/umlwidgets/pinwidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/pinwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlwidgets/portwidget.cpp umbrello-15.08.1/umbrello/umlwidgets/portwidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/portwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/portwidget.h umbrello-15.08.1/umbrello/umlwidgets/portwidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/portwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlwidgets/preconditionwidget.cpp umbrello-15.08.1/umbrello/umlwidgets/preconditionwidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/preconditionwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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->resetPastePoint(); ++ 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-15.08.1.orig/umbrello/umlwidgets/preconditionwidget.h umbrello-15.08.1/umbrello/umlwidgets/preconditionwidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/preconditionwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlwidgets/regionwidget.cpp umbrello-15.08.1/umbrello/umlwidgets/regionwidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/regionwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/regionwidget.h umbrello-15.08.1/umbrello/umlwidgets/regionwidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/regionwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/seqlinewidget.cpp umbrello-15.08.1/umbrello/umlwidgets/seqlinewidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/seqlinewidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/seqlinewidget.h umbrello-15.08.1/umbrello/umlwidgets/seqlinewidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/seqlinewidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlwidgets/signalwidget.cpp umbrello-15.08.1/umbrello/umlwidgets/signalwidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/signalwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlwidgets/signalwidget.h umbrello-15.08.1/umbrello/umlwidgets/signalwidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/signalwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/statewidget.cpp umbrello-15.08.1/umbrello/umlwidgets/statewidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/statewidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/statewidget.h umbrello-15.08.1/umbrello/umlwidgets/statewidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/statewidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlwidgets/statusbartoolbutton.cpp umbrello-15.08.1/umbrello/umlwidgets/statusbartoolbutton.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/statusbartoolbutton.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 ++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. 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-15.08.1.orig/umbrello/umlwidgets/statusbartoolbutton.h umbrello-15.08.1/umbrello/umlwidgets/statusbartoolbutton.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/statusbartoolbutton.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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: 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. 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 ++ * 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-15.08.1.orig/umbrello/umlwidgets/toolbarstateonewidget.cpp umbrello-15.08.1/umbrello/umlwidgets/toolbarstateonewidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/toolbarstateonewidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/toolbarstateonewidget.h umbrello-15.08.1/umbrello/umlwidgets/toolbarstateonewidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/toolbarstateonewidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/umlwidget.cpp umbrello-15.08.1/umbrello/umlwidgets/umlwidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/umlwidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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->getPastePoint(); ++ 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 pastepoint ++ 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-15.08.1.orig/umbrello/umlwidgets/umlwidget.h umbrello-15.08.1/umbrello/umlwidgets/umlwidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/umlwidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlwidgets/usecasewidget.cpp umbrello-15.08.1/umbrello/umlwidgets/usecasewidget.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/usecasewidget.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/usecasewidget.h umbrello-15.08.1/umbrello/umlwidgets/usecasewidget.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/usecasewidget.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlwidgets/widgetbase.cpp umbrello-15.08.1/umbrello/umlwidgets/widgetbase.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/widgetbase.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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 ++ 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-15.08.1.orig/umbrello/umlwidgets/widgetbase.h umbrello-15.08.1/umbrello/umlwidgets/widgetbase.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/widgetbase.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlwidgets/widget_factory.cpp umbrello-15.08.1/umbrello/umlwidgets/widget_factory.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/widget_factory.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/widget_factory.h umbrello-15.08.1/umbrello/umlwidgets/widget_factory.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/widget_factory.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/umlwidgets/widgetlist_utils.cpp umbrello-15.08.1/umbrello/umlwidgets/widgetlist_utils.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/widgetlist_utils.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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-15.08.1.orig/umbrello/umlwidgets/widgetlist_utils.h umbrello-15.08.1/umbrello/umlwidgets/widgetlist_utils.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/widgetlist_utils.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 UML Modeller Authors * ++ ***************************************************************************/ ++ ++#ifndef WIDGETLIST_UTILS_H ++#define WIDGETLIST_UTILS_H ++ ++#include "umlwidgetlist.h" ++ ++/** ++ * General purpose widget list utilities. ++ * Bugs and comments to umbrello-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-15.08.1.orig/umbrello/umlwidgets/widget_utils.cpp umbrello-15.08.1/umbrello/umlwidgets/widget_utils.cpp +--- umbrello-15.08.1.orig/umbrello/umlwidgets/widget_utils.cpp 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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 If true, a solid head is drawn. Otherwise 2 lines are drawn. ++// */ ++// void drawArrowHead(QPainter *painter, const QPointF &arrowPos, ++// const QSizeF& arrowSize, Qt::ArrowType arrowType, ++// bool solid) ++// { ++// 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) { ++// 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-15.08.1.orig/umbrello/umlwidgets/widget_utils.h umbrello-15.08.1/umbrello/umlwidgets/widget_utils.h +--- umbrello-15.08.1.orig/umbrello/umlwidgets/widget_utils.h 1970-01-01 02:00:00.000000000 +0200 ++++ umbrello-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 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 widget utilities. ++ * Bugs and comments to umbrello-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 = 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-15.08.1.orig/umbrello/uniqueconstraint.cpp umbrello-15.08.1/umbrello/uniqueconstraint.cpp +--- umbrello-15.08.1.orig/umbrello/uniqueconstraint.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/uniqueconstraint.h umbrello-15.08.1/umbrello/uniqueconstraint.h +--- umbrello-15.08.1.orig/umbrello/uniqueconstraint.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/usecase.cpp umbrello-15.08.1/umbrello/usecase.cpp +--- umbrello-15.08.1.orig/umbrello/usecase.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/usecase.h umbrello-15.08.1/umbrello/usecase.h +--- umbrello-15.08.1.orig/umbrello/usecase.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/widgets/activitywidget.cpp umbrello-15.08.1/umbrello/widgets/activitywidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/activitywidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/activitywidget.h umbrello-15.08.1/umbrello/widgets/activitywidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/activitywidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/widgets/actorwidget.cpp umbrello-15.08.1/umbrello/widgets/actorwidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/actorwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/actorwidget.h umbrello-15.08.1/umbrello/widgets/actorwidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/actorwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/widgets/artifactwidget.cpp umbrello-15.08.1/umbrello/widgets/artifactwidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/artifactwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/artifactwidget.h umbrello-15.08.1/umbrello/widgets/artifactwidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/artifactwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/widgets/associationline.cpp umbrello-15.08.1/umbrello/widgets/associationline.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/associationline.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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::SolidPattern); +- 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::SolidLine, +- 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::SolidLine); +-} +- +-/** +- * @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-15.08.1.orig/umbrello/widgets/associationline.h umbrello-15.08.1/umbrello/widgets/associationline.h +--- umbrello-15.08.1.orig/umbrello/widgets/associationline.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/associationwidget.cpp umbrello-15.08.1/umbrello/widgets/associationwidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/associationwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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 purposes 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-15.08.1.orig/umbrello/widgets/associationwidget.h umbrello-15.08.1/umbrello/widgets/associationwidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/associationwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/widgets/boxwidget.cpp umbrello-15.08.1/umbrello/widgets/boxwidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/boxwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/boxwidget.h umbrello-15.08.1/umbrello/widgets/boxwidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/boxwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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 purposes. +- * +- * @short Displays a box. +- * @author Jonathan Riddell +- * @see UMLWidget +- * Bugs and comments to umbrello-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-15.08.1.orig/umbrello/widgets/categorywidget.cpp umbrello-15.08.1/umbrello/widgets/categorywidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/categorywidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/categorywidget.h umbrello-15.08.1/umbrello/widgets/categorywidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/categorywidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/widgets/classifierwidget.cpp umbrello-15.08.1/umbrello/widgets/classifierwidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/classifierwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/classifierwidget.h umbrello-15.08.1/umbrello/widgets/classifierwidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/classifierwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/widgets/combinedfragmentwidget.cpp umbrello-15.08.1/umbrello/widgets/combinedfragmentwidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/combinedfragmentwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/combinedfragmentwidget.h umbrello-15.08.1/umbrello/widgets/combinedfragmentwidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/combinedfragmentwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/widgets/componentwidget.cpp umbrello-15.08.1/umbrello/widgets/componentwidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/componentwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/componentwidget.h umbrello-15.08.1/umbrello/widgets/componentwidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/componentwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/widgets/datatypewidget.cpp umbrello-15.08.1/umbrello/widgets/datatypewidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/datatypewidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/datatypewidget.h umbrello-15.08.1/umbrello/widgets/datatypewidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/datatypewidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/widgets/entitywidget.cpp umbrello-15.08.1/umbrello/widgets/entitywidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/entitywidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/entitywidget.h umbrello-15.08.1/umbrello/widgets/entitywidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/entitywidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/widgets/enumwidget.cpp umbrello-15.08.1/umbrello/widgets/enumwidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/enumwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/enumwidget.h umbrello-15.08.1/umbrello/widgets/enumwidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/enumwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/widgets/floatingdashlinewidget.cpp umbrello-15.08.1/umbrello/widgets/floatingdashlinewidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/floatingdashlinewidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/floatingdashlinewidget.h umbrello-15.08.1/umbrello/widgets/floatingdashlinewidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/floatingdashlinewidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/widgets/floatingtextwidget.cpp umbrello-15.08.1/umbrello/widgets/floatingtextwidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/floatingtextwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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 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-15.08.1.orig/umbrello/widgets/floatingtextwidget.h umbrello-15.08.1/umbrello/widgets/floatingtextwidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/floatingtextwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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 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-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-15.08.1.orig/umbrello/widgets/forkjoinwidget.cpp umbrello-15.08.1/umbrello/widgets/forkjoinwidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/forkjoinwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/forkjoinwidget.h umbrello-15.08.1/umbrello/widgets/forkjoinwidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/forkjoinwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/widgets/layoutgrid.cpp umbrello-15.08.1/umbrello/widgets/layoutgrid.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/layoutgrid.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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. 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-15.08.1.orig/umbrello/widgets/layoutgrid.h umbrello-15.08.1/umbrello/widgets/layoutgrid.h +--- umbrello-15.08.1.orig/umbrello/widgets/layoutgrid.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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. 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-15.08.1.orig/umbrello/widgets/linkwidget.cpp umbrello-15.08.1/umbrello/widgets/linkwidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/linkwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/linkwidget.h umbrello-15.08.1/umbrello/widgets/linkwidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/linkwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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 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-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-15.08.1.orig/umbrello/widgets/messagewidget.cpp umbrello-15.08.1/umbrello/widgets/messagewidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/messagewidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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 (triangular) arrowhead pointing in the given direction. +- * The direction can be either Qt::LeftArrow or Qt::RightArrow. +- */ +-void MessageWidget::paintSolidArrowhead(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, 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) +- paintSolidArrowhead(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) +- paintSolidArrowhead(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 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 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 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 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->resetPastePoint(); +- // 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-15.08.1.orig/umbrello/widgets/messagewidget.h umbrello-15.08.1/umbrello/widgets/messagewidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/messagewidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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 paintSolidArrowhead(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-15.08.1.orig/umbrello/widgets/nodewidget.cpp umbrello-15.08.1/umbrello/widgets/nodewidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/nodewidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/nodewidget.h umbrello-15.08.1/umbrello/widgets/nodewidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/nodewidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/widgets/notewidget.cpp umbrello-15.08.1/umbrello/widgets/notewidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/notewidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/notewidget.h umbrello-15.08.1/umbrello/widgets/notewidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/notewidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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 purposes. +- * +- * @short Displays a note box. +- * @author Paul Hensgen +- * @see UMLWidget +- * Bugs and comments to umbrello-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-15.08.1.orig/umbrello/widgets/objectnodewidget.cpp umbrello-15.08.1/umbrello/widgets/objectnodewidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/objectnodewidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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::accept(); +-} +- +- +diff -Nuar umbrello-15.08.1.orig/umbrello/widgets/objectnodewidget.h umbrello-15.08.1/umbrello/widgets/objectnodewidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/objectnodewidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/widgets/objectwidget.cpp umbrello-15.08.1/umbrello/widgets/objectwidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/objectwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/objectwidget.h umbrello-15.08.1/umbrello/widgets/objectwidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/objectwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/widgets/packagewidget.cpp umbrello-15.08.1/umbrello/widgets/packagewidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/packagewidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/packagewidget.h umbrello-15.08.1/umbrello/widgets/packagewidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/packagewidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/widgets/pinportbase.cpp umbrello-15.08.1/umbrello/widgets/pinportbase.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/pinportbase.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/pinportbase.h umbrello-15.08.1/umbrello/widgets/pinportbase.h +--- umbrello-15.08.1.orig/umbrello/widgets/pinportbase.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/widgets/pinwidget.cpp umbrello-15.08.1/umbrello/widgets/pinwidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/pinwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/pinwidget.h umbrello-15.08.1/umbrello/widgets/pinwidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/pinwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/widgets/portwidget.cpp umbrello-15.08.1/umbrello/widgets/portwidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/portwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/portwidget.h umbrello-15.08.1/umbrello/widgets/portwidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/portwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/widgets/preconditionwidget.cpp umbrello-15.08.1/umbrello/widgets/preconditionwidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/preconditionwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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->resetPastePoint(); +- 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-15.08.1.orig/umbrello/widgets/preconditionwidget.h umbrello-15.08.1/umbrello/widgets/preconditionwidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/preconditionwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/widgets/regionwidget.cpp umbrello-15.08.1/umbrello/widgets/regionwidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/regionwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/regionwidget.h umbrello-15.08.1/umbrello/widgets/regionwidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/regionwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/seqlinewidget.cpp umbrello-15.08.1/umbrello/widgets/seqlinewidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/seqlinewidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/seqlinewidget.h umbrello-15.08.1/umbrello/widgets/seqlinewidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/seqlinewidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/widgets/signalwidget.cpp umbrello-15.08.1/umbrello/widgets/signalwidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/signalwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/widgets/signalwidget.h umbrello-15.08.1/umbrello/widgets/signalwidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/signalwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/statewidget.cpp umbrello-15.08.1/umbrello/widgets/statewidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/statewidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/statewidget.h umbrello-15.08.1/umbrello/widgets/statewidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/statewidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/widgets/statusbartoolbutton.cpp umbrello-15.08.1/umbrello/widgets/statusbartoolbutton.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/statusbartoolbutton.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 +-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. 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-15.08.1.orig/umbrello/widgets/statusbartoolbutton.h umbrello-15.08.1/umbrello/widgets/statusbartoolbutton.h +--- umbrello-15.08.1.orig/umbrello/widgets/statusbartoolbutton.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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: 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. 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 +- * 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-15.08.1.orig/umbrello/widgets/toolbarstateonewidget.cpp umbrello-15.08.1/umbrello/widgets/toolbarstateonewidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/toolbarstateonewidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/toolbarstateonewidget.h umbrello-15.08.1/umbrello/widgets/toolbarstateonewidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/toolbarstateonewidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/umlwidget.cpp umbrello-15.08.1/umbrello/widgets/umlwidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/umlwidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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->getPastePoint(); +- 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 pastepoint +- 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-15.08.1.orig/umbrello/widgets/umlwidget.h umbrello-15.08.1/umbrello/widgets/umlwidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/umlwidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/widgets/usecasewidget.cpp umbrello-15.08.1/umbrello/widgets/usecasewidget.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/usecasewidget.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/usecasewidget.h umbrello-15.08.1/umbrello/widgets/usecasewidget.h +--- umbrello-15.08.1.orig/umbrello/widgets/usecasewidget.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/widgets/widgetbase.cpp umbrello-15.08.1/umbrello/widgets/widgetbase.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/widgetbase.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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 +- 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-15.08.1.orig/umbrello/widgets/widgetbase.h umbrello-15.08.1/umbrello/widgets/widgetbase.h +--- umbrello-15.08.1.orig/umbrello/widgets/widgetbase.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/widgets/widget_factory.cpp umbrello-15.08.1/umbrello/widgets/widget_factory.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/widget_factory.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/widget_factory.h umbrello-15.08.1/umbrello/widgets/widget_factory.h +--- umbrello-15.08.1.orig/umbrello/widgets/widget_factory.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-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-15.08.1.orig/umbrello/widgets/widgetlist_utils.cpp umbrello-15.08.1/umbrello/widgets/widgetlist_utils.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/widgetlist_utils.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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-15.08.1.orig/umbrello/widgets/widgetlist_utils.h umbrello-15.08.1/umbrello/widgets/widgetlist_utils.h +--- umbrello-15.08.1.orig/umbrello/widgets/widgetlist_utils.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 UML Modeller Authors * +- ***************************************************************************/ +- +-#ifndef WIDGETLIST_UTILS_H +-#define WIDGETLIST_UTILS_H +- +-#include "umlwidgetlist.h" +- +-/** +- * General purpose widget list utilities. +- * Bugs and comments to umbrello-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-15.08.1.orig/umbrello/widgets/widget_utils.cpp umbrello-15.08.1/umbrello/widgets/widget_utils.cpp +--- umbrello-15.08.1.orig/umbrello/widgets/widget_utils.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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 If true, a solid head is drawn. Otherwise 2 lines are drawn. +-// */ +-// void drawArrowHead(QPainter *painter, const QPointF &arrowPos, +-// const QSizeF& arrowSize, Qt::ArrowType arrowType, +-// bool solid) +-// { +-// 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) { +-// 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-15.08.1.orig/umbrello/widgets/widget_utils.h umbrello-15.08.1/umbrello/widgets/widget_utils.h +--- umbrello-15.08.1.orig/umbrello/widgets/widget_utils.h 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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 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 widget utilities. +- * Bugs and comments to umbrello-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 = 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-15.08.1.orig/unittests/CMakeLists.txt umbrello-15.08.1/unittests/CMakeLists.txt +--- umbrello-15.08.1.orig/unittests/CMakeLists.txt 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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-15.08.1.orig/unittests/testbase.cpp umbrello-15.08.1/unittests/testbase.cpp +--- umbrello-15.08.1.orig/unittests/testbase.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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-15.08.1.orig/unittests/TEST_cppwriter.cpp umbrello-15.08.1/unittests/TEST_cppwriter.cpp +--- umbrello-15.08.1.orig/unittests/TEST_cppwriter.cpp 2015-09-10 01:54:59.000000000 +0300 ++++ umbrello-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? diff --git a/desktop/kde/sdk/umbrello/pspec.xml b/desktop/kde/sdk/umbrello/pspec.xml index cc3aab3eba..44bc15b2bd 100755 --- a/desktop/kde/sdk/umbrello/pspec.xml +++ b/desktop/kde/sdk/umbrello/pspec.xml @@ -16,11 +16,24 @@ qt5-base-devel libxslt-devel + qt5-svg-devel + kio-devel + kparts-devel + kinit-devel + kcompletion-devel + kxmlgui-devel + kauth-devel + kconfig-devel + ktexteditor-devel + kcoreaddons-devel kdoctools-devel + docbook-xsl extra-cmake-modules - cmake - + + upstream.patch + + umbrello