/// <summary>
 /// Adds the declaration for the specified field to the source file
 /// or replaces the already present declaration for a field with the same name.
 /// </summary>
 /// <param name="domGenerator">The CodeDOMGenerator used to generate the field declaration.</param>
 /// <param name="newField">The CodeDom field to be added or replaced.</param>
 void AddOrReplaceField(CodeDOMGenerator domGenerator, CodeMemberField newField)
 {
     try {
         Reparse();
         IField oldField = GetField(completeClass, newField.Name);
         if (oldField != null)
         {
             string fileName = oldField.DeclaringType.CompilationUnit.FileName;
             LoggingService.Debug("-> Old field is declared in file '" + fileName + "', Region: " + oldField.Region.ToString());
             OpenedFile file = FileService.GetOpenedFile(fileName);
             if (file == null)
             {
                 throw new InvalidOperationException("The file where the field is declared is not open, although it belongs to the class.");
             }
             IDocument doc = this.ViewContent.GetDocumentForFile(file);
             if (doc == null)
             {
                 throw new InvalidOperationException("Could not get document for file '" + file.FileName + "'.");
             }
             this.ReplaceFieldDeclaration(doc, oldField, GenerateFieldDeclaration(domGenerator, newField));
             file.MakeDirty();
         }
         else
         {
             int endOffset = this.ViewContent.DesignerCodeFileDocument.PositionToOffset(initializeComponents.BodyRegion.EndLine + 1, 1);
             this.ViewContent.DesignerCodeFileDocument.Insert(endOffset, tabs + GenerateFieldDeclaration(domGenerator, newField) + Environment.NewLine);
         }
     } catch (Exception ex) {
         MessageService.ShowException(ex);
     }
 }
        protected virtual string GenerateFieldDeclaration(CodeDOMGenerator domGenerator, CodeMemberField field)
        {
            StringWriter writer = new StringWriter();

            domGenerator.ConvertContentDefinition(field, writer);
            return(writer.ToString().Trim());
        }
		public virtual void MergeFormChanges(CodeCompileUnit unit)
		{
			Reparse();
			
			// find InitializeComponent method and the class it is declared in
			CodeTypeDeclaration formClass = null;
			CodeMemberMethod initializeComponent = null;
			foreach (CodeNamespace n in unit.Namespaces) {
				foreach (CodeTypeDeclaration typeDecl in n.Types) {
					foreach (CodeTypeMember m in typeDecl.Members) {
						if (m is CodeMemberMethod && m.Name == "InitializeComponent") {
							formClass = typeDecl;
							initializeComponent = (CodeMemberMethod)m;
							break;
						}
					}
				}
			}
			
			if (formClass == null || initializeComponent == null) {
				throw new InvalidOperationException("InitializeComponent method not found in framework-generated CodeDom.");
			}
			if (this.formClass == null) {
				MessageService.ShowMessage("Cannot save form: InitializeComponent method does not exist anymore. You should not modify the Designer.cs file while editing a form.");
				return;
			}
			
			RemoveUnsupportedCode(formClass, initializeComponent);
			
			FixGeneratedCode(this.formClass, initializeComponent);
			
			// generate file and get initialize components string
			StringWriter writer = new StringWriter();
			string indentation = tabs + EditorControlService.GlobalOptions.IndentationString;
			CodeDOMGenerator domGenerator = new CodeDOMGenerator(this.CodeDomProvider, indentation);
			domGenerator.ConvertContentDefinition(initializeComponent, writer);
			
			string statements = writer.ToString();
			
			// initializeComponents.BodyRegion.BeginLine + 1
			DomRegion bodyRegion = GetReplaceRegion(this.ViewContent.DesignerCodeFileDocument, initializeComponents);
			if (bodyRegion.BeginColumn <= 0 || bodyRegion.EndColumn <= 0)
				throw new InvalidOperationException("Column must be > 0");
			int startOffset = this.ViewContent.DesignerCodeFileDocument.PositionToOffset(bodyRegion.BeginLine, bodyRegion.BeginColumn);
			int endOffset   = this.ViewContent.DesignerCodeFileDocument.PositionToOffset(bodyRegion.EndLine, bodyRegion.EndColumn);
			
			this.ViewContent.DesignerCodeFileDocument.Replace(startOffset, endOffset - startOffset, statements);
			
			// apply changes the designer made to field declarations
			// first loop looks for added and changed fields
			foreach (CodeTypeMember m in formClass.Members) {
				if (m is CodeMemberField) {
					CodeMemberField newField = (CodeMemberField)m;
					IField oldField = GetField(completeClass, newField.Name);
					if (oldField == null || FieldChanged(oldField, newField)) {
						AddOrReplaceField(domGenerator, newField);
					}
				}
			}
			
			// second loop looks for removed fields
			List<string> removedFields = new List<string>();
			foreach (IField field in completeClass.Fields) {
				bool found = false;
				foreach (CodeTypeMember m in formClass.Members) {
					if (m is CodeMemberField && m.Name == field.Name) {
						found = true;
						break;
					}
				}
				if (!found) {
					removedFields.Add(field.Name);
				}
			}
			// removing fields is done in two steps because
			// we must not modify the c.Fields collection while it is enumerated
			removedFields.ForEach(RemoveField);
			
			ParserService.BeginParse(this.ViewContent.DesignerCodeFile.FileName, this.ViewContent.DesignerCodeFileDocument);
		}
		/// <summary>
		/// Adds the declaration for the specified field to the source file
		/// or replaces the already present declaration for a field with the same name.
		/// </summary>
		/// <param name="domGenerator">The CodeDOMGenerator used to generate the field declaration.</param>
		/// <param name="newField">The CodeDom field to be added or replaced.</param>
		void AddOrReplaceField(CodeDOMGenerator domGenerator, CodeMemberField newField)
		{
			try {
				Reparse();
				IField oldField = GetField(completeClass, newField.Name);
				if (oldField != null) {
					string fileName = oldField.DeclaringType.CompilationUnit.FileName;
					LoggingService.Debug("-> Old field is declared in file '" + fileName + "', Region: " + oldField.Region.ToString());
					OpenedFile file = FileService.GetOpenedFile(fileName);
					if (file == null) throw new InvalidOperationException("The file where the field is declared is not open, although it belongs to the class.");
					IDocument doc = this.ViewContent.GetDocumentForFile(file);
					if (doc == null) throw new InvalidOperationException("Could not get document for file '" + file.FileName + "'.");
					this.ReplaceFieldDeclaration(doc, oldField, GenerateFieldDeclaration(domGenerator, newField));
					file.MakeDirty();
				} else {
					int endOffset = this.ViewContent.DesignerCodeFileDocument.PositionToOffset(initializeComponents.BodyRegion.EndLine + 1, 1);
					this.ViewContent.DesignerCodeFileDocument.Insert(endOffset, tabs + GenerateFieldDeclaration(domGenerator, newField) + Environment.NewLine);
				}
			} catch (Exception ex) {
				MessageService.ShowException(ex);
			}
		}
		protected virtual string GenerateFieldDeclaration(CodeDOMGenerator domGenerator, CodeMemberField field)
		{
			StringWriter writer = new StringWriter();
			domGenerator.ConvertContentDefinition(field, writer);
			return writer.ToString().Trim();
		}
        public virtual void MergeFormChanges(CodeCompileUnit unit)
        {
            Reparse();

            // find InitializeComponent method and the class it is declared in
            CodeTypeDeclaration formClass           = null;
            CodeMemberMethod    initializeComponent = null;

            foreach (CodeNamespace n in unit.Namespaces)
            {
                foreach (CodeTypeDeclaration typeDecl in n.Types)
                {
                    foreach (CodeTypeMember m in typeDecl.Members)
                    {
                        if (m is CodeMemberMethod && m.Name == "InitializeComponent")
                        {
                            formClass           = typeDecl;
                            initializeComponent = (CodeMemberMethod)m;
                            break;
                        }
                    }
                }
            }

            if (formClass == null || initializeComponent == null)
            {
                throw new InvalidOperationException("InitializeComponent method not found in framework-generated CodeDom.");
            }
            if (this.formClass == null)
            {
                MessageService.ShowMessage("Cannot save form: InitializeComponent method does not exist anymore. You should not modify the Designer.cs file while editing a form.");
                return;
            }

            FixGeneratedCode(this.formClass, initializeComponent);

            // generate file and get initialize components string
            StringWriter     writer       = new StringWriter();
            CodeDOMGenerator domGenerator = new CodeDOMGenerator(this.CodeDomProvider, tabs + '\t');

            domGenerator.ConvertContentDefinition(initializeComponent, writer);

            string statements = writer.ToString();

            // initializeComponents.BodyRegion.BeginLine + 1
            DomRegion bodyRegion = GetReplaceRegion(this.ViewContent.DesignerCodeFileDocument, initializeComponents);

            if (bodyRegion.BeginColumn <= 0 || bodyRegion.EndColumn <= 0)
            {
                throw new InvalidOperationException("Column must be > 0");
            }
            int startOffset = this.ViewContent.DesignerCodeFileDocument.PositionToOffset(bodyRegion.BeginLine, bodyRegion.BeginColumn);
            int endOffset   = this.ViewContent.DesignerCodeFileDocument.PositionToOffset(bodyRegion.EndLine, bodyRegion.EndColumn);

            this.ViewContent.DesignerCodeFileDocument.Replace(startOffset, endOffset - startOffset, statements);

            // apply changes the designer made to field declarations
            // first loop looks for added and changed fields
            foreach (CodeTypeMember m in formClass.Members)
            {
                if (m is CodeMemberField)
                {
                    CodeMemberField newField = (CodeMemberField)m;
                    IField          oldField = GetField(completeClass, newField.Name);
                    if (oldField == null || FieldChanged(oldField, newField))
                    {
                        AddOrReplaceField(domGenerator, newField);
                    }
                }
            }

            // second loop looks for removed fields
            List <string> removedFields = new List <string>();

            foreach (IField field in completeClass.Fields)
            {
                bool found = false;
                foreach (CodeTypeMember m in formClass.Members)
                {
                    if (m is CodeMemberField && m.Name == field.Name)
                    {
                        found = true;
                        break;
                    }
                }
                if (!found)
                {
                    removedFields.Add(field.Name);
                }
            }
            // removing fields is done in two steps because
            // we must not modify the c.Fields collection while it is enumerated
            removedFields.ForEach(RemoveField);

            ParserService.BeginParse(this.ViewContent.DesignerCodeFile.FileName, this.ViewContent.DesignerCodeFileDocument);
        }
		protected override string GenerateFieldDeclaration(CodeDOMGenerator domGenerator, CodeMemberField field)
		{
			// TODO: add support for modifiers
			// (or implement code generation for fields in the Boo CodeDomProvider)
			return "private " + field.Name + " as " + field.Type.BaseType;
		}