Release 4.0.0-preview1-00194
[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     public class SmartEvent : IInvalidatable
165     {
166         private SmartEvent<EventArgs> _smartEvent;
167         private event EventHandler _handlers;
168
169         /// <summary>
170         /// Creates and initializes a new instance of the SmartEvent class.
171         /// </summary>
172         /// <param name="sender">The source of the event.</param>
173         /// <param name="eventName">The event name.</param>
174         public SmartEvent(EvasObject sender, string eventName) : this(sender, sender.RealHandle, eventName)
175         {
176         }
177
178         [EditorBrowsableAttribute(EditorBrowsableState.Never)]
179         public SmartEvent(EvasObject sender, IntPtr handle, string eventName)
180         {
181             _smartEvent = new SmartEvent<EventArgs>(sender, handle, eventName, null);
182         }
183
184         ~SmartEvent()
185         {
186             Dispose(false);
187         }
188
189         /// <summary>
190         /// Adds or removes delegate for event.
191         /// </summary>
192         public event EventHandler On
193         {
194             add
195             {
196                 if (_handlers == null)
197                 {
198                     _smartEvent.On += SendEvent;
199                 }
200                 _handlers += value;
201             }
202
203             remove
204             {
205                 _handlers -= value;
206                 if (_handlers == null)
207                 {
208                     _smartEvent.On -= SendEvent;
209                 }
210             }
211         }
212
213         private void SendEvent(object sender, EventArgs e)
214         {
215             _handlers?.Invoke(sender, e);
216         }
217
218         public void Dispose()
219         {
220             Dispose(true);
221             GC.SuppressFinalize(this);
222         }
223
224         /// <summary>
225         /// Make current instance invalidate.
226         /// </summary>
227         public void MakeInvalidate()
228         {
229             _smartEvent.MakeInvalidate();
230         }
231
232         protected virtual void Dispose(bool disposing)
233         {
234             if (disposing)
235             {
236                 // Place holder to dispose managed state (managed objects).
237                 _smartEvent.Dispose();
238             }
239         }
240     }
241 }