Free cookie consent management tool by TermsFeed Policy Generator

source: stable/HeuristicLab.ExtLibs/HeuristicLab.Netron/3.0.2672.12446/Netron.Diagramming.Core-3.0.2672.12446/Tools/MoveTool.cs @ 17958

Last change on this file since 17958 was 4068, checked in by swagner, 14 years ago

Sorted usings and removed unused usings in entire solution (#1094)

File size: 11.4 KB
Line 
1using System;
2using System.Drawing;
3using System.Windows.Forms;
4
5namespace Netron.Diagramming.Core {
6  /// <summary>
7  /// This tool implement the action of moving shapes on the canvas.
8  /// <para>Note that this tool is slightly different than other tools since it activates itself unless it has been suspended by another tool. </para>
9  /// </summary>
10  public class MoveTool : AbstractTool, IMouseListener {
11
12    #region Fields
13    /// <summary>
14    /// the location of the mouse when the motion starts
15    /// </summary>
16    private Point initialPoint;
17    /// <summary>
18    /// the intermediate location of the mouse during the motion
19    /// </summary>
20    private Point lastPoint;
21
22    private IConnector hoveredConnector;
23    /// <summary>
24    /// the AsConnectorMover field
25    /// </summary>
26    private bool connectorMove;
27    /// <summary>
28    /// Gets or sets the AsConnectorMover
29    /// </summary>
30    public bool AsConnectorMover {
31      get {
32        return connectorMove;
33      }
34      set {
35        connectorMove = value;
36      }
37    }
38
39    public static bool Blocked = false;
40    #endregion
41
42    #region Constructor
43    /// <summary>
44    /// Initializes a new instance of the <see cref="T:MoveTool"/> class.
45    /// </summary>
46    /// <param name="name">The name of the tool.</param>
47    public MoveTool(string name)
48      : base(name) {
49    }
50    #endregion
51
52    #region Methods
53
54    /// <summary>
55    /// Called when the tool is activated.
56    /// </summary>
57    protected override void OnActivateTool() {
58      Controller.View.CurrentCursor = CursorPalette.Move;
59
60    }
61
62    /// <summary>
63    /// Handles the mouse down event
64    /// </summary>
65    /// <param name="e">The <see cref="T:System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param>
66    public bool MouseDown(MouseEventArgs e) {
67      if (e == null)
68        throw new ArgumentNullException("The argument object is 'null'");
69      if (e.Button == MouseButtons.Left && Enabled && !IsSuspended && !Blocked) {
70        if (this.Controller.Model.Selection.SelectedItems.Count > 0) {
71          initialPoint = e.Location;
72          lastPoint = initialPoint;
73          connectorMove = false;
74          //while moving the shapes we'll clear the tracker
75          this.Controller.View.ResetTracker();
76          //now, go for it
77          this.ActivateTool();
78
79          // Even if an entity is hit, I don't think the mouse down
80          // event should be handled here.  That is, return false so
81          // other mouse listeners can respond.  This tool really
82          // does its thing when the mouse is moved.
83          //return true;
84        } else if (this.Controller.Model.Selection.Connector != null && this.Controller.Model.Selection.Connector.Parent is IConnection) {
85          if (!typeof(IShape).IsInstanceOfType(this.Controller.Model.Selection.Connector.Parent)) //note that there is a separate tool to move shape-connectors!
86                    {
87            if (this.Controller.Model.Selection.Connector.AllowMove) {
88              initialPoint = e.Location;
89              lastPoint = initialPoint;
90              connectorMove = true; //keep this for the final packaging into the undo manager
91              this.ActivateTool();
92              //return true;
93            }
94          }
95        }
96
97      }
98      return false;
99    }
100
101    /// <summary>
102    /// Handles the mouse move event
103    /// </summary>
104    /// <param name="e">The <see cref="T:System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param>
105    public void MouseMove(MouseEventArgs e) {
106      if (e == null)
107        throw new ArgumentNullException("The argument object is 'null'");
108      Point point = e.Location;
109      if (IsActive) {
110        //can be a connector
111        if (this.Controller.Model.Selection.Connector != null) {
112          this.Controller.Model.Selection.Connector.MoveBy(new Point(point.X - lastPoint.X, point.Y - lastPoint.Y));
113          #region Do we hit something meaningful?
114
115          if (hoveredConnector != null)
116            hoveredConnector.Hovered = false;
117
118          hoveredConnector = this.Controller.Model.Selection.FindConnectorAt(e.Location);
119          if (hoveredConnector != null)
120            hoveredConnector.Hovered = true;
121          if (hoveredConnector != null && hoveredConnector != this.Controller.Model.Selection.Connector) {
122            Controller.View.CurrentCursor = CursorPalette.Grip;
123
124          } else
125            Controller.View.CurrentCursor = CursorPalette.Move;
126          #endregion
127        } else //can be a selection
128                {
129          foreach (IDiagramEntity entity in this.Controller.Model.Selection.SelectedItems) {
130            if (entity.AllowMove) {
131              entity.MoveBy(new Point(point.X - lastPoint.X, point.Y - lastPoint.Y));
132            }
133          }
134        }
135        lastPoint = point;
136      }
137    }
138    /// <summary>
139    /// When an entity is moved there are various possibilities:
140    /// <list type="bullet">
141    /// <item>
142    /// <term>a connector is moved</term>
143    /// <description>in this case the moved connector can only be part of a onnection because moving shape-connectors is not allowed unless by means of the <see cref="ConnectorMoverTool"/>.
144    /// If a connector attached to a connection is moved we have the following fork:
145    /// <list type="bullet">
146    /// <item>the connector was attached</item>
147    /// <description>the connector has a parent and needs to be detached before being moved and eventually attached to another connector</description>
148    /// <item>the connector is moved</item>
149    /// <description>this is a standard motion and is similar for any <see cref="IDiagramEntity"/>
150    /// </description>
151    /// <item>the connector ends up somewhere near another connector and will become attached to it</item>
152    /// <description>the connector in the proximity of the moved connector will become the parent of it. Note that we previously detached any binding and that a connector can have only one parent.</description>
153    /// </list>
154    /// </description>
155    /// </item>
156    /// <item>an entity is moved</item>
157    /// <description>the normal <see cref="MoveCommand"/> can be used</description>
158    /// <item>a set of entities is moved</item>
159    /// <description>we need to create a bundle to package the entities and then use the <see cref="MoveCommand"/></description>
160    /// </list>
161    /// Several important remarks are in order here:
162    /// <list type="bullet">
163    /// <item>a connector can have only one parent</item>
164    /// <item>we need to package a move action in a command but this command needs NOT to be performed (i.e. call the Redo() method) because the motion already occured through the MouseMove handler. Because of this situation we cannot perform a Redo() on the full package since it would move the entities twice. Hence, commands are execute just after their creation (except for the move).
165    /// <item>when the stack of actions are undone the stack has to be reverted</item>
166    /// </item>
167    /// <item>whatever the situation is, the most economical way to code the different cases is by means of a <see cref="CompoundCommand"/> object</item>
168    /// </list>
169    /// </summary>
170    /// <param name="e">The <see cref="T:System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param>
171    public void MouseUp(MouseEventArgs e) {
172      if (IsActive) {
173        DeactivateTool();
174        //creation of the total undoredo package
175        CompoundCommand package = new CompoundCommand(this.Controller);
176        string message = string.Empty;
177        //notice that the connector can only be a connection connector because of the MouseDown check above
178        if (connectorMove) {
179          #region We are moving a connection-connector
180
181          #region Is the connector attached?
182          //detach only if there is a parent different than a connection; the join of a chained connection is allowed to move
183          if (this.Controller.Model.Selection.Connector.AttachedTo != null && !typeof(IConnection).IsInstanceOfType(this.Controller.Model.Selection.Connector.AttachedTo)) {
184            DetachConnectorCommand detach = new DetachConnectorCommand(this.Controller, this.Controller.Model.Selection.Connector.AttachedTo, this.Controller.Model.Selection.Connector);
185            detach.Redo();
186            package.Commands.Add(detach);
187
188          }
189          #endregion
190
191          #region The moving part
192          //a bundle might look like overkill here but it makes the coding model uniform
193          Bundle bundle = new Bundle(Controller.Model);
194          bundle.Entities.Add(this.Controller.Model.Selection.Connector);
195          MoveCommand move = new MoveCommand(this.Controller, bundle, new Point(lastPoint.X - initialPoint.X, lastPoint.Y - initialPoint.Y));
196          //no Redo() necessary here!
197          package.Commands.Add(move);
198          #endregion
199
200          #region The re-attachment near another connector
201          //let's see if the connection endpoints hit other connectors (different than the selected one!)   
202          //define a predicate delegate to filter things out otherwise the hit will return the moved connector which would results
203          //in a stack overflow later on
204          Predicate<IConnector> predicate =
205              delegate(IConnector conn) {
206                //whatever, except itself and any children of the moved connector
207                //since this would entail a child becoming a parent!
208                if (conn.Hit(e.Location) && conn != this.Controller.Model.Selection.Connector && !this.Controller.Model.Selection.Connector.AttachedConnectors.Contains(conn))
209                  return true;
210                return false;
211              };
212          //find it!
213          IConnector parentConnector = this.Controller.Model.Selection.FindConnector(predicate);
214
215          if (parentConnector != null) //aha, there's an attachment
216                    {
217            BindConnectorsCommand binder = new BindConnectorsCommand(this.Controller, parentConnector, this.Controller.Model.Selection.Connector);
218            package.Commands.Add(binder);
219            binder.Redo(); //this one is necessary since the redo cannot be performed on the whole compound command
220          }
221          #endregion
222
223          message = "Connector move";
224          #endregion
225        } else {
226          #region We are moving entities other than a connector
227          Bundle bundle = new Bundle(Controller.Model);
228          bundle.Entities.AddRange(this.Controller.Model.Selection.SelectedItems);
229          MoveCommand cmd = new MoveCommand(this.Controller, bundle, new Point(lastPoint.X - initialPoint.X, lastPoint.Y - initialPoint.Y));
230          package.Commands.Add(cmd);
231          //not necessary to perform the Redo action of the command since the mouse-move already moved the bundle!
232          #endregion
233
234          message = "Entities move";
235        }
236        //reset the hovered connector, if any
237        if (hoveredConnector != null)
238          hoveredConnector.Hovered = false;
239        package.Text = message;
240        //whatever the content of the package we add it to the undo history               
241        this.Controller.UndoManager.AddUndoCommand(package);
242
243        //show the tracker again
244        this.Controller.View.ShowTracker();
245
246      }
247    }
248    #endregion
249  }
250
251}
Note: See TracBrowser for help on using the repository browser.