Пример #1
0
        /// <summary>
        /// Event handler that is called when the document node has disposed or name changed. Because the path to the node can have changed too,
        /// the path is renewed in this case. The <see cref="OnChanged" /> method is called then for the proxy itself.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="source"></param>
        /// <param name="e"></param>
        private void EhDocNode_TunneledEvent(object sender, object source, Main.TunnelingEventArgs e)
        {
            if (IsDisposeInProgress)
            {
                return;
            }

#if DEBUG_DOCNODEPROXYLOGGING
            Current.Console.WriteLine("RelDocNodeProxy.EhDocNode_TunneledEvent: sender={0}, source={1} e={2}", sender, source, e);
#endif

            bool shouldFireChangedEvent = false;
            var  senderAsNode           = source as IDocumentLeafNode;
            if (!(senderAsNode != null))
            {
                throw new InvalidProgramException();
            }

            if (e is DisposeEventArgs)
            {
                // when our DocNode was disposed, it is probable that the parent of this node (and further parents) are disposed too
                // thus we need to watch the first node that is not disposed
                var docNode = InternalDocNode;
                ClearDocNode();

                if (!(sender is AltaxoDocument)) // if the whole document is disposed, there is no point in trying to watch something
                {
                    // note Dispose is designed to let the hierarchy from child to parent (root) valid, but not from root to child!
                    // thus trying to get an actual document path here is in must cases unsuccessfull. We have to rely on our stored path, and that it was always updated!
                    // the only case were it is successfull if a new node immediately replaces an old document node

                    var node = RelativeDocumentPath.GetNodeOrLeastResolveableNode(_docNodePath, senderAsNode, out var wasResolvedCompletely);
                    if (wasResolvedCompletely)
                    {
                        InternalSetDocNode(node, _parent);
                    }
                    else
                    {
                        SetWatchOnNode(node);
                    }

                    shouldFireChangedEvent = true;
                }
            }
            else if (e is DocumentPathChangedEventArgs)
            {
                if (null != InternalDocNode)
                {
                    InternalDocumentPath = RelativeDocumentPath.GetRelativePathFromTo(_parent, InternalDocNode);
                }

                shouldFireChangedEvent = true;
            }

            if (shouldFireChangedEvent)
            {
                EhSelfChanged(EventArgs.Empty);
            }
        }
Пример #2
0
        /// <summary>
        /// Sets the document node that is held by this proxy.
        /// </summary>
        /// <param name="value">The document node. If <c>docNode</c> implements <see cref="Main.IDocumentLeafNode" />,
        /// the document path is stored for this object in addition to the object itself.</param>
        /// <param name="parentNode">The start point of the document path. Should be equal to the member _parent, but this might be not set now.</param>
        protected void InternalSetDocNode(Main.IDocumentLeafNode value, IDocumentLeafNode parentNode)
        {
            if (!IsValidDocument(value))
            {
                throw new ArgumentException("This type of document is not allowed for the proxy of type " + GetType().ToString());
            }
            if (null == parentNode)
            {
                throw new InvalidOperationException("Parent of this node must be set in order to set the docnode.");
            }

            var oldValue = InternalDocNode;

            if (object.ReferenceEquals(oldValue, value))
            {
                return; // Nothing to do
            }
            if (null != _weakDocNodeChangedHandler)
            {
                _weakDocNodeChangedHandler.Remove();
                _weakDocNodeChangedHandler = null;
            }
            if (null != _weakDocNodeTunneledEventHandler)
            {
                _weakDocNodeTunneledEventHandler.Remove();
                _weakDocNodeTunneledEventHandler = null;
            }

            if (null != oldValue)
            {
                ClearDocNode();
            }

            var newPath = RelativeDocumentPath.GetRelativePathFromTo(parentNode, value);

            if (null != newPath)
            {
                InternalDocumentPath = newPath; // especially in dispose situations, the new path can be null. In this case we leave the path as it was
            }
            _docNodeRef = new WeakReference(value);

#if DEBUG_DOCNODEPROXYLOGGING
            Current.Console.WriteLine("RelDocNodeProxy.SetDocNode, path is <<{0}>>", _docNodePath);
#endif

            value.TunneledEvent += (_weakDocNodeTunneledEventHandler = new WeakActionHandler <object, object, TunnelingEventArgs>(EhDocNode_TunneledEvent, handler => value.TunneledEvent -= handler));

            if (null != _docNodePath && !_docNodePath.IsIdentity) // it does not make sense to watch the changed event of our target node is our parent because the parent can handle the Changed event itself
            {
                value.Changed += (_weakDocNodeChangedHandler = new WeakEventHandler(EhDocNode_Changed, handler => value.Changed -= handler));
            }

            OnAfterSetDocNode();

            EhSelfChanged(new Main.InstanceChangedEventArgs(oldValue, value));
        }
Пример #3
0
        /// <summary>
        /// Event handler that is called when the watched node or a parent node below has disposed or its name changed. We then try to resolve the path again.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="source">Source of the tunneled event.</param>
        /// <param name="e"></param>
        private void EhWatchedNode_TunneledEvent(object sender, object source, Main.TunnelingEventArgs e)
        {
            if (IsDisposeInProgress)
            {
                return;
            }

            if (!(_docNodeRef == null))
            {
                throw new InvalidProgramException();
            }
            var senderAsDocNode = sender as IDocumentLeafNode;
            var sourceAsDocNode = source as IDocumentLeafNode;

            if (!(senderAsDocNode != null))
            {
                throw new InvalidProgramException();
            }
            if (!(sourceAsDocNode != null))
            {
                throw new InvalidProgramException();
            }

            // then we try to resolve the path again
            if ((e is DisposeEventArgs) || (e is DocumentPathChangedEventArgs))
            {
#if DEBUG_DOCNODEPROXYLOGGING
                Current.Console.WriteLine("DocNodeProxy.EhWatchedNode_TunneledEvent");
#endif

                var node = RelativeDocumentPath.GetNodeOrLeastResolveableNode(_docNodePath, sourceAsDocNode, out var wasResolvedCompletely);
                if (null == node)
                {
                    throw new InvalidProgramException(nameof(node) + " should always be != null, since we use absolute paths, and at least an AltaxoDocument should be resolved here.");
                }

                if (wasResolvedCompletely)
                {
                    ClearWatch();
                    InternalSetDocNode(node, _parent);
                }
                else // not completely resolved
                {
                    if (!object.ReferenceEquals(sender, node))
                    {
                        ClearWatch();
                        SetWatchOnNode(node);
                    }
                }
            }
        }
Пример #4
0
        public override void EhParentTunnelingEventHappened(IDocumentNode sender, IDocumentNode originalSource, TunnelingEventArgs e)
        {
            // since we deal with relative path, we have to watch changes to our path too
            if (e is Main.DocumentPathChangedEventArgs)
            {
                var node = InternalDocNode;
                if (null != node)
                {
                    _docNodePath = RelativeDocumentPath.GetRelativePathFromTo(_parent, node);
                }
            }

            base.EhParentTunnelingEventHappened(sender, originalSource, e);
        }
Пример #5
0
        /// <summary>
        /// Event handler that is called when the document node has changed. Because the path to the node can have changed too,
        /// the path is renewed in this case. The <see cref="OnChanged" /> method is called then for the proxy itself.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void EhDocNode_Changed(object sender, EventArgs e)
        {
            if (IsDisposeInProgress)
            {
                return;
            }

#if DEBUG_DOCNODEPROXYLOGGING
            Current.Console.WriteLine("DocNodeProxy.EhDocNode_Changed: sender={0}, e={1}", sender, e);
#endif

            if (null != InternalDocNode)
            {
                _docNodePath = RelativeDocumentPath.GetRelativePathFromTo(_parent, InternalDocNode);
            }

            EhSelfChanged(EventArgs.Empty);
        }
Пример #6
0
        /// <summary>
        /// Gets the node that is designated by the provided <paramref name="path"/>  or the least resolveable node.
        /// </summary>
        /// <param name="path">The document path to resolve.</param>
        /// <param name="startnode">The startnode.</param>
        /// <param name="pathWasCompletelyResolved">If set to <c>true</c> on return, the path was completely resolved. Otherwise, <c>false</c>.</param>
        /// <returns>The resolved node, or the least node on the path that could be resolved.</returns>
        /// <exception cref="System.ArgumentNullException">
        /// path
        /// or
        /// startnode
        /// </exception>
        public static IDocumentLeafNode GetNodeOrLeastResolveableNode(RelativeDocumentPath path, IDocumentLeafNode startnode, out bool pathWasCompletelyResolved)
        {
            if (null == path)
            {
                throw new ArgumentNullException(nameof(path));
            }
            if (null == startnode)
            {
                throw new ArgumentNullException(nameof(startnode));
            }

            var node     = startnode;
            var prevNode = startnode;

            for (int i = 0; i < path._numberOfLevelsDown && null != node; ++i)
            {
                prevNode = node;
                node     = node.ParentNode;
            }

            if (null == node)
            {
                pathWasCompletelyResolved = false;
                return(prevNode);
            }

            pathWasCompletelyResolved = true;
            for (int i = 0; i < path._pathParts.Length && null != node; i++)
            {
                prevNode = node;

                if (node is Main.IDocumentNode)
                {
                    node = ((Main.IDocumentNode)node).GetChildObjectNamed(path._pathParts[i]);
                }
                else
                {
                    node = null;
                }
            } // end for

            pathWasCompletelyResolved = null != node;
            return(node ?? prevNode);
        }
Пример #7
0
        /// <summary>
        /// Event handler that is called when the watched node (a node that is not the document node) has changed. Maybe this watched node had now created a parent node, and our
        /// document path can resolved now. That's why we try to resolve our document path now.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void EhWatchedNode_Changed(object sender, EventArgs e)
        {
            if (IsDisposeInProgress)
            {
                return;
            }

#if DEBUG_DOCNODEPROXYLOGGING
            Current.Console.WriteLine("DocNodeProxy.EhWatchedNode_Changed: sender={0}, e={1}", sender, e);
#endif

            if (!(_docNodeRef == null))
            {
                throw new InvalidProgramException();
            }
            var senderAsDocNode = sender as IDocumentLeafNode;
            if (!(senderAsDocNode != null))
            {
                throw new InvalidProgramException();
            }


            var node = RelativeDocumentPath.GetNodeOrLeastResolveableNode(_docNodePath, senderAsDocNode, out var wasResolvedCompletely);
            if (null == node)
            {
                throw new InvalidProgramException("node should always be != null, since we use absolute paths, and at least an AltaxoDocument should be resolved here.");
            }

            if (wasResolvedCompletely)
            {
                ClearWatch();
                InternalSetDocNode(node, _parent);
            }
            else // not completely resolved
            {
                if (!object.ReferenceEquals(sender, node))
                {
                    ClearWatch();
                    SetWatchOnNode(node);
                }
            }
        }
Пример #8
0
        public static IDocumentLeafNode GetObject(RelativeDocumentPath path, IDocumentLeafNode startnode)
        {
            if (null == path)
            {
                throw new ArgumentNullException(nameof(path));
            }
            if (null == startnode)
            {
                throw new ArgumentNullException(nameof(startnode));
            }

            var node = startnode;

            for (int i = 0; i < path._numberOfLevelsDown && null != node; ++i)
            {
                node = node.ParentNode;
            }

            if (null == node)
            {
                return(null); // Path not resolveable
            }
            for (int i = 0; i < path._pathParts.Length; i++)
            {
                if (node is Main.IDocumentNode)
                {
                    node = ((Main.IDocumentNode)node).GetChildObjectNamed(path._pathParts[i]);
                }
                else
                {
                    return(null);
                }
            } // end for

            return(node);
        }
Пример #9
0
 public RelativeDocumentPath(RelativeDocumentPath from)
     : this(from._numberOfLevelsDown, from._pathParts)
 {
 }
Пример #10
0
		public RelativeDocumentPath(RelativeDocumentPath from)
			: this(from._numberOfLevelsDown, from._pathParts)
		{
		}
Пример #11
0
		/// <summary>
		/// Gets the node that is designated by the provided <paramref name="path"/>  or the least resolveable node.
		/// </summary>
		/// <param name="path">The document path to resolve.</param>
		/// <param name="startnode">The startnode.</param>
		/// <param name="pathWasCompletelyResolved">If set to <c>true</c> on return, the path was completely resolved. Otherwise, <c>false</c>.</param>
		/// <returns>The resolved node, or the least node on the path that could be resolved.</returns>
		/// <exception cref="System.ArgumentNullException">
		/// path
		/// or
		/// startnode
		/// </exception>
		public static IDocumentLeafNode GetNodeOrLeastResolveableNode(RelativeDocumentPath path, IDocumentLeafNode startnode, out bool pathWasCompletelyResolved)
		{
			if (null == path)
				throw new ArgumentNullException(nameof(path));
			if (null == startnode)
				throw new ArgumentNullException(nameof(startnode));

			var node = startnode;
			var prevNode = startnode;

			for (int i = 0; i < path._numberOfLevelsDown && null != node; ++i)
			{
				prevNode = node;
				node = node.ParentNode;
			}

			if (null == node)
			{
				pathWasCompletelyResolved = false;
				return prevNode;
			}

			pathWasCompletelyResolved = true;
			for (int i = 0; i < path._pathParts.Length && null != node; i++)
			{
				prevNode = node;

				if (node is Main.IDocumentNode)
					node = ((Main.IDocumentNode)node).GetChildObjectNamed(path._pathParts[i]);
				else
					node = null;
			} // end for

			pathWasCompletelyResolved = null != node;
			return node ?? prevNode;
		}
Пример #12
0
		public static IDocumentLeafNode GetObject(RelativeDocumentPath path, IDocumentLeafNode startnode)
		{
			if (null == path)
				throw new ArgumentNullException(nameof(path));
			if (null == startnode)
				throw new ArgumentNullException(nameof(startnode));

			var node = startnode;

			for (int i = 0; i < path._numberOfLevelsDown && null != node; ++i)
			{
				node = node.ParentNode;
			}

			if (null == node)
				return null; // Path not resolveable

			for (int i = 0; i < path._pathParts.Length; i++)
			{
				if (node is Main.IDocumentNode)
					node = ((Main.IDocumentNode)node).GetChildObjectNamed(path._pathParts[i]);
				else
					return null;
			} // end for

			return node;
		}
Пример #13
0
		/// <summary>
		/// Event handler that is called when the document node has disposed or name changed. Because the path to the node can have changed too,
		/// the path is renewed in this case. The <see cref="OnChanged" /> method is called then for the proxy itself.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="source"></param>
		/// <param name="e"></param>
		private void EhDocNode_TunneledEvent(object sender, object source, Main.TunnelingEventArgs e)
		{
			if (IsDisposeInProgress)
				return;

#if DEBUG_DOCNODEPROXYLOGGING
			Current.Console.WriteLine("RelDocNodeProxy.EhDocNode_TunneledEvent: sender={0}, source={1} e={2}", sender, source, e);
#endif

			bool shouldFireChangedEvent = false;
			var senderAsNode = source as IDocumentLeafNode;
			if (!(senderAsNode != null)) throw new InvalidProgramException();

			if (e is DisposeEventArgs)
			{
				// when our DocNode was disposed, it is probable that the parent of this node (and further parents) are disposed too
				// thus we need to watch the first node that is not disposed
				var docNode = InternalDocNode;
				ClearDocNode();

				if (!(sender is AltaxoDocument)) // if the whole document is disposed, there is no point in trying to watch something
				{
					// note Dispose is designed to let the hierarchy from child to parent (root) valid, but not from root to child!
					// thus trying to get an actual document path here is in must cases unsuccessfull. We have to rely on our stored path, and that it was always updated!
					// the only case were it is successfull if a new node immediately replaces an old document node

					bool wasResolvedCompletely;
					var node = RelativeDocumentPath.GetNodeOrLeastResolveableNode(_docNodePath, senderAsNode, out wasResolvedCompletely);
					if (wasResolvedCompletely)
					{
						InternalSetDocNode(node, _parent);
					}
					else
					{
						SetWatchOnNode(node);
					}

					shouldFireChangedEvent = true;
				}
			}
			else if (e is DocumentPathChangedEventArgs)
			{
				if (null != InternalDocNode)
				{
					InternalDocumentPath = RelativeDocumentPath.GetRelativePathFromTo(_parent, InternalDocNode);
				}

				shouldFireChangedEvent = true;
			}

			if (shouldFireChangedEvent)
				EhSelfChanged(EventArgs.Empty);
		}