Exemplo n.º 1
0
        private void ProcessExternalAddOrUpdateChange(
            EfiChangeGroup changeGroup, List <EFContainer> containersToRenormalize, ExternalXMLModelChange undoModelChange)
        {
            var changedEFObject = undoModelChange.ChangedEFObject;
            var parentEFObject  = undoModelChange.Parent;

            if (parentEFObject != null)
            {
                var parentEFContainer = parentEFObject as EFContainer;
                Debug.Assert(parentEFContainer != null, "parentEFObject was not an EFContainer!");

                // if this is an "add" for an element, then the parent will parse the new child.
                // if this is an "add" for an attribute, then we have to directly set the XObject
                // if this is an "update" then we will just record it in our model
                if (parentEFContainer != null
                    &&
                    undoModelChange.Action == XObjectChange.Add)
                {
                    var newXElement = undoModelChange.XNode as XElement;

                    if (newXElement != null
                        &&
                        parentEFContainer.ReparseSingleElement(new List <XName>(), newXElement))
                    {
                        var newEFObject = ModelItemAnnotation.GetModelItem(undoModelChange.XNode);
                        Debug.Assert(newEFObject != null, "Couldn't find the ModelItemAnnotation for the newly created XLinq node");
                        if (newEFObject != null)
                        {
                            var newEFElement = newEFObject as EFElement;
                            Debug.Assert(newEFElement != null, "If the XObject was an XElement, then we should have an EFElement as well");
                            if (newEFElement != null)
                            {
                                XmlModelHelper.NormalizeAndResolve(newEFElement);
                            }

                            // we need to rediscover the XLinq annotation to pick up the new EFObject that just got created
                            changedEFObject = ModelItemAnnotation.GetModelItem(undoModelChange.XNode);
                        }
                    }
                    else if (undoModelChange.XNode is XAttribute)
                    {
                        var staleItemBinding      = changedEFObject as ItemBinding;
                        var staleDefaultableValue = changedEFObject as DefaultableValue;

                        // item bindings might have gotten added after their parents got added in which case the MIA will be stale.
                        // we have to step through the new parent, set the xobject manually, rebind, and reset the annotation on the xlinq node.
                        if (staleItemBinding != null)
                        {
                            foreach (var child in parentEFContainer.Children)
                            {
                                var updatedItemBinding = child as ItemBinding;
                                if (updatedItemBinding != null &&
                                    updatedItemBinding.EFTypeName == staleItemBinding.EFTypeName)
                                {
                                    updatedItemBinding.SetXObject(undoModelChange.XNode);
                                    updatedItemBinding.Rebind();
                                    changedEFObject = updatedItemBinding;
                                }
                            }
                        }

                        // for defaultable values that got added after parents were added, we have to discover the actual EFObject in the Escher tree,
                        // set the xobject, and reset the annotation on the existing xlinq node
                        else if (staleDefaultableValue != null)
                        {
                            foreach (var child in parentEFContainer.Children)
                            {
                                var updatedDefaultableValue = child as DefaultableValue;
                                if (updatedDefaultableValue != null &&
                                    updatedDefaultableValue.EFTypeName == staleDefaultableValue.EFTypeName)
                                {
                                    updatedDefaultableValue.SetXObject(undoModelChange.XNode);
                                    changedEFObject = updatedDefaultableValue;
                                }
                            }
                        }

                        ModelItemAnnotation.SetModelItem(undoModelChange.XNode, changedEFObject);
                    }
                }
                else if (undoModelChange.Action == XObjectChange.Value)
                {
                    Debug.Assert(undoModelChange.XNode is XAttribute, "The only 'value' change Escher supports is to XAttributes");
                    if (undoModelChange.XNode is XAttribute)
                    {
                        var existingItemBinding = changedEFObject as ItemBinding;
                        if (existingItemBinding != null)
                        {
                            existingItemBinding.Rebind();
                        }

                        // we have to normalize and resolve the parents of DefaultableValues
                        // because this change could affect the parent's RefName, affecting SingleItemBindings
                        var defaultableValue = changedEFObject as DefaultableValue;
                        if (defaultableValue != null)
                        {
                            XmlModelHelper.NormalizeAndResolve(parentEFContainer);
#if DEBUG
                            var xattr = undoModelChange.XNode as XAttribute;
                            var defaultableValueValue = defaultableValue.ObjectValue as string;
                            if (defaultableValueValue != null)
                            {
                                // verify that the defaultableValue's value & the XAttribute's value are the same
                                Debug.Assert(xattr.Value == defaultableValueValue);
                            }
#endif
                        }
                    }
                }
                else
                {
                    Debug.Assert(false, "Encountered a non-valid type of change to the XML: " + undoModelChange.Action.ToString());
                    throw new ChangeProcessingFailedException();
                }

                // if an object's state is unresolved, then queue it for re-normalization. This occurs
                // for example, if itembinding changes occur before the 'add' changes for their targeted objects
                var itemBinding = changedEFObject as ItemBinding;
                if ((itemBinding != null && false == itemBinding.Resolved) ||
                    parentEFContainer.State != EFElementState.Resolved)
                {
                    containersToRenormalize.Add(parentEFContainer);
                }
                CheckObjectToRenormalize(changedEFObject, ref containersToRenormalize);

                // now tell the views that a new item has been created; this will happen for both an 'add' and a 'change'
                string oldValue = null;
                string newValue = null;
                string property = null;
                GetOldAndNewValues(undoModelChange.XmlChange, out property, out oldValue, out newValue);

                changeGroup.RecordModelChange(GetChangeType(undoModelChange.XmlChange), changedEFObject, property, oldValue, newValue);
            }
            else
            {
                // we got a change event on a root-node in the document.
                // This will cause an NRE when looking for the model-item annotation,
                // so throw this exception to cause the caller to reload the doc
                throw new ChangeProcessingFailedException();
            }
        }
Exemplo n.º 2
0
        private static void ProcessExternalRemoveChange(
            EfiChangeGroup changeGroup, IList <ItemBinding> bindingsForRebind, ExternalXMLModelChange modelChange)
        {
            var changedEFObject = modelChange.ChangedEFObject;
            var parentEFObject  = modelChange.Parent;

            if (changedEFObject != null)
            {
                var staleItemBinding      = changedEFObject as ItemBinding;
                var staleDefaultableValue = changedEFObject as DefaultableValue;

                var parentEFContainer = parentEFObject as EFContainer;
                Debug.Assert(parentEFContainer != null, "parentEfObject was not an EFContainer!");
                if (staleItemBinding != null)
                {
                    // if this is an itembinding, then we have to directly null out the xobject and rebind since the refname is a "symlink" to the xattribute
                    foreach (var child in parentEFContainer.Children)
                    {
                        var updatedItemBinding = child as ItemBinding;
                        if (updatedItemBinding != null &&
                            updatedItemBinding.EFTypeName == staleItemBinding.EFTypeName)
                        {
                            updatedItemBinding.SetXObject(null);
                            updatedItemBinding.Rebind();
                            changedEFObject = updatedItemBinding;
                            break;
                        }
                    }
                }
                else if (staleDefaultableValue != null)
                {
                    foreach (var child in parentEFContainer.Children)
                    {
                        var updatedDefaultableValue = child as DefaultableValue;
                        if (updatedDefaultableValue != null &&
                            updatedDefaultableValue.EFTypeName == staleDefaultableValue.EFTypeName)
                        {
                            updatedDefaultableValue.SetXObject(null);
                            changedEFObject = updatedDefaultableValue;
                            break;
                        }
                    }
                }
                else
                {
                    // Find all the dependent binding.
                    var visitor = new AntiDependencyCollectorVisitor();
                    visitor.Traverse(changedEFObject);
                    foreach (var binding in visitor.AntiDependencyBindings)
                    {
                        if (!bindingsForRebind.Contains(binding))
                        {
                            bindingsForRebind.Add(binding);
                        }
                    }
                    // Delete(false) because it has already been removed from XLinq tree
                    changedEFObject.Delete(false);
                }

                // record the change so views get updated
                changeGroup.RecordModelChange(EfiChange.EfiChangeType.Delete, changedEFObject, String.Empty, String.Empty, String.Empty);
            }
            else
            {
                throw new ChangeProcessingFailedException();
            }
        }
Exemplo n.º 3
0
        private EfiChangeGroup ProcessUndoRedoChanges(XmlTransactionEventArgs xmlTransactionEventArgs)
        {
            using (var tx = new EfiTransaction(this, EfiTransactionOriginator.UndoRedoOriginatorId, xmlTransactionEventArgs.Transaction))
            {
                var changeGroup             = tx.ChangeGroup;
                var undoChanges             = new List <ExternalXMLModelChange>();
                var containersToRenormalize = new List <EFContainer>();
                var bindingsForRebind       = new List <ItemBinding>();
                var namespaces = GetNamespaces();

                // filter the changes received from XmlEditor and resolve changed EFObjects and their parents
                foreach (var xmlChange in xmlTransactionEventArgs.Transaction.Changes())
                {
                    // determine how to process this edit
                    if (xmlChange.Node.NodeType == XmlNodeType.Element ||
                        xmlChange.Node.NodeType == XmlNodeType.Attribute ||
                        xmlChange.Node.NodeType == XmlNodeType.Document)
                    {
                        if (xmlChange.Node.NodeType == XmlNodeType.Element &&
                            xmlChange.Action == XObjectChange.Value)
                        {
                            var nodeValueChange = xmlChange as IXmlNodeValueChange;
                            Debug.Assert(
                                nodeValueChange != null &&
                                string.IsNullOrEmpty(nodeValueChange.OldValue) &&
                                string.IsNullOrEmpty(nodeValueChange.NewValue));

                            // in cases where we are undoing the addition of all children to an element A, the Xml Model
                            // will forcibly add an empty string to the element A so that a "short" end tag "/>" is not created
                            // in this case, the change we will receive is a set value change on an element; we ignore this
                        }
                        else
                        {
                            var emc = new ExternalXMLModelChange(xmlChange, ExpectEFObjectForXObject);
                            if (emc.IsAnnotationChange(namespaces))
                            {
                                continue;
                            }

                            undoChanges.Add(emc);
                        }
                    }
                }

                // go through the undo changes and make changes to the model
                foreach (var undoModelChange in undoChanges)
                {
                    // Should ignore other artifact changes.
                    if (undoModelChange.ChangedEFObject.Artifact != this)
                    {
                        continue;
                    }

                    if (undoModelChange.Action == XObjectChange.Remove)
                    {
                        ProcessExternalRemoveChange(changeGroup, bindingsForRebind, undoModelChange);
                    }
                    else
                    {
                        ProcessExternalAddOrUpdateChange(changeGroup, containersToRenormalize, undoModelChange);
                    }
                }

                // because of the order in which elements were possibly added, certain ItemBindings were not resolved;
                // therefore we have to step through the normalized EFElements again and normalize/resolve so their child
                // ItemBindings will get resolved.
                foreach (var container in containersToRenormalize)
                {
                    XmlModelHelper.NormalizeAndResolve(container);
                }
                XmlModelHelper.RebindItemBindings(bindingsForRebind);

#if DEBUG
                var visitor = GetVerifyModelIntegrityVisitor();
                visitor.Traverse(this);

                if (visitor.ErrorCount > 0)
                {
                    Debug.WriteLine("Model Integrity Verifier found " + visitor.ErrorCount + " error(s):");
                    Debug.WriteLine(visitor.AllSerializedErrors);
                    Debug.Assert(
                        false, "Model Integrity Verifier found " + visitor.ErrorCount + " error(s). See the Debug console for details.");
                }
#endif
                return(changeGroup);
            }
        }
Exemplo n.º 4
0
        private void ProcessExternalAddOrUpdateChange(
            EfiChangeGroup changeGroup, List<EFContainer> containersToRenormalize, ExternalXMLModelChange undoModelChange)
        {
            var changedEFObject = undoModelChange.ChangedEFObject;
            var parentEFObject = undoModelChange.Parent;

            if (parentEFObject != null)
            {
                var parentEFContainer = parentEFObject as EFContainer;
                Debug.Assert(parentEFContainer != null, "parentEFObject was not an EFContainer!");

                // if this is an "add" for an element, then the parent will parse the new child.
                // if this is an "add" for an attribute, then we have to directly set the XObject
                // if this is an "update" then we will just record it in our model
                if (parentEFContainer != null
                    &&
                    undoModelChange.Action == XObjectChange.Add)
                {
                    var newXElement = undoModelChange.XNode as XElement;

                    if (newXElement != null
                        &&
                        parentEFContainer.ReparseSingleElement(new List<XName>(), newXElement))
                    {
                        var newEFObject = ModelItemAnnotation.GetModelItem(undoModelChange.XNode);
                        Debug.Assert(newEFObject != null, "Couldn't find the ModelItemAnnotation for the newly created XLinq node");
                        if (newEFObject != null)
                        {
                            var newEFElement = newEFObject as EFElement;
                            Debug.Assert(newEFElement != null, "If the XObject was an XElement, then we should have an EFElement as well");
                            if (newEFElement != null)
                            {
                                XmlModelHelper.NormalizeAndResolve(newEFElement);
                            }

                            // we need to rediscover the XLinq annotation to pick up the new EFObject that just got created
                            changedEFObject = ModelItemAnnotation.GetModelItem(undoModelChange.XNode);
                        }
                    }
                    else if (undoModelChange.XNode is XAttribute)
                    {
                        var staleItemBinding = changedEFObject as ItemBinding;
                        var staleDefaultableValue = changedEFObject as DefaultableValue;

                        // item bindings might have gotten added after their parents got added in which case the MIA will be stale.
                        // we have to step through the new parent, set the xobject manually, rebind, and reset the annotation on the xlinq node.
                        if (staleItemBinding != null)
                        {
                            foreach (var child in parentEFContainer.Children)
                            {
                                var updatedItemBinding = child as ItemBinding;
                                if (updatedItemBinding != null
                                    && updatedItemBinding.EFTypeName == staleItemBinding.EFTypeName)
                                {
                                    updatedItemBinding.SetXObject(undoModelChange.XNode);
                                    updatedItemBinding.Rebind();
                                    changedEFObject = updatedItemBinding;
                                }
                            }
                        }

                            // for defaultable values that got added after parents were added, we have to discover the actual EFObject in the Escher tree,
                            // set the xobject, and reset the annotation on the existing xlinq node
                        else if (staleDefaultableValue != null)
                        {
                            foreach (var child in parentEFContainer.Children)
                            {
                                var updatedDefaultableValue = child as DefaultableValue;
                                if (updatedDefaultableValue != null
                                    && updatedDefaultableValue.EFTypeName == staleDefaultableValue.EFTypeName)
                                {
                                    updatedDefaultableValue.SetXObject(undoModelChange.XNode);
                                    changedEFObject = updatedDefaultableValue;
                                }
                            }
                        }

                        ModelItemAnnotation.SetModelItem(undoModelChange.XNode, changedEFObject);
                    }
                }
                else if (undoModelChange.Action == XObjectChange.Value)
                {
                    Debug.Assert(undoModelChange.XNode is XAttribute, "The only 'value' change Escher supports is to XAttributes");
                    if (undoModelChange.XNode is XAttribute)
                    {
                        var existingItemBinding = changedEFObject as ItemBinding;
                        if (existingItemBinding != null)
                        {
                            existingItemBinding.Rebind();
                        }

                        // we have to normalize and resolve the parents of DefaultableValues
                        // because this change could affect the parent's RefName, affecting SingleItemBindings
                        var defaultableValue = changedEFObject as DefaultableValue;
                        if (defaultableValue != null)
                        {
                            XmlModelHelper.NormalizeAndResolve(parentEFContainer);
#if DEBUG
                            var xattr = undoModelChange.XNode as XAttribute;
                            var defaultableValueValue = defaultableValue.ObjectValue as string;
                            if (defaultableValueValue != null)
                            {
                                // verify that the defaultableValue's value & the XAttribute's value are the same
                                Debug.Assert(xattr.Value == defaultableValueValue);
                            }
#endif
                        }
                    }
                }
                else
                {
                    Debug.Assert(false, "Encountered a non-valid type of change to the XML: " + undoModelChange.Action.ToString());
                    throw new ChangeProcessingFailedException();
                }

                // if an object's state is unresolved, then queue it for re-normalization. This occurs
                // for example, if itembinding changes occur before the 'add' changes for their targeted objects
                var itemBinding = changedEFObject as ItemBinding;
                if ((itemBinding != null && false == itemBinding.Resolved)
                    || parentEFContainer.State != EFElementState.Resolved)
                {
                    containersToRenormalize.Add(parentEFContainer);
                }
                CheckObjectToRenormalize(changedEFObject, ref containersToRenormalize);

                // now tell the views that a new item has been created; this will happen for both an 'add' and a 'change'
                string oldValue = null;
                string newValue = null;
                string property = null;
                GetOldAndNewValues(undoModelChange.XmlChange, out property, out oldValue, out newValue);

                changeGroup.RecordModelChange(GetChangeType(undoModelChange.XmlChange), changedEFObject, property, oldValue, newValue);
            }
            else
            {
                // we got a change event on a root-node in the document.  
                // This will cause an NRE when looking for the model-item annotation,
                // so throw this exception to cause the caller to reload the doc
                throw new ChangeProcessingFailedException();
            }
        }
Exemplo n.º 5
0
        private static void ProcessExternalRemoveChange(
            EfiChangeGroup changeGroup, IList<ItemBinding> bindingsForRebind, ExternalXMLModelChange modelChange)
        {
            var changedEFObject = modelChange.ChangedEFObject;
            var parentEFObject = modelChange.Parent;
            if (changedEFObject != null)
            {
                var staleItemBinding = changedEFObject as ItemBinding;
                var staleDefaultableValue = changedEFObject as DefaultableValue;

                var parentEFContainer = parentEFObject as EFContainer;
                Debug.Assert(parentEFContainer != null, "parentEfObject was not an EFContainer!");
                if (staleItemBinding != null)
                {
                    // if this is an itembinding, then we have to directly null out the xobject and rebind since the refname is a "symlink" to the xattribute
                    foreach (var child in parentEFContainer.Children)
                    {
                        var updatedItemBinding = child as ItemBinding;
                        if (updatedItemBinding != null
                            && updatedItemBinding.EFTypeName == staleItemBinding.EFTypeName)
                        {
                            updatedItemBinding.SetXObject(null);
                            updatedItemBinding.Rebind();
                            changedEFObject = updatedItemBinding;
                            break;
                        }
                    }
                }
                else if (staleDefaultableValue != null)
                {
                    foreach (var child in parentEFContainer.Children)
                    {
                        var updatedDefaultableValue = child as DefaultableValue;
                        if (updatedDefaultableValue != null
                            && updatedDefaultableValue.EFTypeName == staleDefaultableValue.EFTypeName)
                        {
                            updatedDefaultableValue.SetXObject(null);
                            changedEFObject = updatedDefaultableValue;
                            break;
                        }
                    }
                }
                else
                {
                    // Find all the dependent binding.
                    var visitor = new AntiDependencyCollectorVisitor();
                    visitor.Traverse(changedEFObject);
                    foreach (var binding in visitor.AntiDependencyBindings)
                    {
                        if (!bindingsForRebind.Contains(binding))
                        {
                            bindingsForRebind.Add(binding);
                        }
                    }
                    // Delete(false) because it has already been removed from XLinq tree
                    changedEFObject.Delete(false);
                }

                // record the change so views get updated
                changeGroup.RecordModelChange(EfiChange.EfiChangeType.Delete, changedEFObject, String.Empty, String.Empty, String.Empty);
            }
            else
            {
                throw new ChangeProcessingFailedException();
            }
        }
Exemplo n.º 6
0
        private EfiChangeGroup ProcessUndoRedoChanges(XmlTransactionEventArgs xmlTransactionEventArgs)
        {
            using (var tx = new EfiTransaction(this, EfiTransactionOriginator.UndoRedoOriginatorId, xmlTransactionEventArgs.Transaction))
            {
                var changeGroup = tx.ChangeGroup;
                var undoChanges = new List<ExternalXMLModelChange>();
                var containersToRenormalize = new List<EFContainer>();
                var bindingsForRebind = new List<ItemBinding>();
                var namespaces = GetNamespaces();

                // filter the changes received from XmlEditor and resolve changed EFObjects and their parents
                foreach (var xmlChange in xmlTransactionEventArgs.Transaction.Changes())
                {
                    // determine how to process this edit
                    if (xmlChange.Node.NodeType == XmlNodeType.Element
                        || xmlChange.Node.NodeType == XmlNodeType.Attribute
                        || xmlChange.Node.NodeType == XmlNodeType.Document)
                    {
                        if (xmlChange.Node.NodeType == XmlNodeType.Element
                            && xmlChange.Action == XObjectChange.Value)
                        {
                            var nodeValueChange = xmlChange as IXmlNodeValueChange;
                            Debug.Assert(
                                nodeValueChange != null
                                && string.IsNullOrEmpty(nodeValueChange.OldValue)
                                && string.IsNullOrEmpty(nodeValueChange.NewValue));

                            // in cases where we are undoing the addition of all children to an element A, the Xml Model
                            // will forcibly add an empty string to the element A so that a "short" end tag "/>" is not created
                            // in this case, the change we will receive is a set value change on an element; we ignore this
                        }
                        else
                        {
                            var emc = new ExternalXMLModelChange(xmlChange, ExpectEFObjectForXObject);
                            if (emc.IsAnnotationChange(namespaces))
                            {
                                continue;
                            }

                            undoChanges.Add(emc);
                        }
                    }
                }

                // go through the undo changes and make changes to the model
                foreach (var undoModelChange in undoChanges)
                {
                    // Should ignore other artifact changes.
                    if (undoModelChange.ChangedEFObject.Artifact != this)
                    {
                        continue;
                    }

                    if (undoModelChange.Action == XObjectChange.Remove)
                    {
                        ProcessExternalRemoveChange(changeGroup, bindingsForRebind, undoModelChange);
                    }
                    else
                    {
                        ProcessExternalAddOrUpdateChange(changeGroup, containersToRenormalize, undoModelChange);
                    }
                }

                // because of the order in which elements were possibly added, certain ItemBindings were not resolved;
                // therefore we have to step through the normalized EFElements again and normalize/resolve so their child
                // ItemBindings will get resolved.
                foreach (var container in containersToRenormalize)
                {
                    XmlModelHelper.NormalizeAndResolve(container);
                }
                XmlModelHelper.RebindItemBindings(bindingsForRebind);

#if DEBUG
                var visitor = GetVerifyModelIntegrityVisitor();
                visitor.Traverse(this);

                if (visitor.ErrorCount > 0)
                {
                    Debug.WriteLine("Model Integrity Verifier found " + visitor.ErrorCount + " error(s):");
                    Debug.WriteLine(visitor.AllSerializedErrors);
                    Debug.Assert(
                        false, "Model Integrity Verifier found " + visitor.ErrorCount + " error(s). See the Debug console for details.");
                }
#endif
                return changeGroup;
            }
        }