[Uml-devel] branches/work/soc-umbrello/umbrello
Gopala Krishna A
krishna.ggk at gmail.com
Fri Jul 18 16:11:56 UTC 2008
SVN commit 834309 by gopala:
Ported ActorWidget to use TextItems. The Actor is now repesented as a QPainterPath.
This path is calculated when size of widget changes thereby allowing faster painting. (Paint events should be as fast and light as possible).
M +125 -53 actorwidget.cpp
M +25 -43 actorwidget.h
M +2 -2 widget_factory.cpp
--- branches/work/soc-umbrello/umbrello/actorwidget.cpp #834308:834309
@@ -12,74 +12,146 @@
// own header file
#include "actorwidget.h"
-// system includes
-#include <qpainter.h>
-
// local includes
#include "actor.h"
-#include "umlview.h"
+#include "textitemgroup.h"
+#include "textitem.h"
+// qt includes
+#include <QtGui/QPainter>
-ActorWidget::ActorWidget(UMLScene * scene, UMLActor *a) : NewUMLRectWidget(scene, a)
+const QSizeF ActorWidget::MinimumActorSize = QSizeF(20, 40);
+const qreal ActorWidget::Margin = 5;
+
+/**
+ * Constructs an ActorWidget.
+ *
+ * @param o The Actor class this ActorWidget will display.
+ */
+ActorWidget::ActorWidget(UMLActor *a) : NewUMLRectWidget(a)
{
- NewUMLRectWidget::setBaseType( Uml::wt_Actor );
+ m_baseType = Uml::wt_Actor;
+ m_textItemGroup = new TextItemGroup(this);
}
-ActorWidget::~ActorWidget() {}
+/// Destructor
+ActorWidget::~ActorWidget()
+{
+ delete m_textItemGroup;
+}
+/// Reimplemented to return size hint corresponding to ActorWidget.
+QSizeF ActorWidget::sizeHint(Qt::SizeHint which)
+{
+ if(which == Qt::MinimumSize) {
+ return m_minimumSize;
+ }
+ return NewUMLRectWidget::sizeHint(which);
+}
+
+/**
+ * Overrides the standard paint event.
+ */
void ActorWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *o, QWidget *)
{
- QPainter &p = *painter;
- qreal offsetX = 0, offsetY = 0;
+ painter->setPen(QPen(lineColor(), lineWidth()));
+ painter->setBrush(brush());
- NewUMLRectWidget::setPenFromSettings(p);
- if( NewUMLRectWidget::getUseFillColour() )
- p.setBrush( NewUMLRectWidget::getFillColour() );
- const qreal w = getWidth();
- const qreal h = getHeight();
- p.setFont( NewUMLRectWidget::getFont() );
- const QFontMetrics &fm = getFontMetrics(FT_NORMAL);
- const qreal textWidth = fm.width(getName());
- const qreal fontHeight = fm.lineSpacing();
- const qreal a_height = h - fontHeight - A_MARGIN;
- const qreal h2 = a_height / 2;
- const qreal w2 = w - A_MARGIN * 2;
- const qreal a_width = (h2 > w2 || w > textWidth + A_MARGIN * 2 ? w2 : h2);
- const qreal middleX = w / 2;
- const qreal thirdY = a_height / 3;
-
- //draw actor
- p.drawEllipse(offsetX + middleX - a_width / 2, offsetY, a_width, thirdY); //head
- p.drawLine(offsetX + middleX, offsetY + thirdY,
- offsetX + middleX, offsetY + thirdY * 2); //body
- p.drawLine(offsetX + middleX, offsetY + 2 * thirdY,
- offsetX + middleX - a_width / 2, offsetY + a_height); //left leg
- p.drawLine(offsetX + middleX, offsetY + 2 * thirdY,
- offsetX + middleX + a_width / 2, offsetY + a_height); //right leg
- p.drawLine(offsetX + middleX - a_width / 2, offsetY + thirdY + thirdY / 2,
- offsetX + middleX + a_width / 2, offsetY + thirdY + thirdY / 2); //arms
- //draw text
- p.setPen(QPen(Qt::black));
- p.drawText(offsetX + A_MARGIN, offsetY + h - fontHeight,
- w - A_MARGIN * 2, fontHeight, Qt::AlignCenter, getName());
- if(isSelected()) {
- drawSelected(&p, offsetX, offsetY);
- }
+ painter->drawPath(m_actorPath);
}
-QSizeF ActorWidget::calculateSize() {
- const QFontMetrics &fm = getFontMetrics(FT_NORMAL);
- const int fontHeight = fm.lineSpacing();
- const int textWidth = fm.width(getName());
- qreal width = textWidth > A_WIDTH ? textWidth : A_WIDTH;
- qreal height = A_HEIGHT + fontHeight + A_MARGIN;
- width += A_MARGIN * 2;
- return QSizeF(width, height);
-}
-
-void ActorWidget::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
+/// Saves the widget to the "actorwidget" XMI element.
+void ActorWidget::saveToXMI( QDomDocument & qDoc, QDomElement & qElement )
+{
QDomElement actorElement = qDoc.createElement( "actorwidget" );
NewUMLRectWidget::saveToXMI( qDoc, actorElement );
qElement.appendChild( actorElement );
}
+/**
+ * Reimplemented to calculate minimum size based on the name text and
+ * ActorWidget::MinimumActorSize
+ */
+void ActorWidget::updateGeometry()
+{
+ if(umlObject()) {
+ const int totalItemCount = 1; // Only name text
+ const int nameItemIndex = 0;
+ m_textItemGroup->ensureTextItemCount(totalItemCount);
+
+ TextItem *nameItem = m_textItemGroup->textItemAt(nameItemIndex);
+ nameItem->setDefaultTextColor(fontColor());
+ nameItem->setFont(font());
+ nameItem->setAlignment(Qt::AlignCenter);
+ nameItem->setBackgroundBrush(Qt::NoBrush);
+ nameItem->setText(name());
+
+ // Calculate minimum size.
+ m_minimumSize = m_textItemGroup->calculateMinimumSize();
+ m_minimumSize.rheight() += ActorWidget::MinimumActorSize.height();
+ m_minimumSize.rheight() += 2 * ActorWidget::Margin;
+
+ m_minimumSize.rwidth() = qMax(m_minimumSize.width(),
+ ActorWidget::MinimumActorSize.width());
+ m_minimumSize.rwidth() += 2 * ActorWidget::Margin;
+ }
+ NewUMLRectWidget::updateGeometry();
+}
+
+/**
+ * Reimplemented to calculated new shape based on current size and
+ * also align the actor text.
+ */
+void ActorWidget::sizeHasChanged(const QSizeF& oldSize)
+{
+ const QSizeF sz = size();
+
+ // First adjust the position of text and align it.
+ const int NameIndex = 0;
+ qreal fontHeight = m_textItemGroup->textItemAt(NameIndex)->height();
+ QPointF offset(ActorWidget::Margin,
+ sz.height() - fontHeight - ActorWidget::Margin);
+ m_textItemGroup->setPos(offset);
+ QSizeF groupCurSize = QSizeF(sz.width() - 2 * ActorWidget::Margin,
+ fontHeight);
+ m_textItemGroup->alignVertically(groupCurSize);
+
+ // Calculate actor path again.
+ m_actorPath = QPainterPath();
+ qreal actorHeight = sz.height() - fontHeight -
+ 2 * ActorWidget::Margin;
+ qreal actorWidth = sz.width() - 2 * ActorWidget::Margin;
+
+ // Make sure width of actor isn't too much, it looks ugly otherwise.
+ if(actorWidth > .5 * actorHeight) {
+ actorWidth = .5 * actorHeight;
+ }
+
+ //TODO: Probably use above similar approach to limit height.
+ QRectF headEllipse;
+ headEllipse.setTopLeft(QPointF(.5 * (sz.width() - actorWidth), ActorWidget::Margin));
+ headEllipse.setSize(QSizeF(actorWidth, actorHeight / 3));
+ m_actorPath.addEllipse(headEllipse);
+
+ QLineF bodyLine(.5 * sz.width(), headEllipse.bottom(),
+ .5 * sz.width(), (2. / 3.) * actorHeight);
+ m_actorPath.moveTo(bodyLine.p1());
+ m_actorPath.lineTo(bodyLine.p2());
+
+ QLineF leftLeg(.5 * sz.width(), bodyLine.p2().y(),
+ headEllipse.left(), actorHeight);
+ m_actorPath.moveTo(leftLeg.p1());
+ m_actorPath.lineTo(leftLeg.p2());
+
+ QLineF rightLeg(.5 * sz.width(), bodyLine.p2().y(),
+ headEllipse.right(), actorHeight);
+ m_actorPath.moveTo(rightLeg.p1());
+ m_actorPath.lineTo(rightLeg.p2());
+
+ QLineF arms(headEllipse.left(), .5 * actorHeight,
+ headEllipse.right(), .5 * actorHeight);
+ m_actorPath.moveTo(arms.p1());
+ m_actorPath.lineTo(arms.p2());
+
+ NewUMLRectWidget::sizeHasChanged(oldSize);
+}
--- branches/work/soc-umbrello/umbrello/actorwidget.h #834308:834309
@@ -12,67 +12,49 @@
#ifndef ACTORWIDGET_H
#define ACTORWIDGET_H
-#include "umlwidget.h"
+#include "newumlrectwidget.h"
-#define A_WIDTH 20
-#define A_HEIGHT 40
-#define A_MARGIN 5
-
class UMLActor;
+class TextItemGroup;
/**
- * 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.
+ * This class is the graphical version of a UML Actor and can be
+ * placed in UseCase diagram.
*
- * 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 NewUMLRectWidget class
+ * which adds most of the functionality to this class.
*
- * The ActorWidget class inherits from the @ref NewUMLRectWidget class which adds most
- * of the functionality to this class.
- *
* @short A graphical version of a UML Actor.
* @author Paul Hensgen <phensgen at techie.com>
+ * @author Gopala Krishna (ported using QPainterPath and TextItems)
* @see NewUMLRectWidget
- * @see UMLView
* Bugs and comments to uml-devel at lists.sf.net or http://bugs.kde.org
*/
-
-class ActorWidget : public NewUMLRectWidget {
+class ActorWidget : public NewUMLRectWidget
+{
public:
- /**
- * Constructs an ActorWidget.
- *
- * @param view The parent of this ActorWidget.
- * @param o The Actor class this ActorWidget will display.
- */
- ActorWidget(UMLScene * scene, UMLActor *o);
+ ActorWidget(UMLActor *o);
+ virtual ~ActorWidget();
+ virtual QSizeF sizeHint(Qt::SizeHint which);
- /**
- * destructor
- */
- virtual ~ActorWidget();
+ virtual void paint(QPainter *p, const QStyleOptionGraphicsItem *item, QWidget *w);
- /**
- * Overrides the standard paint event.
- */
- void paint(QPainter *p, const QStyleOptionGraphicsItem *item, QWidget *w);
+ //Note: For loading from XMI, the inherited parent method is used.
+ virtual void saveToXMI( QDomDocument & qDoc, QDomElement & qElement );
- /**
- * Saves the widget to the "actorwidget" XMI element.
- * Note: For loading from XMI, the inherited parent method is used.
- */
- void saveToXMI( QDomDocument & qDoc, QDomElement & qElement );
-
protected:
- /**
- * Overrides method from NewUMLRectWidget.
- */
- QSizeF calculateSize();
+ virtual void updateGeometry();
+ virtual void sizeHasChanged(const QSizeF& oldSize);
+
+private:
+ static const QSizeF MinimumActorSize;
+ static const qreal Margin;
+
+ QPainterPath m_actorPath;
+ QSizeF m_minimumSize;
+ TextItemGroup *m_textItemGroup;
};
#endif
--- branches/work/soc-umbrello/umbrello/widget_factory.cpp #834308:834309
@@ -79,7 +79,7 @@
y = ow->topMargin();
newWidget = ow;
} else
- newWidget = new ActorWidget(scene, static_cast<UMLActor*>(o));
+ newWidget = new ActorWidget(static_cast<UMLActor*>(o));
break;
case Uml::ot_UseCase:
newWidget = new UseCaseWidget(static_cast<UMLUseCase*>(o));
@@ -232,7 +232,7 @@
if (tag == "actorwidget" || tag == "UML:ActorWidget") {
if (validateObjType(Uml::ot_Actor, o, id))
- widget = new ActorWidget(scene, static_cast<UMLActor*>(o));
+ widget = new ActorWidget(static_cast<UMLActor*>(o));
} else if (tag == "usecasewidget" || tag == "UML:UseCaseWidget") {
if (validateObjType(Uml::ot_UseCase, o, id))
widget = new UseCaseWidget(static_cast<UMLUseCase*>(o));
More information about the umbrello-devel
mailing list