2007-06-13 Jonathan Pobst <monkey@jpobst.com>
[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.Collections;
34 using System.Collections.Specialized;
35 using System.ComponentModel;
36
37 namespace System.Windows.Forms {
38         public sealed class Clipboard {
39                 #region Local Variables
40                 #endregion      // Local Variables
41
42                 #region Constructors
43                 private Clipboard() {
44                 }
45                 #endregion      // Constructors
46
47                 #region Private Methods
48                 private static bool ConvertToClipboardData(ref int type, object obj, out byte[] data) {
49                         data = null;
50                         return false;
51                 }
52
53                 private static bool ConvertFromClipboardData(int type, IntPtr data, out object obj) {
54                         obj = null;
55                         if (data == IntPtr.Zero) {
56                                 return false;
57                         }
58                         return false;
59                 }
60                 #endregion      // Private Methods
61
62                 #region Public Static Methods
63 #if NET_2_0
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);
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 #endif
135
136                 public static IDataObject GetDataObject ()
137                 {
138                         return GetDataObject (false);
139                 }
140
141 #if NET_2_0
142                 public static StringCollection GetFileDropList ()
143                 {
144                         IDataObject data = GetDataObject ();
145
146                         if (data == null)
147                                 return null;
148
149                         return (StringCollection)data.GetData (DataFormats.FileDrop, true);
150                 }
151                 
152                 public static Image GetImage ()
153                 {
154                         IDataObject data = GetDataObject ();
155
156                         if (data == null)
157                                 return null;
158
159                         return (Image)data.GetData (DataFormats.Bitmap, true);
160                 }
161                 
162                 public static string GetText ()
163                 {
164                         return GetText (TextDataFormat.UnicodeText);
165                 }
166                 
167                 public static string GetText (TextDataFormat format)
168                 {
169                         if (!Enum.IsDefined (typeof (TextDataFormat), format))
170                                 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for TextDataFormat", format));
171                                 
172                         IDataObject data = GetDataObject ();
173                         
174                         if (data == null)
175                                 return string.Empty;
176                                 
177                         string retval;
178                         
179                         switch (format) {
180                                 case TextDataFormat.Text:
181                                 default:
182                                         retval = (string)data.GetData (DataFormats.Text, true);
183                                         break;
184                                 case TextDataFormat.UnicodeText:
185                                         retval = (string)data.GetData (DataFormats.UnicodeText, true);
186                                         break;
187                                 case TextDataFormat.Rtf:
188                                         retval = (string)data.GetData (DataFormats.Rtf, true);
189                                         break;
190                                 case TextDataFormat.Html:
191                                         retval = (string)data.GetData (DataFormats.Html, true);
192                                         break;
193                                 case TextDataFormat.CommaSeparatedValue:
194                                         retval = (string)data.GetData (DataFormats.CommaSeparatedValue, true);
195                                         break;
196                         }
197                         
198                         return retval == null ? string.Empty : retval;
199                 }
200                 
201                 public static void SetAudio (byte[] audioBytes)
202                 {
203                         if (audioBytes == null)
204                                 throw new ArgumentNullException ("audioBytes");
205                                 
206                         MemoryStream ms = new MemoryStream (audioBytes);
207                         
208                         SetAudio (ms);
209                 }
210                 
211                 public static void SetAudio (Stream audioStream)
212                 {
213                         if (audioStream == null)
214                                 throw new ArgumentNullException ("audioStream");
215
216                         SetData (DataFormats.WaveAudio, audioStream);
217                 }
218
219                 [MonoInternalNote ("Does not use requested format")]
220                 public static void SetData (string format, Object data)
221                 {
222                         if (data == null)
223                                 throw new ArgumentNullException ("data");
224                                 
225                         SetDataObject (data);
226                 }
227 #endif
228
229                 public static void SetDataObject(object data) {
230                         SetDataObject(data, false);  // MSDN says default behavior is to place non-persistent data to clipboard
231                 }
232
233                 public static void SetDataObject(object data, bool copy) {
234                         SetDataObject(data, copy, 10, 100);   // MSDN says default behavior is to try 10 times with 100 ms delay
235                 }
236
237                 internal static void SetDataObjectImpl(object data, bool copy) {
238                         IntPtr                  clipboard_handle;
239                         XplatUI.ObjectToClipboard converter;
240                         int                     native_format;
241                         DataFormats.Format      item_format;
242
243                         converter = new XplatUI.ObjectToClipboard(ConvertToClipboardData);
244
245                         clipboard_handle = XplatUI.ClipboardOpen(false);
246                         XplatUI.ClipboardStore(clipboard_handle, null, 0, null);        // Empty clipboard
247
248                         native_format = -1;
249
250                         if (data is IDataObject) {
251                                 string[] formats;
252
253                                 formats = ((IDataObject)data).GetFormats();
254                                 for (int i = 0; i < formats.Length; i++) {
255                                         item_format = DataFormats.GetFormat(formats[i]);
256                                         if ((item_format != null) && (item_format.Name != DataFormats.StringFormat)) {
257                                                 native_format = item_format.Id;
258                                         }
259
260                                         XplatUI.ClipboardStore(clipboard_handle, ((IDataObject)data).GetData(formats[i]), native_format, converter);
261                                 }
262                         } else {
263                                 item_format = DataFormats.Format.Find(data.GetType().FullName);
264                                 if ((item_format != null) && (item_format.Name != DataFormats.StringFormat)) {
265                                         native_format = item_format.Id;
266                                 }
267
268                                 XplatUI.ClipboardStore(clipboard_handle, data, native_format, converter);
269                         }
270                         XplatUI.ClipboardClose(clipboard_handle);
271                 }
272
273 #if NET_2_0
274                 public 
275 #else
276                 internal 
277 #endif
278                 static void SetDataObject(object data, bool copy, int retryTimes, int retryDelay)
279                 {
280                         if (data == null)
281                                 throw new ArgumentNullException("data");
282                         if (retryTimes < 0)
283                                 throw new ArgumentOutOfRangeException("retryTimes");
284                         if (retryDelay < 0)
285                                 throw new ArgumentOutOfRangeException("retryDelay");
286
287                         // MS implementation actually puts data to clipboard even when retryTimes == 0
288                         bool retry = true;
289                         do
290                         {
291                                 retry = false;
292                                 --retryTimes;
293                                 try
294                                 {
295                                         SetDataObjectImpl(data, copy);
296                                 } catch (ExternalException) {
297                                         if (retryTimes <= 0)
298                                                 throw;
299                                         retry = true;
300                                         Threading.Thread.Sleep(retryDelay);
301                                 }
302                         } while (retry && retryTimes > 0);
303                 }
304
305 #if NET_2_0
306                 [MonoInternalNote ("Needs additional checks for valid paths, see MSDN")]
307                 public static void SetFileDropList (StringCollection filePaths)
308                 {
309                         if (filePaths == null)
310                                 throw new ArgumentNullException ("filePaths");
311                                 
312                         SetData (DataFormats.FileDrop, filePaths);
313                 }
314                 
315                 public static void SetImage (Image image)
316                 {
317                         if (image == null)
318                                 throw new ArgumentNullException ("image");
319                         
320                         SetData (DataFormats.Bitmap, image);
321                 }
322                 
323                 public static void SetText (string text)
324                 {
325                         if (string.IsNullOrEmpty (text))
326                                 throw new ArgumentNullException ("text");
327                                 
328                         SetData (DataFormats.UnicodeText, text);
329                 }
330                 
331                 public static void SetText (string text, TextDataFormat format)
332                 {
333                         if (string.IsNullOrEmpty (text))
334                                 throw new ArgumentNullException ("text");
335                         if (!Enum.IsDefined (typeof (TextDataFormat), format))
336                                 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for TextDataFormat", format));
337
338                         switch (format) {
339                                 case TextDataFormat.Text:
340                                         SetData (DataFormats.Text, text);
341                                         break;
342                                 case TextDataFormat.UnicodeText:
343                                         SetData (DataFormats.UnicodeText, text);
344                                         break;
345                                 case TextDataFormat.Rtf:
346                                         SetData (DataFormats.Rtf, text);
347                                         break;
348                                 case TextDataFormat.Html:
349                                         SetData (DataFormats.Html, text);
350                                         break;
351                                 case TextDataFormat.CommaSeparatedValue:
352                                         SetData (DataFormats.CommaSeparatedValue, text);
353                                         break;
354                         }
355                 }
356 #endif
357                 #endregion      // Public Static Methods
358
359                 #region Internal Static Methods
360                 internal static IDataObject GetDataObject (bool primary_selection)
361                 {
362                         DataObject clipboard;
363                         IntPtr clipboard_handle;
364                         int[] native_formats;
365                         DataFormats.Format item_format;
366                         object managed_clipboard_item;
367                         XplatUI.ClipboardToObject converter;
368
369                         converter = new XplatUI.ClipboardToObject (ConvertFromClipboardData);
370
371                         clipboard_handle = XplatUI.ClipboardOpen (primary_selection);
372                         native_formats = XplatUI.ClipboardAvailableFormats (clipboard_handle);
373                         if (native_formats == null) {
374                                 return null;    // Clipboard empty
375                         }
376
377                         // Build the IDataObject
378                         clipboard = new DataObject ();
379                         for (int i = 0; i < native_formats.Length; i++) {
380                                 // We might get a format we don't understand or know
381                                 item_format = DataFormats.GetFormat (native_formats[i]);
382
383                                 if (item_format != null) {
384                                         managed_clipboard_item = XplatUI.ClipboardRetrieve (clipboard_handle, native_formats[i], converter);
385
386                                         if (managed_clipboard_item != null) {
387                                                 clipboard.SetData (item_format.Name, managed_clipboard_item);
388                                                 // We don't handle 'bitmap' since it involves handles, so we'll equate it to dib
389                                                 if (item_format.Name == DataFormats.Dib) {
390                                                         clipboard.SetData (DataFormats.Bitmap, managed_clipboard_item);
391                                                 }
392                                         }
393                                 }
394                         }
395
396                         XplatUI.ClipboardClose (clipboard_handle);
397
398                         return clipboard;
399                 }
400                 
401                 internal static bool ClipboardContainsFormat (params string[] formats)
402                 {
403                         IntPtr clipboard_handle;
404                         int[] native_formats;
405                         DataFormats.Format item_format;
406
407                         clipboard_handle = XplatUI.ClipboardOpen (false);
408                         native_formats = XplatUI.ClipboardAvailableFormats (clipboard_handle);
409                         
410                         if (native_formats == null)
411                                 return false;
412                                 
413                         foreach (int i in native_formats) {
414                                 // We might get a format we don't understand or know
415                                 item_format = DataFormats.GetFormat (i);
416                                 
417                                 if (item_format != null)
418                                         if (((IList)formats).Contains (item_format.Name))
419                                                 return true;
420                         }
421                                 
422                         return false;
423                 }
424                 #endregion
425         }
426 }