context: 
  using System;
  using System.CodeDom;
  using System.Xml;
  using System.Collections;
  using Stetic.Editor;
  
  namespace Stetic.Wrapper
  {
  	public class MenuBar: Container
  	{
  		ActionTree actionTree;
  		XmlElement menuInfo;
  		bool treeChanged;
  		
  		public MenuBar()
  		{
  		}
  		
  		public override void Dispose ()
  		{
  			DisposeTree ();
  			base.Dispose ();
  		}
  		
  		public static Gtk.MenuBar CreateInstance ()
  		{
  			return new ActionMenuBar ();
  		}
  		
  		protected override bool AllowPlaceholders {
  			get { return false; }
  		}
  		
  		ActionMenuBar menu {
  			get { return (ActionMenuBar) Wrapped; }
  		}
  		
  		public override void Wrap (object obj, bool initialized)
  		{
  			base.Wrap (obj, initialized);
  			CreateTree ();
  		}
  		
  		internal protected override void OnSelected ()
  		{
  			Loading = true;
  			menu.ShowInsertPlaceholder = true;
  			Loading = false;
  		}
  		
  		internal protected override void OnUnselected ()
  		{
  			base.OnUnselected ();
  			Loading = true;
  			menu.ShowInsertPlaceholder = false;
  			menu.Unselect ();
  			Loading = false;
  		}
  		
  		protected override XmlElement WriteProperties (ObjectWriter writer)
  		{
  			XmlElement elem = base.WriteProperties (writer);
  			if (menuInfo != null)
  				elem.AppendChild (writer.XmlDocument.ImportNode (menuInfo, true));
  			else
  				elem.AppendChild (actionTree.Write (writer.XmlDocument, writer.Format));
  			return elem;
  		}
  		
  		protected override void ReadProperties (ObjectReader reader, XmlElement elem)
  		{
  			base.ReadProperties (reader, elem);
  			menuInfo = elem ["node"];
  			treeChanged = false;
  		}
  		
  		public override object GetUndoDiff ()
  		{
  			XmlElement oldElem = treeChanged ? UndoManager.GetObjectStatus (this) ["node"] : null;
  			if (oldElem != null)
  				oldElem = (XmlElement) oldElem.CloneNode (true);
  
  			treeChanged = false;
  			object baseDiff = base.GetUndoDiff ();
  			
  			if (oldElem != null) {
  				XmlElement newElem = UndoManager.GetObjectStatus (this) ["node"];
  				if (newElem != null && oldElem.OuterXml == newElem.OuterXml)
  					oldElem = null;
  			}
  			
  			if (baseDiff == null && oldElem == null)
  				return null;
  			else {
  				object stat = menu.SaveStatus ();
  				return new object[] { baseDiff, oldElem, stat };
  			}
  		}
  		
  		public override object ApplyUndoRedoDiff (object diff)
  		{
  			object[] data = (object[]) diff;
  			object retBaseDiff;
  			XmlElement oldNode = null;
  			
  			if (actionTree != null) {
  				XmlElement status = UndoManager.GetObjectStatus (this);
  				oldNode = status ["node"];
  				if (oldNode != null)
  					oldNode = (XmlElement) oldNode.CloneNode (true);
  			}
  			object oldStat = menu.SaveStatus ();
  			
  			if (data [0] != null)
  				retBaseDiff = base.ApplyUndoRedoDiff (data [0]);
  			else
  				retBaseDiff = null;
  				
  			XmlElement xdiff = (XmlElement) data [1];
  
  			if (xdiff != null) {
  				XmlElement status = UndoManager.GetObjectStatus (this);
  				XmlElement prevNode = status ["node"];
  				if (prevNode != null)
  					status.RemoveChild (prevNode);
  				status.AppendChild (xdiff);
  				
  				if (actionTree != null) {
  					Loading = true;
  					menu.OpenSubmenu = null;
  					DisposeTree ();
  					CreateTree ();
  					actionTree.Read (this, xdiff);
  					menu.FillMenu (actionTree);
  					Loading = false;
  				} else
  					menuInfo = xdiff;
  			}
  			
  			// Restore the status after all menu structure has been properly built
  			GLib.Timeout.Add (50, delegate {
  				menu.RestoreStatus (data[2]);
  				return false;
  			});
  			
  			return new object [] { retBaseDiff, oldNode, oldStat };
  		}
  		
  		protected override void OnNameChanged (WidgetNameChangedArgs args)
  		{
  			base.OnNameChanged (args);
  			if (actionTree != null)
  				actionTree.Name = Name;
  		}
  		
  		internal protected override CodeExpression GenerateObjectCreation (GeneratorContext ctx)
  		{
  			BuildTree ();
  			actionTree.Name = Name;
  			CodeExpression exp = GenerateUiManagerElement (ctx, actionTree);
  			if (exp != null)
  				return new CodeCastExpression (typeof(Gtk.MenuBar).ToGlobalTypeRef (),	exp);
  			else
  				return base.GenerateObjectCreation (ctx);
  		}
  
  		internal protected override void OnDesignerAttach (IDesignArea designer)
  		{
  			base.OnDesignerAttach (designer);
  			BuildTree ();
  			Loading = true;
  			menu.FillMenu (actionTree);
  			Loading = false;
  			
  			if (LocalActionGroups.Count == 0)
  				LocalActionGroups.Add (new ActionGroup ("Default"));
  		}
  		
  		void BuildTree ()
  		{
  			if (menuInfo != null) {
  				DisposeTree ();
  				CreateTree ();
  				actionTree.Read (this, menuInfo);
  				menuInfo = null;
  			}
  		}
  		
  		void CreateTree ()
  		{
  			actionTree = new ActionTree ();
  			actionTree.Name = Name;
  			actionTree.Type = Gtk.UIManagerItemType.Menubar;
  			actionTree.Changed += OnTreeChanged;
  		}
  		
  		void DisposeTree ()
  		{
  			if (actionTree != null) {
  				actionTree.Dispose ();
  
gt: 				actionTree.Changed -= OnTreeChanged;