2007-06-13 Jonathan Pobst <monkey@jpobst.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / DataObject.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.IO;
31 using System.Drawing;
32 using System.Collections;
33 using System.Collections.Specialized;
34 using System.ComponentModel;
35 using System.Runtime.InteropServices;
36
37 namespace System.Windows.Forms {
38         [ClassInterface(ClassInterfaceType.None)]
39         public class DataObject : IDataObject {
40                 #region DataObject.Entry Class
41                 private class Entry {
42                         #region Local Variables
43                         private string  type;
44                         private object  data;
45                         //private bool  autoconvert;
46                         internal Entry  next;
47                         #endregion      // Local Variables
48
49                         #region Constructors
50                         internal Entry(string type, object data, bool autoconvert) {
51                                 this.type = type;
52                                 this.data = data;
53                                 //this.autoconvert = autoconvert;
54                         }
55                         #endregion      // Constructors
56
57                         #region Properties
58                         public object Data {
59                                 get {
60                                         return data;
61                                 }
62
63                                 set {
64                                         data = value;
65                                 }
66                         }
67                         #endregion      // Properties
68
69                         #region Methods
70                         public static int Count(Entry entries) {
71                                 int     result;
72
73                                 result = 0;
74
75                                 while (entries != null) {
76                                         result++;
77                                         entries = entries.next;
78                                 }
79
80                                 return result;
81                         }
82
83                         public static Entry Find(Entry entries, string type) {
84                                 while (entries != null) {
85                                         if (entries.type.Equals(type)) {
86                                                 return entries;
87                                         }
88                                         entries = entries.next;
89                                 }
90
91                                 return null;
92                         }
93
94                         public static Entry FindConvertible(Entry entries, string type) {
95                                 Entry e;
96
97                                 e = Find(entries, type);
98                                 if (e != null) {
99                                         return e;
100                                 }
101
102                                 e = entries;
103                                 while (e != null) {
104                                         if (type == DataFormats.Text) {
105                                                 if (e.type == DataFormats.UnicodeText) {
106                                                         return e;
107                                                 }
108                                         } else if (type == DataFormats.UnicodeText) {
109                                                 if (e.type == DataFormats.Text) {
110                                                         return e;
111                                                 }
112                                         } else if (type == DataFormats.StringFormat) {
113                                                 if (e.type == DataFormats.Text) {
114                                                         return e;
115                                                 } else if (e.type == DataFormats.UnicodeText) {
116                                                         return e;
117                                                 }
118                                         }
119                                         e = e.next;
120                                 }
121
122                                 return null;
123                         }
124
125                         public static string[] Entries(Entry entries, bool convertible) {
126                                 Entry           e;
127                                 ArrayList       list;
128                                 string[]        result;
129
130                                 // Initially store into something that we can grow easily
131                                 list = new ArrayList(Entry.Count(entries));
132                                 e = entries;
133
134                                 while (e != null) {
135                                         list.Add(e.type);
136                                         e = e.next;
137                                 }
138
139                                 if (convertible) {
140                                         // Add the convertibles
141                                         if ((Entry.Find(entries, DataFormats.Text) != null) && (Entry.Find(entries, DataFormats.UnicodeText) == null)) {
142                                                 list.Add(DataFormats.UnicodeText);
143                                         }
144
145                                         if ((Entry.Find(entries, DataFormats.Text) == null) && (Entry.Find(entries, DataFormats.UnicodeText) != null)) {
146                                                 list.Add(DataFormats.Text);
147                                         }
148
149                                         if (((Entry.Find(entries, DataFormats.Text) != null) || (Entry.Find(entries, DataFormats.UnicodeText) != null)) && (Entry.Find(entries, DataFormats.StringFormat) == null)) {
150                                                 list.Add(DataFormats.StringFormat);
151                                         }
152                                 }
153
154                                 // Copy the results into a string array
155                                 result = new string[list.Count];
156                                 for (int i = 0; i < list.Count; i++) {
157                                         result[i] = (string)list[i];
158                                 }
159
160                                 return result;
161                         }
162                         #endregion      // Methods
163                 }
164                 #endregion      // DataObject.Entry class
165
166                 #region Local Variables
167                 private Entry   entries;
168                 #endregion      // Local Variables
169
170                 #region Public Constructors
171                 public DataObject() {
172                         entries = null;
173                 }
174
175                 public DataObject(object data) {
176                         SetData(data);
177                 }
178
179                 public DataObject(string format, object data) {
180                         SetData(format, data);
181                 }
182                 #endregion      // Public Constructors
183
184                 #region Public Instance Methods
185 #if NET_2_0
186                 public virtual bool ContainsAudio ()
187                 {
188                         return GetDataPresent (DataFormats.WaveAudio, true);
189                 }
190                 
191                 public virtual bool ContainsFileDropList ()
192                 {
193                         return GetDataPresent (DataFormats.FileDrop, true);
194                 }
195                 
196                 public virtual bool ContainsImage ()
197                 {
198                         return GetDataPresent (DataFormats.Bitmap, true);
199                 }
200                 
201                 public virtual bool ContainsText ()
202                 {
203                         return GetDataPresent (DataFormats.UnicodeText, true);
204                 }
205                 
206                 public virtual bool ContainsText (TextDataFormat format)
207                 {
208                         if (!Enum.IsDefined (typeof (TextDataFormat), format))
209                                 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for TextDataFormat", format));
210
211                         return GetDataPresent (TextFormatToDataFormat (format), true);
212                 }
213                 
214                 public virtual Stream GetAudioStream ()
215                 {
216                         return (Stream)GetData (DataFormats.WaveAudio, true);
217                 }
218 #endif
219
220                 public virtual object GetData(string format) {
221                         return GetData(format, true);
222                 }
223
224                 public virtual object GetData(string format, bool autoConvert) {
225                         Entry e;
226                         if (autoConvert) {
227                                 e = Entry.FindConvertible(entries, format);
228                         } else {
229                                 e = Entry.Find(entries, format);
230                         }
231                         if (e == null)
232                                 return null;
233                         return e.Data;
234                 }
235
236                 public virtual object GetData(Type format) {
237                         return GetData(format.FullName, true);
238                 }
239
240                 public virtual bool GetDataPresent(string format) {
241                         return GetDataPresent(format, true);
242                 }
243
244                 public virtual bool GetDataPresent(string format, bool autoConvert) {
245                         if (autoConvert) {
246                                 return Entry.FindConvertible(entries, format) != null;
247                         } else {
248                                 return Entry.Find(entries, format) != null;
249                         }
250                 }
251
252                 public virtual bool GetDataPresent(Type format) {
253                         return GetDataPresent(format.FullName, true);
254                 }
255
256 #if NET_2_0
257                 public virtual StringCollection GetFileDropList ()
258                 {
259                         return (StringCollection)GetData (DataFormats.FileDrop, true);
260                 }
261 #endif
262                 public virtual string[] GetFormats() {
263                         return GetFormats(true);
264                 }
265
266                 public virtual string[] GetFormats(bool autoConvert) {
267                         return Entry.Entries(entries, autoConvert);
268                 }
269
270 #if NET_2_0
271                 public virtual Image GetImage ()
272                 {
273                         return (Image)GetData (DataFormats.Bitmap, true);
274                 }
275
276                 public virtual string GetText ()
277                 {
278                         return (string)GetData (DataFormats.UnicodeText, true);
279                 }
280
281                 public virtual string GetText (TextDataFormat format)
282                 {
283                         if (!Enum.IsDefined (typeof (TextDataFormat), format))
284                                 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for TextDataFormat", format));
285
286                         return (string)GetData (TextFormatToDataFormat (format), false);
287                 }
288
289                 public virtual void SetAudio (byte[] audioBytes)
290                 {
291                         if (audioBytes == null)
292                                 throw new ArgumentNullException ("audioBytes");
293
294                         MemoryStream ms = new MemoryStream (audioBytes);
295
296                         SetAudio (ms);
297                 }
298
299                 public virtual void SetAudio (Stream audioStream)
300                 {
301                         if (audioStream == null)
302                                 throw new ArgumentNullException ("audioStream");
303
304                         SetData (DataFormats.WaveAudio, audioStream);
305                 }
306 #endif
307
308                 public virtual void SetData(object data) {
309                         SetData(data.GetType(), data); 
310                 }
311
312                 public virtual void SetData(string format, bool autoConvert, object data) {
313                         Entry   entry;
314                         Entry   e;
315
316                         entry = Entry.Find(entries, format);
317
318                         if (entry == null) {
319                                 entry = new DataObject.Entry(format, data, autoConvert);
320                         } else {
321                                 entry.Data = data;
322                                 return;
323                         }
324
325                         lock (this) {
326                                 if (entries == null) {
327                                         entries = entry;
328                                 } else {
329                                         // Insert into the list of known/defined formats
330                                         e = entries;
331
332                                         while (e.next != null) {
333                                                 e = e.next;
334                                         }
335                                         e.next = entry;
336                                 }
337                         }
338                 }
339
340                 public virtual void SetData(string format, object data) {
341                         SetData(format, true, data);
342                 }
343
344                 public virtual void SetData(Type format, object data) {
345                         SetData(EnsureFormat(format), true, data);
346                 }
347                 
348 #if NET_2_0
349                 [MonoInternalNote ("Needs additional checks for valid paths, see MSDN")]
350                 public virtual void SetFileDropList (StringCollection filePaths)
351                 {
352                         if (filePaths == null)
353                                 throw new ArgumentNullException ("filePaths");
354
355                         SetData (DataFormats.FileDrop, filePaths);
356                 }
357
358                 public virtual void SetImage (Image image)
359                 {
360                         if (image == null)
361                                 throw new ArgumentNullException ("image");
362
363                         SetData (DataFormats.Bitmap, image);
364                 }
365
366                 public virtual void SetText (string text)
367                 {
368                         if (string.IsNullOrEmpty (text))
369                                 throw new ArgumentNullException ("text");
370
371                         SetData (DataFormats.UnicodeText, text);
372                 }
373
374                 public virtual void SetText (string text, TextDataFormat format)
375                 {
376                         if (string.IsNullOrEmpty (text))
377                                 throw new ArgumentNullException ("text");
378                         if (!Enum.IsDefined (typeof (TextDataFormat), format))
379                                 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for TextDataFormat", format));
380
381                         switch (format) {
382                                 case TextDataFormat.Text:
383                                         SetData (DataFormats.Text, text);
384                                         break;
385                                 case TextDataFormat.UnicodeText:
386                                         SetData (DataFormats.UnicodeText, text);
387                                         break;
388                                 case TextDataFormat.Rtf:
389                                         SetData (DataFormats.Rtf, text);
390                                         break;
391                                 case TextDataFormat.Html:
392                                         SetData (DataFormats.Html, text);
393                                         break;
394                                 case TextDataFormat.CommaSeparatedValue:
395                                         SetData (DataFormats.CommaSeparatedValue, text);
396                                         break;
397                         }
398                 }
399 #endif
400                 #endregion      // Public Instance Methods
401
402                 #region Private Methods
403                 internal string EnsureFormat(string name) {
404                         DataFormats.Format f;
405
406                         f = DataFormats.Format.Find(name);
407                         if (f == null) {
408                                 // Register the format
409                                 f = DataFormats.Format.Add(name);
410                         }
411
412                         return f.Name;
413                 }
414
415                 internal string EnsureFormat(Type type) {
416                         return EnsureFormat(type.FullName);
417                 }
418
419 #if NET_2_0
420                 private string TextFormatToDataFormat (TextDataFormat format)
421                 {
422                         switch (format) {
423                                 case TextDataFormat.Text:
424                                 default:
425                                         return DataFormats.Text;
426                                 case TextDataFormat.UnicodeText:
427                                         return DataFormats.UnicodeText;
428                                 case TextDataFormat.Rtf:
429                                         return DataFormats.Rtf;
430                                 case TextDataFormat.Html:
431                                         return DataFormats.Html;
432                                 case TextDataFormat.CommaSeparatedValue:
433                                         return DataFormats.CommaSeparatedValue;
434                         }
435                 }
436 #endif
437                 #endregion      // Private Methods
438         }
439 }