Logo Search packages:      
Sourcecode: kdesdk version File versions

associationwidget.h

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#ifndef ASSOCIATIONWIDGET_H
#define ASSOCIATIONWIDGET_H

#include "linkwidget.h"
#include "umlwidgetlist.h"
#include "messagewidgetlist.h"
#include "associationwidgetlist.h"
#include "linepath.h"

// qt includes

class FloatingText;
class IDChangeLog;
class ListPopupMenu;
class QBitmap;
class QPixmap;
class QDataStream;
class UMLView;
class UMLAssociation;

using namespace Uml;

/**
 * This class represents an association inside a diagram.
 *
 * 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
 * @short This class represents an association inside a diagram.
 * @version $Revision: 1.44 $
 * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
 */
00052 class AssociationWidget : public LinkWidget {
      Q_OBJECT
public:
      /**
       * Enumeration used for stating where a line is on a widget.
       */
00058       enum Region {
            Error = 0,
            West, North, East, South,
            NorthWest, NorthEast, SouthEast, SouthWest,
            Center
      };

      /**
       * Constructor.
       *
       * @param view          The parent view of this widget.
       */
      AssociationWidget(UMLView *view);

      /**
       * Constructor.
       *
       * @param view          The parent view of this widget.
       * @param WidgetA Pointer the role A widget for the association.
       * @param Type          The Association_Type for this association.
       * @param WidgetB Pointer the role B widget for the association.
       */
      AssociationWidget(UMLView *view, UMLWidget* WidgetA,
                    Association_Type Type, UMLWidget* WidgetB);

      /**
       * Deconstructor.
       */
      virtual ~AssociationWidget();

      /**
       * Overrides the assignment operator.
       */
      AssociationWidget& operator=(AssociationWidget & Other);

      /**
       * Overrides the equality test operator.
       */
      bool operator==(AssociationWidget & Other);

      /**
       * Overrides the != operator.
       */
      bool operator!=(AssociationWidget & Other);

      /**
       * Activates the AssociationWidget after a load.
       *
       * @return  True if activation successful.
       */
      bool activate();

      /**
       * Set the widget of the given role.
       *
       * @param widget  Pointer to the UMLWidget.
       */
      void setWidget(UMLWidget* widget, Role_Type role);

      /**
       * Return the multiplicity FloatingText widget of the given role.
       *
       * @return  Pointer to the multiplicity FloatingText object.
       */
      FloatingText* getMultiWidget(Role_Type role);

      /**
       * Return the given role's multiplicity text.
       *
       * @return  Text of the given role's multiplicity widget.
       */
      QString getMulti(Role_Type role) const;

      /**
       * Read property of FloatingText* m_pName.
       *
       * @return  Pointer to the FloatingText name widget.
       */
      FloatingText* getNameWidget();

      /**
       * Returns the m_pName's text.
       *
       * @return  Text of the FloatingText name widget.
       */
      QString getName() const;

      /**
       * Return the given role's FloatingText object.
       *
       * @return  Pointer to the role's FloatingText widget.
       */
      FloatingText* getRoleWidget(Role_Type role);

      /**
       * Returns the documentation about this association.
       *
       * @return  The AssociationWidget's documentation text.
       */
      QString getDoc() const;

      /**
       * Return the given role's FloatingText widget text.
       *
       * @return  The name set at the FloatingText.
       */
      QString getRoleName(Role_Type role) const;

      /**
       * Returns the given role's documentation.
       */
      QString getRoleDoc(Role_Type role) const;

      /**
       * Sets the text in the FloatingText widget representing the Name
       * of this association.
       */
      void setName (QString strRole);

      /**
       * Sets the text in the FloatingText representing the multiplicity
       * at the given side of the association.
       */
      void setMulti(QString strMulti, Role_Type role);

      /**
       * Gets the visibility on the given role of the association.
       */
      Scope getVisibility (Role_Type role) const;

      /**
       * Sets the visibility on the given role of the association.
       */
      void setVisibility (Scope visibility, Role_Type role );

      /**
       * Gets the changeability on the the given end of the Association.
       */
      Changeability_Type getChangeability(Role_Type role) const;

      /**
       * Sets the changeability on the the given end of the Association.
       */
      void setChangeability (Changeability_Type value, Role_Type role);

      /**
       * Gets the ID of the given role widget.
       */
      int getWidgetID(Role_Type role) const;

      /**
       * Gets the given role widget.
       *
       * @return  Pointer to the role's UMLWidget.
       */
      UMLWidget* getWidget(Role_Type role);

      /**
       * Sets the associated widgets.
       *
       * @param widgetA Pointer the role A widget for the association.
       * @param assocType     The Association_Type for this association.
       * @param widgetB Pointer the role B widget for the association.
       */
      bool setWidgets( UMLWidget* widgetA, Association_Type assocType, UMLWidget* widgetB);

      /**
       * Returns true if this association associates widgetA to widgetB,
       * otherwise it returns false.
       *
       * @param widgetA Pointer the role A widget to check.
       * @param widgetB Pointer the role B widget to check.
       * @return  True if widgetA and widgetB are associated.
       */
      bool checkAssoc(UMLWidget * widgetA, UMLWidget *widgetB);

      /**
       * Returns true if the Widget is either at the starting or ending side
       * of the association.
       *
       * @return  True if widget plays role A or B in this assoc.
       */
      bool contains(UMLWidget* widget);

      /**
       * Gets the association's type.
       *
       * @return  This AssociationWidget's Association_Type.
       */
      Association_Type getAssocType() const;

      /**
       * Sets the association's type.
       *
       * @param type          The Association_Type to set.
       */
      void setAssocType(Association_Type type);

      /**
       * Returns a QString object representing this AssociationWidget.
       *
       * @return  Textual representation of the AssociationWidget.
       */
      QString toString();

      /**
       * Read property of bool m_bActivated.
       *
       * @return  True if this AssociationWidget has been activated.
       */
      const bool isActivated();

      /**
       * Set the m_bActivated flag of a widget but does not perform the
       * activate method.
       *
       * @param active  The flag status to set.
       */
      void setActivated(bool active /*=true*/);

      /**
       * Sets the state of whether the widget is selected.
       *
       * @param _select The state of whether the widget is selected.
       */
      void setSelected(bool _select = true);

      /**
       * Returns the state of whether the widget is selected.
       *
       * @return  Returns the state of whether the widget is selected.
       */
00290       bool getSelected() const {
            return m_bSelected;
      }

      /**
       * Returns a pointer to the association widget's line path.
       */
00297       LinePath* getLinePath() {
            return &m_LinePath;
      }

      /**
       * Adjusts the ending point of the association that connects to Widget
       *
       * @param widget  Pointer to the widget that was moved.
       * @param x       New X coordinate of the widget.
       * @param y       New Y coordinate of the widget.
       */
      void widgetMoved(UMLWidget* widget, int x, int y);

      /**
       * Calculates the m_unNameLineSegment value according to the new
       * NameText topleft corner PT.
       * It iterates through all LinePath'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 FloatingText.)
       */
      void calculateNameTextSegment();

      /**
       * Adds a break point (if left mouse button).
       */
      void mouseDoubleClickEvent(QMouseEvent * me);

      /**
       * Sets the association to be selected.
       */
      void mousePressEvent(QMouseEvent * me);

      /**
       * Displays the right mouse buttom menu if right button is pressed.
       */
      void mouseReleaseEvent(QMouseEvent * me);

      /**
       * Moves the break point being dragged.
       */
      void mouseMoveEvent(QMouseEvent * me);

      /**
       *  Returns true if the given point is on the Association.
       */
      bool onAssociation(const QPoint & point);

      /**
       * Moves all the mid points (all expcept start /end ) by the given amount.
       */
      void moveMidPointsBy( int x, int y );

      /**
       * Moves the entire association by the given offset.
       */
      void moveEntireAssoc( int x, int y );

      /**
       * Returns the bounding rectangle of all segments of the association.
       */
      QRect getAssocLineRectangle();

      /**
       * Return the first font found being used by any child widget. (They
       * could be different fonts, so this is a slightly misleading method.)
         */
      QFont getFont () const;

      /**
       * Set all 'owned' child widgets to this font.
       */
      void setFont (QFont font);

      /**
       * Return the given role's changeability FloatingText widget.
       */
      FloatingText* getChangeWidget(Role_Type role);

      /**
       * Sets the text to the FloatingText that display the Role text of this
       * association.
       * For this function to work properly, the associated widget
       *  should already be set.
       */
      bool setRoleName(QString strRole, Role_Type role);

      /**
       * Set the documentation on this association.
       */
      void setDoc(QString doc);

      /**
       * Set the documentation on the given role.
       */
      void setRoleDoc(QString doc, Role_Type role);

      /**
       * Overrides operation from LinkWidget.
       * Required by FloatingText.
       */
      UMLClassifier *getOperationOwner(FloatingText *ft);

      /**
       * Overrides operation from LinkWidget.
       * Required by FloatingText.
       */
      void setOperationText(FloatingText *ft, QString opText);

      /**
       * Overrides operation from LinkWidget.
       * Required by FloatingText.
       *
       * @param ft      The text widget which to update.
       */
      void setMessageText(FloatingText *ft);

      /**
       * Returns the UMLAssociation representation of this object.
       *
       * @return  Pointer to the UMLAssociation that is represented by
       *          this AsociationWidget.
       */
      UMLAssociation * getAssociation ();

      /**
       * Sets the text of the FloatingText identified by the ft's Text_Role.
       * Overrides operation from LinkWidget.
       * Required by FloatingText.
       */
      void setText(FloatingText *ft, QString text);

      /**
       * Calls @ref setTextPosition() on all the labels.
       * Overrides operation from LinkWidget.
       */
      void resetTextPositions();

      /**
       * Shows the association properties dialog and updates the
       * corresponding texts if its execution is successful.
       * Returns true for success.
       */
      bool showDialog();

      /**
       * Sets the Association line index for the given role.
       */
      void setIndex(int index, Role_Type role);

      /**
       * Returns the Association line index for the given role.
       */
      int getIndex(Role_Type role) const;

      /**
       * Sets the total count on the Association region.
       */
      void setTotalCount(int count, Role_Type role);

      /**
       * Returns the total count on the Association region.
       */
      int getTotalCount(Role_Type role) const;

      /**
       * Sets the total count on the Association region for widgetB.
       */
      void setTotalCount(int count);

      /**
       * Overrides operation from LinkWidget.
       * Required by FloatingText.
       *
       * @param seqNum  The new sequence number string to set.
       * @param op            The new operation string to set.
       */
      void setSeqNumAndOp(QString seqNum, QString op);

      /**
       * Overrides operation from LinkWidget.
       * Required by FloatingText.
       *
       * @param ft            The calling FloatingText (unused here.)
       * @param seqNum  Return this AssociationWidget's sequence number string.
       * @param op            Return this AssociationWidget's operation string.
       */
      UMLClassifier * getSeqNumAndOp(FloatingText *ft, QString& seqNum,
                                           QString& op);

      /**
       * Overrides operation from LinkWidget.
       * Required by FloatingText.
       */
      void cleanupBeforeFTsetLink(FloatingText *ft);

      /**
       * Overrides operation from LinkWidget.
       * Required by FloatingText.
       */
      void setupAfterFTsetLink(FloatingText *ft);

      /**
       * Calculates and sets the first and last point in the association's
       * LinePath.
       * Each point is a middle point of its respective UMLWidget's bounding
       * rectangle.
       * This method picks which sides to use for the association.
       */
      void calculateEndingPoints();

      /**
       * Saves this widget to the <UML:AssociationWidget> XMI element.
       */
      void saveToXMI( QDomDocument & qDoc, QDomElement & qElement );

      /**
       * Loads this widget from the <UML:AssociationWidget> XMI element.
       */
      bool loadFromXMI( QDomElement & qElement );

      /**
       * Same as above, but 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 loadFromXMI( QDomElement & qElement, const UMLWidgetList& widgets,
                                   const MessageWidgetList* pMessages = NULL);

private:

      /** set our internal umlAssociation */
      void setUMLAssociation (UMLAssociation * assoc);

        /**
         * Cleans up all the association's data in the related widgets.
         */
        void cleanup();

      /**
       * Merges/syncs the association widget data into UML object
       * representation.
       * CHECK: Can we get rid of this.
       */
      void mergeAssociationDataIntoUMLRepresentation();

      /**
       * Finds out which region contains the point (PosX, PosY).
       *
       * The diagram is divided into four regions by its diagonals :
       *
       *                         Region 2
       *                      \            /
       *                       \          /
       *                        +--------+
       *                        | \    / |
       *           Region 1     |   ><   |    Region 3
       *                        | /    \ |
       *                        +--------+
       *                       /          \
       *                      /            \
       *                         Region 4
       *
       *
       * @param Rect          The bounding rectangle to investigate.
       * @param PosX          X coordinate of the point to seek.
       * @param PosY          Y coordinate of the point to seek.
       * @return  The region number of the region containing the point.
       *          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 Region4 and 1
       *          9 = On diagonal 1 and On diagonal 2 (the center)
       */
      static Region findPointRegion(QRect Rect, int PosX, int PosY);

      /**
       * 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.)
       */
      static int findInterceptOnEdge(QRect rect, Region region, QPoint point);

      /**
       * Overrides moveEvent.
       */
      void moveEvent(QMoveEvent *me);

      /**
       * This function calculates which role should be set for the m_pName
       * FloatingText.
       */
      Text_Role CalculateNameType(Text_Role defaultRoleType);

      /**
       * Returns true if point (PosX, PosY) is close enough to any of the
       * association's segments.
       */
      bool isPointInsideBoundaries(int PosX, int PosY, QPoint & SPoint,
                             uint & StartSegmentIndex, uint & EndSegmentIndex);

      /**
       * Returns a point with interchanged X and Y coordinates.
       */
      static QPoint swapXY(QPoint p);

      /**
       * Returns the total length of the association's LinePath:
       * result = segment_1_length + segment_2_length + ... + segment_n_length
       */
      float totalLength();

      /**
       * 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).
       */
      static QPoint calculatePointAtDistance(QPoint P1, QPoint P2, float Distance);

      /**
       * Calculates which point of a perpendicular line to segment P1P2 that
       * contains P2 has a distance equal to Distance from P2.
       * Let's say such point is PX, the distance from P2 to PX must be equal
       * to Distance.
       */
      static QPoint calculatePointAtDistanceOnPerpendicular(QPoint P1, QPoint P2, float Distance);

      /**
       * Calculates the intersection between line P1P2 and a perpendicular
       * line containing P3, the result is returned in ResultingPoint.
       * The result value represents the distance between ResultingPoint and
       * P3. If this value is negative an error ocurred.
       * This method is not currently used.
       */
      static float perpendicularProjection(QPoint P1, QPoint P2, QPoint P3, QPoint& ResultingPoint);

      /**
       * Calculates the position of the text widget depending on the role
       * that widget is playing.
       * Returns the point at which to put the widget.
       */
      QPoint calculateTextPosition(Text_Role role);

      /**
       * Returns the FloatingText identified by the given text role.
       * Returns NULL if there is no FloatingText active for the text role.
       */
      FloatingText* AssociationWidget::floatingText(Text_Role role);

      /**
       * Puts the text widget with the given role at the given position.
       * This method is usually called after calling @ref calculateTextPostion
       * to get the needed postion.  It is a separate function in case there
       * is a need to place the text without calculation.
       * I.e. the line segment it is on has moved and it should move the same
       * amount as the line.
       */
      void setTextPosition(Text_Role role, QPoint pos);

      /**
       * Moves the text widget with the given role by the difference between
       * the two points.
       */
      void setTextPositionRelatively(Text_Role role, QPoint pos, QPoint oldPosition);

      /**
       * 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.
       */
      Region getWidgetRegion(AssociationWidget * widget) const;

      /**
       * This is a pointer to the Floating Text widget which displays the
       * name of this association.
       */
00694       FloatingText* m_pName;

      /**
       * 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).
       */
00701       struct WidgetRole {

            /**
             * This is a pointer to the Floating Text widget at the role's side
             * of the association.
             * This FloatingText displays the information regarding multiplicity.
             */
00708             FloatingText* m_pMulti;

            /**
             * This is a pointer to the Floating Text widget at the role's side
             * of the association.
             * This FloatingText displays the information regarding changeability.
             */
00715             FloatingText* m_pChangeWidget;

            /**
             * This member holds a pointer to the floating text that displays
             * the role's label of this association.
             */
00721             FloatingText* m_pRole;

            /**
             * This member holds a pointer to the UMLWidget at this role's side
             * of the association.
             */
00727             UMLWidget* m_pWidget;

            /**
             * This role's old top left corner before moving.
             */
00732             QPoint m_OldCorner;

            /**
             * The region of this role's widget.
             */
00737             Region m_WidgetRegion;

            /**
             * The index of where the line is on the region for this role.
             */
00742             int m_nIndex;

            /**
             * The total amount of associations on the region this role's line is on.
             */
00747             int m_nTotalCount;

            // The following items are only used if m_pObject is not set.
            Scope m_Visibility;
            Changeability_Type m_Changeability;
            QString m_RoleDoc;
            QString m_RoleName;
            QString m_Multi;

      } m_role[2];

      /**
       * 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 updateRegionLineCount(int index, int totalCount,
                           AssociationWidget::Region region, Role_Type role);

      /**
       * 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 updateAssociations(int totalCount, Region region, Role_Type role);

      /**
       * Returns the number of lines there are on the given region for
       * either widget A or B of the association.
       */
      int getRegionCount(Region region, Role_Type role);

      /**
       * Initialize attributes of this class at construction time.
       */
      void init (UMLView *view);

      /**
       * Auxiliary method for calculateEndingPoints().
       */
      void doUpdates(int otherX, int otherY, Role_Type role);

      /**
       * For internal purposes only.
       * Other classes/users should use setChangeability() instead.
       */
      void setChangeWidget(QString strChangeWidget, Role_Type role);

      /**
       * Checks to see if the given point is one of the points of the line.
       * If so will try and get the view to flag the point for moving.
       * This is only valid if no other point id being moved and only
       * while the left mouse button is down.
       */
      void checkPoints(QPoint p);

      /**
       * Returns true if the line path starts at the given widget.
       */
      bool linePathStartsAt(const UMLWidget* widget);

      /**
       * Utility: Find the widget identified by the given ID in the given
       * widget or message list.
       * It's somewhat arbitrary that this utility is here as it has no
       * dependencies whatsoever on AssociationWidget.  It just happens
       * to be needed here.  We should pull it out from here if it also
       * becomes needed somewhere else.
       */
      static UMLWidget* findWidget(int id, const UMLWidgetList& widgets,
                                   const MessageWidgetList* pMessages = NULL);

      /**
       * 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 insertIntoLists(int position, const AssociationWidget* assoc);

00830       int m_positions[100];             ///< auxiliary variable for updateAssociations()
00831       int m_positions_len;              ///< auxiliary variable for updateAssociations()
00832       AssociationWidgetList m_ordered;  ///< auxiliary variable for updateAssociations()

      /*QPixmap   *m_pPix;
      QBitmap     *m_pMask;*/

      /**
       * Flag which is true if the activate method has been called for this
       * class instance.
       */
00841       bool m_bActivated;

      /**
       * When the association has a Role Floating Text this text should move
       * when the LinePath moves but only if the closest segment to the
       * role text moves.
       * This segment is:
       * m_LinePath[m_unNameLineSegment] -- m_LinePath[m_unNameLineSegment+1]
       */
00850       uint        m_unNameLineSegment;

      bool        m_bFocus;
      ListPopupMenu     *m_pMenu;
      bool        m_bSelected;
      int         m_nMovingPoint;

      /**
       * The definition points for the association line.
       */
00860       LinePath m_LinePath;

      // The following items are only used if m_pObject is not set.
      QString m_Doc;
      Uml::Association_Type m_AssocType;

public slots:
      /**
       * Handles the selection from the popup menu.
       */
      void slotMenuSelection(int sel);

      /**
       * This slot is entered when an event has occurred on the views display,
       * most likely a mouse event.  Before it sends out that mouse event all
       * children should make sure that they don't have a menu active or there
       * could be more than one popup menu displayed.
       */
      void slotRemovePopupMenu();

      /**
       * Handles any signals that tells everyone not to be selected.
       */
      void slotClearAllSelected();

      /**
       * Merge together the UMLAssociation representation and this widget
       */
      void mergeUMLRepresentationIntoAssociationData();
};
#endif

Generated by  Doxygen 1.6.0   Back to index