/********************************************************************** ** Copyright (C) 2000 Trolltech AS. All rights reserved. ** Copyright (c) 2002 Germain Garand ** ** 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. ** **********************************************************************/ /* ** 06/2002 : Initial release of puic, the PerlTQt User Interface Compiler, ** a work derivated from uic (the TQt User Interface Compiler) ** and pyuic (the PyTQt User Interface Compiler). ** ** G.Garand ** **********************************************************************/ #include #include "uic.h" #include "parser.h" #include "widgetdatabase.h" #include "domtool.h" #include #include #include #include #include #include #define NO_STATIC_COLORS #include #if( TQT_VERSION < 0x030101 ) # include static TQByteArray tqUncompress( const uchar* data, int nbytes ) { if ( !data ) { #if defined(TQT_CHECK_RANGE) qWarning( "qUncompress: data is NULL." ); #endif return TQByteArray(); } if ( nbytes <= 4 ) { #if defined(TQT_CHECK_RANGE) if ( nbytes < 4 || ( data[0]!=0 || data[1]!=0 || data[2]!=0 || data[3]!=0 ) ) qWarning( "qUncompress: Input data is corrupted." ); #endif return TQByteArray(); } ulong expectedSize = ( data[0] << 24 ) | ( data[1] << 16 ) | ( data[2] << 8 ) | data[3]; ulong len = TQMAX( expectedSize, 1 ); TQByteArray baunzip; int res; do { baunzip.resize( len ); res = ::uncompress( (uchar*)baunzip.data(), &len, (uchar*)data+4, nbytes-4 ); switch ( res ) { case Z_OK: if ( len != baunzip.size() ) baunzip.resize( len ); break; case Z_MEM_ERROR: #if defined(TQT_CHECK_RANGE) qWarning( "qUncompress: Z_MEM_ERROR: Not enough memory." ); #endif break; case Z_BUF_ERROR: len *= 2; break; case Z_DATA_ERROR: #if defined(TQT_CHECK_RANGE) qWarning( "qUncompress: Z_DATA_ERROR: Input data is corrupted." ); #endif break; } } while ( res == Z_BUF_ERROR ); if ( res != Z_OK ) baunzip = TQByteArray(); return baunzip; } #endif // TQT_VERSION < 0x030101 using namespace std; 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; } #if 0 //- kept for diffs #if TQT_VERSION >= 0x030900 #error Add this functionality to TQDir (relativePathTo() maybe?) and \ remove it from here and from moc #endif TQCString combinePath( const char *infile, const char *outfile ) { TQFileInfo inFileInfo( TQDir::current(), TQFile::decodeName(infile) ); TQFileInfo outFileInfo( TQDir::current(), TQFile::decodeName(outfile) ); int numCommonComponents = 0; TQStringList inSplitted = TQStringList::split( '/', inFileInfo.dir().canonicalPath(), TRUE ); TQStringList outSplitted = TQStringList::split( '/', outFileInfo.dir().canonicalPath(), TRUE ); while ( !inSplitted.isEmpty() && !outSplitted.isEmpty() && inSplitted.first() == outSplitted.first() ) { inSplitted.remove( inSplitted.begin() ); outSplitted.remove( outSplitted.begin() ); numCommonComponents++; } if ( numCommonComponents < 2 ) { /* The paths don't have the same drive, or they don't have the same root directory. Use an absolute path. */ return TQFile::encodeName( inFileInfo.absFilePath() ); } else { /* The paths have something in common. Use a path relative to the output file. */ while ( !outSplitted.isEmpty() ) { outSplitted.remove( outSplitted.begin() ); inSplitted.prepend( ".." ); } inSplitted.append( inFileInfo.fileName() ); return TQFile::encodeName( inSplitted.join("/") ); } } #endif /*! 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 ); out << indent << "package " << nameOfClass << ";" << endl; out << indent << "use TQt;" << endl; // generate local and local includes required TQStringList globalIncludes, localIncludes, useIncludes; TQStringList::Iterator it; TQStringList sqlClasses; TQMap customWidgetIncludes; TQMap functionImpls; TQString uiPmInclude; // find additional slots TQStringList extraSlots; TQStringList extraSlotTyp; 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; TQString l = n.attribute( "language", "C++" ); if ( l != "C++" && l != "Perl" ) //- mmh continue; TQString slotName = n.firstChild().toText().data().stripWhiteSpace(); if ( slotName.endsWith( ";" ) ) slotName = slotName.left( slotName.length() - 1 ); extraSlots += Parser::cleanArgs(slotName); extraSlotTyp += n.attribute( "returnType", "void" ); } // find additional functions TQStringList extraFuncts; TQStringList extraFunctTyp; nl = e.parentNode().toElement().elementsByTagName( "function" ); for ( i = 0; i < (int) nl.length(); i++ ) { n = nl.item(i).toElement(); if ( n.parentNode().toElement().tagName() != "functions" ) continue; TQString l = n.attribute( "language", "C++" ); if ( l != "C++" && l != "Perl" ) //- mmh continue; TQString functionName = n.firstChild().toText().data().stripWhiteSpace(); if ( functionName.endsWith( ";" ) ) functionName = functionName.left( functionName.length() - 1 ); extraFuncts += Parser::cleanArgs(functionName); extraFunctTyp += n.attribute( "returnType", "void" ); } // find signals TQStringList extraSignals; nl = e.parentNode().toElement().elementsByTagName( "signal" ); for ( i = 0; i < (int) nl.length(); i++ ) { n = nl.item(i).toElement(); if ( n.parentNode().toElement().tagName() != "signals" && n.parentNode().toElement().tagName() != "connections" ) continue; TQString l = n.attribute( "language", "C++" ); if ( l != "C++" && l != "Perl" ) //- mmh continue; TQString sigName = n.firstChild().toText().data().stripWhiteSpace(); if ( sigName.endsWith( ";" ) ) sigName = sigName.left( sigName.length() - 1 ); extraSignals += sigName; } #if 0 //- kept for diffs TQStringList customImages; for ( n = e; !n.isNull(); n = n.nextSibling().toElement() ) { if ( n.tagName() == "customwidgets" ) { nl = n.elementsByTagName( "pixmap" ); for ( i = 0; i < (int) nl.length(); i++ ) customImages += nl.item( i ).firstChild().toText().data(); } } #endif for ( n = e; !n.isNull(); n = n.nextSibling().toElement() ) { if ( n.tagName() == "customwidgets" ) { TQDomElement n2 = n.firstChild().toElement(); while ( !n2.isNull() ) { if ( n2.tagName() == "customwidget" ) { TQDomElement n3 = n2.firstChild().toElement(); TQString cl, header; WidgetDatabaseRecord *r = new WidgetDatabaseRecord; while ( !n3.isNull() ) { if ( n3.tagName() == "class" ) { cl = n3.firstChild().toText().data(); r->name = cl; } else if ( n3.tagName() == "header" ) { CustomInclude ci; ci.header = n3.firstChild().toText().data(); ci.location = n3.attribute( "location", "global" ); r->includeFile = ci.header; header = ci.header; customWidgetIncludes.insert( cl, ci ); } WidgetDatabase::append( r ); n3 = n3.nextSibling().toElement(); } if (cl.isEmpty()) cl = "UnnamedCustomClass"; int ext = header.findRev('.'); if (ext >= 0) header.truncate(ext); if (header.isEmpty()) header = cl.lower(); if (!nofwd) out << "use " << cl << ";" << endl; // FIXME: what about header ? } n2 = n2.nextSibling().toElement(); } } } out << indent << "use TQt::isa qw(" << objClass << ");" << endl; // PerlTQt sig/slot declaration if ( !extraSlots.isEmpty() ) { out << indent << "use TQt::slots" << endl; ++indent; for ( it = extraSlots.begin(); it != extraSlots.end(); ++it ) { perlSlot( it ); out << ( ((*it) == extraSlots.last()) ? ";":",") << endl; } --indent; } // create signals if ( !extraSignals.isEmpty() ) { out << indent << "use TQt::signals" << endl; ++indent; for ( it = extraSignals.begin(); it != extraSignals.end(); ++it ) { perlSlot( it ); out << ( ((*it) == extraSignals.last()) ? ";":",") << endl; } --indent; } // PerlTQt attributes out << indent << "use TQt::attributes qw("<< endl; ++indent; // children if( !objectNames.isEmpty() ) cerr << "WARNING : objectNames should be empty at form.cpp line" << __LINE__ << 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(); createAttrDecl( n ); } objectNames.clear(); // additional attributes (from Designer) TQStringList publicVars, protectedVars, privateVars; nl = e.parentNode().toElement().elementsByTagName( "variable" ); for ( i = 0; i < (int)nl.length(); i++ ) { n = nl.item( i ).toElement(); // Because of compatibility the next lines have to be commented out. // Someday it should be uncommented. //if ( n.parentNode().toElement().tagName() != "variables" ) // continue; TQString access = n.attribute( "access", "protected" ); TQString var = n.firstChild().toText().data().stripWhiteSpace(); if ( var.endsWith( ";" ) ) var.truncate(var.length() - 1); if ( access == "public" ) publicVars += var; else if ( access == "private" ) privateVars += var; else protectedVars += var; } // for now, all member variables are public. if ( !publicVars.isEmpty() ) { for ( it = publicVars.begin(); it != publicVars.end(); ++it ) out << indent << *it << endl; } if ( !protectedVars.isEmpty() ) { for ( it = protectedVars.begin(); it != protectedVars.end(); ++it ) out << indent << *it << endl; } if ( !privateVars.isEmpty() ) { for ( it = privateVars.begin(); it != privateVars.end(); ++it ) out << indent << *it << endl; } // actions, toolbars, menus for ( n = e; !n.isNull(); n = n.nextSibling().toElement() ) { if ( n.tagName() == "actions" ) { for ( TQDomElement a = n.firstChild().toElement(); !a.isNull(); a = a.nextSibling().toElement() ) createActionDecl( a ); } else if ( n.tagName() == "toolbars" ) { for ( TQDomElement a = n.firstChild().toElement(); !a.isNull(); a = a.nextSibling().toElement() ) { if ( a.tagName() == "toolbar" ) out << indent << getObjectName( a ) << endl; } } else if ( n.tagName() == "menubar" ) { out << indent << getObjectName( n ) << endl; for ( TQDomElement a = n.firstChild().toElement(); !a.isNull(); a = a.nextSibling().toElement() ) { if ( a.tagName() == "item" ) out << indent << a.attribute( "name" ) << endl; } } } // Databases Connection holders registerDatabases( e ); dbConnections = unique( dbConnections ); for ( it = dbConnections.begin(); it != dbConnections.end(); ++it ) { if ( !(*it).isEmpty() && (*it) != "(default)") { out << indent << (*it) << "Connection" << endl; } } --indent; out << indent << ");" << endl; out << endl; // 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" || s.right( 6 ) == ".ui.pm") && !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 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" || s.right( 6 ) == ".ui.pm") && !TQFile::exists( s ) ) continue; if ( n2.attribute( "impldecl", "in declaration" ) == "in declaration" ) { useIncludes += s; } else if ( n2.attribute( "impldecl", "in implementation" ) == "in implementation" ) { localIncludes += s; } } } // 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; else localIncludes += s; } // Output the "use" clauses for extra stuff in "Includes (In Declaration)" // => in the perleditor plugin, this is content of the "Use clauses" list for(TQStringList::Iterator it = useIncludes.begin(); it != useIncludes.end(); ++it) out << indent << (*it) << endl; // grab slots/funcs defined in ui.h files / ui.pm files for(TQStringList::Iterator it = localIncludes.begin(); it != localIncludes.end(); ++it) { if((*it).right( 5 ) == ".ui.h") { TQFile f((*it)); if( f.open( IO_ReadOnly ) ) { TQRegExp re("^.*([a-zA-Z0-9_]+\\s*\\(.*\\))\\s*$"); TQRegExp re2("^\\}.*"); TQTextStream t( &f ); TQString s, s2, s3; while ( !t.eof() ) { s = t.readLine(); int pos = re.search(s); if(pos == -1) continue; s2 = re.cap(1); s2 = Parser::cleanArgs(s2); s3 = TQString::null; while( !t.eof() ) { s = t.readLine(); s3 += s + "\n"; if(re2.search(s) != -1) break; } functionImpls.insert( s2, s3 ); if( t.eof() ) break; } f.close(); } } else if((*it).right( 6 ) == ".ui.pm") { //TQFileInfo fname( fileName ); //- FIXME: .ui files seem to require being in CWD? //TQString path = fname.absFilePath(); //path = path.left( path.length() - fname.fileName().length() ); TQFile f(*it); if( f.open( IO_ReadOnly ) ) { TQTextStream t( &f ); TQString s; bool skip = true; int count = 0; while ( !t.eof() ) { s = t.readLine(); if( skip ) { if( s[0] == '#' ) { count++; continue; } else { skip = false; uiPmInclude += "# line " + TQString::number( count+1 ) + " \"" + *it + "\"\n"; } } uiPmInclude += s + "\n"; } f.close(); } } } // 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 += "qlayout.h"; globalIncludes += "qapplication.h"; continue; } if ( name.mid( 4 ) == "ListView" ) globalIncludes += "qheader.h"; if ( name != objClass ) { int wid = WidgetDatabase::idFromClassName( name.replace( TQRegExp("^TQt::"), "Q" ) ); TQMap::Iterator it = customWidgetIncludes.find( name ); if ( it == customWidgetIncludes.end() ) globalIncludes += WidgetDatabase::includeFile( wid ); } } } dbConnections = unique( dbConnections ); if ( dbConnections.count() ) sqlClasses += "TQt::SqlDatabase"; if ( dbCursors.count() ) sqlClasses += "TQt::SqlCursor"; 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 += "TQt::SqlForm"; sqlClasses += "TQt::SqlRecord"; } if (globalIncludes.findIndex("qdatatable.h") >= 0) sqlClasses += "TQt::DataTable"; if (globalIncludes.findIndex("qtableview.h") >= 0) sqlClasses += "TQt::TableView"; if (globalIncludes.findIndex("qdatabrowser.h") >= 0) sqlClasses += "TQt::DataBrowser"; 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(); out << indent << "our $" << img << ";" << endl; 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 << "our $" << img << "_data =\n["; while ( baunzip[a] != '\"' ) a++; for ( ; a < (int) length; a++ ) { char ch; if ((ch = baunzip[a]) == '}') { out << "];\n" << endl; break; } out << ch; } } else { images += img; out << indent << "our $" << img << "_data = pack 'C*'," << endl; ++indent; int a ; for ( a = 0; a < (int) (data.length()/2)-1; a++ ) { out << "0x" << TQString(data[2*a]) << TQString(data[2*a+1]) << ","; if ( a % 12 == 11 ) out << endl << " "; else out << " "; } out << "0x" << TQString(data[2*a]) << TQString(data[2*a+1]) << ";" << endl; --indent; out << endl; } } } } out << endl; } else if ( externPixmaps ) { pixmapLoaderFunction = "TQt::Pixmap::fromMimeSource"; } // constructor(s) out << indent << "sub NEW" << endl; out << indent << "{" << endl; ++indent; if ( objClass == "TQt::Dialog" || objClass == "TQt::Wizard" ) { out << indent << "shift->SUPER::NEW(@_[0..3]);" << endl; } else if ( objClass == "TQt::Widget") { out << indent << "shift->SUPER::NEW(@_[0..2]);" << endl; } else if ( objClass == "TQt::MainWindow" ) { out << indent << "shift->SUPER::NEW(@_[0..2]);" << endl; out << indent << "statusBar();" << endl; isMainWindow = TRUE; } else { out << indent << "shift->SUPER::NEW(@_[0,1]);" << endl; } out << endl; // create pixmaps for all images if ( !images.isEmpty() ) { TQStringList::Iterator it; for ( it = images.begin(); it != images.end(); ++it ) { out << indent << "$" << (*it) << " = TQt::Pixmap();" << endl; out << indent << "$" << (*it) << "->loadFromData($" << (*it) << "_data, length ($" << (*it) << "_data), \"PNG\");" << endl; } out << endl; } // create pixmaps for all images if ( !xpmImages.isEmpty() ) { for ( it = xpmImages.begin(); it != xpmImages.end(); ++it ) { out << indent << "$" << (*it) << " = TQt::Pixmap($" << (*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 = mkStdSet( prop ) + "(" + value; else call = "setProperty(\"" + prop + "\", TQt::Variant(" + value + ")"; call += " );"; if ( n2.tagName() == "string" ) { trout << indent << call << endl; } else if ( prop == "name" ) { out << indent << "if ( name() eq \"unnamed\" )" << endl; out << indent << "{" << endl; ++indent; out << indent << call << endl; --indent; out << indent << "}" << endl; } else { out << indent << call << endl; } } } } out << endl; // create all children, some forms have special requirements if ( objClass == "TQt::Wizard" ) { for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) { if ( tags.contains( n.tagName() ) ) { TQString page = createObjectImpl( n, objClass, "this" ); TQString comment; TQString label = DomTool::readAttribute( n, "title", "", comment ).toString(); out << indent << "addPage( " << page << ", \"\" );" << endl; trout << indent << "setTitle( " << page << ", " << trcall( label, comment ) << " );" << endl; TQVariant def( FALSE, 0 ); if ( DomTool::hasAttribute( n, "backEnabled" ) ) out << indent << "setBackEnabled(" << page << "," << mkBool( DomTool::readAttribute( n, "backEnabled", def).toBool() ) << ");" << endl; if ( DomTool::hasAttribute( n, "nextEnabled" ) ) out << indent << "setNextEnabled(" << page << "," << mkBool( DomTool::readAttribute( n, "nextEnabled", def).toBool() ) << ");" << endl; if ( DomTool::hasAttribute( n, "finishEnabled" ) ) out << indent << "setFinishEnabled(" << page << "," << mkBool( DomTool::readAttribute( n, "finishEnabled", def).toBool() ) << ");" << endl; if ( DomTool::hasAttribute( n, "helpEnabled" ) ) out << indent << "setHelpEnabled(" << page << "," << mkBool( DomTool::readAttribute( n, "helpEnabled", def).toBool() ) << ");" << endl; if ( DomTool::hasAttribute( n, "finish" ) ) out << indent << "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, "this" ); } } // 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 << (*it) << "Connection = TQt::SqlDatabase::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 == "TQt::DataBrowser" || s == "TQt::DataView" ) ) { TQString objName = getObjectName( n ); TQString tab = getDatabaseInfo( n, "table" ); TQString con = getDatabaseInfo( n, "connection" ); out << indent << "my $" << objName << "Form = TQt::SqlForm(this, \"" << objName << "Form\");" << endl; TQDomElement n2; for ( n2 = n.firstChild().toElement(); !n2.isNull(); n2 = n2.nextSibling().toElement() ) createFormImpl( n2, objName, con, tab ); out << indent << 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(), "this" ); 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 << indent << "languageChange();" << endl; // take minimumSizeHint() into account, for height-for-width widgets if ( !geometry.isNull() ) { out << indent << "my $resize = TQt::Size(" << geometry.width() << ", " << geometry.height() << ");" << endl; out << indent << "$resize = $resize->expandedTo(minimumSizeHint());" << endl; out << indent << "resize( $resize );" << endl; out << indent << "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; else if ( sender[0] == '<' || receiver[0] == '<' || signal[0] == '<' || slot[0] == '<' ) continue; sender = registeredName( sender ); receiver = registeredName( receiver ); if ( sender == objName ) sender = "this"; if ( receiver == objName ) receiver = "this"; out << indent << "TQt::Object::connect(" << sender << ", TQT_SIGNAL \"" << signal << "\", "<< receiver << ", TQT_SLOT \"" << slot << "\");" << 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 << "setTabOrder(" << lastName << ", " << name << ");" << endl; lastName = name; } n2 = n2.nextSibling().toElement(); } } } // buddies bool firstBuddy = TRUE; for ( TQValueList::Iterator buddy = buddies.begin(); buddy != buddies.end(); ++buddy ) { if ( isObjectRegistered( (*buddy).buddy ) ) { if ( firstBuddy ) { out << endl; } out << indent << (*buddy).key << "->setBuddy(this->" << registeredName( (*buddy).buddy ) << ");" << endl; firstBuddy = FALSE; } } if ( extraFuncts.find( "init()" ) != extraFuncts.end() || extraSlots.find( "init()" ) != extraSlots.end() ) out << endl << indent << "init();" << endl; // end of constructor --indent; out << indent << "}" << endl; out << endl; if ( extraFuncts.find( "destroy()" ) != extraFuncts.end() || extraSlots.find( "destroy()" ) != extraSlots.end() ) { out << endl; out << indent << "sub DESTROY" << endl; out << indent << "{" << endl; ++indent; out << indent << "destroy();" << endl; out << indent << "SUPER->DESTROY()" << endl; --indent; out << indent << "}" << endl; } // 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 == "TQt::DataTable" || s == "TQt::DataBrowser" ) { if ( !isFrameworkCodeGenerated( nl.item(i).toElement() ) ) continue; if ( s == "TQt::DataTable" ) needSqlTableEventHandler = TRUE; if ( s == "TQt::DataBrowser" ) needSqlDataBrowserEventHandler = TRUE; } if ( needFontEventHandler && needSqlTableEventHandler && needSqlDataBrowserEventHandler ) break; } // PerlTQt - TODO: is this needed ? // Seems not.. let's ifzero for now... if ( 0 && needFontEventHandler ) { // indent = "\t"; // increase indentation for if-clause below out << endl; out << "# Main event handler. Reimplemented to handle" << endl; out << "# application font changes" << endl; out << endl; out << "sub event" << endl; out << "{" << endl; out << " my $ev = shift;" << endl; out << " my $ret = SUPER->event( $ev ); " << endl; if ( needFontEventHandler ) { ++indent; out << " if ( $ev->type() == &TQt::Event::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 << "sub polish" << endl; out << indent << "{" << endl; ++indent; if ( needSqlTableEventHandler ) { for ( i = 0; i < (int) nl.length(); i++ ) { TQString s = getClassName( nl.item(i).toElement() ); if ( s == "TQt::DataTable" ) { 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(" << c << ")" << endl; out << indent << "{" << endl; ++indent; out << indent << "my $cursor = " << c << "->sqlCursor();" << endl; out << endl; out << indent << "if(!$cursor)" << endl; out << indent << "{" << endl; ++indent; if ( conn == "(default)" ) out << indent << "$cursor = TQt::SqlCursor(\"" << tab << "\");" << endl; else out << indent << "$cursor = TQt::SqlCursor(\"" << tab << "\", 1, " << conn << "Connection);" << endl; out << indent << "if ( " << c << "->isReadOnly() ) " << endl; out << indent << "{" << endl; ++indent; out << indent << "$cursor->setMode( &TQt::SqlCursor::ReadOnly )" << endl; --indent; out << indent << "}" << endl; out << indent << c << "->setSqlCursor($cursor, 0, 1);" << endl; --indent; out << endl; out << indent << "}" << endl; out << indent << "if(!$cursor->isActive())" << endl; out << indent << "{" << endl; ++indent; out << indent << c << "->refresh( &TQt::DataTable::RefreshAll );" << endl; --indent; out << indent << "}" << endl; --indent; out << indent << "}" << endl; } } } } if ( needSqlDataBrowserEventHandler ) { nl = e.elementsByTagName( "widget" ); for ( i = 0; i < (int) nl.length(); i++ ) { TQString s = getClassName( nl.item(i).toElement() ); if ( s == "TQt::DataBrowser" ) { 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(" << obj << ")" << endl; out << indent << "{" << endl; ++indent; out << indent << "if(!" << obj << "->sqlCursor())" << endl; out << indent << "{" << endl; ++indent; if ( conn == "(default)" ) out << indent << "my $cursor = TQt::SqlCursor(\"" << tab << "\");" << endl; else out << indent << "my $cursor = TQt::SqlCursor(\"" << tab << "\", 1, " << conn << "Connection);" << endl; out << indent << obj << "->setSqlCursor($cursor, 1);" << endl; out << indent << obj << "->refresh();" << endl; out << indent << obj << "->first();" << endl; --indent; out << indent << "}" << endl; --indent; out << indent << "}" << endl; } } } } out << indent << "SUPER->polish();" << endl; --indent; out << indent << "}" << endl; } out << endl; out << indent << "# Sets the strings of the subwidgets using the current" << endl; out << indent << "# language." << endl; out << endl; out << indent << "sub languageChange" << endl; out << indent << "{" << endl; ++indent; out << languageChangeBody; --indent; out << indent << "}" << endl; out << endl; // create stubs for additional functs/slots if necessary for ( it = extraSlots.begin(); it != extraSlots.end(); ++it ) extraFuncts << *it; if ( !extraFuncts.isEmpty() && writeFunctImpl && uiPmInclude.isNull() ) { for ( it = extraFuncts.begin(); it != extraFuncts.end(); ++it ) { out << endl; int astart = (*it).find('('); out << indent << "sub " << (*it).left(astart)<< endl; out << indent << "{" << endl; bool createWarning = TRUE; TQString fname = Parser::cleanArgs( *it ); TQMap::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 ) out << body << endl; } if ( createWarning ) { ++indent; if ( *it != "init()" && *it != "destroy()" ) out << indent << "print \"" << nameOfClass << "->" << (*it) << ": Not implemented yet.\\n\";" << endl; --indent; } out << indent << "}" << endl; } } else if( !extraFuncts.isEmpty() && writeFunctImpl ) { ++indent; for ( it = extraFuncts.begin(); it != extraFuncts.end(); ++it ) { if ( *it == "init()" || *it == "destroy()" ) continue; int astart = (*it).find('('); TQRegExp r( "(\\nsub\\s+" + (*it).left(astart) + "(?:\\s*#\\s*SLOT:[^\\n]+|[ \t]+)?\\n\\{)(\\s*)(\\}\\n)" ); r.setMinimal( true ); uiPmInclude.replace( r, "\\1\n" + indent + "print \"" + nameOfClass + "->" + (*it) + ": Not implemented yet.\\n\";" + "\n\\3" ); } --indent; } if( !uiPmInclude.isNull() ) out << uiPmInclude; out << endl; out << "1;" << endl; // Perl modules must return true } /*! 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" ) != "TQt::DataTable" ) { TQString field = getDatabaseInfo( e, "field" ); if ( !field.isEmpty() ) { if ( isWidgetInTable( e, connection, table ) ) out << indent << "$" << form << "Form->insert(" << 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 PerlTQt signal/slot definition. void Uic::perlSlot(TQStringList::Iterator &it) { int astart = (*it).find('('); out << indent << (*it).left(astart) << " => "; TQString args = (*it).mid(astart + 1,(*it).find(')') - astart - 1).stripWhiteSpace(); out << "["; if (!args.isEmpty()) { TQStringList arglist = TQStringList::split( TQRegExp(","), args ); out << "'" << arglist.join( "', '") << "'"; } out << "]"; }