Commit 0f47f8fc authored by Oliver Kellogg's avatar Oliver Kellogg
Browse files

Followup to commit b61d3ab7 (moving management of widget owned floating text

from UMLScene to the owning widget)

umbrello/widgets/umlwidget.{h,cpp}
- New virtual function widgetWithID() returns 'this' if given id matches
  either of m_nLocalID, m_umlObject->id(), or m_nId; else returns NULL.
  The intention is that child classes of UMLWidget may reimplement this
  function in order to test the id against their child widgets.

umbrello/widgets/portwidget.{h,cpp}
- Reimplement UMLWidget function widgetWithID() to additionally check
  m_pName.
- In function slotMenuSelection() case ListPopupMenu::mt_NameAsTooltip,
  - If m_pName is non NULL then do not call m_scene->removeWidget(m_pName).
    Reason: m_pName is now entirely managed by PortWidget.
  - If m_pName is NULL then after assigning a new FloatingTextWidget to
    m_pName call m_pName->setParentItem(this).
    This completes the switchover of m_pName management from UMLScene.
    Further, this means that m_pName position is no longer relative to
    UMLScene but instead is now relative to its owning PortWidget.
    Adjust m_pName X/Y computations accordingly.
- In function setFloatingTextWidget(), m_pName->setParentItem(this) if
  m_pName is non NULL.
- In function loadFromXMI(),
  - Remove loading of attribute "textid";
  - If m_pName->loadFromXMI() returns with success then call
    m_pName->setParentItem(this).
- In function saveToXMI(), remove saving of attribute "textid".

umbrello/umlscene.{h,cpp}
- In function widgetOnDiagram(),
  - in foreach loop over m_WidgetList, call obj->widgetWithID(id) instead
    of direct comparison (id == obj->id())
  - in foreach loop over m_MessageList, add TODO note about checking whether
    MessageWidget should reimplement widgetWithID()
- In function findWidget(),
  - in foreach loop over m_WidgetList, replace special casing of wt_Object
    and direct comparison (id == obj->id()) by call to obj->widgetWithID(id)
  - in foreach loop over m_MessageList, add TODO note about checking whether
    MessageWidget should reimplement widgetWithID()
- Remove function findWidgetByLocalId(); due to above change it is redundant
  to findWidget().

umbrello/cmds/widget/cmd_baseWidgetCommand.cpp
umbrello/cmds/widget/cmd_createWidget.cpp
umbrello/cmds/widget/cmd_removeWidget.cpp
- In function redo() call umlScene->findWidget() in lieu of
  umlScene->findWidgetByLocalId() which was removed.

umbrello/widgets/floatingtextwidget.{h,cpp}
- Reimplement UMLWidget function onWidget() to additionally check PortWidget
  parentage.
- In function setText(), avoid calling m_linkWidget->seqNumAndOp() when
  m_linkWidget is NULL.
- In function loadFromXMI(), call setText() instead of directly assigning
  m_Text in order to achieve geometry update. (To be checked.)
- Fix spelling at bool usefulWidget.
- In function saveToXMI(), return immediately if isEmpty() returns true.

umbrello/widgets/pinwidget.cpp
- In function loadFromXMI(), add TODO note about removing the code for
  loading "textid".

umbrello/version.h
- Increment XMI_FILE_VERSION due to changes in function saveToXMI() of
  FloatingTextWidget and PortWidget.
parent 7e997587
......@@ -51,7 +51,7 @@ namespace Uml
UMLWidget* CmdBaseWidgetCommand::widget()
{
UMLWidget* umlWidget = scene()->findWidgetByLocalId(m_widgetId);
UMLWidget* umlWidget = scene()->findWidget(m_widgetId);
Q_ASSERT(umlWidget);
......
......@@ -47,7 +47,7 @@ namespace Uml
*/
void CmdCreateWidget::redo()
{
UMLWidget* umlWidget = scene()->findWidgetByLocalId(m_widgetId);
UMLWidget* umlWidget = scene()->findWidget(m_widgetId);
if (umlWidget == 0) {
// If the widget is not found, the add command was undone. Load the
// widget back from the saved XMI state.
......
......@@ -46,7 +46,7 @@ namespace Uml
void CmdRemoveWidget::redo()
{
UMLScene* umlScene = scene();
UMLWidget* widget = umlScene->findWidgetByLocalId(m_widgetId);
UMLWidget* widget = umlScene->findWidget(m_widgetId);
if (widget != 0) {
umlScene->removeWidgetCmd(widget);
}
......
......@@ -771,8 +771,11 @@ void UMLScene::dragEnterEvent(QGraphicsSceneDragDropEvent *e)
bAccept = false;
else if (ot == UMLObject::ot_Class && !temp->isAbstract())
bAccept = false;
else if (ot == UMLObject::ot_Port && !widgetOnDiagram(temp->umlPackage()->id()))
bAccept = false;
else if (ot == UMLObject::ot_Port) {
const bool componentOnDiagram = widgetOnDiagram(temp->umlPackage()->id());
DEBUG(DBG_SRC) << "ot_Port: componentOnDiagram = " << componentOnDiagram;
bAccept = componentOnDiagram;
}
break;
case DiagramType::EntityRelationship:
if (ot != UMLObject::ot_Entity && ot != UMLObject::ot_Category)
......@@ -803,6 +806,7 @@ void UMLScene::dropEvent(QGraphicsSceneDragDropEvent *e)
{
UMLDragData::LvTypeAndID_List tidList;
if (!UMLDragData::getClip3TypeAndID(e->mimeData(), tidList)) {
DEBUG(DBG_SRC) << "UMLDragData::getClip3TypeAndID returned error";
return;
}
UMLDragData::LvTypeAndID_It tidIt(tidList);
......@@ -1066,11 +1070,14 @@ void UMLScene::checkMessages(ObjectWidget * w)
UMLWidget* UMLScene::widgetOnDiagram(Uml::ID::Type id)
{
foreach(UMLWidget *obj, m_WidgetList) {
if (id == obj->id())
return obj;
UMLWidget* w = obj->widgetWithID(id);
if (w)
return w;
}
foreach(UMLWidget *obj, m_MessageList) {
// CHECK: Should MessageWidget reimplement widgetWithID() ?
// If yes then we should use obj->widgetWithID(id) here too.
if (id == obj->id())
return obj;
}
......@@ -1088,46 +1095,23 @@ UMLWidget* UMLScene::widgetOnDiagram(Uml::ID::Type id)
UMLWidget * UMLScene::findWidget(Uml::ID::Type id)
{
foreach(UMLWidget* obj, m_WidgetList) {
// object widgets are special..the widget id is held by 'localId' attribute (crappy!)
if (obj->baseType() == WidgetBase::wt_Object) {
if (static_cast<ObjectWidget *>(obj)->localID() == id)
return obj;
} else if (obj->id() == id) {
return obj;
UMLWidget* w = obj->widgetWithID(id);
if (w) {
return w;
}
}
foreach(UMLWidget* obj, m_MessageList) {
if (obj->id() == id)
// CHECK: Should MessageWidget reimplement widgetWithID() ?
// If yes then we should use obj->widgetWithID(id) here too.
if (obj->localID() == id ||
obj->id() == id)
return obj;
}
return 0;
}
/**
* Finds a widget with the given local ID.
* @param id The ID of the widget to find.
*
* @return Returns the widget found, returns 0 if no widget found.
*/
UMLWidget * UMLScene::findWidgetByLocalId(Uml::ID::Type id)
{
foreach(UMLWidget* obj, m_WidgetList) {
if (obj->localID() == id) {
return obj;
}
}
foreach(UMLWidget* obj, m_MessageList) {
if (obj->localID() == id) {
return obj;
}
}
return 0;
}
/**
* Finds an association widget with the given ID.
*
......
......@@ -170,7 +170,6 @@ public:
void checkMessages(ObjectWidget * w);
UMLWidget* findWidget(Uml::ID::Type id);
UMLWidget* findWidgetByLocalId(Uml::ID::Type id);
AssociationWidget* findAssocWidget(Uml::ID::Type id);
AssociationWidget* findAssocWidget(Uml::AssociationType::Enum at,
......
......@@ -27,6 +27,6 @@ inline QByteArray umbrelloVersion()
}
// Update this version when changing the XMI file format
#define XMI_FILE_VERSION "1.6.6"
#define XMI_FILE_VERSION "1.6.7"
#endif
......@@ -19,6 +19,7 @@
#include "cmds.h"
#include "debug_utils.h"
#include "linkwidget.h"
#include "portwidget.h"
#include "listpopupmenu.h"
#include "messagewidget.h"
#include "model_utils.h"
......@@ -104,7 +105,8 @@ void FloatingTextWidget::setText(const QString &t)
{
if (m_textRole == Uml::TextRole::Seq_Message || m_textRole == Uml::TextRole::Seq_Message_Self) {
QString seqNum, op;
m_linkWidget->seqNumAndOp(seqNum, op);
if (m_linkWidget)
m_linkWidget->seqNumAndOp(seqNum, op);
if (op.length() > 0) {
if (!m_scene->showOpSig())
op.replace(QRegExp("\\(.*\\)"), "()");
......@@ -453,7 +455,8 @@ void FloatingTextWidget::changeName(const QString& newText)
return;
}
if (m_linkWidget && m_textRole != Uml::TextRole::Seq_Message && m_textRole != Uml::TextRole::Seq_Message_Self) {
if (m_linkWidget && m_textRole != Uml::TextRole::Seq_Message
&& m_textRole != Uml::TextRole::Seq_Message_Self) {
m_linkWidget->setText(this, newText);
}
else {
......@@ -612,6 +615,37 @@ void FloatingTextWidget::constrainMovementForAllWidgets(qreal &diffX, qreal &dif
diffY = constrainedPosition.y() - y();
}
/**
* Override method from UMLWidget in order to additionally check PortWidget parentage.
*
* @param p Point to be checked.
*
* @return 'this' if UMLWidget::onWidget(p) returns non NULL;
* else NULL.
*/
UMLWidget* FloatingTextWidget::onWidget(const QPointF &p)
{
if (UMLWidget::onWidget(p) != NULL)
return this;
PortWidget *pw = dynamic_cast<PortWidget*>(parentItem());
if (pw) {
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
*/
......@@ -645,14 +679,14 @@ bool FloatingTextWidget::loadFromXMI(QDomElement & qElement)
m_preText = qElement.attribute("pretext", "");
m_postText = qElement.attribute("posttext", "");
m_Text = qElement.attribute("text", "");
setText(qElement.attribute("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 usefullWidget = !isEmpty();
return usefullWidget;
bool usefulWidget = !isEmpty();
return usefulWidget;
}
/**
......@@ -661,6 +695,9 @@ bool FloatingTextWidget::loadFromXMI(QDomElement & qElement)
*/
void FloatingTextWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement)
{
if (isEmpty())
return;
QDomElement textElement = qDoc.createElement("floatingtext");
UMLWidget::saveToXMI(qDoc, textElement);
textElement.setAttribute("text", m_Text);
......@@ -690,6 +727,9 @@ void FloatingTextWidget::slotMenuSelection(QAction* action)
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;
......
......@@ -76,6 +76,8 @@ public:
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);
......
......@@ -266,19 +266,24 @@ bool PinWidget::loadFromXMI(QDomElement& qElement)
m_pOw = pWA;
// We dont' really need the textid.
// @todo remove this code
QString textid = qElement.attribute("textid", "-1");
Uml::ID::Type textId = Uml::ID::fromString(textid);
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<FloatingTextWidget*>(flotext);
//return true;
if (flotext->baseType() == WidgetBase::wt_Text) {
uWarning() << "Check XMI file: floatingtext " << textid
<< " is already defined";
m_pName = static_cast<FloatingTextWidget*>(flotext);
return true;
} else {
uError() << "floatingtext xmi.id" << textid
<< " conflicts with existing " << flotext->baseType();
return false;
}
}
} else {
// no textid stored -> get unique new one
textId = UniqueID::gen();
}
//now load child elements
......
......@@ -196,13 +196,14 @@ void PortWidget::slotMenuSelection(QAction* action)
case ListPopupMenu::mt_NameAsTooltip:
if (m_pName) {
action->setChecked(true);
m_scene->removeWidget(m_pName);
delete m_pName;
m_pName = NULL;
setToolTip(m_umlObject->name());
} else {
action->setChecked(false);
m_pName = new FloatingTextWidget(m_scene, Uml::TextRole::Floating, m_umlObject->name());
m_pName->setParentItem(this);
m_pName->setText(m_umlObject->name()); // to get geometry update
m_pName->activate();
const Uml::ID::Type compWidgetId = m_umlObject->umlPackage()->id();
UMLWidget* owner = m_scene->widgetOnDiagram(compWidgetId);
......@@ -212,19 +213,19 @@ void PortWidget::slotMenuSelection(QAction* action)
setY(y());
} else {
if (x() < owner->x())
m_pName->setX(x() - m_pName->width());
m_pName->setX(-m_pName->width());
else if (x() >= owner->x() + owner->width())
m_pName->setX(x() + 15);
m_pName->setX(15);
else
m_pName->setX(x() - m_pName->width() / 2.0 + 7);
m_pName->setX(-m_pName->width() / 2.0 + 7);
if (y() < owner->y())
m_pName->setY(y() - m_pName->height() - 2);
m_pName->setY(-m_pName->height() - 2);
else if (y() >= owner->y() + owner->height())
m_pName->setY(y() + 15);
m_pName->setY(15);
else
m_pName->setY(y() - m_pName->height() / 2.0 + 7);
m_pName->setY(-m_pName->height() / 2.0 + 7);
}
m_scene->addFloatingTextWidget(m_pName);
m_pName->update();
setToolTip(QString());
QToolTip::hideText();
}
......@@ -241,6 +242,8 @@ FloatingTextWidget *PortWidget::floatingTextWidget() {
void PortWidget::setFloatingTextWidget(FloatingTextWidget *ft) {
m_pName = ft;
if (m_pName)
m_pName->setParentItem(this);
}
/**
......@@ -263,6 +266,18 @@ UMLWidget* PortWidget::onWidget(const QPointF &p)
return NULL;
}
/**
* Reimplement function from UMLWidget
*/
UMLWidget* PortWidget::widgetWithID(Uml::ID::Type id)
{
if (UMLWidget::widgetWithID(id))
return this;
if (m_pName && m_pName->widgetWithID(id))
return m_pName;
return NULL;
}
/**
* Loads from a "portwidget" XMI element.
......@@ -272,35 +287,22 @@ bool PortWidget::loadFromXMI(QDomElement & qElement)
if (!UMLWidget::loadFromXMI(qElement))
return false;
QString textid = qElement.attribute("textid", "-1");
Uml::ID::Type textId = Uml::ID::fromString(textid);
if (textId != Uml::ID::None) {
UMLWidget *flotext = m_scene -> findWidget(textId);
if (flotext != NULL) {
if (flotext->baseType() == WidgetBase::wt_Text) {
uWarning() << "Check XMI file: floatingtext " << textid
<< " is already defined";
m_pName = static_cast<FloatingTextWidget*>(flotext);
return true;
} else {
uError() << "floatingtext xmi.id" << textid
<< " conflicts with existing " << flotext->baseType();
return false;
}
}
}
// Optional child element: floatingtext
QDomNode node = qElement.firstChild();
QDomElement element = node.toElement();
if (!element.isNull()) {
QString tag = element.tagName();
if (tag == "floatingtext") {
m_pName = new FloatingTextWidget(m_scene, Uml::TextRole::Floating, m_umlObject->name(), textId);
m_pName = new FloatingTextWidget(m_scene, Uml::TextRole::Floating,
m_umlObject->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;
......@@ -317,7 +319,6 @@ void PortWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement)
QDomElement conceptElement = qDoc.createElement("portwidget");
UMLWidget::saveToXMI(qDoc, conceptElement);
if (m_pName && !m_pName->text().isEmpty()) {
conceptElement.setAttribute("textid", Uml::ID::toString(m_pName->id()));
m_pName -> saveToXMI(qDoc, conceptElement);
}
qElement.appendChild(conceptElement);
......
......@@ -39,6 +39,7 @@ public:
void attachToOwningComponent();
UMLWidget* onWidget(const QPointF& p);
UMLWidget* widgetWithID(Uml::ID::Type id);
FloatingTextWidget *floatingTextWidget();
void setFloatingTextWidget(FloatingTextWidget *ft);
......
......@@ -199,6 +199,27 @@ 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.
*
......
......@@ -61,6 +61,8 @@ public:
void setLocalID(Uml::ID::Type id);
Uml::ID::Type localID() const;
virtual UMLWidget* widgetWithID(Uml::ID::Type id);
virtual QSizeF minimumSize();
void setMinimumSize(const QSizeF &size);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment