/// <summary> /// Refreshes the control according to the model /// </summary> public void RefreshControl() { try { SuspendLayout(); // Clear all _boxes.Clear(); _arrows.Clear(); // Consider all boxes in this panel foreach (TBoxModel model in GetBoxes()) { // Ensure that the box is always visible if (model.X < 0) { model.X = 0; } if (model.Y < 0) { model.Y = 0; } BoxControl <TEnclosing, TBoxModel, TArrowModel> boxControl = CreateBox(model); _boxes[model] = boxControl; } // Consider all arrows in this panel List <TArrowModel> theArrows = GetArrows(); foreach (TArrowModel model in theArrows) { bool showArrow = true; if (model.Source != null) { // ReSharper disable once ConditionIsAlwaysTrueOrFalse showArrow = showArrow && !model.Source.Hidden; } if (model.Target != null) { showArrow = showArrow && !model.Target.Hidden; } if (showArrow) { ArrowControl <TEnclosing, TBoxModel, TArrowModel> arrowControl = CreateArrow(model); _arrows[model] = arrowControl; } } UpdatePositions(); } finally { ResumeLayout(true); } }
/// <summary> /// Handles a mouse up event /// </summary> /// <param name="sender"></param> /// <param name="mouseEventArgs"></param> private void HandleMouseUp(object sender, MouseEventArgs mouseEventArgs) { GraphicElement element = ElementForLocation(mouseEventArgs.Location, _movingBox); if (element != null) { element.HandleMouseUp(sender, mouseEventArgs); } if (_changingArrow != null) { _changingArrow = null; _chaningArrowAction = ChangeAction.None; RefreshControl(); } if (_movingBox != null) { if (_movingBoxHasMoved) { if (element != null) { BaseTreeNode targetNode = CorrespondingNode(element.Model as IModelElement); BaseTreeNode sourceNode = CorrespondingNode(_movingBox.Model as IModelElement); if (targetNode != null && sourceNode != null && sourceNode != targetNode) { targetNode.AcceptDrop(sourceNode); _movingBox.Location = new Point(0, 0); if (Settings.Default.AllowRefactor) { RefactorAndRelocateOperation refactorAndRelocate = new RefactorAndRelocateOperation(sourceNode.Model as ModelElement); refactorAndRelocate.ExecuteUsingProgressDialog(GuiUtils.MdiWindow, "Refactoring", false); } } } // Register the fact that the element has moved // because if (_movingBox.TypedModel.X != _positionBeforeMove.X || _movingBox.TypedModel.Y != _positionBeforeMove.Y) { EfsSystem.Instance.Context.HandleChangeEvent(_movingBox.Model as BaseModelElement, Context.ChangeKind.ModelChange); } } _movingBox = null; _movingBoxHasMoved = false; } }
/// <summary> /// Provides the arrow control which corresponds to the model provided /// </summary> /// <param name="model"></param> /// <returns></returns> public ArrowControl <TEnclosing, TBoxModel, TArrowModel> GetArrowControl(TArrowModel model) { ArrowControl <TEnclosing, TBoxModel, TArrowModel> retVal = null; if (model != null) { if (_arrows.ContainsKey(model)) { retVal = _arrows[model]; } } return(retVal); }
/// <summary> /// Tries to slide the arrow up following the arrow to avoid any collision /// with the already allocated bounding boxes /// </summary> /// <param name="allocatedBoxes">The boxes that already have been allocated</param> /// <param name="arrow">The arrow to consider</param> /// <param name="direction">Indicates whether the sliding should be done upward or downard the arrow orientation</param> /// <returns></returns> private Point Slide(BoxAllocation allocatedBoxes, ArrowControl <TEnclosing, TBoxModel, TArrowModel> arrow, SlideDirection direction) { Point retVal = arrow.GetCenter(); Rectangle colliding = allocatedBoxes.Intersects(arrow.GetTextBoundingBox(retVal)); while (colliding != Rectangle.Empty) { retVal = arrow.Slide(retVal, colliding, direction); colliding = allocatedBoxes.Intersects(arrow.GetTextBoundingBox(retVal)); } return(retVal); }
/// <summary> /// Provides the arrow control which corresponds to the rule /// </summary> /// <param name="referencedModel"></param> /// <returns></returns> public ArrowControl <TEnclosing, TBoxModel, TArrowModel> GetArrowControl(ModelElement referencedModel) { ArrowControl <TEnclosing, TBoxModel, TArrowModel> retVal = null; foreach (ArrowControl <TEnclosing, TBoxModel, TArrowModel> control in _arrows.Values) { if (control.TypedModel.ReferencedModel == referencedModel) { retVal = control; break; } } return(retVal); }
/// <summary> /// Provides the arrow at a given location /// </summary> /// <param name="location"></param> /// <param name="excludedElement">This element should not be considered during search</param> /// <returns></returns> protected ArrowControl <TEnclosing, TBoxModel, TArrowModel> ArrowForLocation(Point location, GraphicElement excludedElement) { ArrowControl <TEnclosing, TBoxModel, TArrowModel> retVal = null; foreach (ArrowControl <TEnclosing, TBoxModel, TArrowModel> arrow in _arrows.Values) { if ((location.X > arrow.Location.X && location.X < arrow.Location.X + arrow.Width) && (location.Y > arrow.Location.Y && location.Y < arrow.Location.Y + arrow.Height)) { if (arrow != excludedElement) { retVal = arrow; } } } return(retVal); }
/// <summary> /// Handles a mouse down event /// </summary> /// <param name="sender"></param> /// <param name="mouseEventArgs"></param> public void HandleMouseDown(object sender, MouseEventArgs mouseEventArgs) { GraphicElement element = ElementForLocation(mouseEventArgs.Location, null); if (element != null) { element.HandleMouseDown(sender, mouseEventArgs); } if (mouseEventArgs.Button == MouseButtons.Left) { Point clickPoint = new Point(mouseEventArgs.X, mouseEventArgs.Y); foreach (ArrowControl <TEnclosing, TBoxModel, TArrowModel> arrow in _arrows.Values) { if (Around(arrow.StartLocation, clickPoint)) { _changingArrow = arrow; _chaningArrowAction = ChangeAction.InitialBox; Selected = arrow; break; } if (Around(arrow.TargetLocation, clickPoint)) { _changingArrow = arrow; _chaningArrowAction = ChangeAction.TargetBox; Selected = arrow; break; } } if (_changingArrow == null) { BoxControl <TEnclosing, TBoxModel, TArrowModel> box = BoxForLocation(clickPoint, null); if (box != null) { _movingBox = box; _movingBoxHasMoved = false; _moveStartLocation = mouseEventArgs.Location; _positionBeforeMove = box.Location; } } } }
/// <summary> /// Creates the editor for the selected object /// </summary> /// <param name="model"></param> /// <returns></returns> public override object CreateEditor(IModelElement model) { object retVal = null; BoxControl <TEnclosing, TBoxModel, TArrowModel> boxControl = GetBoxControl(model as TBoxModel); if (boxControl != null) { retVal = CreateBoxEditor(boxControl); } ArrowControl <TEnclosing, TBoxModel, TArrowModel> arrowControl = GetArrowControl(model as TArrowModel); if (arrowControl != null) { retVal = CreateArrowEditor(arrowControl); } return(retVal); }
/// <summary> /// Constructor /// </summary> /// <param name="control"></param> public ArrowEditor(ArrowControl <TEnclosing, TBoxModel, TArrowModel> control) { Control = control; }
/// <summary> /// Ensures that two arrowss do not overlap by computing an offset between the arrows /// </summary> protected virtual void ComputeArrowPosition() { List <ArrowControl <TEnclosing, TBoxModel, TArrowModel> > workingSet = new List <ArrowControl <TEnclosing, TBoxModel, TArrowModel> >(); workingSet.AddRange(_arrows.Values); while (workingSet.Count > 1) { ArrowControl <TEnclosing, TBoxModel, TArrowModel> t1 = workingSet[0]; workingSet.Remove(t1); // Compute the set of arrows overlapping with t1 List <ArrowControl <TEnclosing, TBoxModel, TArrowModel> > overlap = new List <ArrowControl <TEnclosing, TBoxModel, TArrowModel> > { t1 }; foreach (ArrowControl <TEnclosing, TBoxModel, TArrowModel> t in workingSet) { if (t.TypedModel.Source == t1.TypedModel.Source && t.TypedModel.Target == t1.TypedModel.Target) { overlap.Add(t); } else if ((t.TypedModel.Source == t1.TypedModel.Target && t.TypedModel.Target == t1.TypedModel.Source)) { overlap.Add(t); } } // Remove all arrows of this overlap class from the working set foreach (ArrowControl <TEnclosing, TBoxModel, TArrowModel> t in overlap) { workingSet.Remove(t); } // Shift arrows of this overlap set if they are overlapping (that is, if the set size > 1) if (overlap.Count > 1) { Point shift; // the shift to be applied to the current arrow Point offset; // the offset to apply on all arrows of this overlap set double angle = overlap[0].Angle; if ((angle > Math.PI / 4 && angle < 3 * Math.PI / 4) || (angle < -Math.PI / 4 && angle > -3 * Math.PI / 4)) { // Horizontal shift shift = new Point(-(overlap.Count - 1) * HorizontalShiftSize / 2, 0); offset = new Point(HorizontalShiftSize, 0); } else { // Vertical shift shift = new Point(0, -(overlap.Count - 1) * VerticalShiftSize / 2); offset = new Point(0, VerticalShiftSize); } int i = 0; foreach (ArrowControl <TEnclosing, TBoxModel, TArrowModel> arrow in overlap) { arrow.Offset = shift; shift.Offset(offset); if (arrow.TargetBoxControl == null) { arrow.EndOffset = new Point(0, VerticalShiftSize * i / 2); } i = i + 1; } } } }
/// <summary> /// Factory for arrow editor /// </summary> /// <param name="control"></param> /// <returns></returns> protected virtual ArrowEditor <TEnclosing, TBoxModel, TArrowModel> CreateArrowEditor( ArrowControl <TEnclosing, TBoxModel, TArrowModel> control) { return(new ArrowEditor <TEnclosing, TBoxModel, TArrowModel>(control)); }