kdecore Library: kconfig_compiler.cpp Source File (kdecore Library)

| # kdecore Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# 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;
    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 }

This file is part of the documentation for kdecore Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:18:02 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003