 /*
  *  copyright (C) 2002-2004
  *  Umbrello UML Modeller Authors <uml-devel@ uml.sf.net>
  */

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the 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 "widgetbase.h"
#include "linkwidget.h"
#include "umlwidgetlist.h"
#include "messagewidgetlist.h"
#include "associationwidgetlist.h"
#include "linepath.h"

class IDChangeLog;
class ListPopupMenu;
class QBitmap;
class QPixmap;
class QDataStream;
class UMLDoc;
class UMLView;
class UMLAssociation;
class UMLAttribute;
class UMLOperation;

/**
 * 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.
 * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
 */
class AssociationWidget : public WidgetBase, public LinkWidget {
	Q_OBJECT
public:
	/**
	 * Enumeration used for stating where a line is on a widget.
	 */
	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.
	 * @param umlassoc	Pointer the underlying UMLAssociation (if applicable.)
	 */
	AssociationWidget(UMLView *view, UMLWidget* WidgetA,
			  Uml::Association_Type Type, UMLWidget* WidgetB,
			  UMLAssociation *umlassoc = NULL);

	/**
	 * 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, Uml::Role_Type role);

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

	/**
	 * Return the given role's multiplicity text.
	 *
	 * @return	Text of the given role's multiplicity widget.
	 */
	QString getMulti(Uml::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(Uml::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(Uml::Role_Type role) const;

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

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

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

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

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

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

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

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

	/**
	 * Gets the given role widget.
	 *
	 * @return	Pointer to the role's UMLWidget.
	 */
	UMLWidget* getWidget(Uml::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, Uml::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.
	 */
	Uml::Association_Type getAssocType() const;

	/**
	 * Sets the association's type.
	 *
	 * @param type		The Association_Type to set.
	 */
	void setAssocType(Uml::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.
	 */
	bool getSelected() const {
		return m_bSelected;
	}

	/**
	 * Returns a pointer to the association widget's line path.
	 */
	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 lwSetFont (QFont font);

	/**
	 * Return the given role's changeability FloatingText widget.
	 */
	FloatingText* getChangeWidget(Uml::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(const QString &strRole, Uml::Role_Type role);

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

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

	/**
	 * Overrides operation from LinkWidget.
	 * Required by FloatingText.
	 * @todo Move to LinkWidget.
	 */
	UMLClassifier *getOperationOwner();

	/**
	 * Implements operation from LinkWidget.
	 * Motivated by FloatingText.
	 */
	UMLOperation *getOperation();

	/**
	 * Implements operation from LinkWidget.
	 * Motivated by FloatingText.
	 */
	void setOperation(UMLOperation *op);

	/**
	 * Overrides operation from LinkWidget.
	 * Required by FloatingText.
	 */
	QString getCustomOpText();

	/**
	 * Overrides operation from LinkWidget.
	 * Required by FloatingText.
	 */
	void setCustomOpText(const 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 ();

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

	/**
	 * Sets the text of the FloatingText identified by the ft's Text_Role.
	 * Overrides operation from LinkWidget.
	 * Required by FloatingText.
	 */
	void setText(FloatingText *ft, const 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, Uml::Role_Type role);

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

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

	/**
	 * Returns the total count on the Association region.
	 */
	int getTotalCount(Uml::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(const QString &seqNum, const 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);

	/**
	 * 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();

	/**
	 * Overriding the method from WidgetBase because we need to do
	 * something extra in case this AssociationWidget represents
	 * an attribute of a classifier.
	 */
	void setUMLObject(UMLObject *obj);

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

	/**
	 * Loads this widget from the <assocwidget> 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(const QRect &rect, Region region, const QPoint &point);

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

	/**
	 * This function calculates which role should be set for the m_pName
	 * FloatingText.
	 */
	Uml::Text_Role CalculateNameType(Uml::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(const 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(const QPoint &P1, const 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(const QPoint &P1, const 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(Uml::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* floatingText(Uml::Text_Role role);

	/**
	 * 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 setTextPosition(Uml::Text_Role role);

	/**
	 * Moves the text widget with the given role by the difference between
	 * the two points.
	 */
	void setTextPositionRelatively(Uml::Text_Role role, const 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.
	 */
	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).
	 */
	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.
		 */
		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.
		 */
		FloatingText* m_pChangeWidget;

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

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

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

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

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

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

		// The following items are only used if m_pObject is not set.
		Uml::Scope m_Visibility;
		Uml::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, Uml::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, Uml::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, Uml::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, Uml::Role_Type role);

	/**
	 * For internal purposes only.
	 * Other classes/users should use setChangeability() instead.
	 */
	void setChangeWidget(const QString &strChangeWidget, Uml::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(const QPoint &p);

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

	/**
	 * 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);

	int m_positions[100];             ///< auxiliary variable for updateAssociations()
	int m_positions_len;              ///< auxiliary variable for updateAssociations()
	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.
	 */
	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]
	 */
	uint 		m_unNameLineSegment;
	UMLDoc * m_umldoc;  ///< just a shorthand for UMLApp::app()->getDocument()
	bool 		m_bFocus;
	ListPopupMenu 	*m_pMenu;
	bool 		m_bSelected;
	int 		m_nMovingPoint;

	/**
	 * The definition points for the association line.
	 */
	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();

	/**
	 * Connected to UMLClassifier::attributeRemoved() in case this
	 * AssociationWidget is linked to a classifer's attribute type.
	 *
	 * @param obj		The UMLAttribute removed.
	 */
	void slotAttributeRemoved(UMLObject* obj);

	/**
	 * Synchronize this widget from the UMLAssociation.
	 */
	void syncToModel();
};
#endif
