Changeset 4068 for trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.Netron/3.0.2672.12446/Netron.Diagramming.Core-3.0.2672.12446/Diagram elements/Group/CollapsibleGroupShape.cs
- Timestamp:
- 07/22/10 00:44:01 (14 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/Diagram elements/Group/CollapsibleGroupShape.cs
r3038 r4068 1 1 using System; 2 2 using System.Collections.Generic; 3 using System.Text;4 3 using System.Drawing; 5 4 using System.Windows.Forms; 6 namespace Netron.Diagramming.Core 7 { 8 // ---------------------------------------------------------------------- 9 /// <summary> 10 /// This is an extension of the <see cref="GroupShape"/> which paints 11 /// itself and allows to collapse/expand its content. Note that it does 12 /// not inherit from the <see cref="GroupShape"/> though because it requires 13 /// the <see cref="ShapeMaterialBase"/> mechanism and, hence, inherits 14 /// from the <see cref="ComplexShapeBase"/> class. 15 /// </summary> 16 // ---------------------------------------------------------------------- 17 public partial class CollapsibleGroupShape : ComplexShapeBase, IGroup 18 { 19 #region Fields 20 21 // ------------------------------------------------------------------ 22 /// <summary> 23 /// Implementation of IVersion - the current version of 24 /// CollapsibleGroupShape. 25 /// </summary> 26 // ------------------------------------------------------------------ 27 protected const double collapsibleGroupShapeVersion = 1.0; 28 29 // ------------------------------------------------------------------ 30 /// <summary> 31 /// the Entities field 32 /// </summary> 33 // ------------------------------------------------------------------ 34 private CollectionBase<IDiagramEntity> mEntities; 35 36 // ------------------------------------------------------------------ 37 /// <summary> 38 /// in essence, whether the group shape should be painted 39 /// </summary> 40 // ------------------------------------------------------------------ 41 private bool mEmphasizeGroup = true; 42 43 // ------------------------------------------------------------------ 44 /// <summary> 45 /// the collapse/expand icon 46 /// </summary> 47 // ------------------------------------------------------------------ 48 private SwitchIconMaterial xicon; 49 50 // ------------------------------------------------------------------ 51 /// <summary> 52 /// the rectangle before it's being collapsed 53 /// </summary> 54 // ------------------------------------------------------------------ 55 private Rectangle rectangleMemory; 56 57 // ------------------------------------------------------------------ 58 /// <summary> 59 /// the location memory of the externally connected connectors 60 /// </summary> 61 // ------------------------------------------------------------------ 62 private Dictionary<IConnector, Point> connectorMemory; 63 64 // ------------------------------------------------------------------ 65 /// <summary> 66 /// global offset when a collapsed group is moved around 67 /// </summary> 68 // ------------------------------------------------------------------ 69 private Point groupConnectorOffset = Point.Empty; 70 71 // ------------------------------------------------------------------ 72 /// <summary> 73 /// the Collapsed field 74 /// </summary> 75 // ------------------------------------------------------------------ 76 private bool mCollapsed; 77 78 // ------------------------------------------------------------------ 79 /// <summary> 80 /// the expand hyperlink 81 /// </summary> 82 // ------------------------------------------------------------------ 83 private ClickableLabelMaterial expandLabel; 84 85 // ------------------------------------------------------------------ 86 /// <summary> 87 /// Specifies if ungrouping is allowed. 88 /// </summary> 89 // ------------------------------------------------------------------ 90 bool mAllowUnGroup = false; 91 92 #endregion 93 94 #region Properties 95 96 // ------------------------------------------------------------------ 97 /// <summary> 98 /// Gets the current version. 99 /// </summary> 100 // ------------------------------------------------------------------ 101 public override double Version 102 { 103 get 104 { 105 return collapsibleGroupShapeVersion; 5 namespace Netron.Diagramming.Core { 6 // ---------------------------------------------------------------------- 7 /// <summary> 8 /// This is an extension of the <see cref="GroupShape"/> which paints 9 /// itself and allows to collapse/expand its content. Note that it does 10 /// not inherit from the <see cref="GroupShape"/> though because it requires 11 /// the <see cref="ShapeMaterialBase"/> mechanism and, hence, inherits 12 /// from the <see cref="ComplexShapeBase"/> class. 13 /// </summary> 14 // ---------------------------------------------------------------------- 15 public partial class CollapsibleGroupShape : ComplexShapeBase, IGroup { 16 #region Fields 17 18 // ------------------------------------------------------------------ 19 /// <summary> 20 /// Implementation of IVersion - the current version of 21 /// CollapsibleGroupShape. 22 /// </summary> 23 // ------------------------------------------------------------------ 24 protected const double collapsibleGroupShapeVersion = 1.0; 25 26 // ------------------------------------------------------------------ 27 /// <summary> 28 /// the Entities field 29 /// </summary> 30 // ------------------------------------------------------------------ 31 private CollectionBase<IDiagramEntity> mEntities; 32 33 // ------------------------------------------------------------------ 34 /// <summary> 35 /// in essence, whether the group shape should be painted 36 /// </summary> 37 // ------------------------------------------------------------------ 38 private bool mEmphasizeGroup = true; 39 40 // ------------------------------------------------------------------ 41 /// <summary> 42 /// the collapse/expand icon 43 /// </summary> 44 // ------------------------------------------------------------------ 45 private SwitchIconMaterial xicon; 46 47 // ------------------------------------------------------------------ 48 /// <summary> 49 /// the rectangle before it's being collapsed 50 /// </summary> 51 // ------------------------------------------------------------------ 52 private Rectangle rectangleMemory; 53 54 // ------------------------------------------------------------------ 55 /// <summary> 56 /// the location memory of the externally connected connectors 57 /// </summary> 58 // ------------------------------------------------------------------ 59 private Dictionary<IConnector, Point> connectorMemory; 60 61 // ------------------------------------------------------------------ 62 /// <summary> 63 /// global offset when a collapsed group is moved around 64 /// </summary> 65 // ------------------------------------------------------------------ 66 private Point groupConnectorOffset = Point.Empty; 67 68 // ------------------------------------------------------------------ 69 /// <summary> 70 /// the Collapsed field 71 /// </summary> 72 // ------------------------------------------------------------------ 73 private bool mCollapsed; 74 75 // ------------------------------------------------------------------ 76 /// <summary> 77 /// the expand hyperlink 78 /// </summary> 79 // ------------------------------------------------------------------ 80 private ClickableLabelMaterial expandLabel; 81 82 // ------------------------------------------------------------------ 83 /// <summary> 84 /// Specifies if ungrouping is allowed. 85 /// </summary> 86 // ------------------------------------------------------------------ 87 bool mAllowUnGroup = false; 88 89 #endregion 90 91 #region Properties 92 93 // ------------------------------------------------------------------ 94 /// <summary> 95 /// Gets the current version. 96 /// </summary> 97 // ------------------------------------------------------------------ 98 public override double Version { 99 get { 100 return collapsibleGroupShapeVersion; 101 } 102 } 103 104 // ------------------------------------------------------------------ 105 /// <summary> 106 /// Gets or sets if un-grouping of the entities is allowed. 107 /// </summary> 108 // ------------------------------------------------------------------ 109 public virtual bool CanUnGroup { 110 get { 111 return mAllowUnGroup; 112 } 113 set { 114 mAllowUnGroup = value; 115 } 116 } 117 118 /// <summary> 119 /// Gets or sets whether the group is in a collapsed state 120 /// </summary> 121 public bool Collapsed { 122 get { return mCollapsed; } 123 set { mCollapsed = value; } 124 } 125 126 127 /// <summary> 128 /// Gets or sets whether the group as a shape should be painted on the canvas. 129 /// </summary> 130 /// <value><c>true</c> to paint the group shape; otherwise, <c>false</c>.</value> 131 public bool EmphasizeGroup { 132 get { return mEmphasizeGroup; } 133 set { mEmphasizeGroup = value; } 134 } 135 /// <summary> 136 /// Gets the friendly name of the entity to be displayed in the UI 137 /// </summary> 138 /// <value></value> 139 public override string EntityName { 140 get { 141 return "Group shape"; 142 } 143 } 144 145 /// <summary> 146 /// Gets or sets the rectangle. 147 /// </summary> 148 /// <value>The rectangle.</value> 149 public override Rectangle Rectangle { 150 get { 151 return mRectangle; 152 } 153 } 154 /// <summary> 155 /// Gets or sets the entities directly underneath. To get the whole branch of entities in case of nested groups, <see cref="Leafs"/>. 156 /// </summary> 157 public CollectionBase<IDiagramEntity> Entities { 158 get { return mEntities; } 159 set { 160 161 throw new InconsistencyException("You cannot set the entities, use the already instantiated collection to add or remove items."); 162 163 164 } 165 } 166 /// <summary> 167 /// Gets the whole branch of entities if this group has sub-groups. Contrary to the <see cref="GroupShape"/> the result WILLl contain the group shapes. 168 /// </summary> 169 /// <value>The branch.</value> 170 public CollectionBase<IDiagramEntity> Leafs { 171 get { 172 CollectionBase<IDiagramEntity> flatList = new CollectionBase<IDiagramEntity>(); 173 foreach (IDiagramEntity entity in mEntities) { 174 if (entity is IGroup) { 175 Utils.TraverseCollect(entity as IGroup, ref flatList); 176 } 177 flatList.Add(entity); 178 } 179 return flatList; 180 } 181 } 182 183 #endregion 184 185 #region Constructor 186 ///<summary> 187 ///Default constructor 188 ///</summary> 189 public CollapsibleGroupShape(IModel model) 190 : base(model) { 191 this.mEntities = new CollectionBase<IDiagramEntity>(); 192 this.mEntities.OnItemAdded += new EventHandler<CollectionEventArgs<IDiagramEntity>>(mEntities_OnItemAdded); 193 this.mEntities.OnClear += new EventHandler(mEntities_OnClear); 194 this.mEntities.OnItemRemoved += new EventHandler<CollectionEventArgs<IDiagramEntity>>(mEntities_OnItemRemoved); 195 196 xicon = new SwitchIconMaterial(SwitchIconType.PlusMinus); 197 this.Children.Add(xicon); 198 //do this before attaching the next event handler, otherwise the shape will be added twice to the paintables 199 xicon.Collapsed = false; 200 201 xicon.OnCollapse += new EventHandler(xicon_OnCollapse); 202 xicon.OnExpand += new EventHandler(xicon_OnExpand); 203 204 connectorMemory = new Dictionary<IConnector, Point>(); 205 206 expandLabel = new ClickableLabelMaterial("Expand..."); 207 this.Children.Add(expandLabel); 208 expandLabel.Visible = false; 209 expandLabel.OnClick += new EventHandler(expandLabel_OnClick); 210 } 211 212 void expandLabel_OnClick(object sender, EventArgs e) { 213 xicon.Collapsed = false; 214 } 215 216 void xicon_OnExpand(object sender, EventArgs e) { 217 Expand(); 218 } 219 220 void xicon_OnCollapse(object sender, EventArgs e) { 221 Collapse(); 222 } 223 #endregion 224 225 #region Methods 226 227 /// <summary> 228 /// Collapses this instance. 229 /// </summary> 230 public void Collapse() { 231 rectangleMemory = mRectangle; 232 mRectangle = new Rectangle(mRectangle.Location, new Size(110, 25)); 233 234 foreach (IDiagramEntity entity in Entities) { 235 RemoveFromPaintables(entity); 236 } 237 this.Resizable = false; 238 239 240 connectorMemory.Clear();//forget the previous memory 241 groupConnectorOffset = Point.Empty; 242 //use the flattened collection (Leafs) in case there are sub-groups 243 MoveConnectors(Leafs, new Point((int)(Rectangle.Left + Rectangle.Width / 2), Rectangle.Bottom)); 244 245 Rectangle rec = rectangleMemory; 246 rec.Inflate(20, 20); 247 Invalidate(rec); 248 mCollapsed = true; 249 expandLabel.Visible = true; 250 } 251 internal void RemoveFromPaintables(IDiagramEntity entity) { 252 this.Model.Paintables.Remove(entity); 253 if (entity is CollapsibleGroupShape && !(entity as CollapsibleGroupShape).Collapsed) { 254 foreach (IDiagramEntity ent in (entity as CollapsibleGroupShape).Entities) { 255 RemoveFromPaintables(ent); 256 } 257 258 } 259 } 260 261 internal void AddToPaintables(IDiagramEntity entity) { 262 this.Model.Paintables.Add(entity); 263 if (entity is CollapsibleGroupShape && !(entity as CollapsibleGroupShape).Collapsed) { 264 foreach (IDiagramEntity ent in (entity as CollapsibleGroupShape).Entities) { 265 AddToPaintables(ent); 266 } 267 268 } 269 270 } 271 /// <summary> 272 /// Expands this instance. 273 /// </summary> 274 public void Expand() { 275 mRectangle = rectangleMemory; 276 foreach (IDiagramEntity entity in Entities) { 277 AddToPaintables(entity); 278 } 279 this.Resizable = true; 280 UnMoveConnectors(); 281 Invalidate(mRectangle); 282 mCollapsed = false; 283 connectorMemory.Clear(); 284 expandLabel.Visible = false; 285 } 286 287 288 289 /// <summary> 290 /// Moves the connectors of the children to the central group connector location. 291 /// </summary> 292 internal void MoveConnectors(CollectionBase<IDiagramEntity> entities, Point point) { 293 IConnection cnn; 294 foreach (IDiagramEntity entity in entities) { 295 if (entity is IGroup) { 296 continue; //since we use a flattened collection (the Leafs) we don't care about the groups here 297 //the inclusion of the subgroups in the Leafs is however important to make the subgroups 298 //(in)visible when collapsed/expanded. 299 } 300 if (entity is IShape) { 301 foreach (IConnector cn in (entity as IShape).Connectors) { 302 if (cn.AttachedConnectors.Count > 0) { 303 foreach (IConnector cn2 in cn.AttachedConnectors) { 304 if (cn2.Parent is IConnection) { 305 cnn = cn2.Parent as IConnection; 306 //the ends have to be connected 307 if (cnn.From.AttachedTo.Parent is IShape && cnn.To.AttachedTo.Parent is IShape) { 308 if (entities.Contains(cnn.From.AttachedTo.Parent as IShape) && entities.Contains(cnn.To.AttachedTo.Parent as IShape)) 309 continue;//both endconnectors are internal 310 else//one of the connectors is external 311 { 312 if (entities.Contains(cnn.From.AttachedTo.Parent as IShape)) //the From is internal 313 { 314 MoveConnector(cnn.From, point); 315 } else //the To is internal 316 { 317 MoveConnector(cnn.To, point); 318 } 319 } 320 } 321 } 322 } 106 323 } 324 } 107 325 } 108 109 // ------------------------------------------------------------------ 110 /// <summary> 111 /// Gets or sets if un-grouping of the entities is allowed. 112 /// </summary> 113 // ------------------------------------------------------------------ 114 public virtual bool CanUnGroup 115 { 116 get 117 { 118 return mAllowUnGroup; 119 } 120 set 121 { 122 mAllowUnGroup = value; 123 } 326 } 327 } 328 329 /// <summary> 330 /// Moves the connector to the given location. 331 /// </summary> 332 /// <param name="cn">The cn.</param> 333 /// <param name="point">The point.</param> 334 private void MoveConnector(IConnector cn, Point point) { 335 connectorMemory.Add(cn, cn.Point);//luckily the Point is a struct so the value will be actually copied and we can safely change the value next 336 cn.MoveBy(new Point(point.X - cn.Point.X, point.Y - cn.Point.Y)); 337 cn.Enabled = false; 338 } 339 340 /// <summary> 341 /// Moves the connectors back from the central group connector to their original location. 342 /// </summary> 343 private void UnMoveConnectors() { 344 //some things will go wrong here if the content of the Entities has changed 345 346 //recall the memory and move them; 347 348 Dictionary<IConnector, Point>.KeyCollection keys = connectorMemory.Keys; 349 Point p; 350 foreach (IConnector cn in keys) { 351 p = connectorMemory[cn]; 352 cn.MoveBy(new Point(p.X - cn.Point.X + groupConnectorOffset.X, p.Y - cn.Point.Y + groupConnectorOffset.Y)); 353 cn.Enabled = true; 354 } 355 } 356 357 /// <summary> 358 /// The custom menu to be added to the base menu of this entity 359 /// </summary> 360 /// <returns>ToolStripItem[]</returns> 361 public override ToolStripItem[] Menu() { 362 return null; 363 } 364 /// <summary> 365 /// Handles the OnItemRemoved of the Entities 366 /// </summary> 367 /// <param name="sender">The sender.</param> 368 /// <param name="e">The e.</param> 369 void mEntities_OnItemRemoved(object sender, CollectionEventArgs<IDiagramEntity> e) { 370 CalculateRectangle(); 371 } 372 373 /// <summary> 374 /// Handles the OnClear event of the Entities. 375 /// </summary> 376 /// <param name="sender">The source of the event.</param> 377 /// <param name="e">The <see cref="T:System.EventArgs"/> instance containing the event data.</param> 378 void mEntities_OnClear(object sender, EventArgs e) { 379 mRectangle = Rectangle.Empty; 380 } 381 382 /// <summary> 383 /// Handles the OnItemAdded event of the Entities 384 /// </summary> 385 /// <param name="sender">The sender.</param> 386 /// <param name="e">The e.</param> 387 void mEntities_OnItemAdded(object sender, CollectionEventArgs<IDiagramEntity> e) { 388 //if(mEntities.Count == 1) 389 // mRectangle = e.Item.Rectangle; 390 //else 391 //{ 392 // mRectangle = Rectangle.Union((Rectangle) mRectangle, e.Item.Rectangle); 393 //} 394 CalculateRectangle(); 395 } 396 397 /// <summary> 398 /// Calculates the bounding rectangle of this group. 399 /// </summary> 400 public void CalculateRectangle() { 401 if (mEntities == null || mEntities.Count == 0) 402 return; 403 Rectangle rec = mEntities[0].Rectangle; 404 foreach (IDiagramEntity entity in Entities) { 405 //cascade the calculation if necessary 406 if ((entity is CollapsibleGroupShape) && !(entity as CollapsibleGroupShape).Collapsed) (entity as IGroup).CalculateRectangle(); 407 408 rec = Rectangle.Union(rec, entity.Rectangle); 409 } 410 rec.Inflate(20, 20); 411 this.mRectangle = rec; 412 rec.Offset(5, 5); 413 xicon.Transform(new Rectangle(rec.Location, new Size(16, 16))); 414 415 expandLabel.Transform(new Rectangle(rec.Location.X + 20, rec.Location.Y, 50, 12)); 416 } 417 418 419 /// <summary> 420 /// Paints the entity on the control 421 /// <remarks>This method should not be called since the painting occurs via the <see cref="Model.Paintables"/>.</remarks> 422 /// </summary> 423 /// <param name="g"></param> 424 public override void Paint(System.Drawing.Graphics g) { 425 Rectangle rec = Rectangle; 426 Utils.DrawRoundRect(g, ArtPalette.ConnectionShadow, rec); 427 428 base.Paint(g); 429 } 430 431 /// <summary> 432 /// Tests whether the group is hit by the mouse 433 /// </summary> 434 /// <param name="p"></param> 435 /// <returns></returns> 436 public override bool Hit(System.Drawing.Point p) { 437 if (mCollapsed) 438 return mRectangle.Contains(p); 439 440 foreach (IDiagramEntity entity in mEntities) { 441 if (entity.Hit(p)) 442 return true; 443 } 444 return false; 445 } 446 447 /// <summary> 448 /// Invalidates the entity 449 /// </summary> 450 public override void Invalidate() { 451 452 if (mRectangle == null) 453 return; 454 455 Rectangle rec = mRectangle; 456 rec.Inflate(20, 20); 457 Model.RaiseOnInvalidateRectangle(rec); 458 } 459 460 /// <summary> 461 /// Moves the entity on the canvas 462 /// </summary> 463 /// <param name="p"></param> 464 public override void MoveBy(System.Drawing.Point p) { 465 base.MoveBy(p); 466 467 Rectangle recBefore = mRectangle; 468 recBefore.Inflate(20, 20); 469 470 //no need to invalidate since it'll be done by the individual move actions 471 foreach (IDiagramEntity entity in mEntities) { 472 entity.MoveBy(p); 473 } 474 475 mRectangle.X += p.X; 476 mRectangle.Y += p.Y; 477 //shift the latent copy of the real rectangle if the group is in a collapsed state 478 if (mCollapsed) { 479 rectangleMemory.X += p.X; 480 rectangleMemory.Y += p.Y; 481 //the global offset has to be memorized; when we'll expand the group this offset has to be added to the original values 482 groupConnectorOffset.Offset(p); 483 } 484 485 486 //refresh things 487 this.Invalidate(recBefore);//position before the move 488 this.Invalidate();//current position 489 490 } 491 492 public override bool MouseDown(MouseEventArgs e) { 493 // Was a material hit in the base ComplexShape? 494 if (base.MouseDown(e)) { 495 return true; 496 } 497 498 // If not, should we pass it on to the entities in this 499 // group? 500 foreach (IDiagramEntity entity in this.mEntities) { 501 if (entity.Hit(e.Location)) { 502 if (entity.MouseDown(e)) { 503 return true; 504 } 124 505 } 125 126 /// <summary> 127 /// Gets or sets whether the group is in a collapsed state 128 /// </summary> 129 public bool Collapsed 130 { 131 get { return mCollapsed; } 132 set { mCollapsed = value; } 133 } 134 135 136 /// <summary> 137 /// Gets or sets whether the group as a shape should be painted on the canvas. 138 /// </summary> 139 /// <value><c>true</c> to paint the group shape; otherwise, <c>false</c>.</value> 140 public bool EmphasizeGroup 141 { 142 get { return mEmphasizeGroup; } 143 set { mEmphasizeGroup = value; } 144 } 145 /// <summary> 146 /// Gets the friendly name of the entity to be displayed in the UI 147 /// </summary> 148 /// <value></value> 149 public override string EntityName 150 { 151 get 152 { 153 return "Group shape"; 154 } 155 } 156 157 /// <summary> 158 /// Gets or sets the rectangle. 159 /// </summary> 160 /// <value>The rectangle.</value> 161 public override Rectangle Rectangle 162 { 163 get 164 { 165 return mRectangle; 166 } 167 } 168 /// <summary> 169 /// Gets or sets the entities directly underneath. To get the whole branch of entities in case of nested groups, <see cref="Leafs"/>. 170 /// </summary> 171 public CollectionBase<IDiagramEntity> Entities 172 { 173 get { return mEntities; } 174 set 175 { 176 177 throw new InconsistencyException("You cannot set the entities, use the already instantiated collection to add or remove items."); 178 179 180 } 181 } 182 /// <summary> 183 /// Gets the whole branch of entities if this group has sub-groups. Contrary to the <see cref="GroupShape"/> the result WILLl contain the group shapes. 184 /// </summary> 185 /// <value>The branch.</value> 186 public CollectionBase<IDiagramEntity> Leafs 187 { 188 get 189 { 190 CollectionBase<IDiagramEntity> flatList = new CollectionBase<IDiagramEntity>(); 191 foreach (IDiagramEntity entity in mEntities) 192 { 193 if (entity is IGroup) 194 { 195 Utils.TraverseCollect(entity as IGroup, ref flatList); 196 } 197 flatList.Add(entity); 198 } 199 return flatList; 200 } 201 } 202 203 #endregion 204 205 #region Constructor 206 ///<summary> 207 ///Default constructor 208 ///</summary> 209 public CollapsibleGroupShape(IModel model) 210 : base(model) 211 { 212 this.mEntities = new CollectionBase<IDiagramEntity>(); 213 this.mEntities.OnItemAdded += new EventHandler<CollectionEventArgs<IDiagramEntity>>(mEntities_OnItemAdded); 214 this.mEntities.OnClear += new EventHandler(mEntities_OnClear); 215 this.mEntities.OnItemRemoved += new EventHandler<CollectionEventArgs<IDiagramEntity>>(mEntities_OnItemRemoved); 216 217 xicon = new SwitchIconMaterial(SwitchIconType.PlusMinus); 218 this.Children.Add(xicon); 219 //do this before attaching the next event handler, otherwise the shape will be added twice to the paintables 220 xicon.Collapsed = false; 221 222 xicon.OnCollapse += new EventHandler(xicon_OnCollapse); 223 xicon.OnExpand += new EventHandler(xicon_OnExpand); 224 225 connectorMemory = new Dictionary<IConnector, Point>(); 226 227 expandLabel = new ClickableLabelMaterial("Expand..."); 228 this.Children.Add(expandLabel); 229 expandLabel.Visible = false; 230 expandLabel.OnClick += new EventHandler(expandLabel_OnClick); 231 } 232 233 void expandLabel_OnClick(object sender, EventArgs e) 234 { 235 xicon.Collapsed = false; 236 } 237 238 void xicon_OnExpand(object sender, EventArgs e) 239 { 240 Expand(); 241 } 242 243 void xicon_OnCollapse(object sender, EventArgs e) 244 { 245 Collapse(); 246 } 247 #endregion 248 249 #region Methods 250 251 /// <summary> 252 /// Collapses this instance. 253 /// </summary> 254 public void Collapse() 255 { 256 rectangleMemory = mRectangle; 257 mRectangle = new Rectangle(mRectangle.Location, new Size(110, 25)); 258 259 foreach (IDiagramEntity entity in Entities) 260 { 261 RemoveFromPaintables(entity); 262 } 263 this.Resizable = false; 264 265 266 connectorMemory.Clear();//forget the previous memory 267 groupConnectorOffset = Point.Empty; 268 //use the flattened collection (Leafs) in case there are sub-groups 269 MoveConnectors(Leafs, new Point((int)(Rectangle.Left + Rectangle.Width / 2), Rectangle.Bottom)); 270 271 Rectangle rec = rectangleMemory; 272 rec.Inflate(20, 20); 273 Invalidate(rec); 274 mCollapsed = true; 275 expandLabel.Visible = true; 276 } 277 internal void RemoveFromPaintables(IDiagramEntity entity) 278 { 279 this.Model.Paintables.Remove(entity); 280 if (entity is CollapsibleGroupShape && !(entity as CollapsibleGroupShape).Collapsed) 281 { 282 foreach (IDiagramEntity ent in (entity as CollapsibleGroupShape).Entities) 283 { 284 RemoveFromPaintables(ent); 285 } 286 287 } 288 } 289 290 internal void AddToPaintables(IDiagramEntity entity) 291 { 292 this.Model.Paintables.Add(entity); 293 if (entity is CollapsibleGroupShape && !(entity as CollapsibleGroupShape).Collapsed) 294 { 295 foreach (IDiagramEntity ent in (entity as CollapsibleGroupShape).Entities) 296 { 297 AddToPaintables(ent); 298 } 299 300 } 301 302 } 303 /// <summary> 304 /// Expands this instance. 305 /// </summary> 306 public void Expand() 307 { 308 mRectangle = rectangleMemory; 309 foreach (IDiagramEntity entity in Entities) 310 { 311 AddToPaintables(entity); 312 } 313 this.Resizable = true; 314 UnMoveConnectors(); 315 Invalidate(mRectangle); 316 mCollapsed = false; 317 connectorMemory.Clear(); 318 expandLabel.Visible = false; 319 } 320 321 322 323 /// <summary> 324 /// Moves the connectors of the children to the central group connector location. 325 /// </summary> 326 internal void MoveConnectors(CollectionBase<IDiagramEntity> entities, Point point) 327 { 328 IConnection cnn; 329 foreach (IDiagramEntity entity in entities) 330 { 331 if (entity is IGroup) 332 { 333 continue; //since we use a flattened collection (the Leafs) we don't care about the groups here 334 //the inclusion of the subgroups in the Leafs is however important to make the subgroups 335 //(in)visible when collapsed/expanded. 336 } 337 if (entity is IShape ) 338 { 339 foreach (IConnector cn in (entity as IShape).Connectors) 340 { 341 if (cn.AttachedConnectors.Count > 0) 342 { 343 foreach (IConnector cn2 in cn.AttachedConnectors) 344 { 345 if (cn2.Parent is IConnection) 346 { 347 cnn = cn2.Parent as IConnection; 348 //the ends have to be connected 349 if (cnn.From.AttachedTo.Parent is IShape && cnn.To.AttachedTo.Parent is IShape) 350 { 351 if (entities.Contains(cnn.From.AttachedTo.Parent as IShape) && entities.Contains(cnn.To.AttachedTo.Parent as IShape)) 352 continue;//both endconnectors are internal 353 else//one of the connectors is external 354 { 355 if (entities.Contains(cnn.From.AttachedTo.Parent as IShape)) //the From is internal 356 { 357 MoveConnector(cnn.From, point); 358 } 359 else //the To is internal 360 { 361 MoveConnector(cnn.To, point); 362 } 363 } 364 } 365 } 366 } 367 } 368 } 369 } 370 } 371 } 372 373 /// <summary> 374 /// Moves the connector to the given location. 375 /// </summary> 376 /// <param name="cn">The cn.</param> 377 /// <param name="point">The point.</param> 378 private void MoveConnector(IConnector cn, Point point) 379 { 380 connectorMemory.Add(cn, cn.Point);//luckily the Point is a struct so the value will be actually copied and we can safely change the value next 381 cn.MoveBy(new Point(point.X - cn.Point.X, point.Y - cn.Point.Y)); 382 cn.Enabled = false; 383 } 384 385 /// <summary> 386 /// Moves the connectors back from the central group connector to their original location. 387 /// </summary> 388 private void UnMoveConnectors() 389 { 390 //some things will go wrong here if the content of the Entities has changed 391 392 //recall the memory and move them; 393 394 Dictionary<IConnector, Point>.KeyCollection keys = connectorMemory.Keys; 395 Point p; 396 foreach (IConnector cn in keys) 397 { 398 p = connectorMemory[cn]; 399 cn.MoveBy(new Point(p.X - cn.Point.X + groupConnectorOffset.X, p.Y - cn.Point.Y + groupConnectorOffset.Y)); 400 cn.Enabled = true; 401 } 402 } 403 404 /// <summary> 405 /// The custom menu to be added to the base menu of this entity 406 /// </summary> 407 /// <returns>ToolStripItem[]</returns> 408 public override ToolStripItem[] Menu() 409 { 410 return null; 411 } 412 /// <summary> 413 /// Handles the OnItemRemoved of the Entities 414 /// </summary> 415 /// <param name="sender">The sender.</param> 416 /// <param name="e">The e.</param> 417 void mEntities_OnItemRemoved(object sender, CollectionEventArgs<IDiagramEntity> e) 418 { 419 CalculateRectangle(); 420 } 421 422 /// <summary> 423 /// Handles the OnClear event of the Entities. 424 /// </summary> 425 /// <param name="sender">The source of the event.</param> 426 /// <param name="e">The <see cref="T:System.EventArgs"/> instance containing the event data.</param> 427 void mEntities_OnClear(object sender, EventArgs e) 428 { 429 mRectangle = Rectangle.Empty; 430 } 431 432 /// <summary> 433 /// Handles the OnItemAdded event of the Entities 434 /// </summary> 435 /// <param name="sender">The sender.</param> 436 /// <param name="e">The e.</param> 437 void mEntities_OnItemAdded(object sender, CollectionEventArgs<IDiagramEntity> e) 438 { 439 //if(mEntities.Count == 1) 440 // mRectangle = e.Item.Rectangle; 441 //else 442 //{ 443 // mRectangle = Rectangle.Union((Rectangle) mRectangle, e.Item.Rectangle); 444 //} 445 CalculateRectangle(); 446 } 447 448 /// <summary> 449 /// Calculates the bounding rectangle of this group. 450 /// </summary> 451 public void CalculateRectangle() 452 { 453 if (mEntities == null || mEntities.Count == 0) 454 return; 455 Rectangle rec = mEntities[0].Rectangle; 456 foreach (IDiagramEntity entity in Entities) 457 { 458 //cascade the calculation if necessary 459 if ((entity is CollapsibleGroupShape) && !(entity as CollapsibleGroupShape).Collapsed) (entity as IGroup).CalculateRectangle(); 460 461 rec = Rectangle.Union(rec, entity.Rectangle); 462 } 463 rec.Inflate(20, 20); 464 this.mRectangle = rec; 465 rec.Offset(5, 5); 466 xicon.Transform(new Rectangle(rec.Location, new Size(16, 16))); 467 468 expandLabel.Transform(new Rectangle(rec.Location.X + 20, rec.Location.Y,50, 12)); 469 } 470 471 472 /// <summary> 473 /// Paints the entity on the control 474 /// <remarks>This method should not be called since the painting occurs via the <see cref="Model.Paintables"/>.</remarks> 475 /// </summary> 476 /// <param name="g"></param> 477 public override void Paint(System.Drawing.Graphics g) 478 { 479 Rectangle rec = Rectangle; 480 Utils.DrawRoundRect(g, ArtPalette.ConnectionShadow, rec); 481 482 base.Paint(g); 483 } 484 485 /// <summary> 486 /// Tests whether the group is hit by the mouse 487 /// </summary> 488 /// <param name="p"></param> 489 /// <returns></returns> 490 public override bool Hit(System.Drawing.Point p) 491 { 492 if (mCollapsed) 493 return mRectangle.Contains(p); 494 495 foreach (IDiagramEntity entity in mEntities) 496 { 497 if (entity.Hit(p)) 498 return true; 499 } 500 return false; 501 } 502 503 /// <summary> 504 /// Invalidates the entity 505 /// </summary> 506 public override void Invalidate() 507 { 508 509 if (mRectangle == null) 510 return; 511 512 Rectangle rec = mRectangle; 513 rec.Inflate(20, 20); 514 Model.RaiseOnInvalidateRectangle(rec); 515 } 516 517 /// <summary> 518 /// Moves the entity on the canvas 519 /// </summary> 520 /// <param name="p"></param> 521 public override void MoveBy(System.Drawing.Point p) 522 { 523 base.MoveBy(p); 524 525 Rectangle recBefore = mRectangle; 526 recBefore.Inflate(20, 20); 527 528 //no need to invalidate since it'll be done by the individual move actions 529 foreach (IDiagramEntity entity in mEntities) 530 { 531 entity.MoveBy(p); 532 } 533 534 mRectangle.X += p.X; 535 mRectangle.Y += p.Y; 536 //shift the latent copy of the real rectangle if the group is in a collapsed state 537 if (mCollapsed) 538 { 539 rectangleMemory.X += p.X; 540 rectangleMemory.Y += p.Y; 541 //the global offset has to be memorized; when we'll expand the group this offset has to be added to the original values 542 groupConnectorOffset.Offset(p); 543 } 544 545 546 //refresh things 547 this.Invalidate(recBefore);//position before the move 548 this.Invalidate();//current position 549 550 } 551 552 public override bool MouseDown(MouseEventArgs e) 553 { 554 // Was a material hit in the base ComplexShape? 555 if (base.MouseDown(e)) 556 { 557 return true; 558 } 559 560 // If not, should we pass it on to the entities in this 561 // group? 562 foreach (IDiagramEntity entity in this.mEntities) 563 { 564 if (entity.Hit(e.Location)) 565 { 566 if (entity.MouseDown(e)) 567 { 568 return true; 569 } 570 } 571 } 572 573 return false; 574 } 575 576 577 #endregion 578 } 506 } 507 508 return false; 509 } 510 511 512 #endregion 513 } 579 514 580 515
Note: See TracChangeset
for help on using the changeset viewer.