[NUIComponents] Roll back error modification
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / Common / Container.cs
index 799251c..13577bf 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright(c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 using System;
 using System.Collections.Generic;
+using System.ComponentModel;
 using Tizen.NUI.BaseComponents;
+using Tizen.NUI.Binding;
+using Tizen.NUI.Binding.Internals;
 
 namespace Tizen.NUI
 {
@@ -26,16 +29,76 @@ namespace Tizen.NUI
     /// added to them.
     /// </summary>
     /// <since_tizen> 4 </since_tizen>
-    public abstract class Container : Animatable
+    public abstract class Container : Animatable, IResourcesProvider
     {
+        /// <summary> XamlStyleProperty </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly BindableProperty XamlStyleProperty = BindableProperty.Create(nameof(XamlStyle), typeof(XamlStyle), typeof(Container), default(XamlStyle), propertyChanged: (bindable, oldvalue, newvalue) => ((View)bindable).MergedStyle.Style = (XamlStyle)newvalue);
+
         internal BaseHandle InternalParent;
         private List<View> childViews = new List<View>();
+        private MergedStyle mergedStyle = null;
+        ResourceDictionary _resources;
+        bool IResourcesProvider.IsResourcesCreated => _resources != null;
 
         internal Container(global::System.IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn)
         {
             // No un-managed data hence no need to store a native ptr
         }
 
+        /// This will be public opened in tizen_next after ACR done. Before ACR, need to be hidden as inhouse API.
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public ResourceDictionary XamlResources
+        {
+            get
+            {
+                if (_resources != null)
+                    return _resources;
+                _resources = new ResourceDictionary();
+                ((IResourceDictionary)_resources).ValuesChanged += OnResourcesChanged;
+                return _resources;
+            }
+            set
+            {
+                if (_resources == value)
+                    return;
+                OnPropertyChanging();
+                if (_resources != null)
+                    ((IResourceDictionary)_resources).ValuesChanged -= OnResourcesChanged;
+                _resources = value;
+                OnResourcesChanged(value);
+                if (_resources != null)
+                    ((IResourceDictionary)_resources).ValuesChanged += OnResourcesChanged;
+                OnPropertyChanged();
+            }
+        }
+
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public XamlStyle XamlStyle
+        {
+            get
+            {
+                return (XamlStyle)GetValue(XamlStyleProperty);
+            }
+            set
+            {
+                SetValue(XamlStyleProperty, value);
+            }
+        }
+
+        internal MergedStyle MergedStyle
+        {
+            get
+            {
+                if (null == mergedStyle)
+                {
+                    mergedStyle = new MergedStyle(GetType(), this);
+                }
+
+                return mergedStyle;
+            }
+        }
+
         /// <summary>
         /// List of children of Container.
         /// </summary>
@@ -80,6 +143,119 @@ namespace Tizen.NUI
         }
 
         /// <summary>
+        /// Copy all properties, bindings.
+        /// Copy children without xName from other container, copy all properties, bindings of children with xName.
+        /// </summary>
+        /// <param name="other"></param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void CopyAndKeepXNameInstance(Container other)
+        {
+            CopyFrom(other);
+
+            var nameScopeOfOther = NameScope.GetNameScope(other) as NameScope;
+            var nameScope = NameScope.GetNameScope(this) as NameScope;
+
+            if (null == nameScopeOfOther)
+            {
+                if (null != nameScope)
+                {
+                    return;
+                }
+            }
+            else if (!nameScopeOfOther.Equal(nameScope))
+            {
+                return;
+            }
+
+            var xNameToElementsOfOther = nameScopeOfOther?.NameToElement;
+            var xNameToElements = nameScope?.NameToElement;
+
+            if (null != xNameToElements)
+            {
+                foreach (var pair in xNameToElements)
+                {
+                    if (pair.Value is View view)
+                    {
+                        view.Parent?.Remove(view);
+                    }
+                }
+            }
+
+            for (int i = Children.Count - 1; i >= 0; i--)
+            {
+                var child = GetChildAt((uint)i);
+                Remove(child);
+
+                child.DisposeIncludeChildren();
+            }
+
+            CopyChildren(other);
+
+            if (null != xNameToElementsOfOther)
+            {
+                foreach (var pair in xNameToElementsOfOther)
+                {
+                    if (pair.Value is View view)
+                    {
+                        var parent = view.Parent;
+
+                        if (null != parent)
+                        {
+                            if ((null != xNameToElements) && (xNameToElements[pair.Key] is View holdedXElements))
+                            {
+                                holdedXElements.CopyBindingRelationShip(view);
+                                holdedXElements.CopyFrom(view);
+
+                                parent.ReplaceChild(view, holdedXElements);
+                            }
+                        }
+                    }
+                }
+            }
+
+            ReplaceBindingElementInWholeTree(xNameToElementsOfOther, xNameToElements);
+
+            if (null != xNameToElementsOfOther)
+            {
+                foreach (var pair in xNameToElementsOfOther)
+                {
+                    if (pair.Value is View view)
+                    {
+                        view.Dispose();
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Dispose itself and all children recursively.
+        /// We can call this even itself is disposed.
+        /// </summary>
+        /// <remarks>
+        /// Note that Container.DisposeIncludeChildren() disposed only if it created by xaml.
+        /// </remarks>
+        /// <remarks>
+        /// This is a hidden API(inhouse API) only for internal purpose.
+        /// </remarks>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void DisposeRecursively()
+        {
+            // To avoid useless "OnChildRemoved" callback invoke, Dispose itself before children.
+            if(!Disposed && !IsDisposeQueued)
+            {
+                Dispose();
+            }
+
+            foreach (View child in Children)
+            {
+                child.DisposeRecursively();
+            }
+
+            // Make sure that itself don't have children anymore.
+            childViews?.Clear();
+        }
+
+        /// <summary>
         /// Adds a child view to this Container.
         /// </summary>
         /// <pre>This Container (the parent) has been initialized. The child view has been initialized. The child view is not the same as the parent view.</pre>
@@ -121,9 +297,122 @@ namespace Tizen.NUI
         /// <pre>The container has been initialized.</pre>
         /// <returns>The number of children.</returns>
         /// <since_tizen> 4 </since_tizen>
-        [Obsolete("Deprecated in API9, will be removed in API11. Please use ChildCount property instead!")]
+        [Obsolete("This has been deprecated in API9 and will be removed in API11. Use ChildCount property instead.")]
         public abstract UInt32 GetChildCount();
 
         internal abstract View FindCurrentChildById(uint id);
+
+        internal override void OnParentResourcesChanged(IEnumerable<KeyValuePair<string, object>> values)
+        {
+            if (values == null)
+                return;
+
+            if (!((IResourcesProvider)this).IsResourcesCreated || XamlResources.Count == 0)
+            {
+                base.OnParentResourcesChanged(values);
+                return;
+            }
+
+            var innerKeys = new HashSet<string>();
+            var changedResources = new List<KeyValuePair<string, object>>();
+            foreach (KeyValuePair<string, object> c in XamlResources)
+                innerKeys.Add(c.Key);
+            foreach (KeyValuePair<string, object> value in values)
+            {
+                if (innerKeys.Add(value.Key))
+                    changedResources.Add(value);
+            }
+            if (changedResources.Count != 0)
+                OnResourcesChanged(changedResources);
+        }
+
+        /// <summary>
+        /// Invoked whenever the binding context of the element changes. Implement this method to add class handling for this event.
+        /// </summary>
+        /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected override void OnBindingContextChanged()
+        {
+            var gotBindingContext = false;
+            object bc = null;
+
+            for (var index = 0; index < Children.Count; index++)
+            {
+                Element child = Children[index];
+
+                if (!gotBindingContext)
+                {
+                    bc = BindingContext;
+                    gotBindingContext = true;
+                }
+
+                SetChildInheritedBindingContext(child, bc);
+            }
+            base.OnBindingContextChanged();
+        }
+
+        private void DisposeIncludeChildren()
+        {
+            foreach (var child in Children)
+            {
+                child.DisposeIncludeChildren();
+            }
+
+            if (IsCreateByXaml)
+            {
+                Dispose();
+                ClearBinding();
+            }
+        }
+
+        private void CopyChildren(Container other)
+        {
+            var childrenOfOtherView = new List<View>();
+
+            foreach (var child in other.Children)
+            {
+                childrenOfOtherView.Add(child);
+            }
+
+            foreach (var child in childrenOfOtherView)
+            {
+                Add(child);
+            }
+        }
+
+        private void ReplaceChild(View child, View newChild)
+        {
+            int indexOfView = Children.FindIndex((View v) => { return v == child; });
+
+            var childrenNeedtoReAdd = new Stack<View>();
+
+            for (int i = Children.Count - 1; i > indexOfView; i--)
+            {
+                childrenNeedtoReAdd.Push(Children[i]);
+                Remove(Children[i]);
+            }
+
+            Remove(child);
+
+            childrenNeedtoReAdd.Push(newChild);
+
+            while (0 < childrenNeedtoReAdd.Count)
+            {
+                Add(childrenNeedtoReAdd.Pop());
+            }
+        }
+
+        private void ReplaceBindingElementInWholeTree(Dictionary<string, object> oldNameScope, Dictionary<string, object> newNameScope)
+        {
+            if (IsCreateByXaml)
+            {
+                ReplaceBindingElement(oldNameScope, newNameScope);
+
+                foreach (var child in Children)
+                {
+                    child.ReplaceBindingElementInWholeTree(oldNameScope, newNameScope);
+                }
+            }
+        }
     }
 } // namespace Tizen.NUI