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