Exemple #1
0
        public static DiffTree FromEnumerator(IEnumerator <DiffNode> treeEnumerator, DateTime?timeStamp = null)
        {
            DiffNode current = null;

            while (treeEnumerator.MoveNext())
            {
                current = treeEnumerator.Current;
            }

            return(new DiffTree(current, timeStamp ?? DateTime.UtcNow));
        }
Exemple #2
0
 public DiffTree(DiffNode root, DateTime?timeStamp = null)
 {
     Root      = root;
     TimeStamp = timeStamp ?? DateTime.UtcNow;
 }
Exemple #3
0
 public DiffNodeNamePair(DiffNode node, PropertyName name, bool allowReflection)
 {
     Node            = node;
     Name            = name;
     AllowReflection = allowReflection;
 }
Exemple #4
0
 public static LogMessage ToMessage(DiffNode node, PropertyName name, LogLevel level, bool allowReflection)
 {
     return(node.ToMessage(name, level, allowReflection));
 }
Exemple #5
0
        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));
        }
Exemple #6
0
        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);
        }
Exemple #7
0
 /// <summary>
 /// Converts the given object to a string, showing each of its properties values.
 /// </summary>
 /// <param name="rootPair">old and new document, can be null</param>
 /// <param name="rootNode">diff node describing root object change</param>
 /// <param name="state">describes how to format the string</param>
 /// <returns>String representation</returns>
 public static string ToString(ObjectPair <object> rootPair, DiffNode rootNode, ToStringState state)
 {
     return(Reflector.ToString(rootPair, rootNode, null, state).Trim());
 }
Exemple #8
0
 public string GetName(ObjectPair <object> docPair, DiffNode node, DiffNode parent)
 {
     return(GetName(new ObjectInfo <object>(node.Objects.LastOrDefault(), node.Objects.FirstOrDefault(),
                                            parent != null ? parent.Objects.LastOrDefault() : null, parent != null ? parent.Objects.FirstOrDefault() : null,
                                            docPair.OldObject, docPair.NewObject)));
 }
Exemple #9
0
 public string GetName(DiffNode root, DiffNode node, DiffNode parent)
 {
     return(GetName(ObjectPair.Create(root.Objects.LastOrDefault(), root.Objects.FirstOrDefault()), node, parent));
 }
Exemple #10
0
 /// <summary>
 /// Converts the given object to a string, showing each of its properties values.
 /// </summary>
 /// <param name="rootPair">old and new document, can be null</param>
 /// <param name="docType">May determine whether human readable version requires "peptide"->"molecule" translation</param> // CONSIDER: does this belong in ToStringState?
 /// <param name="rootNode">diff node describing root object change</param>
 /// <param name="state">describes how to format the string</param>
 /// <returns>String representation</returns>
 public static string ToString(ObjectPair <object> rootPair, SrmDocument.DOCUMENT_TYPE docType, DiffNode rootNode, ToStringState state)
 {
     return(Reflector.ToString(rootPair, docType, rootNode, null, state).Trim());
 }
        // TODO: make this function and its overloads in nongeneric Reflector class simpler by introducing new class storing parameters
        private static IEnumerator <DiffNode> EnumerateDiffNodes(ObjectInfo <object> objectInfo, Property thisProperty,
                                                                 bool expand, PropertyPath propertyPath, object elementKey, IList <object> defaults, Func <DiffNode, bool> nodeSelector, DiffNode resultNode, int stackDepth)
        {
            nodeSelector = nodeSelector ?? (n => true);
            if (objectInfo.ObjectPair.ReferenceEquals() && !expand)
            {
                yield break;
            }

            resultNode = resultNode ?? (thisProperty.IsCollectionElement
                ? new ElementPropertyDiffNode(thisProperty, propertyPath, objectInfo.ObjectPair, elementKey, null, expand)
                : new PropertyDiffNode(thisProperty, propertyPath, objectInfo.ObjectPair, null, expand));

            var expandAnyways = false;

            var auditObjPair = objectInfo.ObjectPair.Transform(AuditLogObject.GetAuditLogObject);
            var nameChanged  = auditObjPair.OldObject.IsName && auditObjPair.NewObject.IsName &&
                               auditObjPair.OldObject.AuditLogText != auditObjPair.NewObject.AuditLogText;

            if (ReferenceEquals(objectInfo.OldObject, null) && !ReferenceEquals(objectInfo.NewObject, null) &&
                auditObjPair.NewObject.IsName || nameChanged &&
                // IIdentiyContainer name changes are actually displayed, since we match IIdentiyContainers by their global indices
                !typeof(IIdentiyContainer).IsAssignableFrom(thisProperty.GetPropertyType(objectInfo.ObjectPair)))
            {
                if (!thisProperty.IsRoot)
                {
                    if (!expand)
                    {
                        resultNode.IsFirstExpansionNode = true;
                    }

                    expandAnyways = expand = true;
                }
            }

            // If the object is an IAuditLogObject but not a name one, we don't care about subproperties
            //if (expand && typeof(IAuditLogObject).IsAssignableFrom(thisProperty.GetPropertyType(objectInfo.ObjectPair)) &&
            //    !auditObjPair.OldObject.IsName && !auditObjPair.NewObject.IsName)
            //    expand = false;

            defaults = defaults ?? new List <object>();
            if (expand && Reflector.ProcessDefaults(objectInfo, thisProperty, ref defaults, out var ignore))
            {
                // Don't expand if we changed to a default object
                if (expandAnyways && !ignore && nodeSelector(resultNode)) // Only show this object if it shouldn't be fully ignored if it's a default object (for instance: small molecule only properties)
                {
                    yield return(resultNode);
                }
                yield break;
            }

            // We only compare sub properties if both objects are non null, unless we're expanding
            // and only the old object is null
            if (ReferenceEquals(objectInfo.OldObject, null) && !expand || ReferenceEquals(objectInfo.NewObject, null))
            {
                if (nodeSelector(resultNode))
                {
                    yield return(resultNode);
                }
                yield break;
            }

            // Deal with Collections
            var collection = Reflector.GetCollectionInfo(thisProperty.GetPropertyType(objectInfo.ObjectPair),
                                                         objectInfo.ObjectPair);

            if (collection != null)
            {
                var nodeIter = Reflector.EnumerateCollectionDiffNodes(objectInfo.ChangeObjectPair(collection.Collections), collection,
                                                                      thisProperty, propertyPath, expand, defaults, nodeSelector, resultNode, stackDepth);

                while (nodeIter.MoveNext())
                {
                    yield return(nodeIter.Current);
                }

                yield break;
            }

            // Properties that should directly be checked for equality -- stop recursion
            if (!thisProperty.DiffProperties)
            {
                // Properties that are not TrackParents and not collections are simply compared
                // Also make sure that new val doesn't equal any of the default objects
                if (nodeSelector(resultNode) && (!objectInfo.ObjectPair.Equals() || expand) &&
                    (!expand || thisProperty.IgnoreDefaultParent || !defaults.Any(d => Equals(d, objectInfo.ObjectPair.NewObject))))
                {
                    yield return(resultNode);
                }
                yield break;
            }

            objectInfo = objectInfo.ChangeParentPair(objectInfo.ObjectPair);

            // Compare properties
            foreach (var property in _properties)
            {
                var newPropertyPath = property.AddProperty(propertyPath);

                var newObjectInfo = objectInfo
                                    .ChangeOldObject(ReferenceEquals(objectInfo.OldObject, null)
                        ? null
                        : property.GetValue(objectInfo.OldObject))
                                    .ChangeNewObject(property.GetValue(objectInfo.NewObject));

                var valType  = property.GetPropertyType(newObjectInfo.ObjectPair);
                var nodeIter = Reflector.EnumerateDiffNodes(valType, newObjectInfo, property, expand, newPropertyPath,
                                                            null, defaults, nodeSelector, null, stackDepth);

                DiffNode current = null;
                while (nodeIter.MoveNext())
                {
                    current = nodeIter.Current;
                    yield return(current);
                }

                if (current != null)
                {
                    resultNode.Nodes.Add(current);
                }
            }

            // If there are child nodes, we always want to return the parent node,
            // but if it's just the root node or a diffparent (meaning only the object reference changed)
            // we return null (meaning the objects are equivalent)
            if (resultNode.Nodes.Count == 0 && thisProperty.DiffProperties && !expandAnyways)
            {
                yield break;
            }

            if (nodeSelector(resultNode))
            {
                yield return(resultNode);
            }
        }