[NUI] Unified native singleton class instance getter
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / Clipboard / Clipboard.cs
1 /*
2  * Copyright(c) 2023 Samsung Electronics Co., Ltd.
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.Collections.Generic;
19 using System.ComponentModel;
20 using System.Diagnostics.CodeAnalysis;
21 using System.Linq;
22 using System.Runtime.InteropServices;
23
24 using Tizen.NUI.BaseComponents;
25
26 namespace Tizen.NUI
27 {
28     /// <summary>
29     /// Clipboard.
30     /// </summary>
31     [EditorBrowsable(EditorBrowsableState.Never)]
32     public partial class Clipboard : BaseHandle
33     {
34         private static readonly Clipboard instance = Clipboard.GetInternal();
35
36         /// <summary>
37         /// User callback for clipboard event.
38         /// </summary>
39         /// <remarks>
40         /// Receives requested data through <see cref="Tizen.NUI.ClipEvent"/>.
41         /// </remarks>
42         public delegate void ClipboardCallback(bool success, ClipEvent clipEvent);
43
44         internal bool hasClipboardDataReceived = false;
45         internal Dictionary<uint, ClipboardCallback> receivedCallbackDictionary = new Dictionary<uint, ClipboardCallback>();
46
47         private Clipboard(global::System.IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn)
48         {
49         }
50
51         /// <summary>
52         /// Gets the singleton instance of Clipboard.
53         /// </summary>
54         [EditorBrowsable(EditorBrowsableState.Never)]
55         public static Clipboard Instance
56         {
57             get
58             {
59                 return instance;
60             }
61         }
62
63         private static Clipboard GetInternal()
64         {
65             global::System.IntPtr cPtr = Interop.Clipboard.Get();
66
67             if(cPtr == global::System.IntPtr.Zero)
68             {
69                 NUILog.ErrorBacktrace("Clipboard.Instance called before Application created, or after Application terminated!");
70                 // Do not throw exception until TCT test passed.
71             }
72
73             Clipboard ret = Registry.GetManagedBaseHandleFromNativePtr(cPtr) as Clipboard;
74             if (ret != null)
75             {
76                 NUILog.ErrorBacktrace("Clipboard.GetInternal() Should be called only one time!");
77                 object dummyObect = new object();
78
79                 HandleRef CPtr = new HandleRef(dummyObect, cPtr);
80                 Interop.BaseHandle.DeleteBaseHandle(CPtr);
81                 CPtr = new HandleRef(null, global::System.IntPtr.Zero);
82             }
83             else
84             {
85                 ret = new Clipboard(cPtr, true);
86             }
87
88             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
89             return ret;
90         }
91
92         [EditorBrowsable(EditorBrowsableState.Never)]
93         protected override void Dispose(bool disposing)
94         {
95             if (disposing)
96             {
97                 NUILog.ErrorBacktrace("We should not manually dispose for singleton class!");
98             }
99             else
100             {
101                 base.Dispose(disposing);
102             }
103         }
104
105         /// <summary>
106         /// Request set the given data to the clipboard.
107         /// </summary>
108         /// <param name="mimeType">The mime type of the data.</param>
109         /// <param name="data">The data to be set on the clipboard.</param>
110         /// <returns>True if the internal clipboard sending request is successful.</returns>
111         /// <example>
112         /// The following example demonstrates how to use the SetData.
113         /// <code>
114         /// string MIME_TYPE_PLAIN_TEXT = "text/plain;charset=utf-8";
115         /// Clipboard.Instance.SetData(MIME_TYPE_PLAIN_TEXT, "Hello Clipboard");
116         /// </code>
117         /// </example>
118         [EditorBrowsable(EditorBrowsableState.Never)]
119         public bool SetData(string mimeType, string data)
120         {
121             bool setData = Interop.Clipboard.SetData(SwigCPtr, mimeType, data);
122             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
123             return setData;
124         }
125
126         /// <summary>
127         /// Request get data of the specified mime type from clipboard<br/>
128         /// and invokes the given callback with the received clipboard data.
129         /// </summary>
130         /// <param name="mimeType">The mime type of data to request.</param>
131         /// <param name="dataReceivedCallback">The callback method to handle the received clipboard data.</param>
132         /// <remarks>
133         /// GetData() method is introduced to fetch data of the specified mime type,<br/>
134         /// and it expects a callback function as a parameter.<br/>
135         /// The given callback is invoked with received clipboard data.<br/>
136         /// The callback is designed to be used only once for handling the data.
137         /// </remarks>
138         /// <example>
139         /// The following example demonstrates how to use the GetData and ClipboardCallback.
140         /// <code>
141         /// string MIME_TYPE_PLAIN_TEXT = "text/plain;charset=utf-8";
142         /// Clipboard.Instance.GetData(MIME_TYPE_PLAIN_TEXT, OnClipboardDataReceived);
143         /// ...
144         /// public void OnClipboardDataReceived(bool success, ClipEvent clipEvent)
145         /// {
146         ///     if (!success) return;
147         ///     string mimeType = clipEvent.MimeType;
148         ///     string data = clipEvent.Data;
149         /// }
150         /// </code>
151         /// </example>
152         [EditorBrowsable(EditorBrowsableState.Never)]
153         public void GetData(string mimeType, ClipboardCallback dataReceivedCallback)
154         {
155             if(!hasClipboardDataReceived)
156             {
157                 ClipboardDataReceived += OnClipboardDataReceived;
158                 hasClipboardDataReceived = true;
159             }
160
161             uint id = Interop.Clipboard.GetData(SwigCPtr, mimeType);
162             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
163
164             if (id == 0)
165             {
166                 // Calls the failure callback even if the request fails.
167                 var clipEvent = new ClipEvent()
168                 {
169                     MimeType = string.Empty,
170                     Data = string.Empty,
171                 };
172                 dataReceivedCallback(false, clipEvent);
173             }
174             else
175             {
176                 receivedCallbackDictionary[id] = dataReceivedCallback;
177             }
178         }
179
180         private void OnClipboardDataReceived(object sender, ClipboardEventArgs e)
181         {
182             if (!receivedCallbackDictionary.Any()) return;
183
184             uint id = e.Id;
185             if (receivedCallbackDictionary.ContainsKey(id))
186             {
187                 ClipboardCallback callback = receivedCallbackDictionary[id];
188                 if (callback != null)
189                 {
190                     callback(e.Success, e.ClipEvent);
191                 }
192                 receivedCallbackDictionary.Remove(id);
193             }
194         }
195
196         /// <summary>
197         /// Dispose.
198         /// </summary>
199         protected override void Dispose(DisposeTypes type)
200         {
201             if (disposed)
202             {
203                 return;
204             }
205
206             if (hasClipboardDataReceived)
207             {
208                 ClipboardDataReceived -= OnClipboardDataReceived;
209                 receivedCallbackDictionary.Clear();
210             }
211
212             if (this.HasBody())
213             {
214                 if (clipboardDataReceivedCallback != null)
215                 {
216                     this.ClipboardDataReceivedSignal().Disconnect(clipboardDataReceivedCallback);
217                 }
218
219                 if (clipboardDataSelectedCallback != null)
220                 {
221                     this.ClipboardDataSelectedSignal().Disconnect(clipboardDataSelectedCallback);
222                 }
223             }
224
225             base.Dispose(type);
226         }
227     }
228 }