[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