using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; namespace Netron.Diagramming.Core { // ---------------------------------------------------------------------- /// /// Abstract base class for every diagram entity. /// // ---------------------------------------------------------------------- public abstract partial class DiagramEntityBase : IDiagramEntity, IMouseListener, IHoverListener, IKeyboardListener, IDisposable { #region Events // ------------------------------------------------------------------ /// /// Occurs when the user click on the entity. /// // ------------------------------------------------------------------ public event EventHandler OnClick; // ------------------------------------------------------------------ /// /// Occurs when a mouse button is pressed while over the entity. /// // ------------------------------------------------------------------ public event EventHandler OnMouseDown; // ------------------------------------------------------------------ /// /// Occurs when a mouse button is released while over the entity. /// // ------------------------------------------------------------------ public event EventHandler OnMouseUp; // ------------------------------------------------------------------ /// /// Occurs when the mouse is moved while over the entity. /// // ------------------------------------------------------------------ public event EventHandler OnMouseMove; // ------------------------------------------------------------------ /// /// Occurs when the mouse enters the entity. /// // ------------------------------------------------------------------ public event EventHandler OnMouseEnter; // ------------------------------------------------------------------ /// /// Occurs when the mouse hovers over the entity. /// // ------------------------------------------------------------------ public event EventHandler OnMouseHover; // ------------------------------------------------------------------ /// /// Occurs when the mouse leaves the entity. /// // ------------------------------------------------------------------ public event EventHandler OnMouseLeave; // ------------------------------------------------------------------ /// /// Occurs when the entity's properties have changed /// // ------------------------------------------------------------------ public event EventHandler OnEntityChange; // ------------------------------------------------------------------ /// /// Occurs when the entity is selected. This can be different than the /// OnClick because the selector can select and entity without /// clicking on it. /// // ------------------------------------------------------------------ public event EventHandler OnEntitySelect; #endregion #region Fields // ------------------------------------------------------------------ /// /// Implementation of IVersion - the current version of /// DiagramEntityBase. /// // ------------------------------------------------------------------ protected const double diagramEntityBaseVersion = 1.0; // ------------------------------------------------------------------ /// /// The services of this entity. /// // ------------------------------------------------------------------ protected Dictionary mServices; // ------------------------------------------------------------------ /// /// The Rectangle on which any bundle lives. /// // ------------------------------------------------------------------ protected Rectangle mRectangle = Rectangle.Empty; // ------------------------------------------------------------------ /// /// General prupose tag /// // ------------------------------------------------------------------ protected object mTag; // ------------------------------------------------------------------ /// /// tells whether the current entity is hovered by the mouse /// // ------------------------------------------------------------------ protected bool mHovered; // ------------------------------------------------------------------ /// /// The current magnification of the view. /// // ------------------------------------------------------------------ protected SizeF mMagnification = new SizeF(100F, 100F); // ------------------------------------------------------------------ /// /// The Model to which the eneity belongs. /// // ------------------------------------------------------------------ protected IModel mModel; // ------------------------------------------------------------------ /// /// The layer to which this entity is attached in the Model. /// // ------------------------------------------------------------------ protected ILayer mLayer; // ------------------------------------------------------------------ /// /// tells whether the entity is selected /// // ------------------------------------------------------------------ protected bool mIsSelected; // ------------------------------------------------------------------ /// /// the current draw style /// // ------------------------------------------------------------------ protected IPenStyle mPenStyle; // ------------------------------------------------------------------ /// /// the current paint style /// // ------------------------------------------------------------------ protected IPaintStyle mPaintStyle; // ------------------------------------------------------------------ /// /// the default pen to be used by the Paint method /// // ------------------------------------------------------------------ protected Pen mPen; // ------------------------------------------------------------------ /// /// the default brush to be used by the Paint method /// // ------------------------------------------------------------------ protected Brush mBrush; // ------------------------------------------------------------------ /// /// the name of the entity /// // ------------------------------------------------------------------ protected string mName; // ------------------------------------------------------------------ /// /// a weak reference to the parent /// // ------------------------------------------------------------------ protected WeakReference mParent; // ------------------------------------------------------------------ /// /// the scene index, i.e. the index of this entity in the scene-graph. /// // ------------------------------------------------------------------ protected int mSceneIndex; // ------------------------------------------------------------------ /// /// The top-group to underneath which this entity resides. /// // ------------------------------------------------------------------ protected IGroup mGroup; // ------------------------------------------------------------------ /// /// Specifies if the entity can be moved. /// // ------------------------------------------------------------------ protected bool mAllowMove = true; // ------------------------------------------------------------------ /// /// Specifies if the entity can be deleted. /// // ------------------------------------------------------------------ protected bool mAllowDelete = true; // ------------------------------------------------------------------ /// /// Specifies if the entity can be resized. /// // ------------------------------------------------------------------ protected bool mResizable = true; // ------------------------------------------------------------------ /// /// The minimum size this entity can be. The default value is: /// width = 10, height = 10. This seems to be the min size that /// keeps the connectors relative position correct during a Transform. /// // ------------------------------------------------------------------ protected Size myMinSize = new Size(10, 10); // ------------------------------------------------------------------ /// /// The maximum size this entity can be. The default value is: /// width = 10000, height = 10000. /// // ------------------------------------------------------------------ protected Size myMaxSize = new Size(10000, 10000); // ------------------------------------------------------------------ /// /// The unique identifier of this entity /// // ------------------------------------------------------------------ protected Guid mUid = Guid.NewGuid(); // ------------------------------------------------------------------ /// /// whether the entity is visible /// // ------------------------------------------------------------------ protected bool mVisible = true; // ------------------------------------------------------------------ /// /// The Enabled field. /// // ------------------------------------------------------------------ protected bool mEnabled = true; #endregion #region Properties // ------------------------------------------------------------------ /// /// Gets the current version. /// // ------------------------------------------------------------------ public virtual double Version { get { return diagramEntityBaseVersion; } } // ------------------------------------------------------------------ /// /// Gets the services provided by this entity. /// /// The services. // ------------------------------------------------------------------ public Dictionary Services { get { return mServices; } } // ------------------------------------------------------------------ /// /// Gets or sets whether this entity is Enabled. /// // ------------------------------------------------------------------ public virtual bool Enabled { get { return mEnabled; } set { mEnabled = value; RaiseOnChange(this, new EntityEventArgs(this)); } } // ------------------------------------------------------------------ /// /// Gets or sets a value indicating whether this entity is visible. /// /// true if visible; otherwise, false. // ------------------------------------------------------------------ public virtual bool Visible { get { return mVisible; } set { mVisible = value; RaiseOnChange(this, new EntityEventArgs(this)); } } // ------------------------------------------------------------------ /// /// Gets or sets the drawing style. /// /// The draw style. // ------------------------------------------------------------------ public virtual IPenStyle PenStyle { get { return mPenStyle; } set { mPenStyle = value; RaiseOnChange(this, new EntityEventArgs(this)); UpdatePaintingMaterial(); } } // ------------------------------------------------------------------ /// /// Gets or sets the paint style. /// /// The paint style. // ------------------------------------------------------------------ public virtual IPaintStyle PaintStyle { get { return mPaintStyle; } set { mPaintStyle = value; RaiseOnChange(this, new EntityEventArgs(this)); UpdatePaintingMaterial(); } } // ------------------------------------------------------------------ /// /// Gets the globally unique identifier of this entity /// /// // ------------------------------------------------------------------ public virtual Guid Uid { get { return mUid; } } // ------------------------------------------------------------------ /// /// Gets or sets a value indicating whether this /// can be moved. /// /// true if movable; otherwise, false. // ------------------------------------------------------------------ public virtual bool AllowMove { get { return mAllowMove; } set { mAllowMove = value; } } // ------------------------------------------------------------------ /// /// Gets or sets a value indicating whether this /// can be deleted. /// /// true if deletable; otherwise, false. // ------------------------------------------------------------------ public virtual bool AllowDelete { get { return mAllowDelete; } set { mAllowDelete = value; } } // ------------------------------------------------------------------ /// /// Gets or sets the Resizable /// // ------------------------------------------------------------------ public virtual bool Resizable { get { return mResizable; } set { mResizable = value; } } // ------------------------------------------------------------------ /// /// Gets the minimum size of the entity. /// // ------------------------------------------------------------------ public virtual Size MinSize { get { return myMinSize; } } // ------------------------------------------------------------------ /// /// Gets the maximum size of the entity. /// // ------------------------------------------------------------------ public virtual Size MaxSize { get { return myMaxSize; } } // ------------------------------------------------------------------ /// /// Gets the to paint this entity. /// // ------------------------------------------------------------------ public virtual Brush Brush { get { return mBrush; } } // ------------------------------------------------------------------ /// /// Gets the pen to draw this entity. /// /// The pen. // ------------------------------------------------------------------ public virtual Pen Pen { get { return mPen; } } // ------------------------------------------------------------------ /// /// Gets the friendly name of the entity to be displayed in the UI. /// /// // ------------------------------------------------------------------ public abstract string EntityName { get; } // ------------------------------------------------------------------ /// /// Gets or sets the general purpose tag /// // ------------------------------------------------------------------ public virtual object Tag { get { return mTag; } set { mTag = value; } } // ------------------------------------------------------------------ /// /// Gets or sets the index of this entity in the scene-graph. /// /// The index of the scene. // ------------------------------------------------------------------ public virtual int SceneIndex { get { return mSceneIndex; } set { mSceneIndex = value; } } // ------------------------------------------------------------------ /// /// Gets or sets the unique top-group to which this entity belongs. /// /// // ------------------------------------------------------------------ public virtual IGroup Group { get { return mGroup; } set { mGroup = value; // Propagate downwards if this is a group shape, but not if // the value is 'null' since the group becomes the value of // the Group property. Note that we could have used a formal // depth-traversal algorithm. if (this is IGroup) { if (value == null)//occurs on an ungroup action { foreach (IDiagramEntity entity in (this as IGroup).Entities) { entity.Group = this as IGroup; } } else //occurs when grouping { foreach (IDiagramEntity entity in (this as IGroup).Entities) { entity.Group = value; } } } } } // ------------------------------------------------------------------ /// /// Gets or sets whether the entity is hovered by the mouse /// // ------------------------------------------------------------------ public virtual bool Hovered { get { return mHovered; } set { mHovered = value; Invalidate(); } } // ------------------------------------------------------------------ /// /// Gets or sets the parent of the entity /// // ------------------------------------------------------------------ public virtual object Parent { get { if (mParent != null && mParent.IsAlive) { return mParent.Target; } else { return null; } } set { mParent = new WeakReference(value); RaiseOnChange(this, new EntityEventArgs(this)); } } // ------------------------------------------------------------------ /// /// Gets or sets the name of the entity /// // ------------------------------------------------------------------ public virtual string Name { get { return mName; } set { mName = value; RaiseOnChange(this, new EntityEventArgs(this)); } } #region Bounds and point calculations // ------------------------------------------------------------------ /// /// Gets the bounds of the paintable entity. /// /// // ------------------------------------------------------------------ public abstract Rectangle Rectangle { get; } // ------------------------------------------------------------------ /// /// Gets the top left corner of this entity, which is the same as /// 'Rectangle.Location'. /// // ------------------------------------------------------------------ public virtual Point TopLeftCorner { get { return this.Rectangle.Location; } } // ------------------------------------------------------------------ /// /// Gets the top right corner of this entity. /// // ------------------------------------------------------------------ public virtual Point TopRightCorner { get { return new Point( Rectangle.Right, Rectangle.Top); } } // ------------------------------------------------------------------ /// /// Gets the bottom left corner of this entity. /// // ------------------------------------------------------------------ public virtual Point BottomLeftCorner { get { return new Point( Rectangle.Left, Rectangle.Bottom); } } // ------------------------------------------------------------------ /// /// Gets the bottom right corner of this entity. /// // ------------------------------------------------------------------ public virtual Point BottomRightCorner { get { return new Point( Rectangle.Right, Rectangle.Bottom); } } // ------------------------------------------------------------------ /// /// Gets the center point of the paintable entity (the center of the /// Rectangle). /// /// Point // ------------------------------------------------------------------ public virtual Point Center { get { // Make sure the bounds are legal first. if ((this.mRectangle == null) || (this.mRectangle == Rectangle.Empty)) { return Point.Empty; } int x = (this.mRectangle.Left) + (this.mRectangle.Width / 2); int y = (this.mRectangle.Top) + (this.mRectangle.Height / 2); return new Point(x, y); } } // ------------------------------------------------------------------ /// /// Gets the center of the bottom edge of the bounding rectangle. /// // ------------------------------------------------------------------ public virtual Point BottomCenter { get { return new Point( BottomLeftCorner.X + (mRectangle.Width / 2), BottomLeftCorner.Y); } } // ------------------------------------------------------------------ /// /// Gets the center of the top edge of the bounding rectangle. /// // ------------------------------------------------------------------ public virtual Point TopCenter { get { return new Point( TopLeftCorner.X + (mRectangle.Width / 2), TopLeftCorner.Y); } } #endregion // ------------------------------------------------------------------ /// /// Gets or sets whether the entity is selected /// // ------------------------------------------------------------------ [Browsable(false)] public virtual bool IsSelected { get { return mIsSelected; } set { mIsSelected = value; if (value == true) { this.RaiseOnSelect(this, new EntityEventArgs(this)); } } } // ------------------------------------------------------------------ /// /// Gets or sets the current magnification used by the view. /// // ------------------------------------------------------------------ public virtual SizeF Magnification { get { return mMagnification; } set { mMagnification = value; } } // ------------------------------------------------------------------ /// /// Gets or sets the canvas to which the entity belongs. /// // ------------------------------------------------------------------ [Browsable(false)] public virtual IModel Model { get { return mModel; } set { mModel = value; } } // ------------------------------------------------------------------ /// /// Gets or sets the ILayer this entity is attached to in the IModel. /// // ------------------------------------------------------------------ public virtual ILayer Layer { get { return mLayer; } set { mLayer = value; } } #endregion #region Constructor // ------------------------------------------------------------------ /// /// Constructor with the model of the entity. /// /// IModel // ------------------------------------------------------------------ protected DiagramEntityBase(IModel model) { this.mModel = model; Initialize(); } // ------------------------------------------------------------------ /// /// The empty constructor is required to make deserialization work. /// // ------------------------------------------------------------------ protected DiagramEntityBase() { Initialize(); } #endregion #region Methods // ------------------------------------------------------------------ /// /// Called after an entity is deleted. /// /// DeleteCommand: The un/redoable command /// that's part of the undo/redo mechanism. // ------------------------------------------------------------------ public virtual void OnAfterDelete(DeleteCommand deleteCommand) { } // ------------------------------------------------------------------ /// /// Called before an entity is deleted. /// /// DeleteCommand: The un/redoable command /// that's part of the undo/redo mechanism. // ------------------------------------------------------------------ public virtual void OnBeforeDelete(DeleteCommand deleteCommand) { } // ------------------------------------------------------------------ /// /// Called when a new DiagramEntityBase is instantiated. /// // ------------------------------------------------------------------ protected virtual void Initialize() { PaintStyle = ArtPalette.GetDefaultPaintStyle(); PenStyle = ArtPalette.GetDefaultPenStyle(); mServices = new Dictionary(); mServices[typeof(IMouseListener)] = this; mServices[typeof(IHoverListener)] = this; } // ------------------------------------------------------------------ /// /// Generates a new Uid for this entity. /// /// if the Uid has to be changed recursively /// down to the sub-entities, set to true, otherwise false. // ------------------------------------------------------------------ public virtual void NewUid(bool recursive) { this.mUid = Guid.NewGuid(); RaiseOnChange(this, new EntityEventArgs(this)); } // ------------------------------------------------------------------ /// /// Defines a mechanism for retrieving a service object; that is, an /// object that provides custom support to other objects. /// /// An object that specifies the type of /// service object to get. /// /// A service object of type serviceType.-or- null if there is no /// service object of type serviceType. /// // ------------------------------------------------------------------ public virtual object GetService(Type serviceType) { if (Services.ContainsKey(serviceType)) { return Services[serviceType]; } else { return null; } } // ------------------------------------------------------------------ /// /// Paints the entity on the control /// /// the graphics object to paint on // ------------------------------------------------------------------ public abstract void Paint(Graphics g); // ------------------------------------------------------------------ /// /// Tests whether the entity is hit by the mouse /// /// a Point location /// // ------------------------------------------------------------------ public abstract bool Hit(Point p); // ------------------------------------------------------------------ /// /// Invalidates the entity /// // ------------------------------------------------------------------ public abstract void Invalidate(); // ------------------------------------------------------------------ /// /// Called when the entity is detached from the canvas (temporarily /// removed but not disposed, like in a cut operation). /// // ------------------------------------------------------------------ public virtual void Detached(ILayer layer) { mLayer = null; } // ------------------------------------------------------------------ /// /// Called when the entity is attached to a Layer. /// // ------------------------------------------------------------------ public virtual void Attached(ILayer layer) { mLayer = layer; } // ------------------------------------------------------------------ /// /// Invalidates a rectangle of the canvas /// /// // ------------------------------------------------------------------ public virtual void Invalidate(Rectangle rectangle) { if (Model != null) Model.RaiseOnInvalidateRectangle(rectangle); } // ------------------------------------------------------------------ /// /// Updates pens and brushes /// // ------------------------------------------------------------------ protected virtual void UpdatePaintingMaterial() { // First make sure we have a valid rectangle. if (mRectangle.Width == 0) { mRectangle.Width = 1; } if (mRectangle.Height == 0) { mRectangle.Height = 1; } if (mPenStyle != null) { mPen = mPenStyle.DrawingPen(); } if (mPaintStyle != null) { mBrush = mPaintStyle.GetBrush(this.Rectangle); } Invalidate(); } // ------------------------------------------------------------------ /// /// Moves the entity on the canvas /// /// the shifting vector, not an absolute /// position! // ------------------------------------------------------------------ public abstract void MoveBy(Point p); // ------------------------------------------------------------------ /// /// The custom elements to be added to the menu on a per-entity basis. /// /// ToolStripItem[] // ------------------------------------------------------------------ public abstract ToolStripItem[] Menu(); #region Raisers // ------------------------------------------------------------------ /// /// Raises the onclick event. /// /// // ------------------------------------------------------------------ public virtual void RaiseOnClick(EntityEventArgs e) { if (OnClick != null) OnClick(this, e); } // ------------------------------------------------------------------ /// /// Raises the OnMouseDown event. /// /// EntityMouseEventArgs // ------------------------------------------------------------------ public virtual void RaiseOnMouseDown(EntityMouseEventArgs e) { if (OnMouseDown != null) { OnMouseDown(this, e); } } // ------------------------------------------------------------------ /// /// Raises the OnMouseUp event. /// /// EntityMouseEventArgs // ------------------------------------------------------------------ public virtual void RaiseOnMouseUp(EntityMouseEventArgs e) { if (OnMouseUp != null) { OnMouseUp(this, e); } } // ------------------------------------------------------------------ /// /// Raises the OnMouseMove event. /// /// EntityMouseEventArgs // ------------------------------------------------------------------ public virtual void RaiseOnMouseMove(EntityMouseEventArgs e) { if (OnMouseMove != null) { OnMouseMove(this, e); } } // ------------------------------------------------------------------ /// /// Raises the OnMouseEnter event. /// /// EntityMouseEventArgs // ------------------------------------------------------------------ public virtual void RaiseOnMouseEnter(EntityMouseEventArgs e) { if (OnMouseEnter != null) { OnMouseEnter(this, e); } } // ------------------------------------------------------------------ /// /// Raises the OnMouseEnter event. /// /// EntityMouseEventArgs // ------------------------------------------------------------------ public virtual void RaiseOnMouseHover(EntityMouseEventArgs e) { if (OnMouseHover != null) { OnMouseHover(this, e); } } // ------------------------------------------------------------------ /// /// Raises the OnMouseLeave event. /// /// EntityMouseEventArgs // ------------------------------------------------------------------ public virtual void RaiseOnMouseLeave(EntityMouseEventArgs e) { if (OnMouseLeave != null) { OnMouseLeave(this, e); } } // ------------------------------------------------------------------ /// /// Raises the OnSelect event. /// /// The sender. /// The /// instance /// containing the event data. // ------------------------------------------------------------------ protected virtual void RaiseOnSelect( object sender, EntityEventArgs e) { if (OnEntitySelect != null) { OnEntitySelect(sender, e); } } // ------------------------------------------------------------------ /// /// Raises the OnChange event. /// /// The sender. /// The /// instance /// containing the event data. // ------------------------------------------------------------------ protected virtual void RaiseOnChange(object sender, EntityEventArgs e) { if (OnEntityChange != null) OnEntityChange(sender, e); } #endregion #endregion #region Standard IDispose implementation /// /// Disposes the entity. /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// /// Disposes the entity. /// /// if set to true [disposing]. protected virtual void Dispose(bool disposing) { if (disposing) { #region free managed resources if (mPen != null) { mPen.Dispose(); mPen = null; } if (mBrush != null) { mBrush.Dispose(); mBrush = null; } #endregion } } #endregion #region IMouseListener Members // ------------------------------------------------------------------ /// /// Implementation of the . This is /// the method called when a mouse button is pressed while over this /// entity. /// /// The /// instance /// containing the event data. /// bool: Whether or not the mouse down was handled by this /// entity. The default here is false. Sub-entities should override /// this to provide their own functionality if needed. // ------------------------------------------------------------------ public virtual bool MouseDown(MouseEventArgs e) { this.RaiseOnMouseDown(new EntityMouseEventArgs(this, e)); // By default we're not handling the mouse down event here, // we're just passing it on. Let the sub-entities handle it // by overriding this method. return false; } // ------------------------------------------------------------------ /// /// Implementation of the . This is /// the method called when the mouse is moved while over this /// entity. /// /// The /// instance /// containing the event data. // ------------------------------------------------------------------ public virtual void MouseMove(MouseEventArgs e) { this.RaiseOnMouseMove(new EntityMouseEventArgs(this, e)); } // ------------------------------------------------------------------ /// /// Implementation of the . This is /// the method called when a mouse button is released while over this /// entity. /// /// The /// instance /// containing the event data. // ------------------------------------------------------------------ public virtual void MouseUp(MouseEventArgs e) { this.RaiseOnMouseUp(new EntityMouseEventArgs(this, e)); } #endregion #region IHoverListener Members // ------------------------------------------------------------------ /// /// Implementation of the . This is /// the method called when the mouse hovers over this entity. /// /// The /// instance /// containing the event data. // ------------------------------------------------------------------ public virtual void MouseHover(MouseEventArgs e) { this.RaiseOnMouseHover(new EntityMouseEventArgs(this, e)); } // ------------------------------------------------------------------ /// /// Implementation of the . This is /// the method called when the mouse enters this entity. /// /// The /// instance /// containing the event data. // ------------------------------------------------------------------ public virtual void MouseEnter(MouseEventArgs e) { this.RaiseOnMouseEnter(new EntityMouseEventArgs(this, e)); } // ------------------------------------------------------------------ /// /// Implementation of the . This is /// the method called when the mouse leaves this entity. /// /// The /// instance /// containing the event data. // ------------------------------------------------------------------ public virtual void MouseLeave(MouseEventArgs e) { this.RaiseOnMouseLeave(new EntityMouseEventArgs(this, e)); } #endregion #region IKeyboardListener Members // ------------------------------------------------------------------ /// /// Implementation of the . This is /// the method called when a key is pressed down. /// /// The /// instance /// containing the event data. // ------------------------------------------------------------------ public virtual void KeyDown(KeyEventArgs e) { } // ------------------------------------------------------------------ /// /// Implementation of the . This is /// the method called when a key is released. /// /// The /// instance /// containing the event data. // ------------------------------------------------------------------ public virtual void KeyUp(KeyEventArgs e) { } // ------------------------------------------------------------------ /// /// Implementation of the . This is /// the method called when a key is pressed. /// /// The /// instance /// containing the event data. // ------------------------------------------------------------------ public virtual void KeyPress(KeyPressEventArgs e) { } #endregion } }