// Copyright (c) 2000 - 2001 Phil Thompson /********************************************************************** ** Copyright (C) 2000 Troll Tech AS. All rights reserved. ** ** This file is part of Qt GUI Designer. ** ** This file may be distributed under the terms of the GNU General ** Public License version 2 as published by the Free Software ** Foundation and appearing in the file COPYING included in the ** packaging of this file. If you did not get the file, send email ** to info@trolltech.com ** ** The file is provided AS IS with NO WARRANTY OF ANY KIND, ** INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE. ** **********************************************************************/ #include "uic.h" #include #include #include #include #include #include #include #include #include #include #include #include #include static QString mkBool( bool b ) { return b? "1" : "0"; } static QString mkBool( const QString& s ) { return mkBool( s == "true" || s == "1" ); } static bool toBool( const QString& s ) { return s == "true" || s.toInt() != 0; } // fixString is only used in conjunction with tr(). We need to write out the // string in utf8 and make sure it's converted from utf8 when created. static QString fixString( const QString &str ) { QString s( str ); s.replace( QRegExp( "\\\\" ), "\\\\" ); s.replace( QRegExp( "\"" ), "\\\"" ); s.replace( QRegExp( "\n" ), "\\n\"\n\"" ); s.replace( QRegExp( "\r" ), "\\r" ); bool onlyAscii = TRUE; unsigned int i; for ( i = 0; i < s.length(); i++ ) { if ( s.at(i).unicode() >= 0x80 ) { onlyAscii = FALSE; break; } } if ( onlyAscii ) s = "\"" + s + "\""; else s = "QString.fromUtf8(\"" + s + "\")"; return s; } static QString mkStdSet( const QString& prop ) { return QString( "set" ) + prop[0].upper() + prop.mid(1); } /*! \class Uic uic.h \brief User Interface Compiler The class Uic encapsulates the user interface compiler (uic). */ static QString className; Uic::Uic( QTextStream &outStream, QDomDocument doc, const QString &trm ) : out( outStream ), trmacro( trm ) { item_used = cg_used = pal_used = 0; initIndent(); layouts << "hbox" << "vbox" << "grid"; tags = layouts; tags << "widget"; nameOfClass = getClassName( doc.firstChild().toElement() ); QDomElement firstWidget = doc.firstChild().firstChild().toElement(); while ( firstWidget.tagName() != "widget" ) firstWidget = firstWidget.nextSibling().toElement(); if ( nameOfClass.isEmpty() ) nameOfClass = getObjectName( firstWidget ); // This is a hack. className = nameOfClass; createFormImpl( firstWidget ); } /*! Extracts a class name from \a e */ QString Uic::getClassName( const QDomElement& e ) { QDomElement n; QString cn; for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) { if ( n.tagName() == "class" ) { QString s = n.firstChild().toText().data(); int i; while ( ( i = s.find(' ' )) != -1 ) s[i] = '_'; cn = s; } else if ( n.tagName() == "pixmapfunction" ) { pixmapLoaderFunction = n.firstChild().toText().data(); } } return cn; } /*! Extracts an object name from \a e. It's stored in the 'name' property. */ QString Uic::getObjectName( const QDomElement& e ) { QDomElement n; for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) { if ( n.tagName() == "property" ) { QDomElement n2 = n.firstChild().toElement(); if ( n2.tagName() == "name" && n2.firstChild().toText().data() == "name" ) { return n2.nextSibling().toElement().firstChild().toText().data(); } } } return QString::null; } /*! Extracts an layout name from \a e. It's stored in the 'name' property of the preceeding sibling (the first child of a QLayoutWidget). */ QString Uic::getLayoutName( const QDomElement& e ) { QDomElement p = e.parentNode().toElement(); QString tail = QString::null; if (getClassName(p) != "QLayoutWidget") tail = "Layout"; QDomElement n; for ( n = p.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) { if ( n.tagName() == "property" ) { QDomElement n2 = n.firstChild().toElement(); if ( n2.tagName() == "name" && n2.firstChild().toText().data() == "name" ) { return n2.nextSibling().toElement().firstChild().toText().data() + tail; } } } return e.tagName(); } QByteArray unzipXPM( QString data, ulong& length ) { char *ba = new char[ data.length() / 2 ]; for ( int i = 0; i < (int)data.length() / 2; ++i ) { char h = data[ 2 * i ].latin1(); char l = data[ 2 * i + 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; } if ( length < data.length() * 5 ) length = data.length() * 5; QByteArray baunzip( length ); ::uncompress( (uchar*) baunzip.data(), &length, (uchar*) ba, data.length()/2 ); return baunzip; } /*! Creates an implementation ( cpp-file ) for the form given in \a e \sa createFormDecl(), createObjectImpl() */ void Uic::createFormImpl( const QDomElement &e ) { QStringList::Iterator it; QDomElement n; QDomNodeList nl; int i; QString objClass = getClassName( e ); if ( objClass.isEmpty() ) return; QString objName = getObjectName( e ); // Handle custom widgets. for (n = e; !n.isNull(); n = n.nextSibling().toElement()) { if (n.tagName() != "customwidgets") continue; QDomElement n2 = n.firstChild().toElement(); while (!n2.isNull()) { if (n2.tagName() == "customwidget") { QDomElement n3 = n2.firstChild().toElement(); QString cname, header; while (!n3.isNull()) { if (n3.tagName() == "class") cname = n3.firstChild().toText().data(); else if (n3.tagName() == "header") header = n3.firstChild().toText().data(); n3 = n3.nextSibling().toElement(); } if (cname.isEmpty()) cname = "UnnamedCustomClass"; int ext = header.findRev('.'); if (ext >= 0) header.truncate(ext); if (header.isEmpty()) header = cname.lower(); out << "from " << header << " import " << cname << endl; } n2 = n2.nextSibling().toElement(); } } // find out what images are required QStringList requiredImages; nl = e.elementsByTagName( "pixmap" ); for ( int j = 0; j < (int) nl.length(); j++ ) { requiredImages += nl.item(j).firstChild().toText().data(); } QStringList images; QStringList xpmImages; if ( pixmapLoaderFunction.isEmpty() ) { // 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++ ) { QDomElement tmp = nl.item(i).firstChild().toElement(); QString img = registerObject( tmp.firstChild().toText().data() ); if ( !requiredImages.contains( img ) ) continue; tmp = tmp.nextSibling().toElement(); QString format = tmp.attribute("format", "PNG" ); QString data = tmp.firstChild().toText().data(); out << endl; out << endl; if ( format == "XPM.GZ" ) { xpmImages += img; ulong length = tmp.attribute("length").toULong(); QByteArray baunzip = unzipXPM( data, length ); 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 << "]" << endl; break; } if (ch == '\"') ch = '\''; out << ch; } } else { images += img; out << indent << img << "_data = \\" << endl; pushIndent(); out << indent << "'"; int a ; for ( a = 0; a < (int) (data.length()/2)-1; a++ ) { out << "\\x" << QString(data[2*a]) << QString(data[2*a+1]); if ( a % 12 == 11 ) out << "' \\" << endl << indent << "'"; } out << "\\x" << QString(data[2*a]) << QString(data[2*a+1]) << "'" << endl; popIndent(); } } } } } // register the object and unify its name objName = registerObject( objName ); // constructor out << endl; out << endl; out << indent << "class " << nameOfClass << "(" << objClass << "):" << endl; pushIndent(); if ( objClass == "QDialog" || objClass == "QWizard" ) { out << indent << "def __init__(self,parent = None,name = None,modal = 0,fl = 0):" << endl; pushIndent(); out << indent << objClass << ".__init__(self,parent,name,modal,fl)" << endl; } else if ( objClass == "QWidget" ) { // standard QWidget out << indent << "def __init__(self,parent = None,name = None,fl = 0):" << endl; pushIndent(); out << indent << objClass << ".__init__(self,parent,name,fl)" << endl; } else { out << indent << "def __init__(self,parent = None,name = None):" << endl; pushIndent(); out << indent << objClass << ".__init__(self,parent,name)" << endl; } out << endl; // create pixmaps for all images if ( !images.isEmpty() ) { QStringList::Iterator it; for ( it = images.begin(); it != images.end(); ++it ) { out << indent << (*it) << " = QPixmap()" << endl; out << indent << (*it) << ".loadFromData(" << (*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) << " = QPixmap(" << (*it) << "_data)" << endl; } out << endl; } // set the properties for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) { if ( n.tagName() == "property" ) { bool stdset = toBool( n.attribute( "stdset" ) ); QDomElement n2 = n.firstChild().toElement(); if ( n2.tagName() == "name" ) { QString prop = n2.firstChild().toText().data(); QString value = setObjectProperty( objClass, QString::null, prop, n2.nextSibling().toElement(), stdset ); if ( value.isEmpty() ) continue; if ( prop == "name" ) { out << indent << "if name == None:" << endl; pushIndent(); } out << indent; if ( prop == "geometry" && n2.nextSibling().toElement().tagName() == "rect") { QDomElement n3 = n2.nextSibling().toElement().firstChild().toElement(); int w = 0, h = 0; while ( !n3.isNull() ) { if ( n3.tagName() == "width" ) w = n3.firstChild().toText().data().toInt(); else if ( n3.tagName() == "height" ) h = n3.firstChild().toText().data().toInt(); n3 = n3.nextSibling().toElement(); } out << "self.resize(" << w << "," << h << ")" << endl; } else { if ( stdset ) out << "self." << mkStdSet(prop) << "(" << value << ")" << endl; else out << "self.setProperty('" << prop << "',QVariant(" << value << "))" << endl; } if (prop == "name") { popIndent(); out << endl; } } } } // create all children, some forms have special requirements if ( objClass == "QWizard" ) { for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) { if ( tags.contains( n.tagName() ) ) { QString page = createObjectImpl( n, objClass, "self" ); QString label = DomTool::readAttribute( n, "title", "" ).toString(); out << indent << "self.addPage(" << page << ","<< trmacro << "(" << fixString( label ) << "))" << endl; QVariant def( FALSE, 0 ); 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" ); } } // Get the list of any user defined slots. QStringList userSlots; for ( n = e; !n.isNull(); n = n.nextSibling().toElement() ) { if ( n.tagName() == "connections" ) { for ( QDomElement n2 = n.firstChild().toElement(); !n2.isNull(); n2 = n2.nextSibling().toElement() ) { if ( n2.tagName() == "slot" ) { userSlots += n2.firstChild().toText().data(); } } } } 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++ ) { QString sender, receiver, signal, slot; for ( QDomElement 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; sender = registeredName( sender ); receiver = registeredName( receiver ); // translate formwindow name to "self" if ( sender == objName ) sender = "self"; else sender = "self." + sender; if ( receiver == objName ) receiver = "self"; else receiver = "self." + receiver; // Note that we never use the SLOT() macro in case we have // custom widgets implemented in Python. out << indent << "self.connect(" << sender << ",SIGNAL('" << signal << "'),self." << slot.left(slot.find('(')) << ")" << endl; } } else if ( n.tagName() == "tabstops" ) { // setup tab order out << endl; QString lastName; QDomElement n2 = n.firstChild().toElement(); while ( !n2.isNull() ) { if ( n2.tagName() == "tabstop" ) { QString 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 ( QValueList::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; } } // end of constructor popIndent(); // handle application font changes if required nl = e.elementsByTagName( "widget" ); bool needEventHandler = FALSE; for ( i = 0; i < (int) nl.length(); i++ ) { if ( DomTool::hasProperty( nl.item(i).toElement() , "font" ) ) { needEventHandler = TRUE; break; } } if ( needEventHandler ) { out << endl; out << indent << "def event(self,ev):" << endl; pushIndent(); out << indent << "ret = " << objClass << ".event(self,ev)" << endl; out << endl; out << indent << "if ev.type() == QEvent.ApplicationFontChange:" << endl; pushIndent(); for ( i = 0; i < (int) nl.length(); i++ ) { n = nl.item(i).toElement(); if ( DomTool::hasProperty( n, "font" ) ) createExclusiveProperty( n, "font" ); } out << endl; popIndent(); out << indent << "return ret" << endl; popIndent(); } // Generate user defined slot hooks. for (it = userSlots.begin(); it != userSlots.end(); ++it) { int astart = (*it).find('('); out << endl; 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. QString 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 << "):" << endl; pushIndent(); out << indent << "print '" << nameOfClass << "." << *it << ": not implemented yet'" << endl; popIndent(); } popIndent(); } /*! Creates an implementation for the object given in \a e. Traverses recursively over all children. Returns the name of the generated child object. \sa createObjectDecl() */ QString Uic::createObjectImpl( const QDomElement &e, const QString& parentClass, const QString& parent, const QString& layout ) { QDomElement n; QString objClass, objName, fullObjName; if ( layouts.contains( e.tagName() ) ) return createLayoutImpl( e, parentClass, parent, layout ); objClass = getClassName( e ); if ( objClass.isEmpty() ) return objName; objName = getObjectName( e ); QString definedName = objName; bool isTmpObject = objName.isEmpty() || objClass == "QLayoutWidget"; if ( isTmpObject ) { if ( objClass[0] == 'Q' ) objName = objClass.mid(1); else objName = objClass.lower(); } bool isLine = objClass == "Line"; if ( isLine ) objClass = "QFrame"; out << endl; if ( objClass == "QLayoutWidget" ) { if ( layout.isEmpty() ) { // register the object and unify its name objName = registerObject( objName ); out << indent << objName << " = QWidget(" << parent << ",'" << definedName << "')" << endl; } else { // the layout widget is not necessary, hide it by creating its child in the parent QString result; for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) { if (tags.contains( n.tagName() ) ) result = createObjectImpl( n, parentClass, parent, layout ); } return result; } // Layouts don't go into the class instance dictionary. fullObjName = objName; } else { // register the object and unify its name objName = registerObject( objName ); // Temporary objects don't go into the class instance dictionary. fullObjName = isTmpObject ? objName : "self." + objName; out << indent << fullObjName << " = " << createObjectInstance( objClass, parent, objName ) << endl; } lastItem = "None"; // set the properties and insert items for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) { if ( n.tagName() == "property" ) { bool stdset = toBool( n.attribute( "stdset" ) ); QDomElement n2 = n.firstChild().toElement(); if ( n2.tagName() == "name" ) { QString prop = n2.firstChild().toText().data(); QString value = setObjectProperty( objClass, objName, prop, n2.nextSibling().toElement(), stdset ); if ( value.isEmpty() ) continue; if ( prop == "name" ) continue; if ( prop == "buddy" && value[0] == '\'' && value[(int)value.length()-1] == '\'' ) { buddies << Buddy( objName, value.mid(1, value.length() - 2 ) ); continue; } if ( isLine && prop == "orientation" ) { prop = "frameStyle"; if ( value.right(10) == "Horizontal" ) value = "QFrame.HLine | QFrame.Sunken"; else value = "QFrame.VLine | QFrame.Sunken"; } if ( prop == "buttonGroupId" ) { if ( parentClass == "QButtonGroup" ) out << indent << parent << ".insert(" << fullObjName << "," << value << ")" << endl; continue; } if ( prop == "geometry") { out << indent << fullObjName << ".setGeometry(" << value << ")" << endl; } else { if ( stdset ) out << indent << fullObjName << "." << mkStdSet(prop) << "(" << value << ")" << endl; else out << indent << fullObjName << ".setProperty('" << prop << "',QVariant(" << value << "))" << endl; } } } else if ( n.tagName() == "item" ) { if ( objClass.mid(1) == "ListBox" ) { QString s = createListBoxItemImpl( n, fullObjName ); if ( !s.isEmpty() ) out << indent << s << endl; } else if ( objClass.mid(1) == "ComboBox" ) { QString s = createListBoxItemImpl( n, fullObjName ); if ( !s.isEmpty() ) out << indent << s << endl; } else if ( objClass.mid(1) == "IconView" ) { QString s = createIconViewItemImpl( n, fullObjName ); if ( !s.isEmpty() ) out << indent << s << endl; } else if ( objClass.mid(1) == "ListView" ) { QString s = createListViewItemImpl( n, fullObjName, QString::null ); if ( !s.isEmpty() ) out << s << endl; } } else if ( n.tagName() == "column" ) { if ( objClass.mid(1) == "ListView" ) { QString s = createListViewColumnImpl( n, fullObjName ); if ( !s.isEmpty() ) out << s; } } } // create all children, some widgets have special requirements if ( objClass == "QTabWidget" ) { for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) { if ( tags.contains( n.tagName() ) ) { QString page = createObjectImpl( n, objClass, fullObjName ); QString label = DomTool::readAttribute( n, "title", "" ).toString(); out << indent << fullObjName << ".insertTab(" << page << "," << trmacro << "(" << fixString( label ) << "))" << endl; } } } else { // standard widgets for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) { if ( tags.contains( n.tagName() ) ) createObjectImpl( n, objClass, fullObjName ); } } return fullObjName; } /*! Creates implementation of an listbox item tag. */ QString Uic::createListBoxItemImpl( const QDomElement &e, const QString &parent ) { QDomElement n = e.firstChild().toElement(); QString txt; QString pix; while ( !n.isNull() ) { if ( n.tagName() == "property" ) { QDomElement n2 = n.firstChild().toElement(); if ( n2.tagName() == "name" ) { QString attrib = n2.firstChild().toText().data(); QVariant v = DomTool::elementToVariant( n2.nextSibling().toElement(), QVariant() ); if ( attrib == "text" ) txt = v.toString(); else if ( attrib == "pixmap" ) { pix = v.toString(); if ( !pix.isEmpty() && !pixmapLoaderFunction.isEmpty() ) { pix.prepend( pixmapLoaderFunction + "(" ); pix.append( ")" ); } } } } n = n.nextSibling().toElement(); } return pix.isEmpty() ? parent + ".insertItem(" + trmacro + "(" + fixString( txt ) + "))": parent + ".insertItem(" + pix + "," + trmacro + "(" + fixString( txt ) + "))"; } /*! Creates implementation of an iconview item tag. */ QString Uic::createIconViewItemImpl( const QDomElement &e, const QString &parent ) { QDomElement n = e.firstChild().toElement(); QString txt; QString pix; while ( !n.isNull() ) { if ( n.tagName() == "property" ) { QDomElement n2 = n.firstChild().toElement(); if ( n2.tagName() == "name" ) { QString attrib = n2.firstChild().toText().data(); QVariant v = DomTool::elementToVariant( n2.nextSibling().toElement(), QVariant() ); if ( attrib == "text" ) txt = v.toString(); else if ( attrib == "pixmap" ) { pix = v.toString(); if ( !pix.isEmpty() && !pixmapLoaderFunction.isEmpty() ) { pix.prepend( pixmapLoaderFunction + "( " ); pix.append( " )" ); } } } } n = n.nextSibling().toElement(); } if ( pix.isEmpty() ) return "QIconViewItem(" + parent + "," + trmacro + "(" + fixString( txt ) + "))"; return "QIconViewItem(" + parent + "," + trmacro + "(" + fixString( txt ) + ")," + pix + ")"; } /*! Creates implementation of an listview item tag. */ QString Uic::createListViewItemImpl( const QDomElement &e, const QString &parent, const QString &parentItem ) { QString s; QDomElement n = e.firstChild().toElement(); bool hasChildren = e.elementsByTagName( "item" ).count() > 0; QString item; if ( hasChildren ) { item = registerObject( "item" ); s = indent + item + " = "; } else { item = "item"; if ( item_used ) s = indent + item + " = "; else s = indent + item + " = "; item_used = TRUE; } if ( !parentItem.isEmpty() ) s += "QListViewItem(" + parentItem + "," + lastItem + ")\n"; else s += "QListViewItem(" + parent + "," + lastItem + ")\n"; QStringList textes; QStringList pixmaps; while ( !n.isNull() ) { if ( n.tagName() == "property" ) { QDomElement n2 = n.firstChild().toElement(); if ( n2.tagName() == "name" ) { QString attrib = n2.firstChild().toText().data(); QVariant v = DomTool::elementToVariant( n2.nextSibling().toElement(), QVariant() ); if ( attrib == "text" ) textes << v.toString(); else if ( attrib == "pixmap" ) { QString pix = v.toString(); if ( !pix.isEmpty() && !pixmapLoaderFunction.isEmpty() ) { pix.prepend( pixmapLoaderFunction + "( " ); pix.append( " )" ); } pixmaps << pix; } } } else if ( n.tagName() == "item" ) { s += indent + item + ".setOpen(1)\n"; s += createListViewItemImpl( n, parent, item ); } n = n.nextSibling().toElement(); } for ( int i = 0; i < (int)textes.count(); ++i ) { if ( !textes[ i ].isEmpty() ) s += indent + item + ".setText(" + QString::number( i ) + "," + trmacro + "(" + fixString( textes[ i ] ) + "))\n"; if ( !pixmaps[ i ].isEmpty() ) s += indent + item + ".setPixmap(" + QString::number( i ) + "," + pixmaps[ i ] + ")\n"; } lastItem = item; return s; } /*! Creates implementation of an listview column tag. */ QString Uic::createListViewColumnImpl( const QDomElement &e, const QString &parent ) { QDomElement n = e.firstChild().toElement(); QString txt; QString pix; bool clickable = FALSE, resizeable = FALSE; while ( !n.isNull() ) { if ( n.tagName() == "property" ) { QDomElement n2 = n.firstChild().toElement(); if ( n2.tagName() == "name" ) { QString attrib = n2.firstChild().toText().data(); QVariant v = DomTool::elementToVariant( n2.nextSibling().toElement(), QVariant() ); if ( attrib == "text" ) txt = v.toString(); else if ( attrib == "pixmap" ) { pix = v.toString(); if ( !pix.isEmpty() && !pixmapLoaderFunction.isEmpty() ) { pix.prepend( pixmapLoaderFunction + "( " ); pix.append( " )" ); } } else if ( attrib == "clickable" ) clickable = v.toBool(); else if ( attrib == "resizeable" ) resizeable = v.toBool(); } } n = n.nextSibling().toElement(); } QString s; s = indent + parent + ".addColumn(" + trmacro + "(" + fixString( txt ) + "))\n"; if ( !pix.isEmpty() ) s += indent + parent + ".header().setLabel(" + parent + ".header().count() - 1," + pix + "," + trmacro + "(" + fixString( txt ) + "))\n"; if ( !clickable ) s += indent + parent + ".header().setClickEnabled(0," + parent + ".header().count() - 1)\n"; if ( !resizeable ) s += indent + parent + ".header().setResizeEnabled(0," + parent + ".header().count() - 1)\n"; return s; } /*! Creates the implementation of a layout tag. Called from createObjectImpl(). */ QString Uic::createLayoutImpl( const QDomElement &e, const QString& parentClass, const QString& parent, const QString& layout ) { QDomElement n; QString objClass, objName; objClass = e.tagName(); QString qlayout = "QVBoxLayout"; if ( objClass == "hbox" ) qlayout = "QHBoxLayout"; else if ( objClass == "grid" ) qlayout = "QGridLayout"; bool isGrid = e.tagName() == "grid" ; objName = registerObject( getLayoutName( e ) ); layoutObjects += objName; int margin = DomTool::readProperty( e, "margin", BOXLAYOUT_DEFAULT_MARGIN ).toInt(); int spacing = DomTool::readProperty( e, "spacing", BOXLAYOUT_DEFAULT_SPACING ).toInt(); if ( (parentClass == "QGroupBox" || parentClass == "QButtonGroup") && layout.isEmpty() ) { // special case for group box out << indent << parent << ".setColumnLayout(0,Qt.Vertical)" << endl; out << indent << parent << ".layout().setSpacing(0)" << endl; out << indent << parent << ".layout().setMargin(0)" << endl; out << indent << objName << " = " << qlayout << "(" << parent << ".layout())" << endl; out << indent << objName << ".setAlignment(Qt.AlignTop)" << endl; } else { if ( layout.isEmpty() ) out << indent << objName << " = " << qlayout << "(" << parent << ")" << endl; else out << indent << objName << " = " << qlayout << "()" << endl; } out << indent << objName << ".setSpacing(" << spacing << ")" << endl; out << indent << objName << ".setMargin(" << margin << ")" << endl; if ( !isGrid ) { for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) { if ( n.tagName() == "spacer" ) { QString child = createSpacerImpl( n, parentClass, parent, objName ); out << indent << objName << ".addItem(" << child << ")" << endl; } else if ( tags.contains( n.tagName() ) ) { QString child = createObjectImpl( n, parentClass, parent, objName ); if ( isLayout( child ) ) out << indent << objName << ".addLayout(" << child << ")" << endl; else out << indent << objName << ".addWidget(" << child << ")" << endl; } } } else { for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) { QDomElement ae = n; int row = ae.attribute( "row" ).toInt(); int col = ae.attribute( "column" ).toInt(); int rowspan = ae.attribute( "rowspan" ).toInt(); int colspan = ae.attribute( "colspan" ).toInt(); if ( rowspan < 1 ) rowspan = 1; if ( colspan < 1 ) colspan = 1; if ( n.tagName() == "spacer" ) { QString child = createSpacerImpl( n, parentClass, parent, objName ); if ( rowspan * colspan != 1 ) out << indent << objName << ".addMultiCell(" << child << "," << row << "," << row + rowspan - 1 << "," << col << "," << col + colspan - 1 << ")" << endl; else out << indent << objName << ".addItem(" << child << "," << row << "," << col << ")" << endl; } else if ( tags.contains( n.tagName() ) ) { QString child = createObjectImpl( n, parentClass, parent, objName ); out << endl; QString o = "Widget"; if ( isLayout( child ) ) o = "Layout"; if ( rowspan * colspan != 1 ) out << indent << objName << ".addMultiCell" << o << "(" << child << "," << row << "," << row + rowspan - 1 << "," << col << "," << col + colspan - 1 << ")" << endl; else out << indent << objName << ".add" << o << "(" << child << "," << row << "," << col << ")" << endl; } } } return objName; } QString Uic::createSpacerImpl( const QDomElement &e, const QString& /*parentClass*/, const QString& /*parent*/, const QString& /*layout*/) { QDomElement n; QString objClass, objName; objClass = e.tagName(); objName = registerObject( "spacer" ); QSize size = DomTool::readProperty( e, "sizeHint", QSize(0,0) ).toSize(); QString sizeType = DomTool::readProperty( e, "sizeType", "Expanding" ).toString(); bool isVspacer = DomTool::readProperty( e, "orientation", "Horizontal" ) == "Vertical"; if ( sizeType != "Expanding" && sizeType != "MinimumExpanding" && DomTool::hasProperty( e, "geometry" ) ) { // compatibility Qt 2.2 QRect geom = DomTool::readProperty( e, "geometry", QRect(0,0,0,0) ).toRect(); size = geom.size(); } if ( isVspacer ) out << indent << objName << " = QSpacerItem(" << size.width() << "," << size.height() << ",QSizePolicy.Minimum,QSizePolicy." << sizeType << ")" << endl; else out << indent << objName << " = QSpacerItem(" << size.width() << "," << size.height() << ",QSizePolicy." << sizeType << ",QSizePolicy.Minimum)" << endl; return objName; } /*! Creates a set-call for property \a exclusiveProp of the object given in \a e. If the object does not have this property, the function does nothing. Exclusive properties are used to generate the implementation of application font or palette change handlers in createFormImpl(). */ void Uic::createExclusiveProperty( const QDomElement & e, const QString& exclusiveProp ) { QDomElement n; QString objClass = getClassName( e ); if ( objClass.isEmpty() ) return; QString objName = getObjectName( e ); if ( objClass.isEmpty() ) return; for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) { if ( n.tagName() == "property" ) { bool stdset = toBool( n.attribute( "stdset" ) ); QDomElement n2 = n.firstChild().toElement(); if ( n2.tagName() == "name" ) { QString prop = n2.firstChild().toText().data(); if ( prop != exclusiveProp ) continue; QString value = setObjectProperty( objClass, objName, prop, n2.nextSibling().toElement(), stdset ); if ( value.isEmpty() ) continue; out << indent << objName << ".setProperty('" << prop << "',QVariant(" << value << "))" << endl; } } } } const char* const ColorRole[] = { "Foreground", "Button", "Light", "Midlight", "Dark", "Mid", "Text", "BrightText", "ButtonText", "Base", "Background", "Shadow", "Highlight", "HighlightedText", 0 }; /*! Attention: this function has to be in sync with Resource::setWidgetProperty(). If you change one, change both. */ QString Uic::setObjectProperty( const QString& objClass, const QString& obj, const QString &prop, const QDomElement &e, bool stdset ) { QString v; if ( e.tagName() == "rect" ) { QDomElement n3 = e.firstChild().toElement(); int x = 0, y = 0, w = 0, h = 0; while ( !n3.isNull() ) { if ( n3.tagName() == "x" ) x = n3.firstChild().toText().data().toInt(); else if ( n3.tagName() == "y" ) y = n3.firstChild().toText().data().toInt(); else if ( n3.tagName() == "width" ) w = n3.firstChild().toText().data().toInt(); else if ( n3.tagName() == "height" ) h = n3.firstChild().toText().data().toInt(); n3 = n3.nextSibling().toElement(); } v = "QRect(%1,%2,%3,%4)"; v = v.arg(x).arg(y).arg(w).arg(h); } else if ( e.tagName() == "point" ) { QDomElement n3 = e.firstChild().toElement(); int x = 0, y = 0; while ( !n3.isNull() ) { if ( n3.tagName() == "x" ) x = n3.firstChild().toText().data().toInt(); else if ( n3.tagName() == "y" ) y = n3.firstChild().toText().data().toInt(); n3 = n3.nextSibling().toElement(); } v = "QPoint(%1,%2)"; v = v.arg(x).arg(y); } else if ( e.tagName() == "size" ) { QDomElement n3 = e.firstChild().toElement(); int w = 0, h = 0; while ( !n3.isNull() ) { if ( n3.tagName() == "width" ) w = n3.firstChild().toText().data().toInt(); else if ( n3.tagName() == "height" ) h = n3.firstChild().toText().data().toInt(); n3 = n3.nextSibling().toElement(); } v = "QSize(%1,%2)"; v = v.arg(w).arg(h); } else if ( e.tagName() == "color" ) { QDomElement n3 = e.firstChild().toElement(); int r= 0, g = 0, b = 0; while ( !n3.isNull() ) { if ( n3.tagName() == "red" ) r = n3.firstChild().toText().data().toInt(); else if ( n3.tagName() == "green" ) g = n3.firstChild().toText().data().toInt(); else if ( n3.tagName() == "blue" ) b = n3.firstChild().toText().data().toInt(); n3 = n3.nextSibling().toElement(); } v = "QColor(%1,%2,%3)"; v = v.arg(r).arg(g).arg(b); } else if ( e.tagName() == "font" ) { QDomElement n3 = e.firstChild().toElement(); QString fontname = "f"; if ( !obj.isEmpty() ) { fontname = obj + "_font"; out << indent << fontname << " = QFont(self." << obj << ".font())" << endl; } else { out << indent << fontname << " = QFont(self.font())" << endl; } while ( !n3.isNull() ) { if ( n3.tagName() == "family" ) out << indent << fontname << ".setFamily('" << n3.firstChild().toText().data() << "')" << endl; else if ( n3.tagName() == "pointsize" ) out << indent << fontname << ".setPointSize(" << n3.firstChild().toText().data() << ")" << endl; else if ( n3.tagName() == "bold" ) out << indent << fontname << ".setBold(" << mkBool( n3.firstChild().toText().data() ) << ")" << endl; else if ( n3.tagName() == "italic" ) out << indent << fontname << ".setItalic(" << mkBool( n3.firstChild().toText().data() ) << ")" << endl; else if ( n3.tagName() == "underline" ) out << indent << fontname << ".setUnderline(" << mkBool( n3.firstChild().toText().data() ) << ")" << endl; else if ( n3.tagName() == "strikeout" ) out << indent << fontname << ".setStrikeOut(" << mkBool( n3.firstChild().toText().data() ) << ")" << endl; n3 = n3.nextSibling().toElement(); } if ( prop == "font" ) { if ( !obj.isEmpty() ) out << indent << "self." << obj << ".setFont(" << fontname << ")" << endl; else out << indent << "self.setFont(" << fontname << ")" << endl; } else { v = fontname; } } else if ( e.tagName() == "string" ) { if ( prop == "toolTip" ) { if ( !obj.isEmpty() ) out << indent << "QToolTip.add(self." << obj << "," + trmacro + "(" << fixString( e.firstChild().toText().data() ) << "))" << endl; else out << indent << "QToolTip.add(self," + trmacro + "(" << fixString( e.firstChild().toText().data() ) << "))" << endl; } else if ( prop == "whatsThis" ) { if ( !obj.isEmpty() ) out << indent << "QWhatsThis.add(self." << obj << "," << trmacro << "(" << fixString( e.firstChild().toText().data() ) << "))" << endl; else out << indent << "QWhatsThis.add(self," << trmacro << "(" << fixString( e.firstChild().toText().data() ) << "))" << endl; } else { v = trmacro + "(%1)"; v = v.arg( fixString( e.firstChild().toText().data() ) ); } } else if ( e.tagName() == "cstring" ) { v = "'%1'"; v = v.arg( e.firstChild().toText().data() ); } else if ( e.tagName() == "number" ) { v = "%1"; v = v.arg( e.firstChild().toText().data() ); } else if ( e.tagName() == "bool" ) { if ( stdset ) v = "%1"; else v = "%1,0"; v = v.arg( mkBool( e.firstChild().toText().data() ) ); } else if ( e.tagName() == "pixmap" ) { v = e.firstChild().toText().data(); if ( !pixmapLoaderFunction.isEmpty() ) { v.prepend( pixmapLoaderFunction + "( " ); v.append( " )" ); } } else if ( e.tagName() == "iconset" ) { v = "QIconSet(%1)"; v = v.arg( e.firstChild().toText().data() ); } else if ( e.tagName() == "image" ) { v = e.firstChild().toText().data() + ".convertToImage()"; } else if ( e.tagName() == "enum" ) { v = "%1.%2"; QString oc = objClass; QString ev = e.firstChild().toText().data(); if ( oc == "QListView" && ev == "Manual" ) // #### workaround, rename QListView::Manual of WithMode enum in 3.0 oc = "QScrollView"; v = v.arg( oc ).arg( ev ); } else if ( e.tagName() == "set" ) { QString keys( e.firstChild().toText().data() ); QStringList lst = QStringList::split( '|', keys ); v = ""; for ( QStringList::Iterator it = lst.begin(); it != lst.end(); ++it ) { v += objClass + "." + *it; if ( it != lst.fromLast() ) v += " | "; } } else if ( e.tagName() == "sizepolicy" ) { QDomElement n3 = e.firstChild().toElement(); QSizePolicy sp; while ( !n3.isNull() ) { if ( n3.tagName() == "hsizetype" ) sp.setHorData( (QSizePolicy::SizeType)n3.firstChild().toText().data().toInt() ); else if ( n3.tagName() == "vsizetype" ) sp.setVerData( (QSizePolicy::SizeType)n3.firstChild().toText().data().toInt() ); n3 = n3.nextSibling().toElement(); } QString tmp; if ( !obj.isEmpty() ) tmp = "self." + obj; else tmp = "self"; v = "QSizePolicy(%1,%2," + tmp + ".sizePolicy().hasHeightForWidth())"; v = v.arg( (int)sp.horData() ).arg( (int)sp.verData() ); } else if ( e.tagName() == "palette" ) { QPalette pal; bool no_pixmaps = e.elementsByTagName( "pixmap" ).count() == 0; QDomElement n; if ( no_pixmaps ) { n = e.firstChild().toElement(); while ( !n.isNull() ) { QColorGroup cg; if ( n.tagName() == "active" ) { cg = loadColorGroup( n ); pal.setActive( cg ); } else if ( n.tagName() == "inactive" ) { cg = loadColorGroup( n ); pal.setInactive( cg ); } else if ( n.tagName() == "disabled" ) { cg = loadColorGroup( n ); pal.setDisabled( cg ); } n = n.nextSibling().toElement(); } } if ( no_pixmaps && pal == QPalette( pal.active().button(), pal.active().background() ) ) { v = "QPalette(QColor(%1,%2,%3),QColor(%1,%2,%3))"; v = v.arg( pal.active().button().red() ).arg( pal.active().button().green() ).arg( pal.active().button().blue() ); v = v.arg( pal.active().background().red() ).arg( pal.active().background().green() ).arg( pal.active().background().blue() ); } else { QString palette = "pal"; if ( !pal_used ) { out << indent << palette << " = QPalette()" << endl; pal_used = TRUE; } QString cg = "cg"; if ( !cg_used ) { out << indent << cg << " = QColorGroup()" << endl; cg_used = TRUE; } n = e.firstChild().toElement(); while ( !n.isNull() && n.tagName() != "active") n = n.nextSibling().toElement(); createColorGroupImpl( cg, n ); out << indent << palette << ".setActive(" << cg << ")" << endl; n = e.firstChild().toElement(); while ( !n.isNull() && n.tagName() != "inactive") n = n.nextSibling().toElement(); createColorGroupImpl( cg, n ); out << indent << palette << ".setInactive(" << cg << ")" << endl; n = e.firstChild().toElement(); while ( !n.isNull() && n.tagName() != "disabled") n = n.nextSibling().toElement(); createColorGroupImpl( cg, n ); out << indent << palette << ".setDisabled(" << cg << ")" << endl; v = palette; } } else if ( e.tagName() == "cursor" ) { v = "QCursor(%1)"; v = v.arg( e.firstChild().toText().data() ); } return v; } /*! Creates a colorgroup with name \a name from the color group \a cg */ void Uic::createColorGroupImpl( const QString& name, const QDomElement& e ) { QColorGroup cg; int r = -1; QDomElement n = e.firstChild().toElement(); QString color; while ( !n.isNull() ) { if ( n.tagName() == "color" ) { r++; QColor col = DomTool::readColor( n ); color = "QColor(%1,%2,%3)"; color = color.arg( col.red() ).arg( col.green() ).arg( col.blue() ); if ( col == white ) color = "Qt.white"; else if ( col == black ) color = "Qt.black"; if ( n.nextSibling().toElement().tagName() != "pixmap" ) { out << indent << name << ".setColor(QColorGroup." << ColorRole[r] << "," << color << ")" << endl; } } else if ( n.tagName() == "pixmap" ) { QString pixmap = n.firstChild().toText().data(); if ( !pixmapLoaderFunction.isEmpty() ) { pixmap.prepend( pixmapLoaderFunction + "(" ); pixmap.append( ")" ); } out << indent << name << ".setBrush(QColorGroup." << ColorRole[r] << ",QBrush(" << color << "," << pixmap << "))" << endl; } n = n.nextSibling().toElement(); } } /*! Auxiliary function to load a color group. The colorgroup must not contain pixmaps. */ QColorGroup Uic::loadColorGroup( const QDomElement &e ) { QColorGroup cg; int r = -1; QDomElement n = e.firstChild().toElement(); QColor col; while ( !n.isNull() ) { if ( n.tagName() == "color" ) { r++; cg.setColor( (QColorGroup::ColorRole)r, (col = DomTool::readColor( n ) ) ); } n = n.nextSibling().toElement(); } return cg; } /*! Registers an object with name \a name. The returned name is a valid variable identifier, as similar to \a name as possible and guaranteed to be unique within the form. \sa registeredName(), isObjectRegistered() */ QString Uic::registerObject( const QString& name ) { if ( objectNames.isEmpty() ) { // some temporary variables we need objectNames += "img"; objectNames += "item"; objectNames += "cg"; objectNames += "pal"; } QString result = name; int i; while ( ( i = result.find(' ' )) != -1 ) { result[i] = '_'; } if ( objectNames.contains( result ) ) { int i = 2; while ( objectNames.contains( result + "_" + QString::number(i) ) ) i++; result += "_"; result += QString::number(i); } objectNames += result; objectMapper.insert( name, result ); return result; } /*! Returns the registered name for the original name \a name or \a name if \a name wasn't registered. \sa registerObject(), isObjectRegistered() */ QString Uic::registeredName( const QString& name ) { if ( !objectMapper.contains( name ) ) return name; return objectMapper[name]; } /*! Returns whether the object \a name was registered yet or not. */ bool Uic::isObjectRegistered( const QString& name ) { return objectMapper.contains( name ); } /*! Unifies the entries in stringlist \a list. Should really be a QStringList feature. */ QStringList Uic::unique( const QStringList& list ) { QStringList result; if (list.isEmpty() ) return result; QStringList l = list; l.sort(); result += l.first(); for ( QStringList::Iterator it = l.begin(); it != l.end(); ++it ) { if ( *it != result.last() ) result += *it; } return result; } /*! Creates an instance of class \a objClass, with parent \a parent and name \a objName */ QString Uic::createObjectInstance( const QString& objClass, const QString& parent, const QString& objName ) { if ( objClass.mid(1) == "ComboBox" ) { return objClass + "(0," + parent + ",'" + objName + "')"; } return objClass + "(" + parent + ",'" + objName + "')"; } bool Uic::isLayout( const QString& name ) const { return layoutObjects.contains( name ); } #if defined(BLACKADDER) #include "ba.h" int BA::compilePython(const QString &fileName,const QString &outputFile, const QString &trmacro,bool execCode) { #else int main( int argc, char * argv[] ) { const char *error = 0; QString fileName; QString outputFile; QString trmacro; bool execCode = FALSE; for ( int n = 1; n < argc && error == 0; n++ ) { QCString arg = argv[n]; if ( arg[0] == '-' ) { // option QCString opt = &arg[1]; if ( opt[0] == 'o' ) { // output redirection if ( opt[1] == '\0' ) { if ( !(n < argc-1) ) { error = "Missing output-file name"; break; } outputFile = argv[++n]; } else outputFile = &opt[1]; } else if ( opt == "tr" ) { if ( opt == "tr" || opt[1] == '\0' ) { if ( !(n < argc-1) ) { error = "Missing tr macro."; break; } trmacro = argv[++n]; } else { trmacro = &opt[1]; } } else if ( opt == "x" ) { execCode = TRUE; } } else { if (!fileName.isEmpty()) // can handle only one file error = "Too many input files specified"; else fileName = argv[n]; } } if ( argc < 2 || error || fileName.isEmpty() ) { fprintf( stderr, "PyQt user interface compiler\n" ); if ( error ) fprintf( stderr, "pyuic: %s\n", error ); fprintf( stderr, "Usage: %s [options] \n" "\nGenerate PyQt implementation:\n" " %s [options] \n" "Options:\n" "\t-o file Write output to file rather than stdout\n" "\t-tr func Use func(...) rather than tr(...) for i18n\n" "\t-x Generate extra code to test the class\n" , argv[0], argv[0]); exit( 1 ); } #endif QFile file( fileName ); if ( !file.open( IO_ReadOnly ) ) qFatal( "pyuic: Could not open file '%s' ", (const char *)fileName ); QFile fileOut; if (!outputFile.isEmpty()) { fileOut.setName( outputFile ); if (!fileOut.open( IO_WriteOnly ) ) qFatal( "pyuic: Could not open output file '%s'", (const char *)outputFile ); } else { fileOut.open( IO_WriteOnly, stdout ); } QTextStream out( &fileOut ); out.setEncoding( QTextStream::UnicodeUTF8 ); QDomDocument doc; if ( !doc.setContent( &file ) ) qFatal( "pyuic: Failed to parse %s\n", (const char *)fileName ); out << "# Form implementation generated from reading ui file '" << fileName << "'" << endl; out << "#" << endl; out << "# Created: " << QDateTime::currentDateTime().toString() << endl; out << "# by: The Python User Interface Compiler (pyuic) " << PYQT_VERSION << endl; out << "#" << endl; out << "# WARNING! All changes made in this file will be lost!" << endl; out << endl; out << endl; if (execCode) out << "import sys" << endl; out << "from qt import *" << endl; Uic( out, doc, trmacro.isEmpty() ? QString("self.tr") : trmacro ); if (execCode) { out << endl; out << endl; out << "if __name__ == '__main__':" << endl; out << " a = QApplication(sys.argv)" << endl; out << " QObject.connect(a,SIGNAL('lastWindowClosed()'),a,SLOT('quit()'))" << endl; out << " w = " << className << "()" << endl; out << " a.setMainWidget(w)" << endl; out << " w.show()" << endl; out << " a.exec_loop()" << endl; } return 0; }