private Node AddOrGetClassNode(Type type, ICollection <Type> types) { //if (type.IsValueType || type.Name == "String" || !types.Contains(type)) return null; if (type.IsValueType || type.Name == "String") { return(null); } var baseType = type.BaseType; if (!generatedNodes.ContainsKey(type)) { // // Add a node if it doesn't exist yet and cache it // var node = AddNode(type) as UmlClass; Debug.Assert(node != null); generatedNodes[type] = node; PropertyInfo[] fields = type.GetProperties(); int i = 0; foreach (var field in fields) { Type fieldType; try { fieldType = field.PropertyType; } catch (Exception) { continue; } if (i < 1 && !fieldType.IsValueType && fieldType.Name != "String") //types.Contains(field.PropertyType)) { // // Yes, we want the comprised node in our diagram // { Node comprisedNode = AddOrGetClassNode(fieldType, types); if (comprisedNode != null) { comprisedNode.Pos = node.Pos; TranslateChildNodes(comprisedNode, new Vector3D(50, 0, 0)); var link = new UmlCompositionRelation("135"); link.EndNode = node; // node2 = parent, node1 = child link.StartNode = comprisedNode; node.Links.Add(link); comprisedNode.Links.Add(link); Links.Add(link); i++; } } } // // Now, check the base types of this type // var parentNode = baseType != null && baseType != typeof(object) ? AddOrGetClassNode(baseType, types) : null; if (parentNode != null) { var link = new UmlInheritanceRelation("90"); link.StartNode = node; link.EndNode = parentNode; parentNode.Pos = node.Pos + new Vector3D(0, -50, 0); node.Links.Add(link); parentNode.Links.Add(link); Links.Add(link); } return(node); } return(generatedNodes[type]); }
private void OnCreatorTextChanged(string newCreatorText) { UmlClass umlClassBeforeOperator = null; Link link = null; if (string.IsNullOrWhiteSpace(newCreatorText)) { return; } if (newCreatorText.EndsWith("\r\n")) { currentCreatorAction = CreatorAction.None; if (totalStringBuilder.Length > 0) { totalStringBuilder.Append(" "); } totalStringBuilder.Append(newCreatorText.Substring(0, newCreatorText.Length - 2)); //Commit creator text string[] tokens = newCreatorText.Split(new[] { ' ', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); bool endsWithDot = false; bool endsWithColon = false; bool endsWithN = false; bool not = false; foreach (string token in tokens) { string token2 = token.Trim(); if (token.EndsWith(".")) { endsWithDot = true; token2 = token2.Substring(0, token.Length - 1); } if (token.EndsWith(":")) { endsWithColon = true; token2 = token2.Substring(0, token.Length - 1); } if (token.EndsWith("N")) { endsWithN = true; token2 = token2.Substring(0, token.Length - 1); } switch (token2.ToLower()) { case "reset": totalStringBuilder.Clear(); Diagram.Reset(); CreatorText = null; return; case "resetclass": currentCreatorAction = CreatorAction.ResettingClass; break; case "not": not = true; break; case "delete": currentCreatorAction = CreatorAction.DeletingClass; break; case "rename": currentCreatorAction = CreatorAction.Renaming; break; case "to": if (currentCreatorAction == CreatorAction.Renaming) { currentCreatorAction = CreatorAction.RenamingTo; } break; case "is": link = new UmlInheritanceRelation(InheritanceRelationPreferredAngles); break; case "implements": link = new UmlImplementsInterfaceRelation(InheritanceRelationPreferredAngles); break; case "dependson": case "uses": link = new UmlDependsOnRelation(AssociationRelationPreferredAngles); break; case "owns": case "creates": link = new UmlCompositionRelation(CompositionRelationPreferredAngles, endsWithN ? "N" : "1"); break; case "contains": link = new UmlAggregationRelation(AggregationRelationPreferredAngles, endsWithN ? "N" : "1"); break; case "has": link = new UmlAssociationRelation(AssociationRelationPreferredAngles); break; default: if (link == null) { if (currentCreatorAction == CreatorAction.DeletingClass) { umlClassBeforeOperator = GetOrCreateUmlClass(token2); Diagram.DeleteNode(umlClassBeforeOperator); umlClassBeforeOperator = null; currentCreatorAction = CreatorAction.None; break; } if (currentCreatorAction == CreatorAction.RenamingTo && umlClassBeforeOperator != null) { umlClassBeforeOperator.Name = token2; currentCreatorAction = CreatorAction.None; break; } if (currentCreatorAction == CreatorAction.ResettingClass) { umlClassBeforeOperator = GetOrCreateUmlClass(token2); umlClassBeforeOperator.BackgroundBrush = null; umlClassBeforeOperator = null; currentCreatorAction = CreatorAction.None; break; } if (currentCreatorAction == CreatorAction.None && endsWithColon) { // Current token is a shortcut for 'has <action>:subject' -> '<action>: subject' link = new UmlAssociationRelation(AssociationRelationPreferredAngles); break; } umlClassBeforeOperator = GetOrCreateUmlClass(token2); } else { string name = null; int indexOfColon = token2.IndexOf(":"); // ':' indicates value type. Optional are access modifier and type if (indexOfColon > -1) { // Value type AccessModifier am = AccessModifier.None; int indexOfName = 0; if (token2.StartsWith("-")) { am = AccessModifier.Private; indexOfName = 1; } if (token2.StartsWith("#")) { am = AccessModifier.Protected; indexOfName = 1; } if (token2.StartsWith("$#")) { am = AccessModifier.ProtectedInternal; indexOfName = 2; } if (token2.StartsWith("$")) { am = AccessModifier.Internal; indexOfName = 1; } if (token2.StartsWith("+")) { am = AccessModifier.Public; indexOfName = 1; } name = token2.Substring(indexOfName, indexOfColon - indexOfName); if (indexOfColon < token2.Length - 1) { // colon is not the last character, so there is a type specified string type = token2.Substring(indexOfColon + 1); var lowerType = type.ToLower(); if (!valueTypes.Contains(lowerType) && !name.EndsWith("()")) { // Reference type and no operation token2 = type; link.Label = name; } else { // value type bool isOperation = name.EndsWith("()"); if (isOperation) { name = name.Substring(0, name.Length - 2); umlClassBeforeOperator.Operations.Add(new UmlOperation(name, type, am)); } else { umlClassBeforeOperator.Attributes.Add(new UmlAttribute(name, type, am)); } link = null; // TODO: not break; } } else { // value type bool isOperation = name.EndsWith("()"); if (isOperation) { name = name.Substring(0, name.Length - 2); umlClassBeforeOperator.Operations.Add(new UmlOperation(name, null, am)); } else { umlClassBeforeOperator.Attributes.Add(new UmlAttribute(name, null, am)); } link = null; // TODO: not break; } } var umlClassAfterOperator = GetOrCreateUmlClass(token2); if (umlClassBeforeOperator != null && umlClassAfterOperator != null) { if (not) { List <Link> linksToDelete = new List <Link>(); foreach (var linkToDelete in umlClassBeforeOperator.Links) { if ( linkToDelete.GetType() == link.GetType() && ( (linkToDelete is UmlInheritanceRelation || linkToDelete is UmlAssociationRelation) && linkToDelete.StartNode == umlClassBeforeOperator && linkToDelete.EndNode == umlClassAfterOperator || linkToDelete.StartNode == umlClassAfterOperator && linkToDelete.EndNode == umlClassBeforeOperator ) ) { linksToDelete.Add(linkToDelete); } } foreach (var linkToDelete in linksToDelete) { Diagram.DeleteLink(linkToDelete); } } else { if (link is UmlInheritanceRelation || link is UmlAssociationRelation) { // StartNode <link> EndNode link.StartNode = umlClassBeforeOperator; link.EndNode = umlClassAfterOperator; } else { link.EndNode = umlClassBeforeOperator; link.StartNode = umlClassAfterOperator; } umlClassBeforeOperator.Links.Add(link); umlClassAfterOperator.Links.Add(link); Diagram.Links.Add(link); } link = null; not = false; if (endsWithDot) { umlClassBeforeOperator = umlClassAfterOperator; } } } break; } if (endsWithColon && link != null) { link.Label = token2.Replace("_", " "); } endsWithColon = false; endsWithDot = false; endsWithN = false; } CreatorText = ""; } }