1 //
2 // System.ComponentModel.Design.Serialization.BasicDesignerLoader
3 //
4 // Authors:
5 //	  Ivan N. Zlatev (contact i-nZ.net)
6 //
7 // (C) 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;
35 using System.Windows.Forms;
36 
37 namespace System.ComponentModel.Design.Serialization
38 {
39 	public abstract class BasicDesignerLoader : DesignerLoader, IDesignerLoaderService
40 	{
41 
42 		[Flags]
43 		protected enum ReloadOptions
44 		{
45 			Default,
46 			Force,
47 			ModifyOnError,
48 			NoFlush
49 		}
50 
51 		private bool _loaded;
52 		private bool _loading;
53 		private IDesignerLoaderHost _host;
54 		private int _dependenciesCount;
55 		private bool _notificationsEnabled;
56 		private bool _modified;
57 		private string _baseComponentClassName;
58 		private DesignerSerializationManager _serializationMananger;
59 		private bool _flushing;
60 		private bool _reloadScheduled;
61 		private ReloadOptions _reloadOptions;
62 
BasicDesignerLoader()63 		protected BasicDesignerLoader ()
64 		{
65 			_loading = _loaded = _flushing = _reloadScheduled = false;
66 			_host = null;
67 			_notificationsEnabled = false;
68 			_modified = false;
69 			_dependenciesCount = 0;
70 		}
71 
Initialize()72 		protected virtual void Initialize ()
73 		{
74 			_serializationMananger = new DesignerSerializationManager (_host);
75 
76 			DesignSurfaceServiceContainer serviceContainer = _host.GetService (typeof (IServiceContainer)) as DesignSurfaceServiceContainer;
77 			if (serviceContainer != null) {
78 				serviceContainer.AddService (typeof (IDesignerLoaderService), (IDesignerLoaderService) this);
79 				serviceContainer.AddNonReplaceableService (typeof (IDesignerSerializationManager), _serializationMananger);
80 			}
81 		}
82 
BeginLoad(IDesignerLoaderHost host)83 		public override void BeginLoad (IDesignerLoaderHost host)
84 		{
85 			if (host == null)
86 				throw new ArgumentNullException ("host");
87 			if (_loaded)
88 				throw new InvalidOperationException ("Already loaded.");
89 			if (_host != null && _host != host)
90 				throw new InvalidOperationException ("Trying to load with a different host");
91 
92 			if (_host == null) { // beingload is called on reload - no need to initialize twice.
93 				_host = host;
94 				Initialize ();
95 			}
96 			IDisposable session = _serializationMananger.CreateSession ();
97 
98 			IDesignerLoaderService loader = _host.GetService (typeof (IDesignerLoaderService)) as IDesignerLoaderService;
99 
100 			if (loader != null) {
101 				_dependenciesCount = -1;
102 				loader.AddLoadDependency ();
103 			} else {
104 				OnBeginLoad ();
105 			}
106 
107 			bool successful = true;
108 
109 			try {
110 				PerformLoad (_serializationMananger);
111 			} catch (Exception e) {
112 				successful = false;
113 				_serializationMananger.Errors.Add (e);
114 			}
115 
116 			if (loader != null)
117 				loader.DependentLoadComplete (successful, _serializationMananger.Errors);
118 			else
119 				OnEndLoad (successful, _serializationMananger.Errors);
120 
121 			session.Dispose ();
122 		}
123 
PerformLoad(IDesignerSerializationManager serializationManager)124 		protected abstract void PerformLoad (IDesignerSerializationManager serializationManager);
125 
OnBeginLoad()126 		protected virtual void OnBeginLoad ()
127 		{
128 			_loading = true;
129 		}
130 
OnEndLoad(bool successful, ICollection errors)131 		protected virtual void OnEndLoad (bool successful, ICollection errors)
132 		{
133 			_host.EndLoad (_baseComponentClassName, successful,  errors);
134 
135 			if (successful) {
136 				_loaded = true;
137 				EnableComponentNotification (true);
138 			} else {
139 				if (_reloadScheduled) { // we are reloading
140 					bool modify = ((_reloadOptions & ReloadOptions.ModifyOnError) == ReloadOptions.ModifyOnError);
141 					if (modify) {
142 						OnModifying ();
143 						this.Modified = true;
144 					}
145 				}
146 			}
147 			_loading = false;
148 		}
149 
150 		public override bool Loading {
151 			get { return _loading; }
152 		}
153 
154 		protected IDesignerLoaderHost LoaderHost {
155 			get { return _host; }
156 		}
157 
158 		protected virtual bool Modified {
159 			get { return _modified; }
160 			set { _modified = value; }
161 		}
162 
163 		protected object PropertyProvider {
164 			get {
165 				if (!_loaded)
166 					throw new InvalidOperationException ("host not initialized");
167 				return _serializationMananger.PropertyProvider;
168 			}
169 			set {
170 				if (!_loaded)
171 					throw new InvalidOperationException ("host not initialized");
172 				_serializationMananger.PropertyProvider = value;
173 			}
174 		}
175 
176 		protected bool ReloadPending {
177 			get { return _reloadScheduled; }
178 		}
179 
EnableComponentNotification(bool enable)180 		protected virtual bool EnableComponentNotification (bool enable)
181 		{
182 			if (!_loaded)
183 				throw new InvalidOperationException ("host not initialized");
184 
185 			IComponentChangeService service = _host.GetService (typeof (IComponentChangeService)) as IComponentChangeService;
186 			if (service != null && _notificationsEnabled != enable) {
187 				if (enable) {
188 					service.ComponentAdding += new ComponentEventHandler (OnComponentAdding);
189 					service.ComponentAdded += new ComponentEventHandler (OnComponentAdded);
190 					service.ComponentRemoving += new ComponentEventHandler (OnComponentRemoving);
191 					service.ComponentRemoved += new ComponentEventHandler (OnComponentRemoved);
192 					service.ComponentChanging += new ComponentChangingEventHandler (OnComponentChanging);
193 					service.ComponentChanged += new ComponentChangedEventHandler (OnComponentChanged);
194 					service.ComponentRename += new ComponentRenameEventHandler (OnComponentRename);
195 				} else {
196 					service.ComponentAdding -= new ComponentEventHandler (OnComponentAdding);
197 					service.ComponentAdded -= new ComponentEventHandler (OnComponentAdded);
198 					service.ComponentRemoving -= new ComponentEventHandler (OnComponentRemoving);
199 					service.ComponentRemoved -= new ComponentEventHandler (OnComponentRemoved);
200 					service.ComponentChanging -= new ComponentChangingEventHandler (OnComponentChanging);
201 					service.ComponentChanged -= new ComponentChangedEventHandler (OnComponentChanged);
202 					service.ComponentRename -= new ComponentRenameEventHandler (OnComponentRename);
203 				}
204 			}
205 			return _notificationsEnabled == true ? true : false;
206 		}
207 
OnComponentAdded(object sender, ComponentEventArgs args)208 		private void OnComponentAdded (object sender, ComponentEventArgs args)
209 		{
210 			if (!_loading && _loaded)
211 				this.Modified = true;
212 		}
213 
OnComponentRemoved(object sender, ComponentEventArgs args)214 		private void OnComponentRemoved (object sender, ComponentEventArgs args)
215 		{
216 			if (!_loading && _loaded)
217 				this.Modified = true;
218 		}
219 
OnComponentAdding(object sender, ComponentEventArgs args)220 		private void OnComponentAdding (object sender, ComponentEventArgs args)
221 		{
222 			if (!_loading && _loaded)
223 				OnModifying ();
224 		}
225 
OnComponentRemoving(object sender, ComponentEventArgs args)226 		private void OnComponentRemoving (object sender, ComponentEventArgs args)
227 		{
228 			if (!_loading && _loaded)
229 				OnModifying ();
230 		}
231 
OnComponentChanged(object sender, ComponentChangedEventArgs args)232 		private void OnComponentChanged (object sender, ComponentChangedEventArgs args)
233 		{
234 			if (!_loading && _loaded)
235 				this.Modified = true;
236 		}
237 
OnComponentChanging(object sender, ComponentChangingEventArgs args)238 		private void OnComponentChanging (object sender, ComponentChangingEventArgs args)
239 		{
240 			if (!_loading && _loaded)
241 				OnModifying ();
242 		}
243 
OnComponentRename(object sender, ComponentRenameEventArgs args)244 		private void OnComponentRename (object sender, ComponentRenameEventArgs args)
245 		{
246 			if (!_loading && _loaded) {
247 					OnModifying ();
248 					this.Modified = true;
249 			}
250 		}
251 
Flush()252 		public override void Flush ()
253 		{
254 			if (!_loaded)
255 				throw new InvalidOperationException ("host not initialized");
256 
257 			if (!_flushing && this.Modified) {
258 				_flushing = true;
259 				using ((IDisposable)_serializationMananger.CreateSession ()) {
260 					try {
261 						PerformFlush (_serializationMananger);
262 					} catch (Exception e) {
263 						_serializationMananger.Errors.Add (e);
264 						ReportFlushErrors (_serializationMananger.Errors);
265 					}
266 				}
267 				_flushing = false;
268 			}
269 		}
270 
PerformFlush(IDesignerSerializationManager serializationManager)271 		protected abstract void PerformFlush (IDesignerSerializationManager serializationManager);
272 
273 		// MSDN: The default implementation always returns true.
IsReloadNeeded()274 		protected virtual bool IsReloadNeeded ()
275 		{
276 			return true;
277 		}
278 
279 
OnBeginUnload()280 		protected virtual void OnBeginUnload ()
281 		{
282 		}
283 
OnModifying()284 		protected virtual void OnModifying ()
285 		{
286 		}
287 
288 		// MSDN: reloads are performed at idle time
Reload(ReloadOptions flags)289 		protected void Reload (ReloadOptions flags)
290 		{
291 			if (!_reloadScheduled) {
292 				_reloadScheduled = true;
293 				_reloadOptions = flags;
294 				bool force = ((flags & ReloadOptions.Force) == ReloadOptions.Force);
295 				if (force)
296 					ReloadCore ();
297 				else
298 					Application.Idle += new EventHandler (OnIdle);
299 			}
300 		}
301 
OnIdle(object sender, EventArgs args)302 		private void OnIdle (object sender,  EventArgs args)
303 		{
304 			Application.Idle -= new EventHandler (OnIdle);
305 			ReloadCore ();
306 		}
307 
ReloadCore()308 		private void ReloadCore ()
309 		{
310 			bool flush = !((_reloadOptions & ReloadOptions.NoFlush) == ReloadOptions.NoFlush);
311 
312 			if (flush)
313 				Flush ();
314 			Unload ();
315 			_host.Reload ();
316 			BeginLoad (_host); // calls EndLoad, which will check for ReloadOptions.ModifyOnError
317 			_reloadScheduled = false;
318 		}
319 
Unload()320 		private void Unload ()
321 		{
322 			if (_loaded) {
323 				OnBeginUnload ();
324 				EnableComponentNotification (false);
325 				_loaded = false;
326 				_baseComponentClassName = null;
327 			}
328 		}
329 
330 
331 		// The default implementation of ReportFlushErrors raises the last exception in the collection.
332 		//
ReportFlushErrors(ICollection errors)333 		protected virtual void ReportFlushErrors (ICollection errors)
334 		{
335 			object last = null;
336 			foreach (object o in errors)
337 				last = o;
338 			throw (Exception)last;
339 		}
340 
341 		// Must be called during PerformLoad by subclasses.
SetBaseComponentClassName(string name)342 		protected void SetBaseComponentClassName (string name)
343 		{
344 			if (name == null)
345 				throw new ArgumentNullException ("name");
346 			_baseComponentClassName = name;
347 		}
348 
349 #region IDesignerLoaderService implementation
350 
IDesignerLoaderService.AddLoadDependency()351 		void IDesignerLoaderService.AddLoadDependency ()
352 		{
353 			_dependenciesCount++;
354 			if (_dependenciesCount == 0) {
355 				_dependenciesCount = 1;
356 				OnBeginLoad ();
357 			}
358 		}
359 
IDesignerLoaderService.DependentLoadComplete(bool successful, ICollection errorCollection)360 		void IDesignerLoaderService.DependentLoadComplete (bool successful, ICollection errorCollection)
361 		{
362 			if (_dependenciesCount == 0)
363 				throw new InvalidOperationException ("dependencies == 0");
364 
365 			_dependenciesCount--;
366 			if (_dependenciesCount == 0) {
367 				OnEndLoad (successful,  errorCollection);
368 			}
369 		}
370 
IDesignerLoaderService.Reload()371 		bool IDesignerLoaderService.Reload ()
372 		{
373 			if (_dependenciesCount == 0) {
374 				this.Reload (ReloadOptions.Force);
375 				return true;
376 			}
377 			return false;
378 		}
379 #endregion
380 
GetService(Type serviceType)381 		protected object GetService (Type serviceType)
382 		{
383 			if (_host != null)
384 				return _host.GetService (serviceType);
385 			return null;
386 		}
387 
Dispose()388 		public override void Dispose ()
389 		{
390 			this.LoaderHost.RemoveService (typeof (IDesignerLoaderService));
391 			Unload ();
392 		}
393 	}
394 }
395 
396