public ClassUmlDrawingEngine(Guid diagramId, IVisualisableTypeWithAssociations mainSubject) { DiagramId = diagramId; MainSubject = mainSubject; var subjectAssociation = Factory.GetInstance<SubjectAssociation>().Initialise(mainSubject); MainDrawingSubject = new DiagramElement(DiagramId, subjectAssociation); }
/// <summary> /// Find the association a line or arrowhead being pointed at. /// </summary> /// <param name="lineOrArrowhead">A element containing a arrowhead or line</param> /// <returns>The <see cref="FieldAssociation"/> being pointed at by the line.</returns> public static FieldAssociation FindAssociationTarget(DiagramElement lineOrArrowhead) { if (lineOrArrowhead == null) { throw new ArgumentNullResourceException("lineOrArrowhead", Resources.General_Given_Parameter_Cannot_Be_Null); } var line = lineOrArrowhead.DiagramContent as ConnectionLine; if (line != null) { return line.PointingAt as FieldAssociation; } line = lineOrArrowhead.RelatedDiagramElements.Single(x => x.DiagramContent is ConnectionLine).DiagramContent as ConnectionLine; Debug.Assert(line != null, "Code error: line == null"); return line.PointingAt as FieldAssociation; }
/// <summary> /// Event raised when a mouse button is clicked down over a diagram-element. /// </summary> private void OnDiagramElementMouseDown(object sender, MouseButtonEventArgs e) { if (e.LeftButton != MouseButtonState.Pressed) { return; } Grid grid; if (!OnlyAssociationsShouldDrag(sender, out grid)) { return; } this.DiagramSpace.Focus(); Keyboard.Focus(this.DiagramSpace); if ((Keyboard.Modifiers & ModifierKeys.Shift) != 0) { // When the shift key is held down special logic may be applied, // so don't handle mouse input here. return; } if (this.mouseHandlingMode != MouseHandlingMode.None) { // We are in some other mouse handling mode, don't do anything. return; } this.mouseHandlingMode = MouseHandlingMode.DraggingDiagramElements; this.currentlyDraggingElement = grid.DataContext as DiagramElement; if (this.currentlyDraggingElement == null) { throw new InvalidOperationException("Code Error: all data contexts should be Diagram Elements"); } this.currentlyDraggingElement.ZOrder = 99; this.origContentMouseDownPoint = e.GetPosition(this.DiagramSpace); }
/// <summary> /// Notifies the data context (represented by this Diagram Content) that a previously registered position-dependent diagram element has moved. /// </summary> /// <param name="dependentElement"> /// The dependent element. /// </param> /// <returns> /// A result containing information if layout changes are required with new suggested values. /// </returns> public ParentHasMovedNotificationResult NotifyDiagramContentParentHasMoved(DiagramElement dependentElement) { if (!this.IsInitialised) { CannotUseWithoutInitializationFirst(); } // Not required for this sub-class return new ParentHasMovedNotificationResult(); }
internal void ShowLineDetails(DiagramElement arrowheadOrLine) { FieldAssociation pointingAtAssociation = ClassDiagramSearchTool.FindAssociationTarget(arrowheadOrLine); if (pointingAtAssociation == null) { return; } new UsageDialog().ShowDialog(Resources.ApplicationName, Subject.Name, Subject.Modifiers.TypeTextName, pointingAtAssociation); }
/// <summary> /// Loads the diagram data from file after the subject has already been set by <see cref="AssignDiagramData"/>. /// At this stage the diagram has already been loaded and is displayed on screen. /// This method ensures all diagram elements have been positioned where the file specifies their co-ordinates. /// Also will provide feedback on any mismatches, ie the type has changed and there are more or less associations. /// </summary> /// <param name="deserializedDataFile">The deserialised data file.</param> public void LoadDiagramDataFromFile(object deserializedDataFile) { var data = deserializedDataFile as TypeVisualiserLayoutFile; if (data == null) { throw new InvalidOperationException("Code Error: Attempt to load data from a type which is not an instance of Type Visualiser Layout File."); } var typesNoLongerInDiagram = new List<VisualisableTypeData>(); foreach (TypeLayoutData layoutData in data.CanvasLayout.Types) { // Deal with annotations first - these have not been loaded by setting the subject. if (layoutData.ContentType == typeof(AnnotationData).FullName) { var annotation = new AnnotationData { Id = layoutData.Id, Text = layoutData.Data, }; var annotationElement = new DiagramElement(DiagramId, annotation) { Show = layoutData.Visible, TopLeft = layoutData.TopLeft }; DiagramElements.Add(annotationElement); continue; } DiagramElement element = DiagramElements.FirstOrDefault(x => x.DiagramContent.Id == layoutData.Id); if (element == null) { VisualisableTypeData type = FindTypeInFile(data, layoutData.Id); if (type == null) { throw new InvalidOperationException("Code error: there is a layout data element without a matching association. " + layoutData.Id); } typesNoLongerInDiagram.Add(type); continue; } element.TopLeft = layoutData.TopLeft; element.Show = layoutData.Visible; } RaiseExpandCanvasRequested(); if (typesNoLongerInDiagram.Any()) { UserPrompt.Show(Resources.ViewportController_Error_in_diagram_file, Resources.ViewportController_Some_types_are_not_in_assembly_anymore + string.Join(", ", typesNoLongerInDiagram.Select(x => x.Name))); } }
/// <summary> /// Clears all diagram visual elements. /// </summary> public void Clear() { Subject = null; this.subjectDiagramElement = null; this.drawingEngine = null; DiagramElements.ToList().ForEach(x => x.Cleanup()); DiagramElements.Clear(); }
private IEnumerable<DiagramElement> DrawLine(DiagramElement fromElement, DiagramElement destinationElement, Association destinationAssociation) { Logger.Instance.WriteEntry("DrawLine for {0}", destinationAssociation.AssociatedTo.Name); Logger.Instance.WriteEntry(" From Area: {0}", fromElement.Area); Logger.Instance.WriteEntry(" To Area : {0}", destinationElement.Area); ConnectionLine route = ConnectionLine.FindBestConnectionRoute(fromElement.Area, destinationElement.Area, IsOverlappingWithOtherControls); destinationAssociation.StyleLine(route); var addedElements = new List<DiagramElement>(); Logger.Instance.WriteEntry(" Route calculated from {0:F1}, {1:F1} to {2:F1}, {3:F1}", route.From.X, route.From.Y, route.To.X, route.To.Y); Logger.Instance.WriteEntry(" From angle {0:F1} to angle {1:F1}", route.FromAngle, route.ToAngle); // Create the line diagram element and add to the diagram collection. // The line is linked to the arrow head position. var lineDiagramElement = new DiagramElement(DiagramId, route) { TopLeft = route.From }; lineDiagramElement.RegisterPositionDependency(new[] { fromElement, destinationElement }, IsOverlappingWithOtherControls); addedElements.Add(lineDiagramElement); // Create an arrow head based on the best route and add to the diagram collection. // The arrow head is linked to the associate diagram element. ArrowHead arrowHead = destinationAssociation.CreateLineHead(); var headDiagramElement = new DiagramElement(DiagramId, arrowHead) { TopLeft = route.To }; headDiagramElement.RegisterPositionDependency(new[] { lineDiagramElement }, IsOverlappingWithOtherControls); addedElements.Add(headDiagramElement); return new[] { lineDiagramElement, headDiagramElement }; }
internal bool ShouldThisSecondaryElementBeVisible(DiagramElement element, bool showSuggestion) { if (!showSuggestion) { return false; } if (this.SecondaryAssociationElements.ContainsKey(element.DiagramContent.Id)) { return !this.trivialFilter.HideSecondaryAssociations; } return true; }
private bool SetToolTipText(DiagramElement parent) { if (parent != null) { var route = parent.DiagramContent as ConnectionLine; if (route != null) { ToolTip = route.ToolTip; return true; } } return false; }
/// <summary> /// Notifies the data context (represented by this Diagram Content) that a previously registered position-dependent diagram element has moved. /// </summary> /// <param name="dependentElement">The dependent element.</param> /// <returns> /// A result containing information if layout changes are required with new suggested values. /// </returns> public ParentHasMovedNotificationResult NotifyDiagramContentParentHasMoved(DiagramElement dependentElement) { if (dependentElement == null) { throw new ArgumentNullResourceException("dependentElement", Resources.General_Given_Parameter_Cannot_Be_Null); } var route = dependentElement.DiagramContent as ConnectionLine; if (route == null) { return new ParentHasMovedNotificationResult(); } HeadRotation = route.ExitAngle; CalculateArrowHeadRotationAndTranslation(); return new ParentHasMovedNotificationResult(route.To); }
private IEnumerable<DiagramElement> DrawLineForSecondaryParent(DiagramElement fromDiagramElement, Association parentAssociation) { var fullyExpandedModelType = parentAssociation.AssociatedTo as IVisualisableTypeWithAssociations; if (fullyExpandedModelType == null || fullyExpandedModelType.Parent == null) { return new List<DiagramElement>(); } DiagramElement destinationElement = FindDiagramElementFromContentId(fullyExpandedModelType.Parent.Id); if (destinationElement == null) { return new List<DiagramElement>(); } var destinationAssociation = destinationElement.DiagramContent as Association; return DrawLine(fromDiagramElement, destinationElement, destinationAssociation); }
private IEnumerable<DiagramElement> DrawLineForSecondaryImplements(DiagramElement fromDiagramElement, Association association) { var fullyExpandedModelType = association.AssociatedTo as IVisualisableTypeWithAssociations; if (fullyExpandedModelType == null || !fullyExpandedModelType.ThisTypeImplements.Any()) { return new List<DiagramElement>(); } var addedElements = new List<DiagramElement>(); foreach (ParentAssociation implement in fullyExpandedModelType.ThisTypeImplements) { DiagramElement destinationElement = FindDiagramElementFromContentId(implement.Id); if (destinationElement == null) { continue; } var destinationAssociation = destinationElement.DiagramContent as Association; addedElements.AddRange(DrawLine(fromDiagramElement, destinationElement, destinationAssociation)); } return addedElements; }
/// <summary> /// Event raised when a mouse button is released over a Diagram element. /// </summary> private void OnDiagramElementMouseUp(object sender, MouseButtonEventArgs e) { if (e.LeftButton != MouseButtonState.Pressed) { return; } Grid grid; if (!OnlyAssociationsShouldDrag(sender, out grid)) { return; } if (this.mouseHandlingMode != MouseHandlingMode.DraggingDiagramElements) { // We are not in Diagram-Element dragging mode. return; } this.mouseHandlingMode = MouseHandlingMode.None; this.currentlyDraggingElement = null; e.Handled = true; }
public void AddAnnotation(Point where, AnnotationData annotation = null) { if (where == default(Point)) { return; } if (annotation == null) { annotation = new AnnotationData(); } annotation.Text = EditAnnotationText(annotation); if (string.IsNullOrWhiteSpace(annotation.Text)) { return; } var diagramElement = new DiagramElement(DiagramId, annotation) { TopLeft = where }; DiagramElements.Add(diagramElement); }
/// <summary> /// Determines whether the specified element is visible. /// </summary> /// <param name="element">The element.</param> /// <param name="primaryDiagramElement">if set to <c>true</c> [primary diagram element].</param> /// <returns> /// <c>true</c> if the specified element is visible; otherwise, <c>false</c>. /// </returns> public bool IsVisible(DiagramElement element, bool primaryDiagramElement) { if (element == null || element.DiagramContent == null) { throw new ArgumentNullResourceException("element", Resources.General_Given_Parameter_Cannot_Be_Null); } var association = element.DiagramContent as Association; bool shouldShow = true; if (association != null) { if (association is SubjectAssociation) { // Subject should always be shown. return true; } if (HideSystemTypes) { shouldShow = !association.AssociatedTo.AssemblyQualifiedName.StartsWith("System.", StringComparison.Ordinal); } if (shouldShow && HideTrivialTypes) { shouldShow = !IsTrivialType(association.AssociatedTo.NamespaceQualifiedName); } } if (shouldShow) { if (!primaryDiagramElement) { if ((element.DiagramContent is ConnectionLine || element.DiagramContent is ArrowHead)) { shouldShow = !HideSecondaryAssociations; } } } return shouldShow; }
private void DrawLine(List<DiagramElement> addedElements, DiagramElement associateElement, Dictionary<string, DiagramElement> secondaryElements) { var association = associateElement.DiagramContent as Association; if (association == null) { throw new InvalidCastException("Code Error: Incorrect IDiagramContent type used with type dependency diagram, it must be an Association derivative."); } // Draw the primary line from the diagram's subject to the association. This could also be a line from the subject's parent to a grandparent. DiagramElement fromElement = GetSourceOfLine(association); // Sometimes returns the subject or a parent connecting to a grandparent. addedElements.AddRange(DrawLine(fromElement, associateElement, association)); // Draw any lines from this diagram element to its associations that are included on the diagram. IEnumerable<DiagramElement> results = DrawLineForSecondaryParent(associateElement, association); AppendToCollections(addedElements, secondaryElements, results); results = DrawLineForSecondaryImplements(associateElement, association); AppendToCollections(addedElements, secondaryElements, results); results = DrawLineForSecondaryAssociations(associateElement, association); AppendToCollections(addedElements, secondaryElements, results); }