2007-03-14 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mcs / class / System.Drawing / System.Drawing.Design / ToolboxItem.cs
1 //
2 // System.Drawing.Design.ToolboxItem.cs
3 //
4 // Authors:
5 //   Alejandro Sánchez Acosta
6 //   Andreas Nahr (ClassDevelopment@A-SoftTech.com)
7 //   Jordi Mas i Hernandez, jordimash@gmail.com
8 //   Sebastien Pouliot  <sebastien@ximian.com>
9 //
10 // (C) Alejandro Sánchez Acosta
11 // (C) 2003 Andreas Nahr
12 // Copyright (C) 2004-2006 Novell, Inc (http://www.novell.com)
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 // 
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 // 
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33
34 using System.Collections;
35 using System.ComponentModel;
36 using System.ComponentModel.Design;
37 using System.Reflection;
38 using System.Runtime.Serialization;
39 using System.Security.Permissions;
40
41 namespace System.Drawing.Design 
42 {
43         [Serializable]
44         [PermissionSet (SecurityAction.LinkDemand, Unrestricted = true)]
45         [PermissionSet (SecurityAction.InheritanceDemand, Unrestricted = true)]
46         [MonoTODO ("Implementation is incomplete.")]
47         public class ToolboxItem : ISerializable {
48
49                 private bool locked = false;
50                 private Hashtable properties = new Hashtable ();
51                 
52                 public ToolboxItem ()
53                 {
54                 }
55
56                 public ToolboxItem (Type toolType)
57                 {
58                         Initialize (toolType);
59                 }
60
61                 public AssemblyName AssemblyName {
62                         get { return (AssemblyName) properties["AssemblyName"]; }
63                         set { SetValue ("AssemblyName", value); }
64                 }
65
66                 public Bitmap Bitmap {
67                         get { return (Bitmap) properties["Bitmap"]; }
68                         set { SetValue ("Bitmap", value); }
69                 }
70
71                 public string DisplayName {
72                         get { return GetValue ("DisplayName"); }
73                         set { SetValue ("DisplayName", value); }
74                 }
75
76                 public ICollection Filter {
77                         get {
78                                 ICollection filter = (ICollection) properties["Filter"];
79                                 if (filter == null)
80                                         filter = new ToolboxItemFilterAttribute[0];
81                                 return filter;
82                         }
83                         set { SetValue ("Filter", value); }
84                 }
85 #if NET_2_0
86                 public virtual bool Locked {
87 #else           
88                 protected bool Locked {
89 #endif          
90                         get { return locked; }
91                 }
92
93                 public string TypeName {
94                         get { return GetValue ("TypeName"); }
95                         set { SetValue ("TypeName", value); }
96                 }
97 #if NET_2_0
98                 public string Company {
99                         get { return (string) properties["Company"]; }
100                         set { SetValue ("Company", value); }
101                 }
102
103                 public virtual string ComponentType {
104                         get { return ".NET Component"; }
105                 }
106
107                 public AssemblyName[] DependentAssemblies {
108                         get { return (AssemblyName[]) properties["DependentAssemblies"]; }
109                         set {
110                                 AssemblyName[] names = new AssemblyName [value.Length];
111                                 for (int i=0; i < names.Length; i++)
112                                         names [i] = value [i];
113                                 SetValue ("DependentAssemblies", names);
114                         }
115                 }
116
117                 public string Description {
118                         get { return (string) properties["Description"]; }
119                         set { SetValue ("Description", value); }
120                 }
121
122                 public bool IsTransient {                       
123                         get {
124                                 object o = properties ["IsTransient"];
125                                 return (o == null) ? false : (bool) o;
126                         }
127                         set { SetValue ("IsTransient", value); }
128                 }
129
130                 public IDictionary Properties {
131                          get { return properties; }
132                 }
133
134                 public virtual string Version { 
135                         get { return string.Empty; }
136                 }                               
137
138 #endif          
139                 protected void CheckUnlocked ()
140                 {
141                         if (locked)
142                                 throw new InvalidOperationException ("The ToolboxItem is locked");
143                 }
144
145                 public IComponent[] CreateComponents () 
146                 {
147                         return CreateComponents (null);
148                 }
149
150                 public IComponent[] CreateComponents (IDesignerHost host)
151                 {
152                         OnComponentsCreating (new ToolboxComponentsCreatingEventArgs (host));
153                         IComponent[] Comp = CreateComponentsCore (host);
154                         OnComponentsCreated ( new ToolboxComponentsCreatedEventArgs (Comp));
155                         return Comp;
156                 }
157
158                 // FIXME - get error handling logic correct
159                 protected virtual IComponent[] CreateComponentsCore (IDesignerHost host)
160                 {
161                         if (host == null)
162                                 throw new ArgumentNullException("host");
163
164                         OnComponentsCreating(new ToolboxComponentsCreatingEventArgs(host));
165                         
166                         IComponent[] components;
167                         Type type = GetType(host, AssemblyName, TypeName, true);
168                         if (type == null)
169                                 components = new IComponent[] { };
170                         else
171                                 components = new IComponent[] { host.CreateComponent(type) };
172
173                         OnComponentsCreated(new ToolboxComponentsCreatedEventArgs(components));
174                         return components;
175                 }
176
177 #if NET_2_0
178                 [MonoTODO] 
179                 protected virtual IComponent[] CreateComponentsCore (IDesignerHost host, IDictionary defaultValues)
180                 {
181                         throw new NotImplementedException ();
182                 } 
183
184                 [MonoTODO] 
185                 public IComponent[] CreateComponents (IDesignerHost host, IDictionary defaultValues)
186                 {
187                         throw new NotImplementedException ();
188                 } 
189
190                 [MonoTODO] 
191                 public Type GetType (IDesignerHost host)
192                 {
193                         if (host == null)
194                                 return null;
195                         throw new NotImplementedException ();
196                 }
197
198                 protected virtual object FilterPropertyValue (string propertyName, object value)
199                 {
200                         switch (propertyName) {
201                         case "AssemblyName":
202                                 return (value == null) ? null : (value as ICloneable).Clone ();
203                         case "DisplayName":
204                         case "TypeName":
205                                 return (value == null) ? String.Empty : value;
206                         case "Filter":
207                                 return (value == null) ? new ToolboxItemFilterAttribute [0] : value;
208                         default:
209                                 return value;
210                         }
211                 }
212 #endif
213
214                 protected virtual void Deserialize (SerializationInfo info, StreamingContext context)
215                 {                       
216                         AssemblyName = (AssemblyName)info.GetValue ("AssemblyName", typeof (AssemblyName));
217                         Bitmap = (Bitmap)info.GetValue ("Bitmap", typeof (Bitmap));
218                         Filter = (ICollection)info.GetValue ("Filter", typeof (ICollection));
219                         DisplayName = info.GetString ("DisplayName");
220                         locked = info.GetBoolean ("Locked");
221                         TypeName = info.GetString ("TypeName");
222                 }
223
224                 // FIXME: too harsh??
225                 public override bool Equals (object obj)
226                 {
227                         ToolboxItem ti = (obj as ToolboxItem);
228                         if (ti == null)
229                                 return false;
230                         if (obj == this)
231                                 return true;
232                         return (ti.AssemblyName.Equals (AssemblyName) &&
233                                 ti.Locked.Equals (locked) &&
234                                 ti.TypeName.Equals (TypeName) &&
235                                 ti.DisplayName.Equals (DisplayName) &&
236                                 ti.Bitmap.Equals (Bitmap));
237                 }
238                 
239                 public override int GetHashCode ()
240                 {
241                         // FIXME: other algorithm?
242                         return string.Concat (TypeName, DisplayName).GetHashCode ();
243                 }
244
245                 protected virtual Type GetType (IDesignerHost host, AssemblyName assemblyName, string typeName, bool reference)
246                 {
247                         if (typeName == null)
248                                 throw new ArgumentNullException ("typeName");
249
250                         if (host == null)
251                                 return null;
252
253                         //get ITypeResolutionService from host, as we have no other IServiceProvider here
254                         ITypeResolutionService typeRes = host.GetService(typeof(ITypeResolutionService)) as ITypeResolutionService;
255                         if (typeRes == null)
256                                 throw new Exception("Host does not provide an ITypeResolutionService");
257
258                         //TODO: Using Assembly loader to throw errors. Silent fail and return null?
259                         typeRes.GetAssembly(assemblyName, true);
260                         if (reference)
261                                 typeRes.ReferenceAssembly(assemblyName);
262                         return typeRes.GetType(typeName, true);
263                 }
264
265                 // FIXME - Should we be returning empty bitmap, or null?
266                 public virtual void Initialize (Type type) 
267                 {
268                         CheckUnlocked ();
269                         if (type == null)
270                                 return;
271
272                         AssemblyName = type.Assembly.GetName();
273                         DisplayName = type.Name;
274                         TypeName = type.FullName;
275                         
276                         // seems to be a right place to create the bitmap
277                         System.Drawing.Image image = null;
278                         foreach (object attribute in type.GetCustomAttributes(true)) {
279                                 ToolboxBitmapAttribute tba = attribute as ToolboxBitmapAttribute;
280                                 if (tba != null) {
281                                         image = tba.GetImage (type);
282                                         break;
283                                 }
284                         }
285                         //fallback: check for image even if not attribute
286                         if (image == null)
287                                 image = ToolboxBitmapAttribute.GetImageFromResource (type, null, false);
288                         
289                         if (image != null) {
290                                 if (image is Bitmap)
291                                         Bitmap = (Bitmap) image;
292                                 else
293                                         Bitmap = new Bitmap (image);
294                         }
295
296                         Filter = type.GetCustomAttributes (typeof (ToolboxItemFilterAttribute), true);
297                 }
298                         
299                 void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
300                 {
301                         Serialize (info, context);
302                 }
303
304 #if NET_2_0
305                 public virtual void Lock () 
306 #else           
307                 public void Lock ()
308 #endif                          
309                 {
310                         locked = true;
311                 }
312
313                 protected virtual void OnComponentsCreated (ToolboxComponentsCreatedEventArgs args)
314                 {
315                         if (ComponentsCreated != null)
316                                 this.ComponentsCreated (this, args);
317                 }
318
319                 protected virtual void OnComponentsCreating (ToolboxComponentsCreatingEventArgs args)
320                 {
321                         if (ComponentsCreated != null)
322                                 this.ComponentsCreating (this, args);
323                 }
324
325                 protected virtual void Serialize (SerializationInfo info, StreamingContext context)
326                 {
327                         info.AddValue ("AssemblyName", AssemblyName);
328                         info.AddValue ("Bitmap", Bitmap);
329                         info.AddValue ("Filter", Filter);
330                         info.AddValue ("DisplayName", DisplayName);
331                         info.AddValue ("Locked", locked);
332                         info.AddValue ("TypeName", TypeName);
333                 }
334
335                 public override string ToString()
336                 {
337                         return DisplayName;
338                 }
339
340 #if NET_2_0
341                 protected void ValidatePropertyType (string propertyName, object value, Type expectedType, bool allowNull)
342                 {
343                         if (!allowNull && (value == null))
344                                 throw new ArgumentNullException ("value");
345
346                         if ((value != null) && !expectedType.Equals (value.GetType ())) {
347                                 string msg = Locale.GetText ("Type mismatch between value ({0}) and expected type ({1}).",
348                                         value.GetType (), expectedType);
349                                 throw new ArgumentException (msg, "value");
350                         }
351                 }
352
353                 protected virtual object ValidatePropertyValue (string propertyName, object value)
354                 {
355                         switch (propertyName) {
356                         case "AssemblyName":
357                                 ValidatePropertyType (propertyName, value, typeof (AssemblyName), true);
358                                 break;
359                         case "Bitmap":
360                                 ValidatePropertyType (propertyName, value, typeof (Bitmap), true);
361                                 break;
362                         case "Company":
363                         case "Description":
364                         case "DisplayName":
365                         case "TypeName":
366                                 ValidatePropertyType (propertyName, value, typeof (string), true);
367                                 if (value == null)
368                                         value = String.Empty;
369                                 break;
370                         case "IsTransient":
371                                 ValidatePropertyType (propertyName, value, typeof (bool), false);
372                                 break;
373                         case "Filter":
374                                 ValidatePropertyType (propertyName, value, typeof (ToolboxItemFilterAttribute[]), true);
375                                 if (value == null)
376                                         value = new ToolboxItemFilterAttribute [0];
377                                 break;
378                         case "DependentAssemblies":
379                                 ValidatePropertyType (propertyName, value, typeof (AssemblyName[]), true);
380                                 break;
381                         default:
382                                 break;
383                         }
384                         return value;
385                 }
386
387                 private void SetValue (string propertyName, object value)
388                 {
389                         CheckUnlocked ();
390                         properties [propertyName] = ValidatePropertyValue (propertyName, value);
391                 }
392 #else
393                 private void SetValue (string propertyName, object value)
394                 {
395                         CheckUnlocked ();
396                         properties [propertyName] = value;
397                 }
398 #endif
399                 private string GetValue (string propertyName)
400                 {
401                         string s = (string) properties [propertyName];
402                         return (s == null) ? String.Empty : s;
403                 }
404
405                 public event ToolboxComponentsCreatedEventHandler ComponentsCreated;
406
407                 public event ToolboxComponentsCreatingEventHandler ComponentsCreating;
408         }
409 }