Release 4.0.0-preview1-00051
[platform/core/csapi/tizenfx.git] / src / ElmSharp / ElmSharp / SmartEvent.cs
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 using System;
18 using System.ComponentModel;
19 using System.Collections.Generic;
20 using System.Linq;
21
22 namespace ElmSharp
23 {
24     /// <summary>
25     /// It inherits <see cref="IInvalidatable"/>.
26     /// The event with TEventArgs for <see cref="EvasObject"/>.
27     /// EvasObject can elect SmartEvent occurring inside of them to be reported back to their users via delegates.
28     /// This way, you can extend EvasObject's own <see cref="EvasObjectEvent"/>.
29     /// They are defined by an event string, which identifies them uniquely.
30     /// </summary>
31     /// <typeparam name="TEventArgs">The parameter for the event.</typeparam>
32     public class SmartEvent<TEventArgs> : IInvalidatable where TEventArgs : EventArgs
33     {
34         /// <summary>
35         /// The delegate for creating smart event item args.
36         /// </summary>
37         /// <param name="data">The item data.</param>
38         /// <param name="obj">The sender obj.</param>
39         /// <param name="info">The item sender obj.</param>
40         /// <returns>Return smart event item args.</returns>
41         public delegate TEventArgs SmartEventInfoParser(IntPtr data, IntPtr obj, IntPtr info);
42
43         private EvasObject _sender;
44         private readonly string _eventName;
45         private IntPtr _handle;
46         private readonly SmartEventInfoParser _parser;
47         private readonly List<NativeCallback> _nativeCallbacks = new List<NativeCallback>();
48
49         /// <summary>
50         /// Creates and initializes a new instance of the SmartEvent class.
51         /// </summary>
52         /// <param name="sender">The source of the event.</param>
53         /// <param name="eventName">The event name.</param>
54         /// <param name="parser">The event parameter.</param>
55         public SmartEvent(EvasObject sender, string eventName, SmartEventInfoParser parser) : this(sender, sender.Handle, eventName, parser)
56         {
57         }
58
59         [EditorBrowsableAttribute(EditorBrowsableState.Never)]
60         public SmartEvent(EvasObject sender, IntPtr handle, string eventName, SmartEventInfoParser parser)
61         {
62             _sender = sender;
63             _eventName = eventName;
64             _handle = handle;
65             _parser = parser;
66             sender.AddToEventLifeTracker(this);
67         }
68
69         /// <summary>
70         /// Creates and initializes a new instance of the SmartEvent class.
71         /// </summary>
72         /// <param name="sender">The source of the event.</param>
73         /// <param name="eventName">The event name.</param>
74         public SmartEvent(EvasObject sender, string eventName) : this(sender, eventName, null)
75         {
76         }
77
78         ~SmartEvent()
79         {
80             Dispose(false);
81         }
82
83         private struct NativeCallback
84         {
85             public Interop.Evas.SmartCallback callback;
86             public EventHandler<TEventArgs> eventHandler;
87         }
88
89         /// <summary>
90         /// Adds or removes delegate for event.
91         /// </summary>
92         public event EventHandler<TEventArgs> On
93         {
94             add
95             {
96                 if (_handle == IntPtr.Zero)
97                 {
98                     return;
99                 }
100                 EventHandler<TEventArgs> handler = value;
101                 var cb = new Interop.Evas.SmartCallback((d, o, e) =>
102                 {
103                     TEventArgs ea = _parser == null ? (TEventArgs)EventArgs.Empty : _parser(d, o, e);
104                     handler(_sender, ea);
105                 });
106                 _nativeCallbacks.Add(new NativeCallback { callback = cb, eventHandler = handler });
107                 int i = _nativeCallbacks.Count - 1;
108                 Interop.Evas.evas_object_smart_callback_add(_handle, _eventName, _nativeCallbacks[i].callback, IntPtr.Zero);
109             }
110
111             remove
112             {
113                 if (_handle == IntPtr.Zero)
114                 {
115                     return;
116                 }
117                 EventHandler<TEventArgs> handler = value;
118                 var callbacks = _nativeCallbacks.Where(cb => cb.eventHandler == handler);
119                 foreach (var cb in callbacks)
120                 {
121                     Interop.Evas.evas_object_smart_callback_del(_handle, _eventName, cb.callback);
122                 }
123             }
124         }
125
126         public void Dispose()
127         {
128             Dispose(true);
129             GC.SuppressFinalize(this);
130         }
131
132         /// <summary>
133         /// Make current instance invalidate.
134         /// </summary>
135         public void MakeInvalidate()
136         {
137             _sender = null;
138             _handle = IntPtr.Zero;
139         }
140
141         protected virtual void Dispose(bool disposing)
142         {
143             if (disposing)
144             {
145                 // Place holder to dispose managed state (managed objects).
146             }
147             if (_handle != IntPtr.Zero)
148             {
149                 foreach (var cb in _nativeCallbacks)
150                 {
151                     Interop.Evas.evas_object_smart_callback_del(_handle, _eventName, cb.callback);
152                 }
153             }
154             _nativeCallbacks.Clear();
155         }
156     }
157
158     /// <summary>
159     /// It inherits <see cref="IInvalidatable"/>.
160     /// EvasObject can elect SmartEvent occurring inside of them to be reported back to their users via delegates.
161     /// This way, you can extend EvasObject's own <see cref="EvasObjectEvent"/>.
162     /// They are defined by an event string, which identifies them uniquely.
163     /// </summary>
164     /// <typeparam name="TEventArgs">The parameter for the event.</typeparam>
165     public class SmartEvent : IInvalidatable
166     {
167         private SmartEvent<EventArgs> _smartEvent;
168         private event EventHandler _handlers;
169
170         /// <summary>
171         /// Creates and initializes a new instance of the SmartEvent class.
172         /// </summary>
173         /// <param name="sender">The source of the event.</param>
174         /// <param name="eventName">The event name.</param>
175         public SmartEvent(EvasObject sender, string eventName) : this(sender, sender.RealHandle, eventName)
176         {
177         }
178
179         [EditorBrowsableAttribute(EditorBrowsableState.Never)]
180         public SmartEvent(EvasObject sender, IntPtr handle, string eventName)
181         {
182             _smartEvent = new SmartEvent<EventArgs>(sender, handle, eventName, null);
183         }
184
185         ~SmartEvent()
186         {
187             Dispose(false);
188         }
189
190         /// <summary>
191         /// Adds or removes delegate for event.
192         /// </summary>
193         public event EventHandler On
194         {
195             add
196             {
197                 if (_handlers == null)
198                 {
199                     _smartEvent.On += SendEvent;
200                 }
201                 _handlers += value;
202             }
203
204             remove
205             {
206                 _handlers -= value;
207                 if (_handlers == null)
208                 {
209                     _smartEvent.On -= SendEvent;
210                 }
211             }
212         }
213
214         private void SendEvent(object sender, EventArgs e)
215         {
216             _handlers?.Invoke(sender, e);
217         }
218
219         public void Dispose()
220         {
221             Dispose(true);
222             GC.SuppressFinalize(this);
223         }
224
225         /// <summary>
226         /// Make current instance invalidate.
227         /// </summary>
228         public void MakeInvalidate()
229         {
230             _smartEvent.MakeInvalidate();
231         }
232
233         protected virtual void Dispose(bool disposing)
234         {
235             if (disposing)
236             {
237                 // Place holder to dispose managed state (managed objects).
238                 _smartEvent.Dispose();
239             }
240         }
241     }
242 }