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