/**********************************************************************
** Copyright (C) 2000 Trolltech AS.  All rights reserved.
**
** This file is part of TQt Designer.
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.trolltech.com/gpl/ for GPL licensing information.
**
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/

#include <stdio.h>
#include "uic.h"
#include "parser.h"
#include "widgetdatabase.h"
#include "domtool.h"
#include <tqstringlist.h>
#include <tqfile.h>
#include <tqfileinfo.h>
#include <tqregexp.h>
#define NO_STATIC_COLORS
#include <globaldefs.h>

static TQByteArray unzipXPM( TQString data, ulong& length )
{
    const int lengthOffset = 4;
    int baSize = data.length() / 2 + lengthOffset;
    uchar *ba = new uchar[ baSize ];
    for ( int i = lengthOffset; i < baSize; ++i ) {
        char h = data[ 2 * (i-lengthOffset) ].latin1();
        char l = data[ 2 * (i-lengthOffset) + 1 ].latin1();
        uchar r = 0;
        if ( h <= '9' )
            r += h - '0';
        else
            r += h - 'a' + 10;
        r = r << 4;
        if ( l <= '9' )
            r += l - '0';
        else
            r += l - 'a' + 10;
        ba[ i ] = r;
    }
    // tqUncompress() expects the first 4 bytes to be the expected length of the
    // uncompressed data
    ba[0] = ( length & 0xff000000 ) >> 24;
    ba[1] = ( length & 0x00ff0000 ) >> 16;
    ba[2] = ( length & 0x0000ff00 ) >> 8;
    ba[3] = ( length & 0x000000ff );
    TQByteArray baunzip = tqUncompress( ba, baSize );
    delete[] ba;
    return baunzip;
}



/*!
  Creates an implementation ( cpp-file ) for the form given in \a e

  \sa createFormDecl(), createObjectImpl()
 */
void Uic::createFormImpl( const TQDomElement &e )
{
    TQDomElement n;
    TQDomNodeList nl;
    int i;
    TQString objClass = getClassName( e );
    if ( objClass.isEmpty() )
	return;
    TQString objName = getObjectName( e );

    // generate local and local includes required
    TQStringList globalIncludes;
    TQStringList::Iterator it;
    TQStringList sqlClasses;
    TQStringList axwidgets, databrowsers;

    TQMap<TQString, CustomInclude> customWidgetIncludes;
    TQMap<TQString, TQString> functionImpls;
    // find additional slots and functions
    TQStringList extraSlots;
    TQStringList extraSlotTypes;
    nl = e.parentNode().toElement().elementsByTagName( "slot" );
    for ( i = 0; i < (int) nl.length(); i++ ) {
	n = nl.item(i).toElement();
	if ( n.parentNode().toElement().tagName() != "slots"
	     && n.parentNode().toElement().tagName() != "connections" )
	    continue;
	if ( n.attribute( "language", "C++" ) != "C++" )
	    continue;
	TQString slotName = n.firstChild().toText().data().stripWhiteSpace();
	if ( slotName.endsWith( ";" ) )
	    slotName = slotName.left( slotName.length() - 1 );

	extraSlots += Parser::cleanArgs(slotName);
	extraSlotTypes += n.attribute( "returnType", "void" );
    }

    for ( n = e; !n.isNull(); n = n.nextSibling().toElement() ) {
	if ( n.tagName() == "functions" ) { // compatibility
	    for ( TQDomElement n2 = n.firstChild().toElement(); !n2.isNull(); n2 = n2.nextSibling().toElement() ) {
		if ( n2.tagName() == "function" ) {
		    TQString fname = n2.attribute( "name" );
		    fname = Parser::cleanArgs( fname );
		    functionImpls.insert( fname, n2.firstChild().toText().data() );
		}
	    }
	}
    }

    // additional includes (local or global ) and forward declaractions
    nl = e.parentNode().toElement().elementsByTagName( "include" );
    for ( i = 0; i < (int) nl.length(); i++ ) {
	TQDomElement n2 = nl.item(i).toElement();
        
	TQString s = n2.firstChild().toText().data();
	if ( n2.attribute( "location" ) != "local" ) {
	    if ( s.right( 5 ) == ".ui.h" && !TQFile::exists( s ) )
		continue;
	    if ( n2.attribute( "impldecl", "in implementation" ) != "in implementation" )
		continue;
	    globalIncludes += s;
	}
    }

    // do the local includes afterwards, since global includes have priority on clashes
    TQFileInfo fi(fileName);

    for ( i = 0; i < (int) nl.length(); i++ ) {
	TQDomElement n2 = nl.item(i).toElement();
	TQString s = n2.firstChild().toText().data();
	if ( n2.attribute( "location" ) == "local" &&!globalIncludes.contains( s ) ) {
	    if ( s.right( 5 ) != ".ui.h" )
		continue;

            if ( !TQFile::exists( s ) )
	    {
		s = fi.dirPath() + "/" + s;

		if ( !TQFile::exists( s ) )
		    continue;
	    }

            if ( TQFile::exists( s ) )
            {
                TQFile f(s);
                f.open(IO_ReadOnly);
                TQTextStream headerStream(&f);
                TQString line;
                TQString functionText;
                TQString functionName;
                TQRegExp rx("void .*::(.*\\(.*\\))"); 
                int pos, inFunction = 0;

                while (line = headerStream.readLine())
                {
                   pos = rx.search(line);

                   if (pos > -1)
                   {  
                        if (inFunction)
                            functionImpls.insert(Parser::cleanArgs(functionName),functionText);

                        functionName = rx.cap(1);
                        functionText = "";
                        inFunction = 1;
                   }
                   functionText += line + "\n";
                }

                if (inFunction)
                    functionImpls.insert(Parser::cleanArgs(functionName),functionText);
            }
	}
    }

    // additional custom widget headers
    nl = e.parentNode().toElement().elementsByTagName( "header" );
    for ( i = 0; i < (int) nl.length(); i++ ) {
	TQDomElement n2 = nl.item(i).toElement();
	TQString s = n2.firstChild().toText().data();
	if ( n2.attribute( "location" ) != "local" )
	    globalIncludes += s;
    }

    // includes for child widgets
    for ( it = tags.begin(); it != tags.end(); ++it ) {
	nl = e.parentNode().toElement().elementsByTagName( *it );
	for ( i = 1; i < (int) nl.length(); i++ ) { // start at 1, 0 is the toplevel widget
	    TQString name = getClassName( nl.item(i).toElement() );
	    if ( name == "Spacer" ) {
		globalIncludes += "tqlayout.h";
		globalIncludes += "tqapplication.h";
		continue;
	    }
	    if ( name.mid( 1 ) == "ListView" )
		globalIncludes += "tqheader.h";
	    else if ( name == "TQAxWidget" )
		axwidgets += getObjectName(nl.item(i).toElement());
	    else if ( name == "TQDataBrowser" )
		databrowsers += getObjectName(nl.item(i).toElement());
	    if ( name != objClass ) {
		int wid = WidgetDatabase::idFromClassName( name );
		TQMap<TQString, CustomInclude>::Iterator it = customWidgetIncludes.find( name );
		if ( it == customWidgetIncludes.end() )
		    globalIncludes += WidgetDatabase::includeFile( wid );
	    }
	}
    }

    if (globalIncludes.findIndex("tqtable.h") >= 0)
	out << indent << "from PyTQt.tqttable import TQTable" << endl;

    if (!axwidgets.empty())
	out << indent << "from PyTQt.tqtaxcontainer import TQAxWidget" << endl;

    if (globalIncludes.findIndex("tqextscintilla.h") >= 0)
	out << indent << "from PyTQt.tqtext import TQextScintilla" << endl;

    registerDatabases( e );
    dbConnections = unique( dbConnections );
    if ( dbConnections.count() )
	sqlClasses += "TQSqlDatabase";
    if ( dbCursors.count() )
	sqlClasses += "TQSqlCursor";
    bool dbForm = false;
    if ( dbForms[ "(default)" ].count() )
	dbForm = true;
    bool subDbForms = false;
    for ( it = dbConnections.begin(); it != dbConnections.end(); ++it ) {
	if ( !(*it).isEmpty()  && (*it) != "(default)" ) {
	    if ( dbForms[ (*it) ].count() ) {
		subDbForms = true;
		break;
	    }
	}
    }
    if ( dbForm || subDbForms ) {
	sqlClasses += "TQSqlForm";
	sqlClasses += "TQSqlRecord";
    }

    if (globalIncludes.findIndex("tqdatatable.h") >= 0)
        sqlClasses += "TQDataTable";

    if (globalIncludes.findIndex("tqtableview.h") >= 0)
        sqlClasses += "TQTableView";

    if (globalIncludes.findIndex("tqdatabrowser.h") >= 0)
        sqlClasses += "TQDataBrowser";

    if (globalIncludes.findIndex("tqdataview.h") >= 0)
        sqlClasses += "TQDataView";

    if ( !sqlClasses.empty() ) {
	out << indent << "from PyTQt.tqtsql import";
	const char *sep = " ";

	for ( it = sqlClasses.begin(); it != sqlClasses.end(); ++it ) {
	    out << sep << (*it);
	    sep = ", ";
	}

	out << endl;
    }

    // Add any code from the comments.
    if (!pyCode.isEmpty())
	out << pyCode;

    out << endl;

    // find out what images are required
    TQStringList requiredImages;
    static const char *imgTags[] = { "pixmap", "iconset", 0 };
    for ( i = 0; imgTags[i] != 0; i++ ) {
	nl = e.parentNode().toElement().elementsByTagName( imgTags[i] );
	for ( int j = 0; j < (int) nl.length(); j++ ) {
	    TQDomNode nn = nl.item(j);
	    while ( nn.parentNode() != e.parentNode() )
		nn = nn.parentNode();
	    if ( nn.nodeName() != "customwidgets" )
		requiredImages += nl.item(j).firstChild().toText().data();
	}
    }

    // register the object and unify its name
    objName = registerObject( objName );

    TQStringList images;
    TQStringList xpmImages;
    if ( pixmapLoaderFunction.isEmpty() && !externPixmaps ) {
	// create images
	for ( n = e; !n.isNull(); n = n.nextSibling().toElement() ) {
	    if ( n.tagName()  == "images" ) {
		nl = n.elementsByTagName( "image" );
		for ( i = 0; i < (int) nl.length(); i++ ) {
		    TQString img = registerObject(  nl.item(i).toElement().attribute( "name" ) );
		    if ( !requiredImages.contains( img ) )
			continue;
		    TQDomElement tmp = nl.item(i).firstChild().toElement();
		    if ( tmp.tagName() != "data" )
			continue;
		    TQString format = tmp.attribute("format", "PNG" );
		    TQString data = tmp.firstChild().toText().data();
		    if ( format == "XPM.GZ" ) {
			xpmImages += img;
			ulong length = tmp.attribute("length").toULong();
			TQByteArray baunzip = unzipXPM( data, length );
			length = baunzip.size();
			// shouldn't we test the initial `length' against the
			// resulting `length' to catch corrupt UIC files?
			int a = 0;
			out << indent << img << "_data = [" << endl;
			while ( baunzip[a] != '\"' )
			    a++;
			for ( ; a < (int) length; a++ )
			{
			    char ch;

			    if ((ch = baunzip[a]) == '}')
			    {
				out << endl << "]";
				break;
			    }

			    out << ch;
			}
			out << endl;
		    } else {
			images += img;
			out << indent << img << "_data = \\" << endl;
			++indent;
			out << indent << "b\"";
			int a ;
			for ( a = 0; a < (int) (data.length()/2)-1; a++ ) {
			    out << "\\x" << TQString(data[2*a]) << TQString(data[2*a+1]);
			    if ( a % 12 == 11 )
				out << "\" \\" << endl << indent << "b\"";
			}
			out << "\\x" << TQString(data[2*a]) << TQString(data[2*a+1]) << "\"" << endl;
			--indent;
		    }
		}
	    }
	}
	out << endl;
    } else if ( externPixmaps ) {
	pixmapLoaderFunction = "TQPixmap.fromMimeSource";
    }


    // constructor(s)

    out << indent << "class " << nameOfClass << "(" << objClass << "):" << endl;
    ++indent;

    if ( objClass == "TQDialog" || objClass == "TQWizard" ) {
	out << indent << "def __init__(self,parent = None,name = None,modal = 0,fl = 0):" << endl;
	++indent;
	out << indent << objClass << ".__init__(self,parent,name,modal,fl)" << endl;
    } else if ( objClass == "TQWidget" )  {
	out << indent << "def __init__(self,parent = None,name = None,fl = 0):" << endl;
	++indent;
	out << indent << objClass << ".__init__(self,parent,name,fl)" << endl;
    } else if ( objClass == "TQMainWindow" ) {
	out << indent << "def __init__(self,parent = None,name = None,fl = 0):" << endl;
	++indent;
	out << indent << objClass << ".__init__(self,parent,name,fl)" << endl;
	out << indent << "self.statusBar()" << endl;
	isMainWindow = true;
    } else {
	out << indent << "def __init__(self,parent = None,name = None):" << endl;
	++indent;
	out << indent << objClass << ".__init__(self,parent,name)" << endl;
    }

    out << endl;

    // create pixmaps for all images
    if ( !images.isEmpty() ) {
	TQStringList::Iterator it;
	for ( it = images.begin(); it != images.end(); ++it ) {
	    out << indent << "self." << (*it) << " = TQPixmap()" << endl;
	    out << indent << "self." << (*it) << ".loadFromData(" << (*it) << "_data,b\"PNG\")" << endl;
	}
    }
    // create pixmaps for all images
    if ( !xpmImages.isEmpty() ) {
	for ( it = xpmImages.begin(); it != xpmImages.end(); ++it ) {
	    out << indent << "self." << (*it) << " = TQPixmap(" << (*it) << "_data)" << endl;
	}
	out << endl;
    }


    // set the properties
    TQSize geometry( 0, 0 );

    for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) {
	if ( n.tagName() == "property" ) {
	    bool stdset = stdsetdef;
	    if ( n.hasAttribute( "stdset" ) )
		stdset = toBool( n.attribute( "stdset" ) );
	    TQString prop = n.attribute("name");
	    TQDomElement n2 = n.firstChild().toElement();
	    TQString value = setObjectProperty( objClass, TQString::null, prop, n2, stdset );
	    if ( value.isEmpty() )
		continue;

	    if ( prop == "geometry" && n2.tagName() == "rect") {
		TQDomElement n3 = n2.firstChild().toElement();
		while ( !n3.isNull() ) {
		    if ( n3.tagName() == "width" )
			geometry.setWidth( n3.firstChild().toText().data().toInt() );
		    else if ( n3.tagName() == "height" )
			geometry.setHeight( n3.firstChild().toText().data().toInt() );
		    n3 = n3.nextSibling().toElement();
		}
	    } else {
		TQString call;
		if ( stdset )
		    call = "self." + mkStdSet( prop ) + "(" + value + ")";
		else
		    call = "self.setProperty(\"" + prop + "\",TQVariant(" + value + "))";

                if ( n2.tagName() == "string" ) {
                    trout << trindent << call << endl;
                } else if ( prop == "name" ) {
                    out << indent << "if not name:" << endl;
		    ++indent;
                    out << indent << call << endl;
		    --indent;
		    out << endl;
                } else {
                    out << indent << call << endl;
		}
	    }
	}
    }

    out << endl;

    // create all children, some forms have special requirements

    if ( objClass == "TQWizard" ) {
	for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) {
	    if ( tags.contains( n.tagName()  ) ) {
		TQString page = createObjectImpl( n, objClass, "self" );
		TQString comment;
		TQString label = DomTool::readAttribute( n, "title", "", comment ).toString();
		out << indent << "self.addPage(" << page << ",TQString(\"\"))" << endl;
		trout << trindent << "self.setTitle(" << page << ","<< trcall( label, comment ) << ")" << endl;
		TQVariant def( false );
		if ( DomTool::hasAttribute( n, "backEnabled" ) )
		    out << indent << "self.setBackEnabled(" << page << "," << mkBool( DomTool::readAttribute( n, "backEnabled", def).toBool() ) << ")" << endl;
		if ( DomTool::hasAttribute( n, "nextEnabled" ) )
		    out << indent << "self.setNextEnabled(" << page << "," << mkBool( DomTool::readAttribute( n, "nextEnabled", def).toBool() ) << ")" << endl;
		if ( DomTool::hasAttribute( n, "finishEnabled" ) )
		    out << indent << "self.setFinishEnabled(" << page << "," << mkBool( DomTool::readAttribute( n, "finishEnabled", def).toBool() ) << ")" << endl;
		if ( DomTool::hasAttribute( n, "helpEnabled" ) )
		    out << indent << "self.setHelpEnabled(" << page << "," << mkBool( DomTool::readAttribute( n, "helpEnabled", def).toBool() ) << ")" << endl;
		if ( DomTool::hasAttribute( n, "finish" ) )
		    out << indent << "self.setFinish( " << page << "," << mkBool( DomTool::readAttribute( n, "finish", def).toBool() ) << ")" << endl;
	    }
	}
    } else { // standard widgets
	for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) {
	    if ( tags.contains( n.tagName()  ) )
		createObjectImpl( n, objName, "self" );
	}
    }

    // database support
    dbConnections = unique( dbConnections );
    if ( dbConnections.count() )
	out << endl;
    for ( it = dbConnections.begin(); it != dbConnections.end(); ++it ) {
	if ( !(*it).isEmpty() && (*it) != "(default)") {
	    out << indent << "self." << (*it) << "Connection = TQSqlDatabase.database(\"" <<(*it) << "\")" << endl;
	}
    }

    nl = e.parentNode().toElement().elementsByTagName( "widget" );
    for ( i = 1; i < (int) nl.length(); i++ ) { // start at 1, 0 is the toplevel widget
	n = nl.item(i).toElement();
	TQString s = getClassName( n );
	if ( (dbForm || subDbForms) && (s == "TQDataBrowser" || s == "TQDataView") ) {
	    TQString objName = getObjectName( n );
	    TQString tab = getDatabaseInfo( n, "table" );
	    TQString con = getDatabaseInfo( n, "connection" );
	    out << indent << objName << "Form = TQSqlForm(self,\"" << objName << "Form\")" << endl;
	    TQDomElement n2;
	    for ( n2 = n.firstChild().toElement(); !n2.isNull(); n2 = n2.nextSibling().toElement() )
		createFormImpl( n2, objName, con, tab );
	    out << indent << "self." << objName << ".setForm(" << objName << "Form)" << endl;
	}
    }

    // actions, toolbars, menubar
    bool needEndl = false;
    for ( n = e; !n.isNull(); n = n.nextSibling().toElement() ) {
	if ( n.tagName()  == "actions" ) {
	    if ( !needEndl )
		out << endl;
	    createActionImpl( n.firstChild().toElement(), "self" );
	    needEndl = true;
	}
    }
    if ( needEndl )
	out << endl;
    needEndl = false;
    for ( n = e; !n.isNull(); n = n.nextSibling().toElement() ) {
	if ( n.tagName() == "toolbars" ) {
	    if ( !needEndl )
		out << endl;
	    createToolbarImpl( n, objClass, objName );
	    needEndl = true;
	}
    }
    if ( needEndl )
	out << endl;
    needEndl = false;
    for ( n = e; !n.isNull(); n = n.nextSibling().toElement() ) {
	if ( n.tagName() == "menubar" ) {
	    if ( !needEndl )
		out << endl;
	    createMenuBarImpl( n, objClass, objName );
	    needEndl = true;
	}
    }
    if ( needEndl )
	out << endl;

    out << endl;
    out << indent << "self.languageChange()" << endl;
    out << endl;

    // take minimumSizeHint() into account, for height-for-width widgets
    if ( !geometry.isNull() ) {
        out << indent << "self.resize(TQSize(" << geometry.width() << ","
            << geometry.height() <<").expandedTo(self.minimumSizeHint()))" << endl;
	out << indent << "self.clearWState(TQt.WState_Polished)" << endl;
    }

    for ( n = e; !n.isNull(); n = n.nextSibling().toElement() ) {
	if ( n.tagName()  == "connections" ) {
	    // setup signals and slots connections
	    out << endl;
	    nl = n.elementsByTagName( "connection" );
	    for ( i = 0; i < (int) nl.length(); i++ ) {
		TQString sender, receiver, signal, slot;
		for ( TQDomElement n2 = nl.item(i).firstChild().toElement(); !n2.isNull(); n2 = n2.nextSibling().toElement() ) {
		    if ( n2.tagName() == "sender" )
			sender = n2.firstChild().toText().data();
		    else if ( n2.tagName() == "receiver" )
			receiver = n2.firstChild().toText().data();
		    else if ( n2.tagName() == "signal" )
			signal = n2.firstChild().toText().data();
		    else if ( n2.tagName() == "slot" )
			slot = n2.firstChild().toText().data();
		}
                if ( sender.isEmpty() ||
                     receiver.isEmpty() ||
                     signal.isEmpty() ||
                     slot.isEmpty() )
                    continue;
                if ( sender[0] == '<' ||
                     receiver[0] == '<' ||
                     signal[0] == '<' ||
                     slot[0] == '<' )
		    continue;

		sender = registeredName( sender );
		receiver = registeredName( receiver );

		 // translate formwindow name to "self"
		if ( sender == objName )
		    sender = "self";
		else
		    sender = "self." + sender;

		bool isaxwidget = (axwidgets.findIndex(receiver) >= 0);
		bool isdatabrowser = (databrowsers.findIndex(receiver) >= 0);

		if ( receiver == objName )
		    receiver = "self";
		else
		    receiver = "self." + receiver;

		out << indent << "self.connect(" << sender
		    << ",TQ_SIGNAL(\"" << signal << "\")," << receiver;

		// Normally we never use the TQ_SLOT() macro in case the
		// connection is to a method of a Python custom widget.  The
		// exception is if the receiver is a TQAxWidget where it must be
		// used because the slots are dynamic.
		if (isaxwidget)
		    out << ",TQ_SLOT(\"" << slot << "\")";
		else
		{
		    TQString mname = slot.left(slot.find('('));

		    // Rename slots that have different names in PyTQt.
		    if (isdatabrowser && mname == "del")
			    mname = "delOnCursor";

		    out << "." << mname;
		}

		out << ")" << endl;
	    }
	} else if ( n.tagName()  == "tabstops" ) {
	    // setup tab order
	    out << endl;
	    TQString lastName;
	    TQDomElement n2 = n.firstChild().toElement();
	    while ( !n2.isNull() ) {
		if ( n2.tagName() == "tabstop" ) {
		    TQString name = n2.firstChild().toText().data();
		    name = registeredName( name );
		    if ( !lastName.isEmpty() )
			out << indent << "self.setTabOrder(self." << lastName << ",self." << name << ")" << endl;
		    lastName = name;
		}
		n2 = n2.nextSibling().toElement();
	    }
	}
    }

    // buddies
    bool firstBuddy = true;
    for ( TQValueList<Buddy>::Iterator buddy = buddies.begin(); buddy != buddies.end(); ++buddy ) {
	if ( isObjectRegistered( (*buddy).buddy ) ) {
	    if ( firstBuddy ) {
		out << endl;
	    }
	    out << indent << "self." << (*buddy).key << ".setBuddy(self." << registeredName( (*buddy).buddy ) << ")" << endl;
	    firstBuddy = false;
	}

    }

    if ( extraSlots.find( "init()" ) != extraSlots.end() )
	out << endl << indent << "self.init()" << endl;

    // end of constructor
    --indent;

    // destructor
    if ( extraSlots.find( "destroy()" ) != extraSlots.end() ) {
	out << endl;
	out << indent << "def __del__(self):" << endl;
	++indent;
	out << indent << "self.destroy()" << endl;
	--indent;
    }

    // handle application events if required
    bool needFontEventHandler = false;
    bool needSqlTableEventHandler = false;
    bool needSqlDataBrowserEventHandler = false;
    nl = e.elementsByTagName( "widget" );
    for ( i = 0; i < (int) nl.length(); i++ ) {
	if ( !DomTool::propertiesOfType( nl.item(i).toElement() , "font" ).isEmpty() )
	    needFontEventHandler = true;
	TQString s = getClassName( nl.item(i).toElement() );
	if ( s == "TQDataTable" || s == "TQDataBrowser" ) {
	    if ( !isFrameworkCodeGenerated( nl.item(i).toElement() ) )
		 continue;
	    if ( s == "TQDataTable" )
		needSqlTableEventHandler = true;
	    if ( s == "TQDataBrowser" )
		needSqlDataBrowserEventHandler = true;
	}
	if ( needFontEventHandler && needSqlTableEventHandler && needSqlDataBrowserEventHandler )
	    break;
    }
    if ( needFontEventHandler && false ) {
	//	indent = "\t"; // increase indentation for if-clause below
	out << "/*  " << endl;
	out << " *  Main event handler. Reimplemented to handle" << endl;
	out << " *  application font changes";
	out << " */" << endl;
	out << "bool " << nameOfClass  << "::event( TQEvent* ev )" << endl;
	out << "{" << endl;
	out << "    bool ret = " << objClass << "::event( ev ); " << endl;
	if ( needFontEventHandler ) {
	    ++indent;
	    out << "    if ( ev->type() == TQEvent::ApplicationFontChange ) {" << endl;
	    for ( i = 0; i < (int) nl.length(); i++ ) {
		n = nl.item(i).toElement();
		TQStringList list = DomTool::propertiesOfType( n, "font" );
		for ( it = list.begin(); it != list.end(); ++it )
		    createExclusiveProperty( n, *it );
	    }
	    out << "    }" << endl;
	    --indent;
	}
	out << "}" << endl;
	out << endl;
    }

    if ( needSqlTableEventHandler || needSqlDataBrowserEventHandler ) {
	out << endl;
	out << indent << "# Widget polish.  Reimplemented to handle default data" << endl;
	if ( needSqlTableEventHandler )
	    out << indent << "# table initialization." << endl;
	if ( needSqlDataBrowserEventHandler )
	    out << indent << "# browser initialization." << endl;
	out << indent << "def polish(self):" << endl;
	++indent;
	if ( needSqlTableEventHandler ) {
	    for ( i = 0; i < (int) nl.length(); i++ ) {
		TQString s = getClassName( nl.item(i).toElement() );
		if ( s == "TQDataTable" ) {
		    n = nl.item(i).toElement();
		    TQString c = getObjectName( n );
		    TQString conn = getDatabaseInfo( n, "connection" );
		    TQString tab = getDatabaseInfo( n, "table" );
		    if ( !( conn.isEmpty() || tab.isEmpty() || !isFrameworkCodeGenerated( nl.item(i).toElement() ) ) ) {
			out << indent << "if self." << c << ":" << endl;
			++indent;
			out << indent << "cursor = self." << c << ".sqlCursor()" << endl;
			out << endl;
			out << indent << "if not cursor:" << endl;
			++indent;
			if ( conn == "(default)" )
			    out << indent << "cursor = TQSqlCursor(\"" << tab << "\")" << endl;
			else
			    out << indent << "cursor = TQSqlCursor(\"" << tab << "\",1,self." << conn << "Connection)" << endl;
			out << indent << "if self." << c << ".isReadOnly():" << endl;
			++indent;
			out << indent << "cursor.setMode(TQSqlCursor.ReadOnly)" << endl;
			--indent;
			out << indent << "self." << c << ".setSqlCursor(cursor,0,1)" << endl;
			--indent;
			out << endl;
			out << indent << "if not cursor.isActive():" << endl;
			++indent;
			out << indent << "self." << c << ".refresh(TQDataTable.RefreshAll)" << endl;
			--indent;
			--indent;
		    }
		}
	    }
	}
	if ( needSqlDataBrowserEventHandler ) {
	    nl = e.elementsByTagName( "widget" );
	    for ( i = 0; i < (int) nl.length(); i++ ) {
		TQString s = getClassName( nl.item(i).toElement() );
		if ( s == "TQDataBrowser" ) {
		    TQString obj = getObjectName( nl.item(i).toElement() );
		    TQString tab = getDatabaseInfo( nl.item(i).toElement(),
						   "table" );
		    TQString conn = getDatabaseInfo( nl.item(i).toElement(),
						    "connection" );
		    if ( !(tab.isEmpty() || !isFrameworkCodeGenerated( nl.item(i).toElement() ) ) ) {
			out << indent << "if self." << obj << ":" << endl;
			++indent;
			out << indent << "if not self." << obj << ".sqlCursor():" << endl;
			++indent;
			if ( conn == "(default)" )
			    out << indent << "cursor = TQSqlCursor(\"" << tab << "\")" << endl;
			else
			    out << indent << "cursor = TQSqlCursor(\"" << tab << "\",1,self." << conn << "Connection)" << endl;
			out << indent << "self." << obj << ".setSqlCursor(cursor,1)" << endl;
			out << indent << "self." << obj << ".refresh()" << endl;
			out << indent << "self." << obj << ".first()" << endl;
			--indent;
			--indent;
		    }
		}
	    }
	}
	out << indent << objClass << ".polish(self)" << endl;
	--indent;
    }

    out << endl;
    out << endl;
    out << indent << "def languageChange(self):" << endl;
    uint old = indent.setIndent(0);
    out << languageChangeBody << endl;
    indent.setIndent(old);

    // create  stubs for additional slots if necessary
    if ( !extraSlots.isEmpty() && writeFunctImpl ) {
	TQStringList::ConstIterator cit;

	for ( cit = extraSlots.begin(); cit != extraSlots.end(); ++cit ) {
	    pySlot(cit);

	    bool createWarning = true;
	    TQString fname = Parser::cleanArgs( *cit );
	    TQMap<TQString, TQString>::Iterator fit = functionImpls.find( fname );
	    if ( fit != functionImpls.end() ) {
		int begin = (*fit).find( "{" );
		TQString body = (*fit).mid( begin + 1, (*fit).findRev( "}" ) - begin - 1 );
		createWarning = body.simplifyWhiteSpace().isEmpty();
		if ( !createWarning )
                {
		    ++indent;
                    TQString formatted_body = body.replace(TQRegExp("\n"), TQString("\n") + TQString(indent));
                    out << formatted_body << endl;
                    --indent;
                }
	    }
	    if ( createWarning ) {
		out << endl;
		++indent;
		if ( *cit != "init()" && *cit != "destroy()" )
		    out << indent << "print(\"" << nameOfClass << "." << (*cit) << ": Not implemented yet\")" << endl;
		else
		    out << indent << "pass" << endl;
		--indent;
	    }
	}
    }

    --indent;
}


/*! Creates form support implementation code for the widgets given
  in \a e.

  Traverses recursively over all children.
 */

void Uic::createFormImpl( const TQDomElement& e, const TQString& form, const TQString& connection, const TQString& table )
{
    if ( e.tagName() == "widget" &&
	 e.attribute( "class" ) != "TQDataTable" ) {
	TQString field = getDatabaseInfo( e, "field" );
	if ( !field.isEmpty() ) {
	    if ( isWidgetInTable( e, connection, table ) )
		out << indent << form << "Form.insert(self." << getObjectName( e ) << "," << fixString( field ) << ")" << endl;
	}
    }
    TQDomElement n;
    for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) {
	createFormImpl( n, form, connection, table );
    }
}


// Generate a Python slot definition.

void Uic::pySlot(TQStringList::ConstIterator &it)
{
    out << endl;

    int astart = (*it).find('(');
    out << indent << "def " << (*it).left(astart) << "(self";

    // We don't reproduce the argument names (if any) because we would have to
    // remove the types - too complicated for the moment, so we just count them
    // and give them names based on their position.
 
    TQString args = (*it).mid(astart + 1,(*it).find(')') - astart - 1).stripWhiteSpace();
 
    if (!args.isEmpty()) {
	int nrargs = args.contains(',') + 1;
 
	for (int i = 0; i < nrargs; ++i)
	    out << ",a" << i;
    }
 
    out << "):";
}
