3c1f479b9d
Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
290 lines
9.1 KiB
C#
290 lines
9.1 KiB
C#
//
|
|
// System.ComponentModel.Design.Serialization.CodeDomDesignerLoader
|
|
//
|
|
// Authors:
|
|
// Ivan N. Zlatev (contact i-nZ.net)
|
|
//
|
|
// (C) 2007 Ivan N. Zlatev
|
|
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.ComponentModel;
|
|
using System.ComponentModel.Design;
|
|
|
|
using System.CodeDom;
|
|
using System.CodeDom.Compiler;
|
|
|
|
namespace System.ComponentModel.Design.Serialization
|
|
{
|
|
public abstract class CodeDomDesignerLoader : BasicDesignerLoader, INameCreationService, IDesignerSerializationService
|
|
{
|
|
private CodeDomSerializer _rootSerializer;
|
|
|
|
protected CodeDomDesignerLoader ()
|
|
{
|
|
}
|
|
|
|
protected override void Initialize ()
|
|
{
|
|
base.Initialize ();
|
|
base.LoaderHost.AddService (typeof (IDesignerSerializationService), this);
|
|
base.LoaderHost.AddService (typeof (INameCreationService), this);
|
|
base.LoaderHost.AddService (typeof (ComponentSerializationService), new
|
|
CodeDomComponentSerializationService (base.LoaderHost));
|
|
if (this.TypeResolutionService != null &&
|
|
LoaderHost.GetService (typeof (ITypeResolutionService)) == null)
|
|
LoaderHost.AddService (typeof (ITypeResolutionService), this.TypeResolutionService);
|
|
IDesignerSerializationManager manager = base.LoaderHost.GetService (typeof (IDesignerSerializationManager)) as IDesignerSerializationManager;
|
|
if (manager != null)
|
|
manager.AddSerializationProvider (CodeDomSerializationProvider.Instance);
|
|
}
|
|
|
|
protected override bool IsReloadNeeded ()
|
|
{
|
|
if (this.CodeDomProvider is ICodeDomDesignerReload)
|
|
return ((ICodeDomDesignerReload) CodeDomProvider).ShouldReloadDesigner (Parse ());
|
|
return base.IsReloadNeeded ();
|
|
}
|
|
|
|
protected override void PerformLoad (IDesignerSerializationManager manager)
|
|
{
|
|
if (manager == null)
|
|
throw new ArgumentNullException ("manager");
|
|
|
|
CodeCompileUnit document = this.Parse ();
|
|
if (document == null)
|
|
throw new NotSupportedException ("The language did not provide a code parser for this file");
|
|
|
|
string namespaceName = null;
|
|
CodeTypeDeclaration rootDocument = GetFirstCodeTypeDecl (document, out namespaceName);
|
|
if (rootDocument == null)
|
|
throw new InvalidOperationException ("Cannot find a declaration in a namespace to load.");
|
|
|
|
_rootSerializer = manager.GetSerializer (manager.GetType (rootDocument.BaseTypes[0].BaseType),
|
|
typeof (RootCodeDomSerializer)) as CodeDomSerializer;
|
|
if (_rootSerializer == null)
|
|
throw new InvalidOperationException ("Serialization not supported for this class");
|
|
|
|
_rootSerializer.Deserialize (manager, rootDocument);
|
|
|
|
base.SetBaseComponentClassName (namespaceName + "." + rootDocument.Name);
|
|
}
|
|
|
|
private CodeTypeDeclaration GetFirstCodeTypeDecl (CodeCompileUnit document, out string namespaceName)
|
|
{
|
|
namespaceName = null;
|
|
|
|
foreach (CodeNamespace namesp in document.Namespaces) {
|
|
foreach (CodeTypeDeclaration declaration in namesp.Types) {
|
|
if (declaration.IsClass) {
|
|
namespaceName = namesp.Name;
|
|
return declaration;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
protected override void PerformFlush (IDesignerSerializationManager manager)
|
|
{
|
|
if (_rootSerializer != null) {
|
|
CodeTypeDeclaration typeDecl = (CodeTypeDeclaration) _rootSerializer.Serialize (manager,
|
|
base.LoaderHost.RootComponent);
|
|
this.Write (MergeTypeDeclWithCompileUnit (typeDecl, this.Parse ()));
|
|
}
|
|
}
|
|
|
|
// Will either add the class or replace an existing class
|
|
// with the one from GenerateClass ()
|
|
//
|
|
private CodeCompileUnit MergeTypeDeclWithCompileUnit (CodeTypeDeclaration typeDecl, CodeCompileUnit unit)
|
|
{
|
|
CodeNamespace namespac = null;
|
|
int typeIndex = -1;
|
|
|
|
foreach (CodeNamespace namesp in unit.Namespaces) {
|
|
for (int i=0; i< namesp.Types.Count; i++) {
|
|
if (namesp.Types[i].IsClass) {
|
|
typeIndex = i;
|
|
namespac = namesp;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (typeIndex != -1)
|
|
namespac.Types.RemoveAt (typeIndex);
|
|
|
|
namespac.Types.Add (typeDecl);
|
|
|
|
return unit;
|
|
}
|
|
|
|
protected override void OnBeginLoad ()
|
|
{
|
|
base.OnBeginLoad ();
|
|
|
|
IComponentChangeService service = base.GetService (typeof (IComponentChangeService)) as IComponentChangeService;
|
|
if (service != null)
|
|
service.ComponentRename += this.OnComponentRename_EventHandler;
|
|
}
|
|
|
|
protected override void OnBeginUnload ()
|
|
{
|
|
base.OnBeginUnload ();
|
|
|
|
IComponentChangeService service = base.GetService (typeof (IComponentChangeService)) as IComponentChangeService;
|
|
if (service != null)
|
|
service.ComponentRename -= this.OnComponentRename_EventHandler;
|
|
}
|
|
|
|
protected override void OnEndLoad (bool successful, ICollection errors)
|
|
{
|
|
base.OnEndLoad (successful, errors);
|
|
// XXX: msdn says overriden
|
|
}
|
|
|
|
private void OnComponentRename_EventHandler (object sender, ComponentRenameEventArgs args)
|
|
{
|
|
this.OnComponentRename (args.Component, args.OldName, args.NewName);
|
|
}
|
|
|
|
// MSDN says that here one should raise ComponentRename event and that's nonsense.
|
|
//
|
|
protected virtual void OnComponentRename (object component, string oldName, string newName)
|
|
{
|
|
// What shall we do with the drunken sailor,
|
|
// what shall we do with the drunken sailor early in the morning?
|
|
}
|
|
|
|
protected abstract CodeDomProvider CodeDomProvider { get; }
|
|
protected abstract ITypeResolutionService TypeResolutionService { get; }
|
|
protected abstract CodeCompileUnit Parse ();
|
|
protected abstract void Write (CodeCompileUnit unit);
|
|
|
|
public override void Dispose ()
|
|
{
|
|
base.Dispose ();
|
|
}
|
|
|
|
#region INameCreationService implementation
|
|
|
|
// very simplistic implementation to generate names like "button1", "someControl2", etc
|
|
//
|
|
string INameCreationService.CreateName (IContainer container, Type dataType)
|
|
{
|
|
if (dataType == null)
|
|
throw new ArgumentNullException ("dataType");
|
|
|
|
string name = dataType.Name;
|
|
char lower = Char.ToLower (name[0]);
|
|
name = name.Remove (0, 1);
|
|
name = name.Insert (0, Char.ToString (lower));
|
|
|
|
int uniqueId = 1;
|
|
bool unique = false;
|
|
|
|
while (!unique) {
|
|
if (container != null && container.Components[name + uniqueId] != null) {
|
|
uniqueId++;
|
|
} else {
|
|
unique = true;
|
|
name = name + uniqueId;
|
|
}
|
|
}
|
|
|
|
if (this.CodeDomProvider != null)
|
|
name = CodeDomProvider.CreateValidIdentifier (name);
|
|
|
|
return name;
|
|
}
|
|
|
|
bool INameCreationService.IsValidName (string name)
|
|
{
|
|
if (name == null)
|
|
throw new ArgumentNullException ("name");
|
|
|
|
bool valid = true;
|
|
if (base.LoaderHost != null && base.LoaderHost.Container.Components[name] != null) {
|
|
valid = false;
|
|
} else {
|
|
if (this.CodeDomProvider != null) {
|
|
valid = CodeDomProvider.IsValidIdentifier (name);
|
|
} else {
|
|
if (name.Trim().Length == 0)
|
|
valid = false;
|
|
foreach (char c in name) {
|
|
if (!Char.IsLetterOrDigit (c)) {
|
|
valid = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return valid;
|
|
}
|
|
|
|
void INameCreationService.ValidateName (string name)
|
|
{
|
|
if (!((INameCreationService) this).IsValidName (name))
|
|
throw new ArgumentException ("Invalid name '" + name + "'");
|
|
}
|
|
#endregion
|
|
|
|
|
|
#region IDesignerSerializationService implementation
|
|
|
|
ICollection IDesignerSerializationService.Deserialize (object serializationData)
|
|
{
|
|
if (serializationData == null)
|
|
throw new ArgumentNullException ("serializationData");
|
|
|
|
ComponentSerializationService service = LoaderHost.GetService (typeof (ComponentSerializationService)) as ComponentSerializationService;
|
|
SerializationStore store = serializationData as SerializationStore;
|
|
if (service != null && serializationData != null)
|
|
return service.Deserialize (store, this.LoaderHost.Container);
|
|
return new object[0];
|
|
}
|
|
|
|
object IDesignerSerializationService.Serialize (ICollection objects)
|
|
{
|
|
if (objects == null)
|
|
throw new ArgumentNullException ("objects");
|
|
|
|
ComponentSerializationService service = LoaderHost.GetService (typeof (ComponentSerializationService)) as ComponentSerializationService;
|
|
if (service != null) {
|
|
SerializationStore store = service.CreateStore ();
|
|
foreach (object o in objects)
|
|
service.Serialize (store, o);
|
|
store.Close ();
|
|
return store;
|
|
}
|
|
return null;
|
|
}
|
|
#endregion
|
|
}
|
|
}
|
|
|