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;
        }
예제 #3
0
        /// <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);
        }
예제 #4
0
        /// <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();
        }
예제 #5
0
        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);
        }
예제 #6
0
        /// <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)));
            }
        }
예제 #7
0
 /// <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;
        }
예제 #10
0
        private bool SetToolTipText(DiagramElement parent)
        {
            if (parent != null)
            {
                var route = parent.DiagramContent as ConnectionLine;
                if (route != null)
                {
                    ToolTip = route.ToolTip;
                    return true;
                }
            }

            return false;
        }
예제 #11
0
        /// <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);
        }
예제 #12
0
        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);
        }
예제 #13
0
        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;
        }
예제 #14
0
        /// <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;
        }
예제 #15
0
        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);
        }
예제 #16
0
        /// <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;
        }
예제 #17
0
        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);
        }