Esempio n. 1
0
        protected virtual void AddToXlinq(string attributeValue)
        {
            Debug.Assert(XObject == null, "Object already serialized");

            // sometimes we want to lazy create the attribute when it's first set
            if (!string.IsNullOrEmpty(EFTypeName))
            {
                Debug.Assert(
                    Parent != null && Parent.XContainer != null, "Can't serialize this if the Parent or it's XContainer is missing");

                XAttribute attribute = null;
                if (Namespace != null)
                {
                    attribute = new XAttribute(Namespace + EFTypeName, attributeValue);
                }
                else
                {
                    attribute = new XAttribute(EFTypeName, attributeValue);
                }

                SetXObject(attribute);
                ModelItemAnnotation.SetModelItem(attribute, this);

                // always append attributes
                Parent.XContainer.Add(attribute);
            }
        }
Esempio n. 2
0
        /// <summary>
        ///     NOTE: this is called from the EFObject c'tor so only that class is fully instantiated!
        /// </summary>
        /// <param name="parent"></param>
        /// <returns></returns>
        protected override void AddToXlinq()
        {
            State = EFElementState.ParseAttempted;

            Debug.Assert(XObject == null, "Object already serialized");
            Debug.Assert(!string.IsNullOrEmpty(EFTypeName), "Can't create XElement without the name");
            Debug.Assert(Parent != null && Parent.XContainer != null, "Can't serialize this if the Parent or it's XContainer is missing");

            var ns      = Artifact.ModelManager.GetRootNamespace(Parent);
            var element = new XElement(ns == null ? EFTypeName : ns + EFTypeName);

            SetXObject(element);
            ModelItemAnnotation.SetModelItem(element, this);

            AddXElementToParent(element);

            State = EFElementState.Parsed;
        }
Esempio n. 3
0
        protected EFObject(EFContainer parent, XObject xobject)
        {
            // note that it is OK if parent is null here; derived classes should assert
            // in their own constructor if they want to ensure that parent is not null
            _parent = parent;

            if (xobject == null)
            {
                // Incase parent is null, elements will be created without any namespace
                // the implementation of AddToXLinq will add the model item annotation.
                AddToXlinq();
            }
            else
            {
                _xobject = xobject;
                ModelItemAnnotation.SetModelItem(_xobject, this);
            }

            Debug.Assert(_xobject == null || ModelItemAnnotation.GetModelItem(_xobject) != null, "xobject didn't have a model annotation!");

            SetState(IS_CONSTRUCTION_COMPLETED);
        }
Esempio 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();
            }
        }
Esempio n. 5
0
        /// <summary>
        ///     Move Property's XElement before the specified position.
        ///     If position parameter is null, the property XElement will be moved to the last position.
        /// </summary>
        internal void MoveTo(InsertPropertyPosition position)
        {
            Debug.Assert(
                PreviousSiblingInPropertyXElementOrder != null || NextSiblingInPropertyXElementOrder != null,
                "Why do we need to move the property if it is the only property?");
            Debug.Assert(position != null, "InsertPropertyPosition parameter is null.");
            if (position != null)
            {
                // Check if the InsertPropertyPosition's InsertAt is not null.
                Debug.Assert(position.InsertAtProperty != null, "Why InsertPropertyPosition's InsertAt is null?");
                if (position.InsertAtProperty != null)
                {
                    // Instead of re-parenting the property's XElement, we are going to clone the XElement, insert the clone and delete the old XElement.
                    // This is a workaround for an XML editor bug where re-parenting an element causes asserts.

                    // First create the new XElement.
                    var tempDoc             = XDocument.Parse(XElement.ToString(SaveOptions.None), LoadOptions.None);
                    var newPropertyXElement = tempDoc.Root;
                    newPropertyXElement.Remove();

                    // Remove known namespaces from the element since the namespaces are already set in the parent node.
                    // This is workaround because XDocument automatically appends the default namespace in the property XElement.
                    foreach (var a in newPropertyXElement.Attributes())
                    {
                        if (a.IsNamespaceDeclaration &&
                            (a.Value == SchemaManager.GetCSDLNamespaceName(Artifact.SchemaVersion) ||
                             a.Value == SchemaManager.GetSSDLNamespaceName(Artifact.SchemaVersion) ||
                             a.Value == SchemaManager.GetAnnotationNamespaceName()))
                        {
                            a.Remove();
                        }
                    }

                    var toBeDeleteElement = XElement;

                    // format the XML we just parsed so that the XElement will have the same indenting.
                    Utils.FormatXML(newPropertyXElement, GetIndentLevel());

                    // Call method that will insert the XElement to the specified location.
                    InsertPosition = position;
                    AddXElementToParent(newPropertyXElement);

                    // Re-establish the links between EFElement and XElement.
                    SetXObject(newPropertyXElement);
                    Debug.Assert(
                        XElement == newPropertyXElement,
                        "Unexpected XElement value. Expected:" + newPropertyXElement + " , Actual:" + XElement);

                    ModelItemAnnotation.SetModelItem(newPropertyXElement, this);
                    Debug.Assert(
                        ModelItemAnnotation.GetModelItem(newPropertyXElement) == this,
                        "The new XElement should contain annotation to the model property.");

                    // Delete both old XElement and the preceding whitespace.
                    // Preceding whitespace is preferred over trailing whitespace because we don't want to remove the last property's trailing white-space since
                    // it has different indent level than the rest (see EFElement's EnsureFirstNodeWhitespaceSeparation method).
                    var preceedingNewLine = toBeDeleteElement.PreviousNode as XText;
                    while (preceedingNewLine != null &&
                           String.IsNullOrWhiteSpace(preceedingNewLine.Value))
                    {
                        var toBeDeletedWhiteSpace = preceedingNewLine;
                        preceedingNewLine = preceedingNewLine.PreviousNode as XText;
                        toBeDeletedWhiteSpace.Remove();
                    }
                    toBeDeleteElement.Remove();

#if DEBUG
                    // Assert if the property is not moved to the correct location.
                    if (position.InsertBefore)
                    {
                        Debug.Assert(
                            position.InsertAtProperty == NextSiblingInPropertyXElementOrder,
                            "Expected next sibling property: " + position.InsertAtProperty.DisplayName + " , Actual next sibling:"
                            + NextSiblingInPropertyXElementOrder.DisplayName);
                    }
                    else
                    {
                        Debug.Assert(
                            position.InsertAtProperty == PreviousSiblingInPropertyXElementOrder,
                            "Expected previous sibling property: " + position.InsertAtProperty.DisplayName + " , Actual previous sibling:"
                            + PreviousSiblingInPropertyXElementOrder.DisplayName);
                    }
#endif
                }
            }
        }