Fix callback order issue, memory leak issue in GenItem,GenItemClass
authorSeungkeun Lee <sngn.lee@samsung.com>
Mon, 26 Sep 2016 22:57:52 +0000 (07:57 +0900)
committerSeungkeun Lee <sngn.lee@samsung.com>
Mon, 26 Sep 2016 23:28:39 +0000 (08:28 +0900)
 - GenItemClass::DeleteHandler was called, after related item was cleanup
   So, developer can't access to related item in DeleteHandler.
   I change the source of DeleteHandler
 - Memory leak on ItemObject
   s_IdToItemTable and s_HandleToItemTable was not removed when Item was deleted, So ItemObject can't released.

Change-Id: Ibe5ada852f1c1d777ece5667b3aafa5be4cf119d

src/ElmSharp/ElmSharp/GenGrid.cs
src/ElmSharp/ElmSharp/GenItem.cs
src/ElmSharp/ElmSharp/GenItemClass.cs
src/ElmSharp/ElmSharp/GenList.cs
src/ElmSharp/ElmSharp/ItemObject.cs
test/ElmSharp.Test/ElmSharp.Test.csproj
test/ElmSharp.Test/TC/GenListTest6.cs [new file with mode: 0644]

index 8601e1a..3d3db3b 100644 (file)
@@ -236,15 +236,15 @@ namespace ElmSharp
             _unrealized = new Interop.SmartEvent<GenGridItemEventArgs>(this, Handle, "unrealized", GenGridItemEventArgs.CreateFromSmartEvent);
             _longpressed = new Interop.SmartEvent<GenGridItemEventArgs>(this, Handle, "longpressed", GenGridItemEventArgs.CreateFromSmartEvent);
 
-            _selected.On += (s, e) => { ItemSelected?.Invoke(this, e); };
-            _unselected.On += (s, e) => { ItemUnselected?.Invoke(this, e); };
-            _activated.On += (s, e) => { ItemActivated?.Invoke(this, e); };
-            _pressed.On += (s, e) => { ItemPressed?.Invoke(this, e); };
-            _released.On += (s, e) => { ItemReleased?.Invoke(this, e); };
-            _doubleClicked.On += (s, e) => { ItemDoubleClicked?.Invoke(this, e); };
-            _realized.On += (s, e) => { ItemRealized?.Invoke(this, e); };
-            _unrealized.On += (s, e) => { ItemUnrealized?.Invoke(this, e); };
-            _longpressed.On += (s, e) => { ItemLongPressed?.Invoke(this, e); };
+            _selected.On += (s, e) => { if (e.Item != null) ItemSelected?.Invoke(this, e); };
+            _unselected.On += (s, e) => { if (e.Item != null) ItemUnselected?.Invoke(this, e); };
+            _activated.On += (s, e) => { if (e.Item != null) ItemActivated?.Invoke(this, e); };
+            _pressed.On += (s, e) => { if (e.Item != null) ItemPressed?.Invoke(this, e); };
+            _released.On += (s, e) => { if (e.Item != null) ItemReleased?.Invoke(this, e); };
+            _doubleClicked.On += (s, e) => { if (e.Item != null) ItemDoubleClicked?.Invoke(this, e); };
+            _realized.On += (s, e) => { if (e.Item != null) ItemRealized?.Invoke(this, e); };
+            _unrealized.On += (s, e) => { if (e.Item != null) ItemUnrealized?.Invoke(this, e); };
+            _longpressed.On += (s, e) => { if (e.Item != null) ItemLongPressed?.Invoke(this, e); };
 
         }
 
index 67fcf65..8b6528f 100644 (file)
@@ -1,4 +1,4 @@
-using System;
+using System;
 
 namespace ElmSharp
 {
@@ -16,6 +16,7 @@ namespace ElmSharp
         public abstract void Update();
         protected override void OnInvalidate()
         {
+            ItemClass?.SendItemDeleted(Data);
             Data = null;
             ItemClass = null;
         }
index 6d64b66..fa31f02 100644 (file)
@@ -73,6 +73,12 @@ namespace ElmSharp
             GC.SuppressFinalize(this);
         }
 
+        internal void SendItemDeleted(object data)
+        {
+            // data is user inserted value with GenItem
+            DeleteHandler?.Invoke(data);
+        }
+
         private string GetTextCallback(IntPtr data, IntPtr obj, IntPtr part)
         {
             GenItem item = ItemObject.GetItemById((int)data) as GenItem;
@@ -85,8 +91,12 @@ namespace ElmSharp
         }
         private void DelCallback(IntPtr data, IntPtr obj)
         {
-            GenItem item = ItemObject.GetItemById((int)data) as GenItem;
-            DeleteHandler?.Invoke(item?.Data);
+            // We can't use this callback
+            // because, when item was deleted
+            // First, ItemObject deleted callback was called
+            // and We need to clean up ItemObject related objects
+            // This callback was called after ItemObject deleted callback was completed.
+            // So, We can't get resource reletated with ItemObject
         }
     }
 
index 3be368e..3f9cfc4 100644 (file)
@@ -216,16 +216,16 @@ namespace ElmSharp
             _scrollAnimationStopped = new Interop.SmartEvent(this, Handle, "scroll,anim,stop");
             _changed = new Interop.SmartEvent(this, Handle, "changed");
 
-            _selected.On += (s, e) => { ItemSelected?.Invoke(this, e); };
-            _unselected.On += (s, e) => { ItemUnselected?.Invoke(this, e); };
-            _activated.On += (s, e) => { ItemActivated?.Invoke(this, e); };
-            _pressed.On += (s, e) => { ItemPressed?.Invoke(this, e); };
-            _released.On += (s, e) => { ItemReleased?.Invoke(this, e); };
-            _doubleClicked.On += (s, e) => { ItemDoubleClicked?.Invoke(this, e); };
-            _expanded.On += (s, e) => { ItemExpanded?.Invoke(this, e); };
-            _realized.On += (s, e) => { ItemRealized?.Invoke(this, e); };
-            _unrealized.On += (s, e) => { ItemUnrealized?.Invoke(this, e); };
-            _longpressed.On += (s, e) => { ItemLongPressed?.Invoke(this, e); };
+            _selected.On += (s, e) => { if (e.Item != null) ItemSelected?.Invoke(this, e); };
+            _unselected.On += (s, e) => { if (e.Item != null) ItemUnselected?.Invoke(this, e); };
+            _activated.On += (s, e) => { if (e.Item != null) ItemActivated?.Invoke(this, e); };
+            _pressed.On += (s, e) => { if (e.Item != null) ItemPressed?.Invoke(this, e); };
+            _released.On += (s, e) => { if (e.Item != null) ItemReleased?.Invoke(this, e); };
+            _doubleClicked.On += (s, e) => { if (e.Item != null) ItemDoubleClicked?.Invoke(this, e); };
+            _expanded.On += (s, e) => { if (e.Item != null) ItemExpanded?.Invoke(this, e); };
+            _realized.On += (s, e) => { if (e.Item != null) ItemRealized?.Invoke(this, e); };
+            _unrealized.On += (s, e) => { if (e.Item != null) ItemUnrealized?.Invoke(this, e); };
+            _longpressed.On += (s, e) => { if (e.Item != null) ItemLongPressed?.Invoke(this, e); };
         }
 
         void AddInternal(GenListItem item)
index 65f28dc..e8c9be7 100644 (file)
@@ -117,6 +117,14 @@ namespace ElmSharp
         {
             Deleted?.Invoke(this, EventArgs.Empty);
             OnInvalidate();
+            if (s_IdToItemTable.ContainsKey(Id))
+            {
+                s_IdToItemTable.Remove(Id);
+            }
+            if (s_HandleToItemTable.ContainsKey(_handle))
+            {
+                s_HandleToItemTable.Remove(_handle);
+            }
             _handle = IntPtr.Zero;
         }
 
index 57edf88..4dbd9e0 100644 (file)
@@ -57,6 +57,7 @@
     <Compile Include="TC\GenListTest2.cs" />\r
     <Compile Include="TC\GenListTest3.cs" />\r
     <Compile Include="TC\GenListTest4.cs" />\r
+    <Compile Include="TC\GenListTest6.cs" />\r
     <Compile Include="TC\PerformanceTest.cs" />\r
     <Compile Include="TC\GenListTest5.cs" />\r
     <Compile Include="TC\IconTest1.cs" />\r
     <_FullFrameworkReferenceAssemblyPaths>$(MSBuildThisFileDirectory)</_FullFrameworkReferenceAssemblyPaths>\r
     <AutoUnifyAssemblyReferences>true</AutoUnifyAssemblyReferences>\r
   </PropertyGroup>\r
-</Project>
+  <ProjectExtensions>\r
+    <VisualStudio>\r
+      <FlavorProperties GUID="{2F98DAC9-6F16-457B-AED7-D43CAC379341}" Configuration="Debug|Any CPU">\r
+        <ProjectCorporateFlavorCfg />\r
+      </FlavorProperties>\r
+      <FlavorProperties GUID="{2F98DAC9-6F16-457B-AED7-D43CAC379341}" Configuration="Release|Any CPU">\r
+        <ProjectCorporateFlavorCfg />\r
+      </FlavorProperties>\r
+    </VisualStudio>\r
+  </ProjectExtensions>\r
+</Project>
\ No newline at end of file
diff --git a/test/ElmSharp.Test/TC/GenListTest6.cs b/test/ElmSharp.Test/TC/GenListTest6.cs
new file mode 100644 (file)
index 0000000..a6006aa
--- /dev/null
@@ -0,0 +1,125 @@
+using System;
+using ElmSharp;
+
+namespace ElmSharp.Test
+{
+    class GenListTest6 : TestCaseBase
+    {
+        public override string TestName => "GenListTest6";
+        public override string TestDescription => "To test deletion of GenListItem";
+        GenListItem selected = null;
+
+
+        public override void Run(Window window)
+        {
+            Conformant conformant = new Conformant(window);
+            conformant.Show();
+            Box box = new Box(window)
+            {
+                AlignmentX = -1,
+                AlignmentY = -1,
+                WeightX = 1,
+                WeightY = 1,
+            };
+            box.Show();
+            conformant.SetContent(box);
+
+
+            GenList list = new GenList(window)
+            {
+                Homogeneous = true,
+                AlignmentX = -1,
+                AlignmentY = -1,
+                WeightX = 1,
+                WeightY = 1
+            };
+
+            GenItemClass defaultClass = new GenItemClass("default")
+            {
+                GetTextHandler = (obj, part) =>
+                {
+                    return string.Format("{0} - {1}", (string)obj, part);
+                },
+                DeleteHandler = new GenItemClass.DeleteDelegate((obj) =>
+                {
+                    Console.WriteLine("DeleteHandler was called with... {0}", (string)obj);
+                }),
+            };
+            GenListItem[] items = new GenListItem[100];
+            for (int i = 0; i < 100; i++)
+            {
+                items[i] = list.Append(defaultClass, string.Format("{0} Item", i));
+            }
+            list.Show();
+            list.ItemSelected += List_ItemSelected;
+            list.ItemActivated += List_ItemActivated;
+            list.ItemUnselected += List_ItemUnselected;
+            list.ItemPressed += List_ItemPressed;
+            list.ItemRealized += List_ItemRealized;
+            list.ItemReleased += List_ItemReleased;
+            list.ItemUnrealized += List_ItemUnrealized;
+            list.ItemLongPressed += List_ItemLongPressed;
+            list.ItemDoubleClicked += List_ItemDoubleClicked;
+            box.PackEnd(list);
+            Button first = new Button(window)
+            {
+                Text = "Delete",
+                AlignmentX = -1,
+                WeightX = 1,
+            };
+            first.Clicked += (s, e) =>
+            {
+                selected?.Delete();
+            };
+            first.Show();
+            box.PackEnd(first);
+
+        }
+
+        private void List_ItemSelected(object sender, GenListItemEventArgs e)
+        {
+            selected = e.Item;
+            Console.WriteLine("{0} Item was selected", (string)(e.Item.Data));
+        }
+        private void List_ItemDoubleClicked(object sender, GenListItemEventArgs e)
+        {
+            Console.WriteLine("{0} Item was double clicked", (string)(e.Item.Data));
+        }
+
+        private void List_ItemLongPressed(object sender, GenListItemEventArgs e)
+        {
+            Console.WriteLine("{0} Item was Long pressed", (string)(e.Item.Data));
+        }
+
+        private void List_ItemUnrealized(object sender, GenListItemEventArgs e)
+        {
+            Console.WriteLine("!!!! Item was Unrealized!!!");
+            Console.WriteLine("{0} Item was unrealzed", (string)(e.Item.Data));
+        }
+
+        private void List_ItemReleased(object sender, GenListItemEventArgs e)
+        {
+            Console.WriteLine("{0} Item was released", (string)(e.Item.Data));
+        }
+
+        private void List_ItemRealized(object sender, GenListItemEventArgs e)
+        {
+            Console.WriteLine("{0} Item was Realized", (string)(e.Item.Data));
+        }
+
+        private void List_ItemPressed(object sender, GenListItemEventArgs e)
+        {
+            Console.WriteLine("{0} Item was Pressed", (string)(e.Item.Data));
+        }
+
+        private void List_ItemUnselected(object sender, GenListItemEventArgs e)
+        {
+            Console.WriteLine("{0} Item was unselected", (string)(e.Item.Data));
+        }
+
+        private void List_ItemActivated(object sender, GenListItemEventArgs e)
+        {
+            Console.WriteLine("{0} Item was Activated", (string)(e.Item.Data));
+        }
+    }
+}