kdecore Library API Documentation

kconfig_compiler.cpp

00001 // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002 /*
00003     This file is part of KDE.
00004 
00005     Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
00006     Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
00007     Copyright (c) 2003 Zack Rusin <zack@kde.org>
00008 
00009     This library is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU Library General Public
00011     License as published by the Free Software Foundation; either
00012     version 2 of the License, or (at your option) any later version.
00013 
00014     This library is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017     Library General Public License for more details.
00018 
00019     You should have received a copy of the GNU Library General Public License
00020     along with this library; see the file COPYING.LIB.  If not, write to
00021     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00022     Boston, MA 02111-1307, USA.
00023 */
00024 
00025 #include <qfile.h>
00026 #include <qtextstream.h>
00027 #include <qdom.h>
00028 #include <qregexp.h>
00029 
00030 #include <kaboutdata.h>
00031 #include <kapplication.h>
00032 #include <kdebug.h>
00033 #include <klocale.h>
00034 #include <kcmdlineargs.h>
00035 #include <kglobal.h>
00036 #include <kconfig.h>
00037 #include <ksimpleconfig.h>
00038 #include <kstandarddirs.h>
00039 
00040 #include <iostream>
00041 
00042 static const KCmdLineOptions options[] =
00043 {
00044   { "d", 0, 0 },
00045   { "directory <dir>", I18N_NOOP("Directory to generate files in"), "." },
00046   { "+file.kcfg", I18N_NOOP("Input kcfg XML file"), 0 },
00047   { "+file.kcfgc", I18N_NOOP("Code generation options file"), 0 },
00048   KCmdLineLastOption
00049 };
00050 
00051 
00052 bool globalEnums;
00053 bool itemAccessors;
00054 QStringList allNames;
00055 QRegExp *validNameRegexp;
00056 
00057 class CfgEntry
00058 {
00059   public:
00060     struct Choice
00061     {
00062       QString name;
00063       QString label;
00064       QString whatsThis;
00065     };
00066 
00067     CfgEntry( const QString &group, const QString &type, const QString &key,
00068               const QString &name, const QString &label,
00069               const QString &whatsThis, const QString &code,
00070               const QString &defaultValue, const QValueList<Choice> &choices,
00071               bool hidden )
00072       : mGroup( group ), mType( type ), mKey( key ), mName( name ),
00073         mLabel( label ), mWhatsThis( whatsThis ), mCode( code ),
00074         mDefaultValue( defaultValue ),
00075         mChoices( choices ), mHidden( hidden )
00076     {
00077     }
00078 
00079     void setGroup( const QString &group ) { mGroup = group; }
00080     QString group() const { return mGroup; }
00081 
00082     void setType( const QString &type ) { mType = type; }
00083     QString type() const { return mType; }
00084 
00085     void setKey( const QString &key ) { mKey = key; }
00086     QString key() const { return mKey; }
00087 
00088     void setName( const QString &name ) { mName = name; }
00089     QString name() const { return mName; }
00090 
00091     void setLabel( const QString &label ) { mLabel = label; }
00092     QString label() const { return mLabel; }
00093 
00094     void setWhatsThis( const QString &whatsThis ) { mWhatsThis = whatsThis; }
00095     QString whatsThis() const { return mWhatsThis; }
00096 
00097     void setDefaultValue( const QString &d ) { mDefaultValue = d; }
00098     QString defaultValue() const { return mDefaultValue; }
00099 
00100     void setCode( const QString &d ) { mCode = d; }
00101     QString code() const { return mCode; }
00102 
00103     void setMinValue( const QString &d ) { mMin = d; }
00104     QString minValue() const { return mMin; }
00105 
00106     void setMaxValue( const QString &d ) { mMax = d; }
00107     QString maxValue() const { return mMax; }
00108 
00109     void setParam( const QString &d ) { mParam = d; }
00110     QString param() const { return mParam; }
00111 
00112     void setParamName( const QString &d ) { mParamName = d; }
00113     QString paramName() const { return mParamName; }
00114 
00115     void setParamType( const QString &d ) { mParamType = d; }
00116     QString paramType() const { return mParamType; }
00117 
00118     void setChoices( const QValueList<Choice> &d ) { mChoices = d; }
00119     QValueList<Choice> choices() const { return mChoices; }
00120 
00121     void setParamValues( const QStringList &d ) { mParamValues = d; }
00122     QStringList paramValues() const { return mParamValues; }
00123 
00124     void setParamDefaultValues( const QStringList &d ) { mParamDefaultValues = d; }
00125     QString paramDefaultValue(int i) const { return mParamDefaultValues[i]; }
00126 
00127     void setParamMax( int d ) { mParamMax = d; }
00128     int paramMax() const { return mParamMax; }
00129 
00130     bool hidden() const { return mHidden; }
00131 
00132     void dump() const
00133     {
00134       kdDebug() << "<entry>" << endl;
00135       kdDebug() << "  group: " << mGroup << endl;
00136       kdDebug() << "  type: " << mType << endl;
00137       kdDebug() << "  key: " << mKey << endl;
00138       kdDebug() << "  name: " << mName << endl;
00139       kdDebug() << "  label: " << mLabel << endl;
00140 // whatsthis
00141       kdDebug() << "  code: " << mCode << endl;
00142 //      kdDebug() << "  values: " << mValues.join(":") << endl;
00143 
00144       if (!param().isEmpty())
00145       {
00146         kdDebug() << "  param name: "<< mParamName << endl;
00147         kdDebug() << "  param type: "<< mParamType << endl;
00148         kdDebug() << "  paramvalues: " << mParamValues.join(":") << endl;
00149       }
00150       kdDebug() << "  default: " << mDefaultValue << endl;
00151       kdDebug() << "  hidden: " << mHidden << endl;
00152       kdDebug() << "  min: " << mMin << endl;
00153       kdDebug() << "  max: " << mMax << endl;
00154       kdDebug() << "</entry>" << endl;
00155     }
00156 
00157   private:
00158     QString mGroup;
00159     QString mType;
00160     QString mKey;
00161     QString mName;
00162     QString mLabel;
00163     QString mWhatsThis;
00164     QString mCode;
00165     QString mDefaultValue;
00166     QString mParam;
00167     QString mParamName;
00168     QString mParamType;
00169     QValueList<Choice> mChoices;
00170     QStringList mParamValues;
00171     QStringList mParamDefaultValues;
00172     int mParamMax;
00173     bool mHidden;
00174     QString mMin;
00175     QString mMax;
00176 };
00177 
00178 class Param {
00179 public:
00180   QString name;
00181   QString type;
00182 };
00183 
00184 static QString varName(const QString &n)
00185 {
00186   QString result = "m"+n;
00187   result[1] = result[1].upper();
00188   return result;
00189 }
00190 
00191 static QString enumName(const QString &n)
00192 {
00193   QString result = "Enum"+n;
00194   result[4] = result[4].upper();
00195   return result;
00196 }
00197 
00198 static QString setFunction(const QString &n)
00199 {
00200   QString result = "set"+n;
00201   result[3] = result[3].upper();
00202   return result;
00203 }
00204 
00205 
00206 static QString getFunction(const QString &n)
00207 {
00208   QString result = n;
00209   result[0] = result[0].lower();
00210   return result;
00211 }
00212 
00213 
00214 static void addQuotes( QString &s )
00215 {
00216   if ( s.left( 1 ) != "\"" ) s.prepend( "\"" );
00217   if ( s.right( 1 ) != "\"" ) s.append( "\"" );
00218 }
00219 
00220 static QString quoteString( const QString &s )
00221 {
00222   QString r = s;
00223   r.replace( "\\", "\\\\" );
00224   r.replace( "\"", "\\\"" );
00225   r.replace( "\r", "" );
00226   r.replace( "\n", "\\n\"\n\"" );
00227   return "\"" + r + "\"";
00228 }
00229 
00230 static QString literalString( const QString &s )
00231 {
00232   bool isAscii = true;
00233   for(int i = s.length(); i--;)
00234      if (s[i].unicode() > 127) isAscii = false;
00235 
00236   if (isAscii)
00237      return "QString::fromLatin1( " + quoteString(s) + " )";
00238   else
00239      return "QString::fromUtf8( " + quoteString(s) + " )";
00240 }
00241 
00242 static QString dumpNode(const QDomNode &node)
00243 {
00244   QString msg;
00245   QTextStream s(&msg, IO_WriteOnly );
00246   node.save(s, 0);
00247 
00248   msg = msg.simplifyWhiteSpace();
00249   if (msg.length() > 40)
00250     return msg.left(37)+"...";
00251   return msg;
00252 }
00253 
00254 static QString filenameOnly(QString path)
00255 {
00256    int i = path.findRev('/');
00257    if (i >= 0)
00258       return path.mid(i+1);
00259    return path;
00260 }
00261 
00262 static void preProcessDefault( QString &defaultValue, const QString &name,
00263                                const QString &type,
00264                                const QValueList<CfgEntry::Choice> &choices,
00265                                QString &code )
00266 {
00267     if ( type == "String" && !defaultValue.isEmpty() ) {
00268       defaultValue = literalString(defaultValue);
00269 
00270     } else if ( type == "Path" && !defaultValue.isEmpty() ) {
00271       defaultValue = literalString( defaultValue );
00272 
00273     } else if ( (type == "StringList" || type == "PathList") && !defaultValue.isEmpty() ) {
00274       QTextStream cpp( &code, IO_WriteOnly | IO_Append );
00275       if (!code.isEmpty())
00276          cpp << endl;
00277 
00278       cpp << "  QStringList default" << name << ";" << endl;
00279       QStringList defaults = QStringList::split( ",", defaultValue );
00280       QStringList::ConstIterator it;
00281       for( it = defaults.begin(); it != defaults.end(); ++it ) {
00282         cpp << "  default" << name << ".append( QString::fromUtf8( \"" << *it << "\" ) );"
00283             << endl;
00284       }
00285       defaultValue = "default" + name;
00286 
00287     } else if ( type == "Color" && !defaultValue.isEmpty() ) {
00288       QRegExp colorRe("\\d+,\\s*\\d+,\\s*\\d+");
00289       if (colorRe.exactMatch(defaultValue))
00290       {
00291         defaultValue = "QColor( " + defaultValue + " )";
00292       }
00293       else
00294       {
00295         defaultValue = "QColor( \"" + defaultValue + "\" )";
00296       }
00297 
00298     } else if ( type == "Enum" ) {
00299       if ( !globalEnums ) {
00300         QValueList<CfgEntry::Choice>::ConstIterator it;
00301         for( it = choices.begin(); it != choices.end(); ++it ) {
00302           if ( (*it).name == defaultValue ) {
00303             defaultValue.prepend( enumName(name) + "::");
00304             break;
00305           }
00306         }
00307       }
00308 
00309     } else if ( type == "IntList" ) {
00310       QTextStream cpp( &code, IO_WriteOnly | IO_Append );
00311       if (!code.isEmpty())
00312          cpp << endl;
00313 
00314       cpp << "  QValueList<int> default" << name << ";" << endl;
00315       QStringList defaults = QStringList::split( ",", defaultValue );
00316       QStringList::ConstIterator it;
00317       for( it = defaults.begin(); it != defaults.end(); ++it ) {
00318         cpp << "  default" << name << ".append( " << *it << " );"
00319             << endl;
00320       }
00321       defaultValue = "default" + name;
00322     }
00323 }
00324 
00325 
00326 CfgEntry *parseEntry( const QString &group, const QDomElement &element )
00327 {
00328   bool defaultCode = false;
00329   QString type = element.attribute( "type" );
00330   QString name = element.attribute( "name" );
00331   QString key = element.attribute( "key" );
00332   QString hidden = element.attribute( "hidden" );
00333   QString label;
00334   QString whatsThis;
00335   QString defaultValue;
00336   QString code;
00337   QString param;
00338   QString paramName;
00339   QString paramType;
00340   QValueList<CfgEntry::Choice> choices;
00341   QStringList paramValues;
00342   QStringList paramDefaultValues;
00343   QString minValue;
00344   QString maxValue;
00345   int paramMax = 0;
00346 
00347   QDomNode n;
00348   for ( n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
00349     QDomElement e = n.toElement();
00350     QString tag = e.tagName();
00351     if ( tag == "label" ) label = e.text();
00352     else if ( tag == "whatsthis" ) whatsThis = e.text();
00353     else if ( tag == "min" ) minValue = e.text();
00354     else if ( tag == "max" ) maxValue = e.text();
00355     else if ( tag == "code" ) code = e.text();
00356     else if ( tag == "parameter" )
00357     {
00358       param = e.attribute( "name" );
00359       paramType = e.attribute( "type" );
00360       if ( param.isEmpty() ) {
00361         kdError() << "Parameter must have a name: " << dumpNode(e) << endl;
00362         return 0;
00363       }
00364       if ( paramType.isEmpty() ) {
00365         kdError() << "Parameter must have a type: " << dumpNode(e) << endl;
00366         return 0;
00367       }
00368       if ((paramType == "Int") || (paramType == "UInt"))
00369       {
00370          bool ok;
00371          paramMax = e.attribute("max").toInt(&ok);
00372          if (!ok)
00373          {
00374            kdError() << "Integer parameter must have a maximum (e.g. max=\"0\"): " << dumpNode(e) << endl;
00375            return 0;
00376          }
00377       }
00378       else if (paramType == "Enum")
00379       {
00380          QDomNode n2;
00381          for ( n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) {
00382            QDomElement e2 = n2.toElement();
00383            if (e2.tagName() == "values")
00384            {
00385              QDomNode n3;
00386              for ( n3 = e2.firstChild(); !n3.isNull(); n3 = n3.nextSibling() ) {
00387                QDomElement e3 = n3.toElement();
00388                if (e3.tagName() == "value")
00389                {
00390                   paramValues.append( e3.text() );
00391                }
00392              }
00393              break;
00394            }
00395          }
00396          if (paramValues.isEmpty())
00397          {
00398            kdError() << "No values specified for parameter '" << param << "'." << endl;
00399            return 0;
00400          }
00401          paramMax = paramValues.count()-1;
00402       }
00403       else
00404       {
00405         kdError() << "Parameter '" << param << "' has type " << paramType << " but must be of type int, uint or Enum." << endl;
00406         return 0;
00407       }
00408     }
00409     else if ( tag == "default" )
00410     {
00411       if (e.attribute("param").isEmpty())
00412       {
00413         defaultValue = e.text();
00414         if (e.attribute( "code" ) == "true")
00415           defaultCode = true;
00416       }
00417     }
00418     else if ( tag == "choices" ) {
00419       QDomNode n2;
00420       for( n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) {
00421         QDomElement e2 = n2.toElement();
00422         if ( e2.tagName() == "choice" ) {
00423           QDomNode n3;
00424           CfgEntry::Choice choice;
00425           choice.name = e2.attribute( "name" );
00426           if ( choice.name.isEmpty() ) {
00427             kdError() << "Tag <choice> requires attribute 'name'." << endl;
00428           }
00429           for( n3 = e2.firstChild(); !n3.isNull(); n3 = n3.nextSibling() ) {
00430             QDomElement e3 = n3.toElement();
00431             if ( e3.tagName() == "label" ) choice.label = e3.text();
00432             if ( e3.tagName() == "whatsthis" ) choice.whatsThis = e3.text();
00433           }
00434           choices.append( choice );
00435         }
00436       }
00437     }
00438   }
00439 
00440   bool nameIsEmpty = name.isEmpty();
00441   if ( nameIsEmpty && key.isEmpty() ) {
00442     kdError() << "Entry must have a name or a key: " << dumpNode(element) << endl;
00443     return 0;
00444   }
00445 
00446   if ( key.isEmpty() ) {
00447     key = name;
00448   }
00449 
00450   if ( nameIsEmpty ) {
00451     name = key;
00452     name.replace( " ", QString::null );
00453   } else if ( name.contains( ' ' ) ) {
00454     kdWarning()<<"Entry '"<<name<<"' contains spaces! <name> elements can't contain speces!"<<endl;
00455     name.remove( ' ' );
00456   }
00457 
00458   if (name.contains("$("))
00459   {
00460     if (param.isEmpty())
00461     {
00462       kdError() << "Name may not be parameterized: " << name << endl;
00463       return 0;
00464     }
00465   }
00466   else
00467   {
00468     if (!param.isEmpty())
00469     {
00470       kdError() << "Name must contain '$(" << param << ")': " << name << endl;
00471       return 0;
00472     }
00473   }
00474 
00475   if ( label.isEmpty() ) {
00476     label = key;
00477   }
00478 
00479   if ( type.isEmpty() ) type = "String"; // XXX : implicit type might be bad
00480 
00481   if (!param.isEmpty())
00482   {
00483     // Adjust name
00484     paramName = name;
00485     name.replace("$("+param+")", QString::null);
00486     // Lookup defaults for indexed entries
00487     for(int i = 0; i <= paramMax; i++)
00488     {
00489       paramDefaultValues.append(QString::null);
00490     }
00491 
00492     QDomNode n;
00493     for ( n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
00494       QDomElement e = n.toElement();
00495       QString tag = e.tagName();
00496       if ( tag == "default" )
00497       {
00498         QString index = e.attribute("param");
00499         if (index.isEmpty())
00500            continue;
00501 
00502         bool ok;
00503         int i = index.toInt(&ok);
00504         if (!ok)
00505         {
00506           i = paramValues.findIndex(index);
00507           if (i == -1)
00508           {
00509             kdError() << "Index '" << index << "' for default value is unknown." << endl;
00510             return 0;
00511           }
00512         }
00513 
00514         if ((i < 0) || (i > paramMax))
00515         {
00516           kdError() << "Index '" << i << "' for default value is out of range [0, "<< paramMax<<"]." << endl;
00517           return 0;
00518         }
00519 
00520         QString tmpDefaultValue = e.text();
00521 
00522         if (e.attribute( "code" ) != "true")
00523            preProcessDefault(tmpDefaultValue, name, type, choices, code);
00524 
00525         paramDefaultValues[i] = tmpDefaultValue;
00526       }
00527     }
00528   }
00529 
00530   if (!validNameRegexp->exactMatch(name))
00531   {
00532     if (nameIsEmpty)
00533       kdError() << "The key '" << key << "' can not be used as name for the entry because "
00534                    "it is not a valid name. You need to specify a valid name for this entry." << endl;
00535     else
00536       kdError() << "The name '" << name << "' is not a valid name for an entry." << endl;
00537     return 0;
00538   }
00539 
00540   if (allNames.contains(name))
00541   {
00542     if (nameIsEmpty)
00543       kdError() << "The key '" << key << "' can not be used as name for the entry because "
00544                    "it does not result in a unique name. You need to specify a unique name for this entry." << endl;
00545     else
00546       kdError() << "The name '" << name << "' is not unique." << endl;
00547     return 0;
00548   }
00549   allNames.append(name);
00550 
00551   if (!defaultCode)
00552   {
00553     preProcessDefault(defaultValue, name, type, choices, code);
00554   }
00555 
00556   CfgEntry *result = new CfgEntry( group, type, key, name, label, whatsThis,
00557                                    code, defaultValue, choices,
00558                                    hidden == "true" );
00559   if (!param.isEmpty())
00560   {
00561     result->setParam(param);
00562     result->setParamName(paramName);
00563     result->setParamType(paramType);
00564     result->setParamValues(paramValues);
00565     result->setParamDefaultValues(paramDefaultValues);
00566     result->setParamMax(paramMax);
00567   }
00568   result->setMinValue(minValue);
00569   result->setMaxValue(maxValue);
00570 
00571   return result;
00572 }
00573 
00577 QString param( const QString &type )
00578 {
00579     if ( type == "String" )           return "const QString &";
00580     else if ( type == "StringList" )  return "const QStringList &";
00581     else if ( type == "Font" )        return "const QFont &";
00582     else if ( type == "Rect" )        return "const QRect &";
00583     else if ( type == "Size" )        return "const QSize &";
00584     else if ( type == "Color" )       return "const QColor &";
00585     else if ( type == "Point" )       return "const QPoint &";
00586     else if ( type == "Int" )         return "int";
00587     else if ( type == "UInt" )        return "uint";
00588     else if ( type == "Bool" )        return "bool";
00589     else if ( type == "Double" )      return "double";
00590     else if ( type == "DateTime" )    return "const QDateTime &";
00591     else if ( type == "Int64" )       return "Q_INT64";
00592     else if ( type == "UInt64" )      return "Q_UINT64";
00593     else if ( type == "IntList" )     return "const QValueList<int> &";
00594     else if ( type == "Enum" )        return "int";
00595     else if ( type == "Path" )        return "const QString &";
00596     else if ( type == "PathList" )    return "const QStringList &";
00597     else if ( type == "Password" )    return "const QString &";
00598     else {
00599         kdError() <<"kconfig_compiler does not support type \""<< type <<"\""<<endl;
00600         return "QString"; //For now, but an assert would be better
00601     }
00602 }
00603 
00607 QString cppType( const QString &type )
00608 {
00609     if ( type == "String" )           return "QString";
00610     else if ( type == "StringList" )  return "QStringList";
00611     else if ( type == "Font" )        return "QFont";
00612     else if ( type == "Rect" )        return "QRect";
00613     else if ( type == "Size" )        return "QSize";
00614     else if ( type == "Color" )       return "QColor";
00615     else if ( type == "Point" )       return "QPoint";
00616     else if ( type == "Int" )         return "int";
00617     else if ( type == "UInt" )        return "uint";
00618     else if ( type == "Bool" )        return "bool";
00619     else if ( type == "Double" )      return "double";
00620     else if ( type == "DateTime" )    return "QDateTime";
00621     else if ( type == "Int64" )       return "Q_INT64";
00622     else if ( type == "UInt64" )      return "Q_UINT64";
00623     else if ( type == "IntList" )     return "QValueList<int>";
00624     else if ( type == "Enum" )        return "int";
00625     else if ( type == "Path" )        return "QString";
00626     else if ( type == "PathList" )    return "QStringList";
00627     else if ( type == "Password" )    return "QString";
00628     else {
00629         kdError()<<"kconfig_compiler does not support type \""<< type <<"\""<<endl;
00630         return "QString"; //For now, but an assert would be better
00631     }
00632 }
00633 
00634 QString defaultValue( const QString &type )
00635 {
00636     if ( type == "String" )           return "\"\""; // Use empty string, not null string!
00637     else if ( type == "StringList" )  return "QStringList()";
00638     else if ( type == "Font" )        return "KGlobalSettings::generalFont()";
00639     else if ( type == "Rect" )        return "QRect()";
00640     else if ( type == "Size" )        return "QSize()";
00641     else if ( type == "Color" )       return "QColor(128, 128, 128)";
00642     else if ( type == "Point" )       return "QPoint()";
00643     else if ( type == "Int" )         return "0";
00644     else if ( type == "UInt" )        return "0";
00645     else if ( type == "Bool" )        return "false";
00646     else if ( type == "Double" )      return "0.0";
00647     else if ( type == "DateTime" )    return "QDateTime()";
00648     else if ( type == "Int64" )       return "0";
00649     else if ( type == "UInt64" )      return "0";
00650     else if ( type == "IntList" )     return "QValueList<int>()";
00651     else if ( type == "Enum" )        return "0";
00652     else if ( type == "Path" )        return "\"\""; // Use empty string, not null string!
00653     else if ( type == "PathList" )    return "QStringList()";
00654     else if ( type == "Password" )    return "\"\""; // Use empty string, not null string!
00655     else {
00656         kdWarning()<<"Error, kconfig_compiler doesn't support the \""<< type <<"\" type!"<<endl;
00657         return "QString"; //For now, but an assert would be better
00658     }
00659 }
00660 
00661 QString itemType( const QString &type )
00662 {
00663   QString t;
00664 
00665   t = type;
00666   t.replace( 0, 1, t.left( 1 ).upper() );
00667 
00668   return t;
00669 }
00670 
00671 static QString itemDeclaration(const CfgEntry *e)
00672 {
00673   if (itemAccessors)
00674      return QString::null;
00675 
00676   return "  KConfigSkeleton::Item"+itemType( e->type() ) +
00677          "  *item" + e->name() +
00678          ( (!e->param().isEmpty())?(QString("[%1]").arg(e->paramMax()+1)) : QString::null) +
00679          ";\n";
00680 }
00681 
00682 static QString itemVar(const CfgEntry *e)
00683 {
00684   if (itemAccessors)
00685      return varName( e->name() ) + "Item";
00686 
00687   return "item" + e->name();
00688 
00689 }
00690 
00691 QString newItem( const QString &type, const QString &name, const QString &key,
00692                  const QString &defaultValue, const QString &param = QString::null)
00693 {
00694   QString t = "new KConfigSkeleton::Item" + itemType( type ) +
00695               "( currentGroup(), " + key + ", " + varName( name ) + param;
00696   if ( type == "Enum" ) t += ", values" + name;
00697   if ( !defaultValue.isEmpty() ) {
00698     t += ", ";
00699     if ( type == "String" ) t += defaultValue;
00700     else t+= defaultValue;
00701   }
00702   t += " );";
00703 
00704   return t;
00705 }
00706 
00707 QString paramString(const QString &s, const CfgEntry *e, int i)
00708 {
00709   QString result = s;
00710   QString needle = "$("+e->param()+")";
00711   if (result.contains(needle))
00712   {
00713     QString tmp;
00714     if (e->paramType() == "Enum")
00715     {
00716       tmp = e->paramValues()[i];
00717     }
00718     else
00719     {
00720       tmp = QString::number(i);
00721     }
00722 
00723     result.replace(needle, tmp);
00724   }
00725   return result;
00726 }
00727 
00728 QString paramString(const QString &group, const QValueList<Param> &parameters)
00729 {
00730   QString paramString = group;
00731   QString arguments;
00732   int i = 1;
00733   for (QValueList<Param>::ConstIterator it = parameters.begin();
00734        it != parameters.end(); ++it)
00735   {
00736      if (paramString.contains("$("+(*it).name+")"))
00737      {
00738        QString tmp;
00739        tmp.sprintf("%%%d", i++);
00740        paramString.replace("$("+(*it).name+")", tmp);
00741        arguments += ".arg( mParam"+(*it).name+" )";
00742      }
00743   }
00744   if (arguments.isEmpty())
00745     return "QString::fromLatin1( \""+group+"\" )";
00746 
00747   return "QString::fromLatin1( \""+paramString+"\" )"+arguments;
00748 }
00749 
00750 /* int i is the value of the parameter */
00751 QString userTextsFunctions( CfgEntry *e, QString itemVarStr=QString::null, QString i=QString::null )
00752 {
00753   QString txt;
00754   if (itemVarStr.isNull()) itemVarStr=itemVar(e);
00755   if ( !e->label().isEmpty() ) {
00756     txt += "  " + itemVarStr + "->setLabel( i18n(";
00757     if ( !e->param().isEmpty() )
00758       txt += quoteString(e->label().replace("$("+e->param()+")", i));
00759     else
00760       txt+= quoteString(e->label());
00761     txt+= ") );\n";
00762   }
00763   if ( !e->whatsThis().isEmpty() ) {
00764     txt += "  " + itemVarStr + "->setWhatsThis( i18n(";
00765     if ( !e->param().isEmpty() )
00766       txt += quoteString(e->whatsThis().replace("$("+e->param()+")", i));
00767     else
00768       txt+= quoteString(e->whatsThis());
00769     txt+=") );\n";
00770   }
00771   return txt;
00772 }
00773 
00774 int main( int argc, char **argv )
00775 {
00776   KAboutData aboutData( "kconfig_compiler", I18N_NOOP("KDE .kcfg compiler"), "0.3",
00777     I18N_NOOP("KConfig Compiler") , KAboutData::License_LGPL );
00778   aboutData.addAuthor( "Cornelius Schumacher", 0, "schumacher@kde.org" );
00779   aboutData.addAuthor( "Waldo Bastian", 0, "bastian@kde.org" );
00780   aboutData.addAuthor( "Zack Rusin", 0, "zack@kde.org" );
00781   aboutData.addCredit( "Reinhold Kainhofer", "Fix for parametrized entries",
00782       "reinhold@kainhofer.com", "http://reinhold.kainhofer.com" );
00783 
00784   KCmdLineArgs::init( argc, argv, &aboutData );
00785   KCmdLineArgs::addCmdLineOptions( options );
00786 
00787   KInstance app( &aboutData );
00788 
00789   KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
00790 
00791   if ( args->count() < 2 ) {
00792     kdError() << "Too few arguments." << endl;
00793     return 1;
00794   }
00795   if ( args->count() > 2 ) {
00796     kdError() << "Too many arguments." << endl;
00797     return 1;
00798   }
00799 
00800   validNameRegexp = new QRegExp("[a-zA-Z_][a-zA-Z0-9_]*");
00801 
00802   QString baseDir = QFile::decodeName(args->getOption("directory"));
00803   if (!baseDir.endsWith("/"))
00804     baseDir.append("/");
00805 
00806   QString inputFilename = args->url( 0 ).path();
00807   QString codegenFilename = args->url( 1 ).path();
00808 
00809   if (!codegenFilename.endsWith(".kcfgc"))
00810   {
00811     kdError() << "Codegen options file must have extension .kcfgc" << endl;
00812     return 1;
00813   }
00814   QString baseName = args->url( 1 ).fileName();
00815   baseName = baseName.left(baseName.length() - 6);
00816 
00817   KSimpleConfig codegenConfig( codegenFilename, true );
00818 
00819   QString nameSpace = codegenConfig.readEntry("NameSpace");
00820   QString className = codegenConfig.readEntry("ClassName");
00821   QString inherits = codegenConfig.readEntry("Inherits");
00822   QString visibility = codegenConfig.readEntry("Visibility");
00823   if (!visibility.isEmpty()) visibility+=" ";
00824   bool singleton = codegenConfig.readBoolEntry("Singleton", false);
00825   bool staticAccessors = singleton;
00826   bool customAddons = codegenConfig.readBoolEntry("CustomAdditions");
00827   QString memberVariables = codegenConfig.readEntry("MemberVariables");
00828   QStringList headerIncludes = codegenConfig.readListEntry("IncludeFiles");
00829   QStringList mutators = codegenConfig.readListEntry("Mutators");
00830   bool allMutators = false;
00831   if ((mutators.count() == 1) && (mutators[0].lower() == "true"))
00832      allMutators = true;
00833   itemAccessors = codegenConfig.readBoolEntry( "ItemAccessors", false );
00834   bool setUserTexts = codegenConfig.readBoolEntry( "SetUserTexts", false );
00835 
00836   globalEnums = codegenConfig.readBoolEntry( "GlobalEnums", false );
00837 
00838   QFile input( inputFilename );
00839 
00840   QDomDocument doc;
00841   QString errorMsg;
00842   int errorRow;
00843   int errorCol;
00844   if ( !doc.setContent( &input, &errorMsg, &errorRow, &errorCol ) ) {
00845     kdError() << "Unable to load document." << endl;
00846     kdError() << "Parse error in " << args->url( 0 ).fileName() << ", line " << errorRow << ", col " << errorCol << ": " << errorMsg << endl;
00847     return 1;
00848   }
00849 
00850   QDomElement cfgElement = doc.documentElement();
00851 
00852   if ( cfgElement.isNull() ) {
00853     kdError() << "No document in kcfg file" << endl;
00854     return 1;
00855   }
00856 
00857   QString cfgFileName;
00858   bool cfgFileNameArg = false;
00859   QValueList<Param> parameters;
00860   QStringList includes;
00861 
00862   QPtrList<CfgEntry> entries;
00863   entries.setAutoDelete( true );
00864 
00865   QDomNode n;
00866   for ( n = cfgElement.firstChild(); !n.isNull(); n = n.nextSibling() ) {
00867     QDomElement e = n.toElement();
00868 
00869     QString tag = e.tagName();
00870 
00871     if ( tag == "include" ) {
00872       QString includeFile = e.text();
00873       if (!includeFile.isEmpty())
00874         includes.append(includeFile);
00875 
00876     } else if ( tag == "kcfgfile" ) {
00877       cfgFileName = e.attribute( "name" );
00878       cfgFileNameArg = e.attribute( "arg" ).lower() == "true";
00879       QDomNode n2;
00880       for( n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) {
00881         QDomElement e2 = n2.toElement();
00882         if ( e2.tagName() == "parameter" ) {
00883           Param p;
00884           p.name = e2.attribute( "name" );
00885           p.type = e2.attribute( "type" );
00886           if (p.type.isEmpty())
00887              p.type = "String";
00888           parameters.append( p );
00889         }
00890       }
00891 
00892     } else if ( tag == "group" ) {
00893       QString group = e.attribute( "name" );
00894       if ( group.isEmpty() ) {
00895         kdError() << "Group without name" << endl;
00896         return 1;
00897       }
00898       QDomNode n2;
00899       for( n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) {
00900         QDomElement e2 = n2.toElement();
00901         if ( e2.tagName() != "entry" ) continue;
00902         CfgEntry *entry = parseEntry( group, e2 );
00903         if ( entry ) entries.append( entry );
00904         else {
00905           kdError() << "Can't parse entry." << endl;
00906           return 1;
00907         }
00908       }
00909     }
00910   }
00911 
00912   if ( inherits.isEmpty() ) inherits = "KConfigSkeleton";
00913 
00914   if ( className.isEmpty() ) {
00915     kdError() << "Class name missing" << endl;
00916     return 1;
00917   }
00918 
00919   if ( singleton && !parameters.isEmpty() ) {
00920     kdError() << "Singleton class can not have parameters" << endl;
00921     return 1;
00922   }
00923 
00924   if ( !cfgFileName.isEmpty() && cfgFileNameArg)
00925   {
00926     kdError() << "Having both a fixed filename and a filename as argument is not possible." << endl;
00927     return 1;
00928   }
00929 
00930   if ( entries.isEmpty() ) {
00931     kdWarning() << "No entries." << endl;
00932   }
00933 
00934 #if 0
00935   CfgEntry *cfg;
00936   for( cfg = entries.first(); cfg; cfg = entries.next() ) {
00937     cfg->dump();
00938   }
00939 #endif
00940 
00941   QString headerFileName = baseName + ".h";
00942   QString implementationFileName = baseName + ".cpp";
00943   QString cppPreamble; // code to be inserted at the beginnin of the cpp file, e.g. initialization of static values
00944 
00945   QFile header( baseDir + headerFileName );
00946   if ( !header.open( IO_WriteOnly ) ) {
00947     kdError() << "Can't open '" << headerFileName << "for writing." << endl;
00948     return 1;
00949   }
00950 
00951   QTextStream h( &header );
00952 
00953   h << "// This file is generated by kconfig_compiler from " << args->url(0).fileName() << "." << endl;
00954   h << "// All changes you do to this file will be lost." << endl;
00955 
00956   h << "#ifndef " << ( !nameSpace.isEmpty() ? nameSpace.upper() + "_" : "" )
00957     << className.upper() << "_H" << endl;
00958   h << "#define " << ( !nameSpace.isEmpty() ? nameSpace.upper() + "_" : "" )
00959     << className.upper() << "_H" << endl << endl;
00960 
00961   // Includes
00962   QStringList::ConstIterator it;
00963   for( it = headerIncludes.begin(); it != headerIncludes.end(); ++it ) {
00964     h << "#include <" << *it << ">" << endl;
00965   }
00966 
00967   if ( headerIncludes.count() > 0 ) h << endl;
00968 
00969   if ( !singleton && cfgFileNameArg && parameters.isEmpty() )
00970     h << "#include <kglobal.h>" << endl;
00971 
00972   h << "#include <kconfigskeleton.h>" << endl << endl;
00973 
00974   if ( !nameSpace.isEmpty() )
00975     h << "namespace " << nameSpace << " {" << endl << endl;
00976 
00977   // Class declaration header
00978   h << "class " << visibility << className << " : public " << inherits << endl;
00979   h << "{" << endl;
00980   h << "  public:" << endl;
00981 
00982   // enums
00983   CfgEntry *e;
00984   for( e = entries.first(); e; e = entries.next() ) {
00985     QValueList<CfgEntry::Choice> choices = e->choices();
00986     if ( !choices.isEmpty() ) {
00987       QStringList values;
00988       QValueList<CfgEntry::Choice>::ConstIterator itChoice;
00989       for( itChoice = choices.begin(); itChoice != choices.end(); ++itChoice ) {
00990         values.append( (*itChoice).name );
00991       }
00992       if ( globalEnums ) {
00993         h << "    enum { " << values.join( ", " ) << " };" << endl;
00994       } else {
00995         h << "    class " << enumName(e->name()) << endl;
00996         h << "    {" << endl;
00997         h << "      public:" << endl;
00998         h << "      enum type { " << values.join( ", " ) << ", COUNT };" << endl;
00999         h << "    };" << endl;
01000       }
01001     }
01002     QStringList values = e->paramValues();
01003     if ( !values.isEmpty() ) {
01004       if ( globalEnums ) {
01005         h << "    enum { " << values.join( ", " ) << " };" << endl;
01006         h << "    static const char* const " << enumName(e->param()) << "ToString[];" << endl;
01007         cppPreamble += "const char* const " + className + "::" + enumName(e->param()) + "ToString[] = " +
01008             "{ \"" + values.join( "\", \"" ) + "\" };\n";
01009       } else {
01010         h << "    class " << enumName(e->param()) << endl;
01011         h << "    {" << endl;
01012         h << "      public:" << endl;
01013         h << "      enum type { " << values.join( ", " ) << ", COUNT };" << endl;
01014         h << "      static const char* const enumToString[];" << endl;
01015         h << "    };" << endl;
01016         cppPreamble += "const char* const " + className + "::" + enumName(e->param()) + "::enumToString[] = " +
01017             "{ \"" + values.join( "\", \"" ) + "\" };\n";
01018       }
01019     }
01020   }
01021 
01022   h << endl;
01023 
01024   // Constructor or singleton accessor
01025   if ( !singleton ) {
01026     h << "    " << className << "(";
01027     if (cfgFileNameArg)
01028        h << " KSharedConfig::Ptr config" << (parameters.isEmpty() ? " = KGlobal::sharedConfig()" : ", ");
01029     for (QValueList<Param>::ConstIterator it = parameters.begin();
01030          it != parameters.end(); ++it)
01031     {
01032        if (it != parameters.begin())
01033          h << ",";
01034        h << " " << param((*it).type) << " " << (*it).name;
01035     }
01036     h << " );" << endl;
01037   } else {
01038     h << "    static " << className << " *self();" << endl;
01039     if (cfgFileNameArg)
01040       h << "    static void instance(const char * cfgfilename);" << endl;
01041   }
01042 
01043   // Destructor
01044   h << "    ~" << className << "();" << endl << endl;
01045 
01046   QString This;
01047   QString Const;
01048   if (staticAccessors)
01049     This = "self()->";
01050   else
01051     Const = " const";
01052 
01053   for( e = entries.first(); e; e = entries.next() ) {
01054     QString n = e->name();
01055     QString t = e->type();
01056 
01057     // Manipulator
01058     if (allMutators || mutators.contains(n))
01059     {
01060       h << "    /**" << endl;
01061       h << "      Set " << e->label() << endl;
01062       h << "    */" << endl;
01063       if (staticAccessors)
01064         h << "    static" << endl;
01065       h << "    void " << setFunction(n) << "( ";
01066       if (!e->param().isEmpty())
01067         h << cppType(e->paramType()) << " i, ";
01068       h << param( t ) << " v )" << endl;
01069       h << "    {" << endl;
01070       h << "      if (!" << This << "isImmutable( QString::fromLatin1( \"";
01071       if (!e->param().isEmpty()) {
01072         h << e->paramName().replace("$("+e->param()+")", "%1") << "\" ).arg( ";
01073         if ( e->paramType() == "Enum" ) {
01074           h << "QString::fromLatin1( ";
01075           if (globalEnums)
01076             h << enumName(e->param()) << "ToString[i]";
01077           else
01078             h << enumName(e->param()) << "::enumToString[i]";
01079           h << " )";
01080         } else {
01081           h << "i";
01082         }
01083         h << " )";
01084       } else
01085         h << n << "\" )";
01086       h << " ))" << endl;
01087       h << "        " << This << varName(n);
01088       if (!e->param().isEmpty())
01089         h << "[i]";
01090       h << " = v;" << endl;
01091       h << "    }" << endl << endl;
01092     }
01093 
01094     // Accessor
01095     h << "    /**" << endl;
01096     h << "      Get " << e->label() << endl;
01097     h << "    */" << endl;
01098     if (staticAccessors)
01099       h << "    static" << endl;
01100     h << "    " << cppType(t) << " " << getFunction(n) << "(";
01101     if (!e->param().isEmpty())
01102       h << " " << cppType(e->paramType()) <<" i ";
01103     h << ")" << Const << endl;
01104     h << "    {" << endl;
01105     h << "      return " << This << varName(n);
01106     if (!e->param().isEmpty()) h << "[i]";
01107     h << ";" << endl;
01108     h << "    }" << endl;
01109 
01110     // Item accessor
01111     if ( itemAccessors ) {
01112       h << endl;
01113       h << "    /**" << endl;
01114       h << "      Get Item object corresponding to " << n << "()"
01115         << endl;
01116       h << "    */" << endl;
01117       h << "    Item" << itemType( e->type() ) << " *"
01118         << getFunction( n ) << "Item(";
01119       if (!e->param().isEmpty()) {
01120         h << " " << cppType(e->paramType()) << " i ";
01121       }
01122       h << ")" << endl;
01123       h << "    {" << endl;
01124       h << "      return " << itemVar(e);
01125       if (!e->param().isEmpty()) h << "[i]";
01126       h << ";" << endl;
01127       h << "    }" << endl;
01128     }
01129 
01130     h << endl;
01131   }
01132 
01133   // Static writeConfig method for singleton
01134   if ( singleton ) {
01135     h << "    static" << endl;
01136     h << "    void writeConfig()" << endl;
01137     h << "    {" << endl;
01138     h << "      static_cast<KConfigSkeleton*>(self())->writeConfig();" << endl;
01139     h << "    }" << endl;
01140   }
01141 
01142   h << "  protected:" << endl;
01143 
01144   // Private constructor for singleton
01145   if ( singleton ) {
01146     h << "    " << className << "(";
01147     if ( cfgFileNameArg )
01148       h << "const char *arg";
01149     h << ");" << endl;
01150     h << "    static " << className << " *mSelf;" << endl << endl;
01151   }
01152 
01153   // Member variables
01154   if ( !memberVariables.isEmpty() && memberVariables != "private" ) {
01155     h << "  " << memberVariables << ":" << endl;
01156   }
01157 
01158   // Class Parameters
01159   for (QValueList<Param>::ConstIterator it = parameters.begin();
01160        it != parameters.end(); ++it)
01161   {
01162      h << "    " << cppType((*it).type) << " mParam" << (*it).name << ";" << endl;
01163   }
01164 
01165   QString group;
01166   for( e = entries.first(); e; e = entries.next() ) {
01167     if ( e->group() != group ) {
01168       group = e->group();
01169       h << endl;
01170       h << "    // " << group << endl;
01171     }
01172     h << "    " << cppType(e->type()) << " " << varName(e->name());
01173     if (!e->param().isEmpty())
01174     {
01175       h << QString("[%1]").arg(e->paramMax()+1);
01176     }
01177     h << ";" << endl;
01178   }
01179 
01180   h << endl << "  private:" << endl;
01181   if ( itemAccessors ) {
01182     for( e = entries.first(); e; e = entries.next() ) {
01183       h << "    Item" << itemType( e->type() ) << " *" << itemVar( e );
01184       if (!e->param().isEmpty() ) h << QString("[%1]").arg( e->paramMax()+1 );
01185       h << ";" << endl;
01186     }
01187   }
01188 
01189   if (customAddons)
01190   {
01191      h << "    // Include custom additions" << endl;
01192      h << "    #include \"" << filenameOnly(baseName) << "_addons.h\"" <<endl;
01193   }
01194 
01195   h << "};" << endl << endl;
01196 
01197   if ( !nameSpace.isEmpty() ) h << "}" << endl << endl;
01198 
01199   h << "#endif" << endl << endl;
01200 
01201 
01202   header.close();
01203 
01204   QFile implementation( baseDir + implementationFileName );
01205   if ( !implementation.open( IO_WriteOnly ) ) {
01206     kdError() << "Can't open '" << implementationFileName << "for writing."
01207               << endl;
01208     return 1;
01209   }
01210 
01211   QTextStream cpp( &implementation );
01212 
01213 
01214   cpp << "// This file is generated by kconfig_compiler from " << args->url(0).fileName() << "." << endl;
01215   cpp << "// All changes you do to this file will be lost." << endl << endl;
01216 
01217   cpp << "#include \"" << headerFileName << "\"" << endl << endl;
01218 
01219   if ( setUserTexts ) cpp << "#include <klocale.h>" << endl << endl;
01220 
01221   // Includes
01222   for( it = includes.begin(); it != includes.end(); ++it ) {
01223     cpp << "#include <" << *it << ">" << endl;
01224   }
01225 
01226   // Header required by singleton implementation
01227   if ( singleton )
01228     cpp << "#include <kstaticdeleter.h>" << endl << endl;
01229   if ( singleton && cfgFileNameArg )
01230     cpp << "#include <kdebug.h>" << endl << endl;
01231 
01232   if ( !nameSpace.isEmpty() )
01233     cpp << "using namespace " << nameSpace << ";" << endl << endl;
01234 
01235   // Singleton implementation
01236   if ( singleton ) {
01237     cpp << className << " *" << className << "::mSelf = 0;" << endl;
01238     cpp << "static KStaticDeleter<" << className << "> static" << className << "Deleter;" << endl << endl;
01239 
01240     cpp << className << " *" << className << "::self()" << endl;
01241     cpp << "{" << endl;
01242     if ( cfgFileNameArg ) {
01243       cpp << "  if (!mSelf)" << endl;
01244       cpp << "     kdFatal() << \"you need to call " << className << "::instance before using\" << endl;" << endl;
01245     } else {
01246     cpp << "  if ( !mSelf ) {" << endl;
01247     cpp << "    static" << className << "Deleter.setObject( mSelf, new " << className << "() );" << endl;
01248     cpp << "    mSelf->readConfig();" << endl;
01249     cpp << "  }" << endl << endl;
01250     }
01251     cpp << "  return mSelf;" << endl;
01252     cpp << "}" << endl << endl;
01253 
01254     if ( cfgFileNameArg ) {
01255       cpp << "void " << className << "::instance(const char *cfgfilename)" << endl;
01256       cpp << "{" << endl;
01257       cpp << "  if (mSelf) {" << endl;
01258       cpp << "     kdError() << \"" << className << "::instance called after the first use - ignoring\" << endl;" << endl;
01259       cpp << "     return;" << endl;
01260       cpp << "  }" << endl;
01261       cpp << "  static" << className << "Deleter.setObject( mSelf, new " << className << "(cfgfilename) );" << endl;
01262       cpp << "  mSelf->readConfig();" << endl;
01263       cpp << "}" << endl << endl;
01264     }
01265   }
01266 
01267   if ( !cppPreamble.isEmpty() )
01268     cpp << cppPreamble << endl;
01269 
01270   // Constructor
01271   cpp << className << "::" << className << "( ";
01272   if ( cfgFileNameArg ) {
01273     if ( !singleton )
01274       cpp << " KSharedConfig::Ptr config";
01275     else
01276       cpp << " const char *config";
01277     cpp << (parameters.isEmpty() ? " " : ", ");
01278   }
01279 
01280   for (QValueList<Param>::ConstIterator it = parameters.begin();
01281        it != parameters.end(); ++it)
01282   {
01283      if (it != parameters.begin())
01284        cpp << ",";
01285      cpp << " " << param((*it).type) << " " << (*it).name;
01286   }
01287   cpp << " )" << endl;
01288 
01289   cpp << "  : " << inherits << "(";
01290   if ( !cfgFileName.isEmpty() ) cpp << " QString::fromLatin1( \"" << cfgFileName << "\" ";
01291   if ( cfgFileNameArg ) cpp << " config ";
01292   if ( !cfgFileName.isEmpty() ) cpp << ") ";
01293   cpp << ")" << endl;
01294 
01295   // Store parameters
01296   for (QValueList<Param>::ConstIterator it = parameters.begin();
01297        it != parameters.end(); ++it)
01298   {
01299      cpp << "  , mParam" << (*it).name << "(" << (*it).name << ")" << endl;
01300   }
01301 
01302   cpp << "{" << endl;
01303 
01304   // Needed in case the singleton class is used as baseclass for
01305   // another singleton.
01306   if ( singleton )
01307     cpp << "  mSelf = this;" << endl;
01308 
01309   group = QString::null;
01310   for( e = entries.first(); e; e = entries.next() ) {
01311     if ( e->group() != group ) {
01312       if ( !group.isEmpty() ) cpp << endl;
01313       group = e->group();
01314       cpp << "  setCurrentGroup( " << paramString(group, parameters) << " );" << endl << endl;
01315     }
01316 
01317     QString key = paramString(e->key(), parameters);
01318     if ( !e->code().isEmpty())
01319     {
01320       cpp << e->code() << endl;
01321     }
01322     if ( e->type() == "Enum" ) {
01323       cpp << "  QValueList<KConfigSkeleton::ItemEnum::Choice> values"
01324           << e->name() << ";" << endl;
01325       QValueList<CfgEntry::Choice> choices = e->choices();
01326       QValueList<CfgEntry::Choice>::ConstIterator it;
01327       for( it = choices.begin(); it != choices.end(); ++it ) {
01328         cpp << "  {" << endl;
01329         cpp << "    KConfigSkeleton::ItemEnum::Choice choice;" << endl;
01330         cpp << "    choice.name = QString::fromLatin1( \"" << (*it).name << "\" );" << endl;
01331         if ( setUserTexts ) {
01332           if ( !(*it).label.isEmpty() )
01333             cpp << "    choice.label = i18n(" << quoteString((*it).label) << ");" << endl;
01334           if ( !(*it).whatsThis.isEmpty() )
01335             cpp << "    choice.whatsThis = i18n(" << quoteString((*it).whatsThis) << ");" << endl;
01336         }
01337         cpp << "    values" << e->name() << ".append( choice );" << endl;
01338         cpp << "  }" << endl;
01339       }
01340     }
01341     cpp << itemDeclaration(e);
01342     if (e->param().isEmpty())
01343     {
01344       // Normal case
01345       cpp << "  " << itemVar(e) << " = "
01346           << newItem( e->type(), e->name(), key, e->defaultValue() ) << endl;
01347 
01348       if ( !e->minValue().isEmpty() )
01349         cpp << "  " << itemVar(e) << "->setMinValue(" << e->minValue() << ");" << endl;
01350       if ( !e->maxValue().isEmpty() )
01351         cpp << "  " << itemVar(e) << "->setMaxValue(" << e->maxValue() << ");" << endl;
01352 
01353       if ( setUserTexts )
01354         cpp << userTextsFunctions( e );
01355 
01356       cpp << "  addItem( " << itemVar(e);
01357       QString quotedName = e->name();
01358       addQuotes( quotedName );
01359       if ( quotedName != key ) cpp << ", QString::fromLatin1( \"" << e->name() << "\" )";
01360       cpp << " );" << endl;
01361     }
01362     else
01363     {
01364       // Indexed
01365       for(int i = 0; i <= e->paramMax(); i++)
01366       {
01367         QString defaultStr;
01368         QString itemVarStr(itemVar(e)+QString("[%1]").arg(i));
01369 
01370         if ( !e->paramDefaultValue(i).isEmpty() )
01371           defaultStr = e->paramDefaultValue(i);
01372         else if ( !e->defaultValue().isEmpty() )
01373           defaultStr = paramString(e->defaultValue(), e, i);
01374         else
01375           defaultStr = defaultValue( e->type() );
01376 
01377         cpp << "  " << itemVarStr << " = "
01378             << newItem( e->type(), e->name(), paramString(key, e, i), defaultStr, QString("[%1]").arg(i) )
01379             << endl;
01380 
01381         if ( setUserTexts )
01382           cpp << userTextsFunctions( e, itemVarStr, e->paramName() );
01383 
01384         // Make mutators for enum parameters work by adding them with $(..) replaced by the
01385         // param name. The check for isImmutable in the set* functions doesn't have the param
01386         // name available, just the corresponding enum value (int), so we need to store the
01387         // param names in a separate static list!.
01388         cpp << "  addItem( " << itemVarStr << ", QString::fromLatin1( \"";
01389         if ( e->paramType()=="Enum" )
01390           cpp << e->paramName().replace( "$("+e->param()+")", "%1").arg(e->paramValues()[i] );
01391         else
01392           cpp << e->paramName().replace( "$("+e->param()+")", "%1").arg(i);
01393         cpp << "\" ) );" << endl;
01394       }
01395     }
01396   }
01397 
01398   cpp << "}" << endl << endl;
01399 
01400   // Destructor
01401   cpp << className << "::~" << className << "()" << endl;
01402   cpp << "{" << endl;
01403   if ( singleton ) {
01404     cpp << "  if ( mSelf == this )" << endl;
01405     cpp << "    static" << className << "Deleter.setObject( mSelf, 0, false );" << endl;
01406   }
01407   cpp << "}" << endl << endl;
01408 
01409   implementation.close();
01410 }
KDE Logo
This file is part of the documentation for kdecore Library Version 3.4.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Jul 20 13:44:59 2006 by doxygen 1.4.4 written by Dimitri van Heesch, © 1997-2003