2008-06-18 Ivan N. Zlatev <contact@i-nz.net>
[mono.git] / mcs / class / System.Design / System.ComponentModel.Design / DesignerHost.cs
1 //
2 // System.ComponentModel.Design.DesignerHost
3 //
4 // Authors:      
5 //        Ivan N. Zlatev (contact i-nZ.net)
6 //
7 // (C) 2006-2007 Ivan N. Zlatev
8
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29
30 #if NET_2_0
31
32 using System;
33 using System.Collections;
34 using System.ComponentModel;
35 using System.ComponentModel.Design.Serialization;
36 using System.Windows.Forms.Design;
37 using System.Reflection;
38
39 namespace System.ComponentModel.Design
40 {
41
42         // A container for components and their designers
43         //
44         internal sealed class DesignerHost : Container, IDesignerLoaderHost, IDesignerHost, IServiceProvider, IComponentChangeService
45         {
46
47
48 #region DesignerHostTransaction : DesignerTransaction
49
50                 private enum TransactionAction
51                 {
52                         Commit,
53                         Cancel
54                 }
55
56                 private sealed class DesignerHostTransaction : DesignerTransaction
57                 {
58                         
59                         DesignerHost _designerHost;
60                         
61                         public DesignerHostTransaction (DesignerHost host, string description) : base (description)
62                         {
63                                 _designerHost = host;
64                         }
65
66                         protected override void OnCancel ()
67                         {
68                                 _designerHost.OnTransactionClosing (this, TransactionAction.Cancel);
69                                 _designerHost.OnTransactionClosed (this, TransactionAction.Cancel);
70                         }
71                         
72                         protected override void OnCommit ()
73                         {
74                                 _designerHost.OnTransactionClosing (this, TransactionAction.Commit);
75                                 _designerHost.OnTransactionClosed (this, TransactionAction.Commit);
76                         }
77
78                 } // DesignerHostTransaction
79
80 #endregion
81
82                 
83                 private IServiceProvider _serviceProvider;
84                 private Hashtable _designers;
85                 private Stack _transactions;
86                 private IServiceContainer _serviceContainer;
87                 private bool _loading;
88                 
89                 public DesignerHost (IServiceProvider serviceProvider)
90                 {
91                         if (serviceProvider == null)
92                                 throw new ArgumentNullException ("serviceProvider");
93
94                         _serviceProvider = serviceProvider;
95                         _serviceContainer = serviceProvider.GetService (typeof (IServiceContainer)) as IServiceContainer;
96                         _designers = new Hashtable ();
97                         _transactions = new Stack ();
98                         _loading = true;
99                 }
100
101                 
102 #region IContainer
103
104                 // XXX: More validation here?
105                 // (e.g: Make use of a potentially existing INameCreationService)
106                 //
107                 public override void Add (IComponent component, string name)
108                 {
109                         AddPreProcess (component, name);
110                         base.Add (component, name);
111                         AddPostProcess (component, name);
112                 }
113
114                 internal void AddPreProcess (IComponent component, string name)
115                 {
116                         if (ComponentAdding != null)
117                                 ComponentAdding (this, new ComponentEventArgs (component));
118                 }
119
120                 internal void AddPostProcess (IComponent component, string name)
121                 {
122                         IDesigner designer;
123
124                         if (_rootComponent == null) {
125                                 _rootComponent = component;
126                                 designer = this.CreateDesigner (component, true);
127                         }
128                         else {
129                                 designer = this.CreateDesigner (component, false);
130                         }
131                         
132                         if (designer != null) {
133                                 _designers[component] = designer;
134                                 designer.Initialize (component);
135                         } else {
136                                 IUIService uiService = GetService (typeof (IUIService)) as IUIService;
137                                 if (uiService != null) {
138                                         uiService.ShowError ("Unable to load a designer for component type '" +
139                                                              component.GetType ().Name + "'");
140                                 }
141                                 this.DestroyComponent (component);
142                         }
143
144                         // Activate the host and design surface once the root component is added to
145                         // the container and its designer is loaded and added to the designers collection
146                         if (component == _rootComponent)
147                                 this.Activate ();
148
149                         if (component is IExtenderProvider) {
150                                 IExtenderProviderService service = this.GetService (typeof (IExtenderProviderService)) as IExtenderProviderService;
151                                 if (service != null)
152                                         service.AddExtenderProvider ((IExtenderProvider) component);
153                         }
154
155                         if (ComponentAdded != null)
156                                 ComponentAdded (this, new ComponentEventArgs (component));
157                 }
158
159                 public override void Remove (IComponent component)
160                 {
161                         DesignerTransaction transaction = this.CreateTransaction ("Remove " + component.Site.Name);
162                         RemovePreProcess (component);
163                         base.Remove (component);
164                         RemovePostProcess (component);
165                         transaction.Commit ();
166                 }
167
168                 internal void RemovePreProcess (IComponent component)
169                 {
170                         if (ComponentRemoving != null)
171                                 ComponentRemoving (this, new ComponentEventArgs (component));
172
173                         IDesigner designer = _designers[component] as IDesigner;
174                         if (designer != null)
175                                 designer.Dispose ();
176
177                         _designers.Remove (component);
178
179                         if (component == _rootComponent)
180                                 _rootComponent = null;
181
182                         if (component is IExtenderProvider) {
183                                 IExtenderProviderService service = GetService (typeof (IExtenderProviderService)) as IExtenderProviderService;
184                                 if (service != null)
185                                         service.RemoveExtenderProvider ((IExtenderProvider) component);
186                         }
187                 }
188
189                 internal void RemovePostProcess (IComponent component)
190                 {
191                         if (ComponentRemoved != null)
192                                 ComponentRemoved (this, new ComponentEventArgs (component));
193                 }
194
195                 protected override ISite CreateSite (IComponent component, string name)
196                 {
197                         if (name == null) {
198                                 INameCreationService nameService = this.GetService (typeof (INameCreationService)) as INameCreationService;
199                                 if (nameService != null)
200                                         name = nameService.CreateName (this, component.GetType ());
201                         }
202                         return new DesignModeSite (component, name, this, this);
203                 }
204                 
205 #endregion
206
207                 
208 #region IDesignerHost
209
210                 private IComponent _rootComponent;
211                 
212                 public IContainer Container {
213                         get { return this; }
214                 }
215
216                 public bool InTransaction {
217                         get {
218                                 if (_transactions != null && _transactions.Count > 0)
219                                         return true;
220
221                                 return false;
222                         }
223                 }
224
225                 public bool Loading {
226                         get { return _loading; }
227                 }
228
229                 public IComponent RootComponent {
230                         get { return _rootComponent; }
231                 }
232
233                 public string RootComponentClassName {
234                         get {
235                                 if (_rootComponent != null)
236                                         return ((object)_rootComponent).GetType ().AssemblyQualifiedName;
237
238                                 return null;
239                         }
240                 }
241
242                 public string TransactionDescription {
243                         get {
244                                 if (_transactions != null && _transactions.Count > 0)
245                                         return ((DesignerHostTransaction) _transactions.Peek()).Description;
246                                         
247                                 return null;
248                         }
249                 }
250
251                 
252                 // GUI loading in the designer should be done after the Activated event is raised.
253                 //
254                 public void Activate ()
255                 {
256                         ISelectionService selectionService = GetService (typeof (ISelectionService)) as ISelectionService;
257
258                         // Set the Primary Selection to be the root component
259                         //
260                         if (selectionService != null)
261                                 selectionService.SetSelectedComponents (new IComponent[] { _rootComponent });
262                         
263                         if (Activated != null)
264                                 Activated (this, EventArgs.Empty);
265                 }
266                 
267                 public IComponent CreateComponent (Type componentClass)
268                 {
269                         return CreateComponent (componentClass, null);
270                 }
271
272                 public IComponent CreateComponent (Type componentClass, string name)
273                 {
274                         if (componentClass == null)
275                                 throw new ArgumentNullException ("componentClass");
276                                 
277                         else if (!typeof(IComponent).IsAssignableFrom(componentClass))
278                                 throw new ArgumentException ("componentClass");
279
280                         IComponent component = this.CreateInstance (componentClass) as IComponent;
281                         this.Add (component, name);
282                         
283                         return component;
284                 }
285
286                 internal object CreateInstance (Type type)
287                 {
288                         if (type == null)
289                                 throw new System.ArgumentNullException ("type");
290                         
291                         // FIXME: Should I use TypeDescriptor.CreateInstance() for 2.0 ?
292                         //
293                         return Activator.CreateInstance (type, BindingFlags.CreateInstance | BindingFlags.Public
294                                                          | BindingFlags.Instance, null,  null, null);
295                 }
296
297                 internal IDesigner CreateDesigner (IComponent component, bool rootDesigner)
298                 {
299                         if (component == null)
300                                 throw new System.ArgumentNullException ("component");
301                          
302                         if (rootDesigner) {
303                                 //return TypeDescriptor.CreateDesigner (component, typeof (IRootDesigner));
304                                 return this.CreateDesigner (component, typeof (IRootDesigner));
305                         }
306                         else {
307                                 //return TypeDescriptor.CreateDesigner (component, typeof (IDesigner));
308                                 return this.CreateDesigner (component, typeof (IDesigner));
309                         }
310                 }
311
312                 // Since most of the specific designers are missing this temporary method 
313                 // will fallback to the first available designer type in the type's base types
314                 //
315                 private IDesigner CreateDesigner (IComponent component, Type designerBaseType)
316                 {
317                         IDesigner instance = null;
318                         AttributeCollection attributes = TypeDescriptor.GetAttributes (component);
319
320                         foreach (Attribute attribute in attributes) {
321                                 DesignerAttribute designerAttr = attribute as DesignerAttribute;
322                                 if (designerAttr != null &&
323                                         (designerBaseType.FullName == designerAttr.DesignerBaseTypeName ||
324                                         designerBaseType.AssemblyQualifiedName == designerAttr.DesignerBaseTypeName)) {
325                                         Type type = Type.GetType (designerAttr.DesignerTypeName);
326                                         if (type == null && designerBaseType == typeof (IRootDesigner))
327                                                 type = typeof (System.Windows.Forms.Design.DocumentDesigner);
328                                         if (type != null)
329                                                 instance = (IDesigner) Activator.CreateInstance (type);
330                                         break;
331                                 }
332                         }
333
334                         if (instance == null) {
335                                 Type baseType = component.GetType ().BaseType;
336                                 do {
337                                         attributes = TypeDescriptor.GetAttributes (baseType);
338                                         foreach (Attribute attribute in attributes) {
339                                                 DesignerAttribute designerAttr = attribute as DesignerAttribute;
340                                                 if (designerAttr != null && 
341                                                         (designerBaseType.FullName == designerAttr.DesignerBaseTypeName ||
342                                                         designerBaseType.AssemblyQualifiedName == designerAttr.DesignerBaseTypeName)) {
343                                                         Type type = Type.GetType (designerAttr.DesignerTypeName);
344                                                         if (type != null)
345                                                                 instance = (IDesigner) Activator.CreateInstance (type);
346                                                         break;
347                                                 }
348                                         }
349                                         baseType = baseType.BaseType;
350                                 } while (instance == null && baseType != null);
351                         }
352
353                         return instance;
354                 }
355
356                 public void DestroyComponent (IComponent component)
357                 {
358                         if (component.Site != null && component.Site.Container == this) {
359                                 this.Remove (component); // takes care for the designer as well
360                                 component.Dispose ();
361                         }
362                 }
363
364                 public IDesigner GetDesigner (IComponent component)
365                 {
366                         if (component == null)
367                                 throw new ArgumentNullException ("component");
368                         
369                         return _designers[component] as IDesigner;
370                 }
371
372                 public DesignerTransaction CreateTransaction ()
373                 {
374                         return CreateTransaction (null);
375                 }
376                 
377                 public DesignerTransaction CreateTransaction (string description)
378                 {
379                         if (TransactionOpening != null)
380                                 TransactionOpening (this, EventArgs.Empty);
381                         
382                         DesignerHostTransaction transaction = new DesignerHostTransaction (this, description);
383                         _transactions.Push (transaction);
384
385                         if (TransactionOpened != null)
386                                 TransactionOpened (this, EventArgs.Empty);
387                         
388                         return transaction;
389                 }
390
391
392                 public Type GetType (string typeName)
393                 {
394                         Type result;
395                         ITypeResolutionService s = GetService (typeof (ITypeResolutionService)) as ITypeResolutionService;
396                         
397                         if (s != null)
398                                 result = s.GetType (typeName);
399                         else
400                                 result = Type.GetType (typeName);
401                         
402                         return result;
403                 }
404
405                 // Take care of disposing the designer the base.Dispose will cleanup
406                 // the components.
407                 //
408                 protected override void Dispose (bool disposing)
409                 {
410                         Unload ();
411                         base.Dispose (disposing);
412                 }
413
414                 
415                 public event EventHandler Activated;
416                 public event EventHandler Deactivated;
417                 public event EventHandler LoadComplete;  
418                 public event DesignerTransactionCloseEventHandler TransactionClosed;
419                 public event DesignerTransactionCloseEventHandler TransactionClosing;
420                 public event EventHandler TransactionOpened;
421                 public event EventHandler TransactionOpening;
422
423                 private void OnTransactionClosing (DesignerHostTransaction raiser, TransactionAction action)
424                 {
425                         bool commit = false;
426                         bool lastTransaction = false;
427
428                         if (_transactions.Peek () != raiser)
429                                 throw new InvalidOperationException ("Current transaction differs from the one a commit was requested for.");
430
431                         if (_transactions.Count == 1)
432                                 lastTransaction = true;
433                         if (action == TransactionAction.Commit)
434                                 commit = true;
435
436                         if (TransactionClosing != null)
437                                 TransactionClosing (this, new DesignerTransactionCloseEventArgs (commit, lastTransaction));  
438                 }
439
440                 private void OnTransactionClosed (DesignerHostTransaction raiser, TransactionAction action)
441                 {
442                         bool commit = false;
443                         bool lastTransaction = false;
444
445                         if (_transactions.Peek () != raiser)
446                                 throw new InvalidOperationException ("Current transaction differs from the one a commit was requested for.");
447
448                         if (_transactions.Count == 1)
449                                 lastTransaction = true;
450                         if (action == TransactionAction.Commit)
451                                 commit = true;
452
453                         _transactions.Pop ();
454
455                         if (TransactionClosed != null)
456                                 TransactionClosed (this, new DesignerTransactionCloseEventArgs (commit, lastTransaction));
457                 }
458                 
459 #endregion
460
461                 
462 #region IDesignerLoaderHost
463                 
464                 internal event LoadedEventHandler DesignerLoaderHostLoaded;
465                 internal event EventHandler DesignerLoaderHostLoading;
466                 internal event EventHandler DesignerLoaderHostUnloading;
467                 internal event EventHandler DesignerLoaderHostUnloaded;
468                 
469                 public void EndLoad (string rootClassName, bool successful, ICollection errorCollection)
470                 {
471                         if (DesignerLoaderHostLoaded != null)
472                                 DesignerLoaderHostLoaded (this, new LoadedEventArgs (successful, errorCollection));
473                         
474                         if (LoadComplete != null)
475                                 LoadComplete (this, EventArgs.Empty);
476
477                         _loading = false; // _loading = true is set by the ctor
478                 }
479
480                 // BasicDesignerLoader invokes this.Reload, then invokes BeginLoad on itself, 
481                 // then when loading it the loader is done it ends up in this.EndLoad.
482                 // At the end of the day Reload is more like Unload.
483                 // 
484                 public void Reload ()
485                 {
486                         _loading = true;
487                         Unload ();
488                         if (DesignerLoaderHostLoading != null)
489                                 DesignerLoaderHostLoading (this, EventArgs.Empty);
490                 }
491
492                 private void Unload ()
493                 {
494                         if (DesignerLoaderHostUnloading != null)
495                                 DesignerLoaderHostUnloading (this, EventArgs.Empty);
496
497                         IComponent[] components = new IComponent[this.Components.Count];
498                         this.Components.CopyTo (components, 0);
499                         
500                         foreach (IComponent component in components)
501                                 this.Remove (component);
502
503                         _transactions.Clear ();
504                         
505                         if (DesignerLoaderHostUnloaded != null)
506                                 DesignerLoaderHostUnloaded (this, EventArgs.Empty);
507                 }
508                                                 
509 #endregion
510
511
512 #region IComponentChangeService
513                 
514         public event ComponentEventHandler ComponentAdded;
515         public event ComponentEventHandler ComponentAdding;
516         public event ComponentChangedEventHandler ComponentChanged;
517         public event ComponentChangingEventHandler ComponentChanging;
518         public event ComponentEventHandler ComponentRemoved;
519         public event ComponentEventHandler ComponentRemoving;
520         public event ComponentRenameEventHandler ComponentRename;
521            
522                 
523         public void OnComponentChanged (object component, MemberDescriptor member, object oldValue, object newValue)
524         {
525                 if (ComponentChanged != null)
526                         ComponentChanged (this, new ComponentChangedEventArgs (component, member, oldValue, newValue));
527         }
528                                 
529         public void OnComponentChanging (object component, MemberDescriptor member)
530         {
531                 if (ComponentChanging != null)
532                         ComponentChanging (this, new ComponentChangingEventArgs (component, member));
533         }
534
535         internal void OnComponentRename (object component, string oldName, string newName)
536         {
537                 if (ComponentRename != null)
538                         ComponentRename (this, new ComponentRenameEventArgs (component, oldName, newName));
539         }
540                 
541 #endregion
542
543         
544 #region IServiceContainer
545                 // Wrapper around the DesignSurface service container
546                 //
547
548                 public void AddService (Type serviceType, object serviceInstance)
549                 {
550                         _serviceContainer.AddService (serviceType, serviceInstance);
551                 }
552                 
553                 public void AddService (Type serviceType, object serviceInstance, bool promote)
554                 {
555                         _serviceContainer.AddService (serviceType, serviceInstance, promote);
556                 }
557                 
558                 public void AddService (Type serviceType, ServiceCreatorCallback callback)
559                 {
560                         _serviceContainer.AddService (serviceType, callback);
561                 }
562
563                 public void AddService (Type serviceType, ServiceCreatorCallback callback, bool promote)
564                 {
565                         _serviceContainer.AddService (serviceType, callback, promote);
566                 }
567
568                 public void RemoveService (Type serviceType)
569                 {
570                         _serviceContainer.RemoveService (serviceType);
571                 }
572
573                 public void RemoveService (Type serviceType, bool promote)
574                 {
575                         _serviceContainer.RemoveService (serviceType, promote);
576                 }
577                         
578 #endregion
579
580
581 #region IServiceProvider
582
583         public new object GetService (Type serviceType)
584         {
585                 if (_serviceProvider != null)
586                         return _serviceProvider.GetService (serviceType);
587                 return null;
588         }
589                 
590 #endregion
591           
592                 }
593
594         }
595 #endif