// 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]; TQApplication dummyapp=new TQApplication(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 TQMenuBar menubar;"); foreach (XmlNode node in menubarElement.ChildNodes) { XmlElement el=node as XmlElement; if (el.Name=="item") { writer.WriteLine("\tpublic TQPopupMenu {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 TQAction {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 TQToolBar {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},TQT_SIGNAL(\"{1}\"),{2},TQT_SLOT(\"{3}\"));", sender,signal,receiver,slot); } break; } } private void createConstructor() { //Later handle non qwidgets better (dialog,....) writer.WriteLine("\n\tpublic "+className+"(TQWidget 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 TQPixmap({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 TQAction(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 TQMenuBar(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 TQPopupMenu(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 TQToolBar(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")=="TQWizard") { 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 "TQTabWidget": 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 TQSpacerItem({1},{2},{3},{4});", name,shx,shy, (orientation=="VERTICAL")?"Qt.TQSizePolicy.SizeType.Minimum":("Qt.TQSizePolicy.SizeType."+toPascal(sizeType)), (orientation!="VERTICAL")?"Qt.TQSizePolicy.SizeType.Minimum":("Qt.TQSizePolicy.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?"TQVBoxLayout ":"")+name+"= new TQVBoxLayout("+ ((parent==null)?"":parent)+");"); setupLayout(name,obj); return obj; case "hbox": writer.WriteLine("\t\t"+(privateLayout?"TQHBoxLayout ":"")+name+"= new TQHBoxLayout("+ ((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=(tmpcolsENUM TRANSLATION<"); } break; case "iconset" : sc += "new TQIconSet("+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 TQApplication (args);\n"+ "\t\t"+className+" test = new "+className+" (null,\"\");\n"+ "\t\tapp.SetMainWidget (test);\n"+ "\t\ttest.Show ();\n"+ "\t\tapp.Exec ();\n"+ "\t}"); } } }