// A Qt compatible UI to C#  generator.
//
// Copyright (C) 2002  Joseph Wenninger (jowenn@kde.org)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation.
// 
// MODIFICATION: ONLY VERSION 2 IS VALID
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

using System;
using System.IO;
using System.Xml;
using System.Text;
using System.Collections;
using System.Reflection;
using Qt;

namespace QtSharp {

	enum ElementType{LayoutType,WidgetType,PropertyType};


	public class Generator {

		void Usage ()
		{
			Console.Write (
				"generator -f file.ui -m\n\n" +
				"   -f || --file  file.ui        The file to parse.\n"+
				"   -m                           Create test main.\n\n" );
		}

		public static void Main (string[] args)
		{
			Generator gen = new Generator (args);
		}



		XmlTextReader xtr;
		TextWriter writer;
		Hashtable fields;
		String uifile;
		bool createMain;
		String generatedClass;

		Assembly qtAssembly;


		public Generator (string[] args)
		{


			try {
				String []dummyargs=new String[0];
				QApplication dummyapp=new QApplication(dummyargs,false);
				qtAssembly=Assembly.GetAssembly(dummyapp.GetType());
//				qtAssembly=Assembly.Load("Qt.dll");
				Console.WriteLine("CodeBase="+qtAssembly.CodeBase);
			}
			catch (Exception e) {
				Console.WriteLine(e.Message);
				Console.WriteLine("exiting");
				return;
			}				

			uifile = null;
			string outfile = null;
			createMain=false;
			generatedClass=null;

			int argc = args.Length;
			for (int i = 0; i < argc; i++) {
				string arg = args[i];
				if (arg.StartsWith("-") || arg.StartsWith("/")) {
					switch (arg) {
						case "-f": case "--file":
							if ((i + 1) >= argc) {
								Usage();
								return;
							}
							uifile = args[++i];
							continue;
						case "-m": createMain=true; break;
						default:
							Usage ();
							return;
					}
				}
			}
			if (uifile == null) {
				Usage();
				return;
			}
			if (!uifile.EndsWith(".ui"))
			{
				Usage();
				return;
			}

            		if (!File.Exists (uifile)) {
        	        	Console.WriteLine ("\n   No UI file at {0}\n", uifile);
	                	return;
			}

			outfile=uifile.Substring(0,uifile.Length-3);
			outfile+=".cs";
			Console.WriteLine ("\n Converting {0} ==> {1}\n",uifile,outfile);

               		
                        writer = new StreamWriter(outfile, false, new ASCIIEncoding());
                        
                        writer.WriteLine("//**********************************************************************");
                        writer.WriteLine("// This file has been generated by the uicsharp User Interface compiler");
			writer.WriteLine("// the input file has been: "+uifile);
                        writer.WriteLine("//**********************************************************************");
			writer.WriteLine("\nusing System;\nusing Qt;\n");
			fields= new Hashtable();
			createClass();
			writer.Flush();
			writer.Close();
			
            	}

	
		XmlDocument uiDoc;
		XmlElement  widgetElement;
		XmlElement  menubarElement;
		XmlElement  toolbarsElement;
		XmlElement  actionsElement;
		XmlElement  imagesElement;
		String className;
		String defLayoutSpacing;
		String defLayoutMargin;
		String buddyList;


                public void createClass ()
                {
			menubarElement=null;
			toolbarsElement=null;
			actionsElement=null;
			imagesElement=null;
			defLayoutSpacing="1";
			defLayoutMargin="1";
			String classname=null;		
			String ancestor=null;
			buddyList="";
			uiDoc=new XmlDocument();
			uiDoc.Load(uifile);
			Console.WriteLine(uiDoc.DocumentElement.Name);  
			XmlElement dummy=uiDoc.DocumentElement.FirstChild as XmlElement;
			while (dummy!=null)
			{
				Console.WriteLine("not null");
				switch (dummy.Name) {
					case "class": 	className=dummy.InnerText;
							break;
					case "widget":  widgetElement=dummy;
							Console.WriteLine("Widget element has been found");
							break;
					case "menubar": menubarElement=dummy;
							break;
					case "toolbars": toolbarsElement=dummy;
							break;
					case "actions": actionsElement=dummy;
							break;
					case "images": imagesElement=dummy;
							break;
					case "layoutdefaults":	defLayoutSpacing=dummy.GetAttribute("spacing");
								defLayoutMargin=dummy.GetAttribute("margin");
								break;
				}
				dummy=dummy.NextSibling as XmlElement;
			}
			Console.WriteLine("class should be named: "+className);
			writer.WriteLine("public class "+className+" : "+widgetElement.GetAttribute("class")+"\n{");
			addSubMembers(widgetElement);
			addImagesMembers();
			addMenuBarMembers();
			addToolBarMembers();
			addActionMembers();

			createConstructor();
//			setupSignalsSlots();

			if (createMain) writeMain();
			writer.WriteLine("}");
		}
		

		private void addImagesMembers()
		{
			if (imagesElement==null) return;
			writer.WriteLine("\t//Images member fields");
			foreach (XmlNode node in imagesElement.ChildNodes) {
				XmlElement el=node as XmlElement;
				writer.WriteLine("\tString[] "+el.GetAttribute("name")+"_data={\"22 22 7 1\","+
				"\". c None\",\"# c #000000\",\"b c #2e2e2e\",\"c c #5c5c5c\","+
				"\"d c #878787\",\"e c #c2c2c2\",\"a c #ffffff\","+
				"\"......................\",\"....##########........\","+
"\"....#aaaaaaa#b#.......\",\"....#aaaaaaa#cb#......\",\"....#aaaaaaa#dcb#.....\","+
"\"....#aaaaaaa#edcb#....\",\"....#aaaaaaa#aedcb#...\",\"....#aaaaaaa#######...\","+
"\"....#aaaaaaaaaaaaa#...\",\"....#aaaaaaaaaaaaa#...\",\"....#aaaaaaaaaaaaa#...\","+
"\"....#aaaaaaaaaaaaa#...\",\"....#aaaaaaaaaaaaa#...\",\"....#aaaaaaaaaaaaa#...\","+
"\"....#aaaaaaaaaaaaa#...\",\"....#aaaaaaaaaaaaa#...\",\"....#aaaaaaaaaaaaa#...\","+
"\"....#aaaaaaaaaaaaa#...\",\"....#aaaaaaaaaaaaa#...\",\"....###############...\","+
"\"......................\",\"......................\"};");
				writer.WriteLine("\tQPixmap {0};",el.GetAttribute("name"));

			}
		}

		private void addMenuBarMembers()
		{
			if (menubarElement==null) return;
			writer.WriteLine("\t//Menubar member fields");
			writer.WriteLine("\t QMenuBar menubar;");
			foreach (XmlNode node in menubarElement.ChildNodes) {
				XmlElement el=node as XmlElement;
				if (el.Name=="item") {
					writer.WriteLine("\tpublic QPopupMenu {0};",el.GetAttribute("name"));
				}
			}
		}

		private void addActionMembers()
		{
			if (actionsElement==null) return;
			writer.WriteLine("\t//Action member fields");
			foreach (XmlNode node in actionsElement.ChildNodes) {
				XmlElement el=node as XmlElement;
				if (el.Name=="action") {
					writer.WriteLine("\tpublic QAction {0};",getName(el));
				}
			}
		}

		private void addToolBarMembers()
		{
			if (toolbarsElement==null) return;
			writer.WriteLine("\t//Toolbar member fields");
			foreach (XmlNode node in toolbarsElement.ChildNodes) {
				XmlElement el=node as XmlElement;
				if (el.Name=="toolbar") {
					writer.WriteLine("\tpublic QToolBar {0};",getName(el));
				}
			}
		}



		private void addSubMembers(XmlElement widget)
		{
			String [] membertypes={"widget","vbox","hbox","grid"};
			foreach (String membertype in membertypes)  {
				XmlNodeList nl=widget.GetElementsByTagName(membertype);
				foreach (XmlNode submembernode in nl) {
					if (submembernode.ParentNode!=widget) continue; // I think this is a workaround for a classlib bug
					XmlElement submember=submembernode as XmlElement;
					addSubMembers(submember);
					if (submember.GetAttribute("class")=="QLayoutWidget") continue; //they are private
					String membername=getName(submember);
					if (membername==String.Empty) continue;
					writer.WriteLine("\t"+submember.GetAttribute("class")+" "+membername+";");
					Console.WriteLine((submember as  XmlElement).Name);
				}
			}
		}

		private String getName(XmlElement element)
		{
			if (element.GetAttribute("uicsharp_name")!=String.Empty)
				return element.GetAttribute("uicsharp_name");
			foreach(XmlNode property in element.ChildNodes) {
				//if (property.ParentNode!=element) continue ;//see comment in addSubMembers
				XmlElement prop=property as XmlElement;
				if (prop.Name!="property") continue;
				if (prop.GetAttribute("name")=="name") {
					return (prop.FirstChild.InnerXml=="unnamed")?String.Empty:prop.FirstChild.InnerXml;
				}
			}
			return String.Empty;
		}


		private void setupTabOrder()
		{
			foreach (XmlNode node in uiDoc.DocumentElement.ChildNodes) {
				XmlElement element=node as XmlElement;
				if (element.Name!="tabstops") continue;
				writer.WriteLine("\n\t\t// tab stop order");
				foreach( XmlNode tsnode in element.ChildNodes) {
					XmlElement ts=tsnode as XmlElement;
					if (ts.NextSibling==null) break;
					XmlElement ts1=ts.NextSibling as XmlElement;
					writer.WriteLine("\t\tSetTabOrder({0},{1});",ts.InnerText,ts1.InnerText);
				}
				break;
			}
			
		}

                private void setupConnections()
                {
			return;
                        foreach (XmlNode node in uiDoc.DocumentElement.ChildNodes) {
                                XmlElement element=node as XmlElement;
                                if (element.Name!="connections") continue;
                                writer.WriteLine("\n\t\t// setting up signal / slot connections");
                                foreach( XmlNode connnode in element.ChildNodes) {
                                        XmlElement conn=connnode as XmlElement;

                                        XmlElement tmp=conn.FirstChild as XmlElement;
                                        String sender=tmp.InnerText;
					sender=(sender==className)?"this":sender;
                                        tmp=tmp.NextSibling as XmlElement;
                                        String signal=tmp.InnerText;

                                        tmp=tmp.NextSibling as XmlElement;
                                        String receiver=tmp.InnerText;
					receiver=(receiver==className)?"this":receiver;

                                        tmp=tmp.NextSibling as XmlElement;
                                        String slot=tmp.InnerText;

                                        writer.WriteLine("\t\tQObject.Connect({0},SIGNAL(\"{1}\"),{2},SLOT(\"{3}\"));",
						sender,signal,receiver,slot);
                                }
                                break;
                        }

                }


		private void createConstructor()
		{
			//Later handle non qwidgets better (dialog,....)
			writer.WriteLine("\n\tpublic "+className+"(QWidget parent, String name) :base(parent, name) {");
			writer.WriteLine("\t\tif (name==null) SetName(\""+className+"\");");
			setupImages();
			setupActions();
			setupToolBars();			
			setupMenuBar();
			constructEverything();
			setupConnections();
			setupTabOrder();
			setProperties(widgetElement);

			if (buddyList!=String.Empty) writer.WriteLine("\n\t\t//link buddies\n"+buddyList);

//			writer.WriteLine("\t\tinit();\n\t}");
			writer.WriteLine("\n\t}");
		}


		private void setupImages()
		{
			if (imagesElement==null) return;
			writer.WriteLine("\t//images");
			foreach (XmlNode node in imagesElement.ChildNodes) {
				XmlElement el=node as XmlElement;
				writer.WriteLine("\t\t{0}=new QPixmap({1}_data);",
					el.GetAttribute("name"),el.GetAttribute("name"));
			}
		}

		private void setupActions()
		{
			if (actionsElement==null) return;
			writer.WriteLine("\t//actions");
			foreach (XmlNode aNode in actionsElement.ChildNodes) {
				XmlElement action=aNode as XmlElement;
				if (action.Name!="action") continue;
				writer.WriteLine("\t\t{0}= new QAction(this,\"{1}\");",getName(action),getName(action));
				foreach (XmlNode pNode in action.ChildNodes) {
					XmlElement prop=pNode as XmlElement;
					if (prop.Name!="property") continue;
					if (prop.GetAttribute("name")=="name") continue;
					writer.WriteLine(generateSetProperty(getName(action),"",prop));
				}
			}
		}


		private void setupMenuBar()
		{
			if (menubarElement==null) return;
			writer.WriteLine("\t//menubar");
			String barname=getName(menubarElement);
			writer.WriteLine("\t\t{0}=new QMenuBar(this,\"{1}\");",barname,barname);
			int count=0;
			foreach (XmlNode mNode in menubarElement.ChildNodes) {
				XmlElement item=mNode as XmlElement;
				if (item.Name!="item") continue;
				String submenu_name=item.GetAttribute("name");
				String submenu_text=stringify(item.GetAttribute("text"));
				writer.WriteLine("\t\t{0}=new QPopupMenu(this);",submenu_name);

				foreach (XmlNode node in item.ChildNodes) {
					XmlElement element=node as XmlElement;
					if ((element.Name=="property") && (element.GetAttribute("name")!="name")) generateSetProperty(barname,"",element);
					else if (element.Name=="separator") writer.WriteLine("\t\t{0}.InsertSeparator();",submenu_name);
					else if (element.Name=="action") writer.WriteLine("\t\t{0}.AddTo({1});",element.GetAttribute("name"),submenu_name);
				}
				writer.WriteLine("\t\t{0}.InsertItem(\"{1}\",{2},{3});",barname,
					submenu_text,submenu_name,count.ToString());
				count++;
				
			}
		}

		private void setupToolBars()
		{
			if (toolbarsElement==null) return;
			writer.WriteLine("\t//toolbars");
			foreach (XmlNode tNode in toolbarsElement.ChildNodes) {
				XmlElement toolbar=tNode as XmlElement;
				if (toolbar.Name!="toolbar") continue;
				String varname=getName(toolbar);
				writer.WriteLine("\t\t{0}=new QToolBar(this,\"{1}\");",varname,varname);
				writer.WriteLine("\t\tthis.AddDockWindow({0},(Qt.Dock){1},false);",varname,toolbar.GetAttribute("dock"));
				foreach (XmlNode node in toolbar.ChildNodes) {
					XmlElement element=node as XmlElement;
					if ((element.Name=="property") && (element.GetAttribute("name")!="name")) generateSetProperty(varname,"",element);
					else if (element.Name=="separator") writer.WriteLine("\t\t{0}.AddSeparator();",varname);
					else if (element.Name=="action") writer.WriteLine("\t\t{0}.AddTo({1});",element.GetAttribute("name"),varname);
				}
			}
		}

		private ElementType elementType(XmlElement el)
		{		
			switch (el.Name) {
				case "widget": return (el.GetAttribute("class")=="QLayoutWidget")?
							ElementType.LayoutType:ElementType.WidgetType;
				case "vbox": return ElementType.LayoutType;
				case "hbox": return ElementType.LayoutType;
				case "grid": return ElementType.LayoutType;
				case "spacer": return ElementType.LayoutType;
				default: return ElementType.PropertyType;
			}
		}

		private void constructEverything() 
		{
			foreach (XmlNode subNode in widgetElement.ChildNodes)
			{
				XmlElement obj=subNode as XmlElement;
				switch (elementType(obj)) {
					case ElementType.WidgetType: constructChild("this",obj,true);
								     widgetAdd("this",widgetElement,obj);
								     break;
					case ElementType.LayoutType: constructChild("this",obj,true);
								     break;
					default: break;
				}
			}
			
		}

		
		private void widgetAdd(String parname,XmlElement par, XmlElement obj)
		{
			if (par==widgetElement) {
				if (par.GetAttribute("class")=="QWizard")
				{
					writer.WriteLine("\t\tAddPage("+getName(obj)+", "+getName(obj)+".Caption());");
				}
			}
			else {
				if (elementType(par)==ElementType.LayoutType) {
					if (getLayoutType(par)=="grid") {
						writer.WriteLine("\t\t"+getName(par)+insertIntoGrid("Widget",getName(obj),obj));
					}
					else writer.WriteLine("\t\t"+parname+".Add("+getName(obj)+");");
				}
				else switch(par.GetAttribute("class")) {
					case "QTabWidget": writer.WriteLine("\t\t"+parname+".InsertTab("+getName(obj)+",\"\");");
								break;
					default: break;
				}
			}
		}


		private String getLayoutType(XmlElement el)
		{
			String tmp=el.Name;
			if (tmp=="widget")  tmp=el.GetAttribute("uicsharp_type");
			return tmp;
		}


		private String insertIntoGrid(String what, String name, XmlElement obj)
		{
				String col,row,colspan,rowspan,endcol,endrow;

				int tmpcols=int.Parse(
					(obj.GetAttribute("column")==String.Empty)?
					"0":obj.GetAttribute("column"))+
					int.Parse((obj.GetAttribute("colspan")==String.Empty)?
                                        "1":obj.GetAttribute("colspan"))-1;

				int tmprows=int.Parse(
					(obj.GetAttribute("row")==String.Empty)?
					"0":obj.GetAttribute("row"))+
					int.Parse((obj.GetAttribute("rowspan")==String.Empty)?
                                        "1":obj.GetAttribute("rowspan"))-1;

				col=obj.GetAttribute("column");
				row=obj.GetAttribute("row");
				endcol=tmpcols.ToString();
				endrow=tmprows.ToString();
				if ((col==endcol) && (row==endrow))
				{
					return ".Add"+what+"( "+name+", "+row + ", "+col +");";
				}
				else
				{
					what=(what=="Item")?"":what;
					return ".AddMultiCell"+what+"( "+name+", "+row+","+endrow+", "+col+", "+endcol+");";
				}

		}

		private void layoutAdd(XmlElement par, XmlElement obj)
		{
			String what=(getLayoutType(obj)=="spacer")?"Item":"Layout";
			if (getLayoutType(par)!="grid"){
				writer.WriteLine("\t\t"+getName(par)+".Add"+what+"("+getName(obj)+");");
			}
			else
			{
				writer.WriteLine("\t\t"+getName(par)+insertIntoGrid(what,getName(obj),obj));
			}
		}

		
		void createSpacer(String name, XmlElement obj) {
			String orientation;
			String sizeType;
			String shx,shy;
			orientation=null;
			sizeType=null;
			shx=null;
			shy=null;
			foreach (XmlNode node in obj.ChildNodes) {
				XmlElement el=node as XmlElement;
				if (el.Name!="property") continue;
				switch (el.GetAttribute("name")) {
					case "orientation": orientation=(((el.FirstChild as XmlElement).InnerText).ToUpper());
								break;
					case "sizeType" : sizeType=(((el.FirstChild as XmlElement).InnerText));
								break;
					case "sizeHint" : foreach (XmlNode shn in (el.FirstChild as XmlElement).ChildNodes) {
								XmlElement she=shn as XmlElement;
								switch (she.Name) {
									case "width": shx=she.InnerText;
											break;
									case "height": shy=she.InnerText;
											break;
								}
							}
								break;
				}
			}
			writer.WriteLine("\t\tQSpacerItem {0}=new QSpacerItem({1},{2},{3},{4});",
				name,shx,shy,
				(orientation=="VERTICAL")?"Qt.QSizePolicy.SizeType.Minimum":("Qt.QSizePolicy.SizeType."+toPascal(sizeType)),
				(orientation!="VERTICAL")?"Qt.QSizePolicy.SizeType.Minimum":("Qt.QSizePolicy.SizeType."+toPascal(sizeType)));
		}
		
		int layoutcnt=1;

		XmlElement createLayout(String parent, XmlElement obj, ref String name, bool privateLayout)
		{	
			name = ((name==String.Empty)?getName(obj):name);
			if (name==String.Empty)
			{
				name="my_internal_Layout"+layoutcnt;
				privateLayout=true;
				layoutcnt++;
			}

			if ((privateLayout) && (obj.Name!="widget"))
				obj.SetAttribute("uicsharp_name",name);
			
			if ((obj.Name!="widget") && (obj.GetAttribute("uicsharp_parent")!=String.Empty))
				parent=obj.GetAttribute("uicsharp_parent");

			switch (obj.Name) {
				case "vbox": writer.WriteLine("\t\t"+(privateLayout?"QVBoxLayout ":"")+name+"= new QVBoxLayout("+
						((parent==null)?"":parent)+");");
					     setupLayout(name,obj);
					     return obj;
				case "hbox": writer.WriteLine("\t\t"+(privateLayout?"QHBoxLayout ":"")+name+"= new QHBoxLayout("+
						((parent==null)?"":parent)+");");
					     setupLayout(name,obj);
					     return obj;
				case "spacer": createSpacer(name,obj);
						return obj;
				case "widget":
						foreach (XmlNode node in obj.ChildNodes)
						{
							if (elementType(node as XmlElement)==ElementType.LayoutType) {
								(node as XmlElement).SetAttribute("uicsharp_margin","0");
								XmlElement el=createLayout(parent,node as XmlElement,ref name,true);
								obj.SetAttribute("uicsharp_name",getName(el));
								obj.SetAttribute("uicsharp_type",el.Name);
								return el;
							}
						}
						return null;
				case "grid":
						int cols=1;
						int rows=1;
						foreach (XmlNode node in obj.ChildNodes){
							XmlElement elem=node as XmlElement;
							ElementType etype=elementType(elem);
							if ((etype==ElementType.LayoutType) ||
								(etype==ElementType.WidgetType)) {
								Console.WriteLine("Grid size calculation group");
								int tmpcols=int.Parse(
									(elem.GetAttribute("column")==String.Empty)?
										"0":elem.GetAttribute("column"))+
									int.Parse((elem.GetAttribute("colspan")==String.Empty)?
                                                                                "1":elem.GetAttribute("colspan"))-1;

								int tmprows=int.Parse(
									(elem.GetAttribute("row")==String.Empty)?
										"0":elem.GetAttribute("row"))+
									int.Parse((elem.GetAttribute("rowspan")==String.Empty)?
                                                                                "1":elem.GetAttribute("rowspan"))-1;

								cols=(tmpcols<cols)?cols:tmpcols;
								rows=(tmprows<rows)?rows:tmprows;			
							}
						}
						writer.WriteLine("\t\t"+ (privateLayout?"QGridLayout ":"")+name +"= new QGridLayout ("+
							((parent==null)?"":(parent+", "))+rows+", "+cols+");");
						setupLayout(name,obj);
						return  obj;
				}

			return obj;						

		}


		private void setupLayout(String name,XmlElement layout)
		{
			
			String margin=layout.GetAttribute("uicsharp_margin");
			if (margin==String.Empty){
				foreach(XmlNode node in layout.ChildNodes) {
					XmlElement el=node as XmlElement;
					if ((el.Name=="property") && (el.GetAttribute("name")=="margin")) {
						margin=(el.FirstChild as XmlElement).InnerText;
						break;
					}
				}
			}
			if (margin==String.Empty) margin=defLayoutMargin;

			String spacing=layout.GetAttribute("uicsharp_spacing");
			if (spacing==String.Empty){
				foreach(XmlNode node in layout.ChildNodes) {
					XmlElement el=node as XmlElement;
					if ((el.Name=="property") && (el.GetAttribute("name")=="spacing")) {
						margin=(el.FirstChild as XmlElement).InnerText;
						break;
					}
				}
			}
			if (spacing==String.Empty) spacing=defLayoutSpacing;

			String alignment=layout.GetAttribute("uicsharp_alignment");
			if (alignment!=String.Empty) writer.WriteLine("\t\t{0}.SetAlignment({1});",name,alignment);

			writer.WriteLine("\t\t{0}.SetMargin({1});",name,margin);
			writer.WriteLine("\t\t{0}.SetSpacing({1});",name,spacing);
		}


		private void widgetType(XmlElement obj, ref String typename, ref XmlElement subcontainer, bool write)
		{
			typename=obj.GetAttribute("class");
			if ((typename!="QGroupBox") && (typename!="ButtonGroup")) return;
			foreach (XmlNode node in obj.ChildNodes) {
				if (elementType(node as XmlElement)==ElementType.LayoutType) {
					XmlElement el =node as XmlElement;
//					subcontainer=el;
					el.SetAttribute("uicsharp_type",el.Name);
					el.SetAttribute("uicsharp_name",getName(obj)+"Layout");
					el.SetAttribute("uicsharp_parent",getName(obj)+".Layout()");
					el.SetAttribute("uicsharp_margin","0");
					el.SetAttribute("uicsharp_alignment","(int)Qt.AlignmentFlags.AlignTop");

					switch (el.Name) {
						case "vbox": 	typename="QGroupBox";
								if (write)
								writer.WriteLine("\t\t QVBoxLayout "+el.GetAttribute("uicsharp_name")+";");
								 return;
						case "hbox": typename="QGroupBox";
								if (write)
								writer.WriteLine("\t\t QHBoxLayout "+el.GetAttribute("uicsharp_name")+";");
								 return;
						case "grid": typename="QGroupBox";
								if (write)
								writer.WriteLine("\t\t QGridLayout "+el.GetAttribute("uicsharp_name")+";");
								 return;

				
					}
				}
			}
//			typename=null;
		}

		private void specialInit(XmlElement el)
		{
			if (el.GetAttribute("class").EndsWith("GroupBox"))
				writer.WriteLine("\t\t"+getName(el)+".SetColumnLayout(0,Qt.Orientation.Vertical);");
		}


		private String toPascal(String data)
		{
			return System.Char.ToUpper(data[0]).ToString()+ data.Substring(1,data.Length-1);
		}

		private String stringify(String data)
		{
			data=data.Replace("\"","\\\"");
			data=data.Replace("\n","\\n");
			return data;
		}


		private String toBool(String data)
		{
			if ((data=="1") || (data=="true")) return "true"; else return "false";
		}

		private String generateSetProperty(String varName, String widgetClass, XmlElement prop) 
		{
			if ((prop.GetAttribute("name")=="whatsThis") || (prop.GetAttribute("name")=="toolTip"))
			{
				String tmp="\t\tQ"+toPascal(prop.GetAttribute("name"))+".Add("+varName+", \""+
					stringify((prop.FirstChild as XmlElement).InnerText)+"\");";
				return tmp;
			}
			
			String methodName="Set"+toPascal(prop.GetAttribute("name"));
			String sc=methodName+" (";

			XmlElement value=(prop.FirstChild as XmlElement);

			switch (value.Name) {
				case "string" : if (prop.GetAttribute("name")!="accel") sc += "\""+stringify(value.InnerText)+"\"";
						else sc+="new QKeySequence(\""+stringify(value.InnerText)+"\")";
						break;
				case "cstring" : sc += value.InnerText;
						break;
				case "rect" : String rx=null,ry=null,rw=null,rh=null;
						foreach (XmlNode srn in value.ChildNodes) {
							XmlElement sre=srn as XmlElement;
							switch (sre.Name) {
								case "x" : rx=sre.InnerText;
									break;
								case "y" : ry=sre.InnerText;
									break;
								case "height" : rh=sre.InnerText;
									break;
								case "width" : rw=sre.InnerText;
									break;
								default: break;
							}
						}
						if ((varName=="this") && (methodName=="SetGeometry"))
							sc = "Resize ((new QSize("+rw+", "+rh+")).ExpandedTo(SizeHint())";
						else
							sc += "new QRect("+rx+", "+ry+", "+rw+", "+rh+")";

						break;
				case "enum" : 
						try {
							Type ct=qtAssembly.GetType("Qt."+widgetClass,true);
							MemberInfo []mi=ct.GetMember(methodName);
							ParameterInfo []pi=((MethodBase)mi[0]).GetParameters();
							String ptn=pi[0].ParameterType.FullName;
							Console.WriteLine("Parameter Type Name: "+ptn);
							ptn=ptn.Replace("+",".");
							sc+=ptn+"."+toPascal(value.InnerText);
						}
						catch (Exception e) {
							Console.WriteLine(e.Message+":"+widgetClass);
							Console.WriteLine("ERROR DURING >ENUM TRANSLATION<");
						}

						break;
				case "iconset" : sc += "new QIconSet("+value.InnerText+")";
						break;
				case "bool" : sc += value.InnerText;
						break;
				case "font": 	String fvn=varName+"_Font";
						sc="\t\tQFont "+fvn+" = ("+varName+".Font());\n";
						foreach(XmlNode fn in value.ChildNodes) {
							XmlElement fe=fn as XmlElement;
							switch (fe.Name) {
								case "pointsize": 
									sc+="\t\t"+fvn+".SetPointSize("+fe.InnerText+");\n";
									break;
								case "bold":
									sc+="\t\t"+fvn+".SetBold("+toBool(fe.InnerText)+");\n";
									break;
								case "italic":
									sc+="\t\t"+fvn+".SetItalic("+toBool(fe.InnerText)+");\n";
									break;
								case "underline":
									sc+="\t\t"+fvn+".SetUnderline("+toBool(fe.InnerText)+");\n";
									break;
								case "strikeout":
									sc+="\t\t"+fvn+".SetStrikeOut("+toBool(fe.InnerText)+");\n";
									break;
							}
						}
						sc +="\t\t"+varName+".SetFont("+fvn+");";
						return sc;
				default: Console.WriteLine("Not yet supported property type : "+value.Name);
						return String.Empty;
			}
	
			sc += " )";
			return "\t\t"+varName+"."+sc+";";

		}
		
		
		private void setProperties(XmlElement obj)
		{
			String myWidgetClass=null;
			XmlElement dummy=null;

			widgetType(obj, ref myWidgetClass, ref dummy,false);

			foreach (XmlNode node in obj.ChildNodes) {
				XmlElement prop = node as XmlElement;
				if (prop.Name!="property") continue;
				if (prop.GetAttribute("name")=="buddy") {
					buddyList+="\n"+generateSetProperty(getName(obj),myWidgetClass,prop);
					continue;
				}
				if (prop.GetAttribute("name")=="name") continue;
				String str=generateSetProperty((obj==widgetElement)?"this":getName(obj),myWidgetClass,prop);
				if (str!=String.Empty) writer.WriteLine(str);
			}
		}


		private void constructChild(String parent,XmlElement obj,bool mainLayout)
		{
			ElementType mytype=elementType(obj);
			String myname=getName(obj);
			XmlElement lobj=null;
			switch (mytype){
				case ElementType.WidgetType: 
								String widgettype=null;
								XmlElement tmpobj=null;
								widgetType(obj,ref widgettype,ref tmpobj,true);
								mainLayout=true;
								XmlElement origNode=obj;
								if (tmpobj!=null) {
									mytype=ElementType.LayoutType;
									lobj=obj;
									obj=tmpobj;
									mainLayout=false;
								}
								writer.WriteLine("\t\t"+myname+"=new "+widgettype
								+"("+parent+", \""+myname+"\");");
								specialInit(origNode);
								setProperties(origNode);
								parent=myname;
								break;
				case ElementType.LayoutType: 
							lobj=obj;
							myname="";
							obj=createLayout(mainLayout?parent:null,obj,ref myname,false);
							mainLayout=false;
							break;
				default: return;
			}

                        foreach (XmlNode subNode in obj.ChildNodes)
                        {
                                XmlElement subObj=subNode as XmlElement;
                                switch (elementType(subObj)) {
                                        case ElementType.WidgetType: constructChild(parent,subObj,mainLayout);
                                                                     widgetAdd(myname,obj,subObj);
                                                                     break;
                                        case ElementType.LayoutType: constructChild(parent,subObj,mainLayout);
								     if (mytype==ElementType.LayoutType) layoutAdd(lobj,subObj);
								     break;
                                        default: break;
                                }
                        }

		}


		private void writeMain()
		{
			writer.WriteLine("\tpublic static void Main (String[] args)\n"+
                	"\t{\n"+
                        "\t\tQApplication app = new QApplication (args);\n"+
                        "\t\t"+className+" test = new "+className+" (null,\"\");\n"+
                        "\t\tapp.SetMainWidget (test);\n"+
                        "\t\ttest.Show ();\n"+
                        "\t\tapp.Exec ();\n"+
                	"\t}");
		}
	} 
}
