context: 
  using System;
  using System.CodeDom;
  using System.Xml;
  using System.Collections;
  using Stetic.Undo;
  
  namespace Stetic.Wrapper
  {
  	public sealed class ActionGroup: ObjectWrapper
  	{
  		string name;
  		ActionCollection actions;
  		ObjectWrapper owner;
  		bool generatePublic = true;
  		
  		public event ActionEventHandler ActionAdded;
  		public event ActionEventHandler ActionRemoved;
  		public event ActionEventHandler ActionChanged;
  		
  		public ActionGroup ()
  		{
  			actions = new ActionCollection (this);
  		}
  		
  		public ActionGroup (string name): this ()
  		{
  			this.name = name;
  		}
  		
  		public override void Dispose ()
  		{
  			foreach (Action a in actions)
  				a.Dispose ();
  			base.Dispose ();
  		}
  		
  		public ActionCollection Actions {
  			get { return actions; }
  		}
  		
  		public string Name {
  			get { return name; }
  			set { 
  				name = value;
  				NotifyChanged ();
  			}
  		}
  		
  		public bool GeneratePublic {
  			get { return generatePublic; }
  			set { generatePublic = value; }
  		}
  		
  		public Action GetAction (string name)
  		{
  			foreach (Action ac in actions)
  				if (ac.Name == name)
  					return ac;
  			return null;
  		}
  		
  		internal string GetValidName (Action reqAction, string name)
  		{
  			int max = 0;
  			bool found = false;
  			foreach (Action ac in Actions) {
  				if (ac == reqAction)
  					continue;
  					
  				string bname;
  				int index;
  				WidgetUtils.ParseWidgetName (ac.Name, out bname, out index);
  				
  				if (name == ac.Name)
  					found = true;
  				if (name == bname && index > max)
  					max = index;
  			}
  			if (found)
  				return name + (max+1);
  			else
  				return name;
  		}
  		
  		public override XmlElement Write (ObjectWriter writer)
  		{
  			XmlElement group = writer.XmlDocument.CreateElement ("action-group");
  			group.SetAttribute ("name", name);
  			if (writer.CreateUndoInfo)
  				group.SetAttribute ("undoId", UndoId);
  			foreach (Action ac in actions) {
  				if (ac.Name.Length > 0)
  					group.AppendChild (writer.WriteObject (ac));
  			}
  			return group;
  		}
  		
  		public override void Read (ObjectReader reader, XmlElement elem)
  		{
  			name = elem.GetAttribute ("name");
  			string uid = elem.GetAttribute ("undoId");
  			if (uid.Length > 0)
  				UndoId = uid;
  			foreach (XmlElement child in elem.SelectNodes ("action")) {
  				Action ac = new Action ();
  				ac.Read (reader, child);
  				actions.Add (ac);
  			}
  		}
  		
  		internal protected override CodeExpression GenerateObjectCreation (GeneratorContext ctx)
  		{
  			return new CodeObjectCreateExpression (
  				typeof(Gtk.ActionGroup).ToGlobalTypeRef (),
  				new CodePrimitiveExpression (Name)
  			);
  		}
  		
  		internal protected override void GenerateBuildCode (GeneratorContext ctx, CodeExpression var)
  		{
  			foreach (Action action in Actions) {
  				// Create the action
  				CodeExpression acVarExp = ctx.GenerateInstanceExpression (action, action.GenerateObjectCreation (ctx));
  				ctx.GenerateBuildCode (action, acVarExp);
  				ctx.Statements.Add (
  					new CodeMethodInvokeExpression (
  						var,
  						"Add",
  						acVarExp,
  						new CodePrimitiveExpression (action.Accelerator)
  					)
  				);
  			}
  		}
  		
  		internal void SetOwner (ObjectWrapper owner)
  		{
  			this.owner = owner;
  		}
  		
  		internal override UndoManager GetUndoManagerInternal ()
  		{
  			if (owner != null)
  				return owner.UndoManager;
  			else
  				return base.GetUndoManagerInternal ();
  		}
  		
  		public override ObjectWrapper FindObjectByUndoId (string id)
  		{
  			ObjectWrapper ow = base.FindObjectByUndoId (id);
  			if (ow != null) return ow;
  			
  			foreach (Action ac in Actions) {
  				ow = ac.FindObjectByUndoId (id);
  				if (ow != null)
  					return ow;
  			}
  			return null;
  		}
  		
  		DiffGenerator GetDiffGenerator ()
  		{
  			DiffGenerator gen = new DiffGenerator ();
  			gen.CurrentStatusAdaptor = new ActionDiffAdaptor (Project);
  			XmlDiffAdaptor xad = new XmlDiffAdaptor ();
  			xad.ChildElementName = "action";
  			gen.NewStatusAdaptor = xad;
  			return gen;
  		}
  		
  		public override object GetUndoDiff ()
  		{
  			XmlElement oldElem = UndoManager.GetObjectStatus (this);
  			UndoWriter writer = new UndoWriter (oldElem.OwnerDocument, UndoManager);
  			
  			XmlElement newElem = Write (writer);
  			ObjectDiff actionsDiff = GetDiffGenerator().GetDiff (this, oldElem);
  			UndoManager.UpdateObjectStatus (this, newElem);
  			return actionsDiff;
  		}
  		
  		public override object ApplyUndoRedoDiff (object diff)
  		{
  			ObjectDiff actionsDiff = (ObjectDiff) diff;
  			
  			XmlElement status = UndoManager.GetObjectStatus (this);
  			
  			DiffGenerator differ = GetDiffGenerator();
  			differ.ApplyDiff (this, actionsDiff);
  			actionsDiff = differ.GetDiff (this, status);
  			
  			UndoWriter writer = new UndoWriter (status.OwnerDocument, UndoManager);
  			XmlElement newElem = Write (writer);
  			UndoManager.UpdateObjectStatus (this, newElem);
  			
  			return actionsDiff;
  		}
  		
  		internal void NotifyActionAdded (Action ac)
  		{
  			ac.SetActionGroup (this);
  			ac.ObjectChanged += OnActionChanged;
  			ac.SignalAdded += OnSignalAdded;
  			ac.SignalRemoved += OnSignalRemoved;
  			ac.SignalChanged += OnSignalChanged;
  			
  			ac.UpdateNameIndex ();
  			
  			NotifyChanged ();
  			
  			if (ActionAdded != null)
  				ActionAdded (this, new ActionEventArgs (ac));
  		}
  		
  		internal void NotifyActionRemoved (Action ac)
  		{
  			ac.SetActionGroup (null);
  			ac.ObjectChanged -= OnActionChanged;
  			ac.SignalAdded -= OnSignalAdded;
  			ac.SignalRemoved -= OnSignalRemoved;
  			ac.SignalChanged -= OnSignalChanged;
  
  			NotifyChanged ();
  			
  			if (ActionRemoved != null)
  				ActionRemoved (this, new ActionEventArgs (ac));
  		}
  		
  		void OnActionChanged (object s, ObjectWrapperEventArgs args)
  		{
  			NotifyChanged ();
  			if (ActionChanged != null)
  				ActionChanged (this, new ActionEventArgs ((Action) args.Wrapper));
  		}
  		
  		void OnSignalAdded (object s, SignalEventArgs args)
  		{
  			OnSignalAdded (args);
  		}
  		
  		void OnSignalRemoved (object s, SignalEventArgs args)
  		{
  			OnSignalRemoved (args);
  		}
  		
  		void OnSignalChanged (object s, SignalChangedEventArgs args)
  		{
  			OnSignalChanged (args);
  		}
  	}
  	
  	public class ActionGroupCollection: CollectionBase
  	{
  		ActionGroup[] toClear;
  		ObjectWrapper owner;
  		
  		internal void SetOwner (ObjectWrapper owner)
  		{
  			this.owner = owner;
  		}
  		
  		public void Add (ActionGroup group)
  		{
  			List.Add (group);
  		}
  		
  		public void Insert (int n, ActionGroup group)
  		{
  			List.Insert (n, group);
  		}
  		
  		public ActionGroup this [int n] {
  			get { return (ActionGroup) List [n]; }
  		}
  		
  		public ActionGroup this [string name] {
  			get {
  				foreach (ActionGroup grp in List)
  					if (grp.Name == name)
  						return grp;
  				return null;
  			}
  		}
  		
  		internal ObjectWrapper FindObjectByUndoId (string id)
  		{
  			foreach (ActionGroup ag in List) {
  				ObjectWrapper ow = ag.FindObjectByUndoId (id);
  				if (ow != null)
  					return ow;
  			}
  			return null;
  		}
  		
  		DiffGenerator GetDiffGenerator (IProject prj)
  		{
  			DiffGenerator gen = new DiffGenerator ();
  
gt: 			gen.CurrentStatusAdaptor = new ActionDiffAdaptor (prj);