public DiffNodeNamePair FindFirstMultiChildParent(DiffTree tree, PropertyName name, bool shortenName, bool allowReflection, DiffNode parentNode = null) { var oneNode = Nodes.Count == 1; var propertyNameString = Property.GetName(tree.Root, this, parentNode); // Collection elements should be referred to by their name or string representation var propName = IsCollectionElement ? new PropertyElementName(ObjectToString(allowReflection)) : (Property.IsTab ? new PropertyTabName(propertyNameString) : new PropertyName(propertyNameString)); // If the node can't be displayed and its name cant be ignored, // we can't go further down the tree. This can happen theoretically but hasn't occured anywhere yet if (propName.Name == null && !Property.IgnoreName) { return(new DiffNodeNamePair(parentNode?.ChangeExpanded(false), name, allowReflection)); } var newName = name.SubProperty(propName); var elemName = Property.GetElementName(); if (shortenName && Property.GetElementName() != null && !IsCollectionElement) { if (oneNode) { // Remove everything from the path and replace it with the element name, e.g "Settings > DataSettings > GroupComparisons" // becomes "GroupComparison:" newName = PropertyName.ROOT.SubProperty(new PropertyElementName(elemName)); } else { // Multiple changes have been made to the collection newName = propName; } } if (Property.IgnoreName && !IsCollectionElement) { newName = name; } var objects = Objects.Select(AuditLogObject.GetAuditLogObject) .Where(o => o == null || o.IsName).ToArray(); if (objects.Length == 2) { var type = Property.GetPropertyType(ObjectPair.Create(objects[1], objects[0])); if (((objects[0] != null) != (objects[1] != null) || (objects[0] != null && objects[1] != null && objects[0].AuditLogText != objects[1].AuditLogText && !typeof(DocNode).IsAssignableFrom(type))) && !Property.IsRoot) { oneNode = false; // Stop recursion, since in the undo-redo/summary log we don't want to go deeper for objects where the name changed } } return(oneNode && !IsFirstExpansionNode ? Nodes[0].FindFirstMultiChildParent(tree, newName, shortenName, allowReflection, this) : new DiffNodeNamePair(ChangeExpanded(false), newName, allowReflection)); }
/// <summary> /// Creates a log entry representing the changes in the diff tree /// </summary> /// <param name="document">Document changes were made to</param> /// <param name="tree">Tree that should be logged</param> /// <param name="extraInfo">Text that should be displayed when clicking the magnifying glass in the audit log form</param> /// <returns></returns> public static AuditLogEntry CreateSettingsChangeEntry(SrmDocument document, DiffTree tree, string extraInfo = null) { if (tree.Root == null) { return(null); } var result = new AuditLogEntry(document, tree.TimeStamp, string.Empty, true, extraInfo); var nodeNamePair = tree.Root.FindFirstMultiChildParent(tree, PropertyName.ROOT, true, false); // Remove "Settings" from property name if possible if (nodeNamePair.Name != null && nodeNamePair.Name.Parent != PropertyName.ROOT) { var name = nodeNamePair.Name; while (name.Parent.Parent != PropertyName.ROOT) { name = name.Parent; } if (name.Parent.Name == "{0:Settings}") // Not L10N { name = RemoveTopmostParent(nodeNamePair.Name); nodeNamePair = nodeNamePair.ChangeName(name); } } result.UndoRedo = nodeNamePair.ToMessage(LogLevel.undo_redo); result.Summary = tree.Root.FindFirstMultiChildParent(tree, PropertyName.ROOT, false, false) .ToMessage(LogLevel.summary); result.AllInfo = tree.Root.FindAllLeafNodes(tree, PropertyName.ROOT, true) .Select(n => n.ToMessage(LogLevel.all_info)).ToArray(); return(result); }
public static string ToString(ObjectPair <object> rootPair, T obj, ToStringState state) { var objectInfo = new ObjectInfo <object>().ChangeNewObject(obj) .ChangeRootObjectPair(rootPair ?? ObjectPair <object> .Create(null, null)); var rootProp = RootProperty.Create(typeof(T)); var enumerator = EnumerateDiffNodes(objectInfo, rootProp, true); return(ToString(objectInfo.ParentObjectPair, DiffTree.FromEnumerator(enumerator, DateTime.Now).Root, state)); }
/// <summary> /// Compares the settings objects of the given documents and creates an entry /// for the differences /// </summary> /// <param name="documentPair">The pair of documents to compare</param> /// <returns>A log entry containing the changes</returns> public static AuditLogEntry SettingsLogFunction(SrmDocumentPair documentPair) { var property = RootProperty.Create(typeof(SrmSettings), "Settings"); // Not L10N var objInfo = new ObjectInfo <object>(documentPair.OldDoc.Settings, documentPair.NewDoc.Settings, documentPair.OldDoc, documentPair.NewDoc, documentPair.OldDoc, documentPair.NewDoc); var tree = DiffTree.FromEnumerator(Reflector <SrmSettings> .EnumerateDiffNodes(objInfo, property, false)); return(tree.Root != null?CreateSettingsChangeEntry(documentPair.OldDoc, tree) : null); }
public static AuditLogEntry DiffDocNodes(MessageType action, SrmDocumentPair documentPair, params object[] actionParameters) { var property = RootProperty.Create(typeof(Targets)); var objInfo = new ObjectInfo <object>(documentPair.OldDoc.Targets, documentPair.NewDoc.Targets, documentPair.OldDoc, documentPair.NewDoc, documentPair.OldDoc, documentPair.NewDoc); var diffTree = DiffTree.FromEnumerator(Reflector <Targets> .EnumerateDiffNodes(objInfo, property, false), DateTime.Now); if (diffTree.Root != null) { var message = new MessageInfo(action, actionParameters); var entry = CreateSettingsChangeEntry(documentPair.OldDoc, diffTree) .ChangeUndoRedo(message); return(entry); } return(null); }
protected virtual AuditLogEntry CreateEntry(SrmDocumentPair docPair) { var baseEntry = CreateBaseEntry(docPair); var rootProp = RootProperty.Create(typeof(T)); var objectInfo = new ObjectInfo <object>() .ChangeObjectPair(ObjectPair <object> .Create(null, this)) .ChangeRootObjectPair(docPair.ToObjectType()); var diffTree = DiffTree.FromEnumerator(Reflector <T> .EnumerateDiffNodes(docPair.ToObjectType(), rootProp, (T)this), DateTime.Now); if (diffTree.Root == null) { return(baseEntry); } var settingsString = Reflector <T> .ToString(objectInfo.RootObjectPair, diffTree.Root, ToStringState.DEFAULT.ChangeFormatWhitespace(true)); var entry = AuditLogEntry.CreateSettingsChangeEntry(docPair.OldDoc, diffTree, settingsString); return(baseEntry.Merge(entry)); }
public List <DiffNodeNamePair> FindAllLeafNodes(DiffTree tree, PropertyName name, bool allowReflection, DiffNode parentNode = null) { var result = new List <DiffNodeNamePair>(); var propertyNameString = Property.GetName(tree.Root, this, parentNode); var isName = false; // Collection elements should be referred to by their name or string representation var propName = IsCollectionElement ? new PropertyElementName(ObjectToString(allowReflection, Objects.FirstOrDefault(o => o != null), out isName)) : (Property.IsTab ? new PropertyTabName(propertyNameString) : new PropertyName(propertyNameString)); // The name can not be ignored if the node is a collection change (since then the child nodes of the collection change // have the same attribute as the collection change node) var canIgnoreName = (Property.IgnoreName && !IsCollectionElement); if (!canIgnoreName) { name = name != null?name.SubProperty(propName) : propName; } // We can't display sub changes of an element if it's unnamed, so we display its // string representation as a change if (IsCollectionElement && !isName && !canIgnoreName) { result.Add(new DiffNodeNamePair(this, name, allowReflection)); return(result); } var obj = Objects.FirstOrDefault(); var isNamedChange = IsFirstExpansionNode || (obj != null && AuditLogObject.IsNameObject(obj)) && Expanded && !canIgnoreName; if (isNamedChange) { result.Add(new DiffNodeNamePair(this, name, allowReflection)); } if (Nodes.Count == 0) { if (!isNamedChange) { result.Add(new DiffNodeNamePair(this, name, allowReflection)); } } else { var collectionPropDiffNode = this as CollectionPropertyDiffNode; if (collectionPropDiffNode != null && collectionPropDiffNode.RemovedAll) { result.Add(new DiffNodeNamePair(this, name, allowReflection)); } else { foreach (var n in Nodes) { result.AddRange(n.FindAllLeafNodes(tree, name, allowReflection, this)); } } } return(result); }