Merge pull request #347 from JamesB7/master
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / Clipboard.cs
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 // 
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 // 
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 //
20 // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
21 //
22 // Authors:
23 //      Peter Bartok    (pbartok@novell.com)
24 //
25 //
26
27 // COMPLETE
28
29 using System;
30 using System.Drawing;
31 using System.IO;
32 using System.Runtime.InteropServices;
33 using System.Runtime.Serialization;
34 using System.Collections;
35 using System.Collections.Specialized;
36 using System.ComponentModel;
37
38 namespace System.Windows.Forms {
39         public sealed class Clipboard {
40                 #region Local Variables
41                 #endregion      // Local Variables
42
43                 #region Constructors
44                 private Clipboard() {
45                 }
46                 #endregion      // Constructors
47
48                 #region Private Methods
49                 private static bool ConvertToClipboardData(ref int type, object obj, out byte[] data) {
50                         data = null;
51                         return false;
52                 }
53
54                 private static bool ConvertFromClipboardData(int type, IntPtr data, out object obj) {
55                         obj = null;
56                         if (data == IntPtr.Zero) {
57                                 return false;
58                         }
59                         return false;
60                 }
61                 #endregion      // Private Methods
62
63                 #region Public Static Methods
64                 public static void Clear ()
65                 {
66                         IntPtr clipboard_handle;
67
68                         clipboard_handle = XplatUI.ClipboardOpen (false);
69                         XplatUI.ClipboardStore (clipboard_handle, null, 0, null, false);
70                 }
71
72                 public static bool ContainsAudio ()
73                 {
74                         return ClipboardContainsFormat (DataFormats.WaveAudio);
75                 }
76                 
77                 public static bool ContainsData (string format)
78                 {
79                         return ClipboardContainsFormat (format);
80                 }
81                 
82                 public static bool ContainsFileDropList ()
83                 {
84                         return ClipboardContainsFormat (DataFormats.FileDrop);
85                 }
86                 
87                 public static bool ContainsImage ()
88                 {
89                         return ClipboardContainsFormat (DataFormats.Bitmap);
90                 }
91                 
92                 public static bool ContainsText ()
93                 {
94                         return ClipboardContainsFormat (DataFormats.Text, DataFormats.UnicodeText);
95                 }
96                 
97                 public static bool ContainsText (TextDataFormat format)
98                 {
99                         switch (format) {
100                                 case TextDataFormat.Text:
101                                         return ClipboardContainsFormat (DataFormats.Text);
102                                 case TextDataFormat.UnicodeText:
103                                         return ClipboardContainsFormat (DataFormats.UnicodeText);
104                                 case TextDataFormat.Rtf:
105                                         return ClipboardContainsFormat (DataFormats.Rtf);
106                                 case TextDataFormat.Html:
107                                         return ClipboardContainsFormat (DataFormats.Html);
108                                 case TextDataFormat.CommaSeparatedValue:
109                                         return ClipboardContainsFormat (DataFormats.CommaSeparatedValue);
110                         }
111                         
112                         return false;
113                 }
114                 
115                 public static Stream GetAudioStream ()
116                 {
117                         IDataObject data = GetDataObject ();
118
119                         if (data == null)
120                                 return null;
121
122                         return (Stream)data.GetData (DataFormats.WaveAudio, true);
123                 }
124                 
125                 public static Object GetData (string format)
126                 {
127                         IDataObject data = GetDataObject ();
128
129                         if (data == null)
130                                 return null;
131
132                         return data.GetData (format, true);
133                 }
134
135                 public static IDataObject GetDataObject ()
136                 {
137                         return GetDataObject (false);
138                 }
139
140                 public static StringCollection GetFileDropList ()
141                 {
142                         IDataObject data = GetDataObject ();
143
144                         if (data == null)
145                                 return null;
146
147                         return (StringCollection)data.GetData (DataFormats.FileDrop, true);
148                 }
149                 
150                 public static Image GetImage ()
151                 {
152                         IDataObject data = GetDataObject ();
153
154                         if (data == null)
155                                 return null;
156
157                         return (Image)data.GetData (DataFormats.Bitmap, true);
158                 }
159                 
160                 public static string GetText ()
161                 {
162                         return GetText (TextDataFormat.UnicodeText);
163                 }
164                 
165                 public static string GetText (TextDataFormat format)
166                 {
167                         if (!Enum.IsDefined (typeof (TextDataFormat), format))
168                                 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for TextDataFormat", format));
169                                 
170                         IDataObject data = GetDataObject ();
171                         
172                         if (data == null)
173                                 return string.Empty;
174                                 
175                         string retval;
176                         
177                         switch (format) {
178                                 case TextDataFormat.Text:
179                                 default:
180                                         retval = (string)data.GetData (DataFormats.Text, true);
181                                         break;
182                                 case TextDataFormat.UnicodeText:
183                                         retval = (string)data.GetData (DataFormats.UnicodeText, true);
184                                         break;
185                                 case TextDataFormat.Rtf:
186                                         retval = (string)data.GetData (DataFormats.Rtf, true);
187                                         break;
188                                 case TextDataFormat.Html:
189                                         retval = (string)data.GetData (DataFormats.Html, true);
190                                         break;
191                                 case TextDataFormat.CommaSeparatedValue:
192                                         retval = (string)data.GetData (DataFormats.CommaSeparatedValue, true);
193                                         break;
194                         }
195                         
196                         return retval == null ? string.Empty : retval;
197                 }
198                 
199                 public static void SetAudio (byte[] audioBytes)
200                 {
201                         if (audioBytes == null)
202                                 throw new ArgumentNullException ("audioBytes");
203                                 
204                         MemoryStream ms = new MemoryStream (audioBytes);
205                         
206                         SetAudio (ms);
207                 }
208                 
209                 public static void SetAudio (Stream audioStream)
210                 {
211                         if (audioStream == null)
212                                 throw new ArgumentNullException ("audioStream");
213
214                         SetData (DataFormats.WaveAudio, audioStream);
215                 }
216
217                 public static void SetData (string format, Object data)
218                 {
219                         if (data == null)
220                                 throw new ArgumentNullException ("data");
221                                 
222                         DataObject data_object = new DataObject (format, data);
223                         SetDataObject (data_object);
224                 }
225
226                 public static void SetDataObject(object data) {
227                         SetDataObject(data, false);  // MSDN says default behavior is to place non-persistent data to clipboard
228                 }
229
230                 public static void SetDataObject(object data, bool copy) {
231                         SetDataObject(data, copy, 10, 100);   // MSDN says default behavior is to try 10 times with 100 ms delay
232                 }
233
234                 internal static void SetDataObjectImpl(object data, bool copy) {
235                         IntPtr                  clipboard_handle;
236                         XplatUI.ObjectToClipboard converter;
237                         int                     native_format;
238                         DataFormats.Format      item_format;
239
240                         converter = new XplatUI.ObjectToClipboard(ConvertToClipboardData);
241
242                         clipboard_handle = XplatUI.ClipboardOpen(false);
243                         XplatUI.ClipboardStore(clipboard_handle, null, 0, null, copy);  // Empty clipboard
244
245                         native_format = -1;
246
247                         if (data is IDataObject) {
248                                 string[] formats;
249
250                                 IDataObject data_object = data as IDataObject;
251                                 formats = data_object.GetFormats();
252                                 for (int i = 0; i < formats.Length; i++) {
253                                         item_format = DataFormats.GetFormat(formats[i]);
254                                         if ((item_format != null) && (item_format.Name != DataFormats.StringFormat)) {
255                                                 native_format = item_format.Id;
256                                         }
257
258                                         object obj = data_object.GetData (formats [i]);
259
260                                         // this is used only by custom formats
261                                         if (IsDataSerializable (obj))
262                                                 item_format.is_serializable = true;
263
264                                         XplatUI.ClipboardStore(clipboard_handle, obj, native_format, converter, copy);
265                                 }
266                         } else {
267                                 item_format = DataFormats.Format.Find(data.GetType().FullName);
268                                 if ((item_format != null) && (item_format.Name != DataFormats.StringFormat)) {
269                                         native_format = item_format.Id;
270                                 }
271
272                                 XplatUI.ClipboardStore(clipboard_handle, data, native_format, converter, copy);
273                         }
274                         XplatUI.ClipboardClose(clipboard_handle);
275                 }
276
277                 static bool IsDataSerializable (object obj)
278                 {
279                         if (obj is ISerializable)
280                                 return true;
281
282                         AttributeCollection attrs = TypeDescriptor.GetAttributes (obj);
283                         return attrs [typeof (SerializableAttribute)] != null;
284                 }
285
286                 public static void SetDataObject(object data, bool copy, int retryTimes, int retryDelay)
287                 {
288                         if (data == null)
289                                 throw new ArgumentNullException("data");
290                         if (retryTimes < 0)
291                                 throw new ArgumentOutOfRangeException("retryTimes");
292                         if (retryDelay < 0)
293                                 throw new ArgumentOutOfRangeException("retryDelay");
294
295                         // MS implementation actually puts data to clipboard even when retryTimes == 0
296                         bool retry = true;
297                         do
298                         {
299                                 retry = false;
300                                 --retryTimes;
301                                 try
302                                 {
303                                         SetDataObjectImpl(data, copy);
304                                 } catch (ExternalException) {
305                                         if (retryTimes <= 0)
306                                                 throw;
307                                         retry = true;
308                                         Threading.Thread.Sleep(retryDelay);
309                                 }
310                         } while (retry && retryTimes > 0);
311                 }
312
313                 [MonoInternalNote ("Needs additional checks for valid paths, see MSDN")]
314                 public static void SetFileDropList (StringCollection filePaths)
315                 {
316                         if (filePaths == null)
317                                 throw new ArgumentNullException ("filePaths");
318                                 
319                         SetData (DataFormats.FileDrop, filePaths);
320                 }
321                 
322                 public static void SetImage (Image image)
323                 {
324                         if (image == null)
325                                 throw new ArgumentNullException ("image");
326                         
327                         SetData (DataFormats.Bitmap, image);
328                 }
329                 
330                 public static void SetText (string text)
331                 {
332                         if (string.IsNullOrEmpty (text))
333                                 throw new ArgumentNullException ("text");
334                                 
335                         SetData (DataFormats.UnicodeText, text);
336                 }
337                 
338                 public static void SetText (string text, TextDataFormat format)
339                 {
340                         if (string.IsNullOrEmpty (text))
341                                 throw new ArgumentNullException ("text");
342                         if (!Enum.IsDefined (typeof (TextDataFormat), format))
343                                 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for TextDataFormat", format));
344
345                         switch (format) {
346                                 case TextDataFormat.Text:
347                                         SetData (DataFormats.Text, text);
348                                         break;
349                                 case TextDataFormat.UnicodeText:
350                                         SetData (DataFormats.UnicodeText, text);
351                                         break;
352                                 case TextDataFormat.Rtf:
353                                         SetData (DataFormats.Rtf, text);
354                                         break;
355                                 case TextDataFormat.Html:
356                                         SetData (DataFormats.Html, text);
357                                         break;
358                                 case TextDataFormat.CommaSeparatedValue:
359                                         SetData (DataFormats.CommaSeparatedValue, text);
360                                         break;
361                         }
362                 }
363                 #endregion      // Public Static Methods
364
365                 #region Internal Static Methods
366                 internal static IDataObject GetDataObject (bool primary_selection)
367                 {
368                         DataObject clipboard;
369                         IntPtr clipboard_handle;
370                         int[] native_formats;
371                         DataFormats.Format item_format;
372                         object managed_clipboard_item;
373                         XplatUI.ClipboardToObject converter;
374
375                         converter = new XplatUI.ClipboardToObject (ConvertFromClipboardData);
376
377                         clipboard_handle = XplatUI.ClipboardOpen (primary_selection);
378                         native_formats = XplatUI.ClipboardAvailableFormats (clipboard_handle);
379                         if (native_formats == null) {
380                                 return null;    // Clipboard empty
381                         }
382
383                         // Build the IDataObject
384                         clipboard = new DataObject ();
385                         for (int i = 0; i < native_formats.Length; i++) {
386                                 // We might get a format we don't understand or know
387                                 item_format = DataFormats.GetFormat (native_formats[i]);
388
389                                 if (item_format != null) {
390                                         managed_clipboard_item = XplatUI.ClipboardRetrieve (clipboard_handle, native_formats[i], converter);
391
392                                         if (managed_clipboard_item != null) {
393                                                 clipboard.SetData (item_format.Name, managed_clipboard_item);
394                                                 // We don't handle 'bitmap' since it involves handles, so we'll equate it to dib
395                                                 if (item_format.Name == DataFormats.Dib) {
396                                                         clipboard.SetData (DataFormats.Bitmap, managed_clipboard_item);
397                                                 }
398                                         }
399                                 }
400                         }
401
402                         XplatUI.ClipboardClose (clipboard_handle);
403
404                         return clipboard;
405                 }
406                 
407                 internal static bool ClipboardContainsFormat (params string[] formats)
408                 {
409                         IntPtr clipboard_handle;
410                         int[] native_formats;
411                         DataFormats.Format item_format;
412
413                         clipboard_handle = XplatUI.ClipboardOpen (false);
414                         native_formats = XplatUI.ClipboardAvailableFormats (clipboard_handle);
415                         
416                         if (native_formats == null)
417                                 return false;
418                                 
419                         foreach (int i in native_formats) {
420                                 // We might get a format we don't understand or know
421                                 item_format = DataFormats.GetFormat (i);
422                                 
423                                 if (item_format != null)
424                                         if (((IList)formats).Contains (item_format.Name))
425                                                 return true;
426                         }
427                                 
428                         return false;
429                 }
430                 #endregion
431         }
432 }