private static bool IsDescendentOrSelf(SimpleXmlChange existingChange, SimpleXmlChange newChange)
 {
     var child = existingChange.Node;
     var parent = newChange.Node;
     if (child == parent)
     {
         if (child.Parent == null)
         {
             //either two deletes
             //or a node N was added and then deleted
             if (existingChange.Parent == newChange.Parent)
             {
                 return true;
             }
         }
         else if (newChange.Parent == existingChange.Parent)
         {
             //do not return true in case of move
             return true;
         }
     }
     var pe = parent as XElement;
     if (pe != null)
     {
         for (var e = existingChange.Parent as XElement; e != null; e = e.Parent)
         {
             if (e == pe)
             {
                 return true;
             }
         }
     }
     return false;
 }
        private void OnBeforeChange(object sender, XObjectChangeEventArgs e)
        {
            var node = sender as XObject;

            // We do not allow editing DTDs through XmlModel
            if (node is XDocumentType)
            {
                var msg = String.Format(CultureInfo.CurrentCulture, Resources.VanillaProvider_DtdNodesReadOnly);
                throw new NotSupportedException(msg);
            }
            var action = e.ObjectChange;
            currentChange = null;

            XElement element = null;
            XAttribute attribute = null;
            XText text = null;
            XProcessingInstruction pi = null;
            XComment comment = null;

            switch (action)
            {
                case XObjectChange.Add:
                    var addChange = new AddNodeChangeInternal(node, action);
                    currentChange = addChange;
                    break;
                case XObjectChange.Remove:
                    var removeChange = new RemoveNodeChange(node, action);
                    removeChange.Parent = node.Parent;
                    if (removeChange.Parent == null)
                    {
                        removeChange.Parent = node.Document;
                    }
                    var attrib = (node as XAttribute);
                    if (attrib != null)
                    {
                        removeChange.NextNode = attrib.NextAttribute;
                    }
                    else
                    {
                        removeChange.NextNode = (node as XNode).NextNode;
                    }
                    currentChange = removeChange;
                    break;
                case XObjectChange.Name:
                    var nameChange = new NodeNameChange(node, action);
                    if ((element = node as XElement) != null)
                    {
                        nameChange.OldName = element.Name;
                    }
                    else if ((pi = node as XProcessingInstruction) != null)
                    {
                        nameChange.OldName = XName.Get(pi.Target);
                    }
                    else
                    {
                        Debug.Assert(false, "The name of something changed that we're not handling here!");
                        throw new NotSupportedException();
                    }
                    currentChange = nameChange;
                    break;
                case XObjectChange.Value:
                    var valueChange = new NodeValueChange(node, action);
                    if ((element = node as XElement) != null)
                    {
                        valueChange.OldValue = element.Value;
                    }
                    else if ((attribute = node as XAttribute) != null)
                    {
                        valueChange.OldValue = attribute.Value;
                    }
                    else if ((text = node as XText) != null)
                    {
                        valueChange.OldValue = text.Value;
                        if (text.Parent != null)
                        {
                            valueChange.Parent = text.Parent;
                        }
                        else
                        {
                            valueChange.Parent = text.Document;
                        }
                    }
                    else if ((comment = node as XComment) != null)
                    {
                        valueChange.OldValue = comment.Value;
                    }
                    else if ((pi = node as XProcessingInstruction) != null)
                    {
                        valueChange.OldValue = pi.Data;
                    }
                    else
                    {
                        Debug.Assert(false, "The value of something changed that we're not handling here!");
                        throw new NotSupportedException();
                    }
                    currentChange = valueChange;
                    break;
            }
        }
 private RemoveStatus RemoveAllDescendentChanges(SimpleXmlChange newChange)
 {
     // This node is being removed, therefore any change to any child of this
     // node is now unnecessary, so we can filter them out.
     var rc = RemoveStatus.None;
     List<XmlModelCommand> toRemove = null;
     for (int i = committedPosition, n = txCommands.Count; i < n; i++)
     {
         var cmd = txCommands[i];
         var change = cmd.Change;
         if (IsDescendentOrSelf(change, newChange))
         {
             if (change.Node == newChange.Node
                 && change.Action == XObjectChange.Add)
             {
                 rc = RemoveStatus.FoundSelfAdd; // we are removing an add of the same node!
             }
             if (toRemove == null)
             {
                 toRemove = new List<XmlModelCommand>();
             }
             toRemove.Add(cmd);
         }
     }
     RemoveRange(txCommands, toRemove);
     return rc;
 }
 public XmlModelCommand(SimpleXmlChange change)
     : base()
 {
     this._change = change;
 }