• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

KDECore

kconfig_compiler.cpp

Go to the documentation of this file.
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     Copyright (c) 2006 Michaƫl Larouche <michael.larouche@kdemail.net>
00009     Copyright (c) 2008 Allen Winter <winter@kde.org>
00010 
00011     This library is free software; you can redistribute it and/or
00012     modify it under the terms of the GNU Library General Public
00013     License as published by the Free Software Foundation; either
00014     version 2 of the License, or (at your option) any later version.
00015 
00016     This library is distributed in the hope that it will be useful,
00017     but WITHOUT ANY WARRANTY; without even the implied warranty of
00018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019     Library General Public License for more details.
00020 
00021     You should have received a copy of the GNU Library General Public License
00022     along with this library; see the file COPYING.LIB.  If not, write to
00023     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00024     Boston, MA 02110-1301, USA.
00025 */
00026 
00027 // Compiling this file with this flag is just crazy
00028 #undef QT_NO_CAST_FROM_ASCII
00029 
00030 #include <QtCore/QCoreApplication>
00031 #include <QtCore/QFile>
00032 #include <QtCore/QFileInfo>
00033 #include <QtCore/QSettings>
00034 #include <QtCore/QTextStream>
00035 #include <QtXml/QDomAttr>
00036 #include <QtCore/QRegExp>
00037 #include <QtCore/QStringList>
00038 
00039 #include <ostream>
00040 #include <iostream>
00041 #include <stdlib.h>
00042 
00043 namespace
00044 {
00045   QTextStream cout(stdout);
00046   QTextStream cerr(stderr);
00047 }
00048 
00049 static void parseArgs(const QStringList &args, QString &directory, QString &file1, QString &file2)
00050 {
00051     int fileCount = 0;
00052     directory = QChar::fromLatin1('.');
00053 
00054     for (int i = 1; i < args.count(); ++i) {
00055         if (args.at(i) == QLatin1String("-d") ||  args.at(i) == QLatin1String("--directory")) {
00056             if (i + 1 > args.count()) {
00057                 cerr << args.at(i) << " needs an argument" << endl;
00058                 exit(1);
00059             }
00060             directory = args.at(++i);
00061         } else if (args.at(i).startsWith(QLatin1String("-d"))) {
00062             directory = args.at(i).mid(2);
00063         } else if (args.at(i) == QLatin1String("--help") || args.at(i) == QLatin1String("-h")) {
00064             cout << "Options:" << endl;
00065             cout << "  -L --license              Display software license" << endl;
00066             cout << "  -d, --directory <dir>     Directory to generate files in [.]" << endl;
00067             cout << "  -h, --help                Display this help" << endl;
00068             cout << endl;
00069             cout << "Arguments:" << endl;
00070             cout << "      file.kcfg                 Input kcfg XML file" << endl;
00071             cout << "      file.kcfgc                Code generation options file" << endl;
00072             exit(0);
00073         } else if (args.at(i) == QLatin1String("--license") || args.at(i) == QLatin1String("-L")) {
00074             cout << "Copyright 2003 Cornelius Schumacher, Waldo Bastian, Zack Rusin," << endl;
00075             cout << "    Reinhold Kainhofer, Duncan Mac-Vicar P., Harald Fernengel" << endl;
00076             cout << "This program comes with ABSOLUTELY NO WARRANTY." << endl;
00077             cout << "You may redistribute copies of this program" << endl;
00078             cout << "under the terms of the GNU Library Public License." << endl;
00079             cout << "For more information about these matters, see the file named COPYING." << endl;
00080             exit(0);
00081         } else if (args.at(i).startsWith(QLatin1Char('-'))) {
00082             cerr << "Unknown option: " << args.at(i) << endl;
00083             exit(1);
00084         } else if (fileCount == 0) {
00085             file1 = args.at(i);
00086             ++fileCount;
00087         } else if (fileCount == 1) {
00088             file2 = args.at(i);
00089             ++fileCount;
00090         } else {
00091             cerr << "Too many arguments" << endl;
00092             exit(1);
00093         }
00094     }
00095     if (fileCount < 2) {
00096         cerr << "Too few arguments" << endl;
00097         exit(1);
00098     }
00099 }
00100 
00101 QStringList allNames;
00102 QRegExp *validNameRegexp;
00103 QString This;
00104 QString Const;
00105 
00109 class CfgConfig
00110 {
00111 public:
00112   CfgConfig( const QString &codegenFilename )
00113   {
00114     // Configure the compiler with some settings
00115     QSettings codegenConfig(codegenFilename, QSettings::IniFormat);
00116 
00117     nameSpace = codegenConfig.value("NameSpace").toString();
00118     className = codegenConfig.value("ClassName").toString();
00119     if ( className.isEmpty() ) {
00120       cerr << "Class name missing" << endl;
00121       exit(1);
00122     }
00123     inherits = codegenConfig.value("Inherits").toString();
00124     if ( inherits.isEmpty() ) inherits = "KConfigSkeleton";
00125     visibility = codegenConfig.value("Visibility").toString();
00126     if ( !visibility.isEmpty() ) visibility += ' ';
00127     forceStringFilename = codegenConfig.value("ForceStringFilename", false).toBool();
00128     singleton = codegenConfig.value("Singleton", false).toBool();
00129     staticAccessors = singleton;
00130     customAddons = codegenConfig.value("CustomAdditions", false).toBool();
00131     memberVariables = codegenConfig.value("MemberVariables").toString();
00132     dpointer = (memberVariables == "dpointer");
00133     headerIncludes = codegenConfig.value("IncludeFiles", QStringList()).toStringList();
00134     sourceIncludes = codegenConfig.value("SourceIncludeFiles", QStringList()).toStringList();
00135     mutators = codegenConfig.value("Mutators", QStringList()).toStringList();
00136     allMutators = ((mutators.count() == 1) && (mutators.at(0).toLower() == "true"));
00137     itemAccessors = codegenConfig.value("ItemAccessors", false).toBool();
00138     setUserTexts = codegenConfig.value("SetUserTexts", false).toBool();
00139     defaultGetters = codegenConfig.value("DefaultValueGetters", QStringList()).toStringList();
00140     allDefaultGetters = (defaultGetters.count() == 1) && (defaultGetters.at(0).toLower() == "true");
00141     globalEnums = codegenConfig.value("GlobalEnums", false).toBool();
00142     useEnumTypes = codegenConfig.value("UseEnumTypes", false).toBool();
00143   }
00144 
00145 public:
00146   // These are read from the .kcfgc configuration file
00147   QString nameSpace;     // The namespace for the class to be generated
00148   QString className;     // The class name to be generated
00149   QString inherits;      // The class the generated class inherits (if empty, from KConfigSkeleton)
00150   QString visibility;
00151   bool forceStringFilename;
00152   bool singleton;        // The class will be a singleton
00153   bool staticAccessors;  // provide or not static accessors
00154   bool customAddons;
00155   QString memberVariables;
00156   QStringList headerIncludes;
00157   QStringList sourceIncludes;
00158   QStringList mutators;
00159   QStringList defaultGetters;
00160   bool allMutators;
00161   bool setUserTexts;
00162   bool allDefaultGetters;
00163   bool dpointer;
00164   bool globalEnums;
00165   bool useEnumTypes;
00166   bool itemAccessors;
00167 };
00168 
00169 
00170 struct SignalArguments
00171 {
00172       QString type;
00173       QString variableName;
00174 };
00175 
00176 class Signal {
00177 public:
00178   QString name;
00179   QString label;
00180   QList<SignalArguments> arguments;
00181 };
00182 
00183 
00184 
00185 
00186 class CfgEntry
00187 {
00188   public:
00189     struct Choice
00190     {
00191       QString name;
00192       QString context;
00193       QString label;
00194       QString toolTip;
00195       QString whatsThis;
00196     };
00197     class Choices
00198     {
00199       public:
00200         Choices() {}
00201         Choices( const QList<Choice> &d, const QString &n, const QString &p )
00202              : prefix(p), choices(d), mName(n)
00203         {
00204           int i = n.indexOf(QLatin1String("::"));
00205           if (i >= 0)
00206             mExternalQual = n.left(i + 2);
00207         }
00208         QString prefix;
00209         QList<Choice> choices;
00210         const QString& name() const  { return mName; }
00211         const QString& externalQualifier() const  { return mExternalQual; }
00212         bool external() const  { return !mExternalQual.isEmpty(); }
00213       private:
00214         QString mName;
00215         QString mExternalQual;
00216     };
00217 
00218     CfgEntry( const QString &group, const QString &type, const QString &key,
00219               const QString &name, const QString &context, const QString &label,
00220               const QString &toolTip, const QString &whatsThis, const QString &code,
00221               const QString &defaultValue, const Choices &choices, const QList<Signal> signalList,
00222               bool hidden )
00223       : mGroup( group ), mType( type ), mKey( key ), mName( name ),
00224         mContext( context ), mLabel( label ), mToolTip( toolTip ), mWhatsThis( whatsThis ),
00225         mCode( code ), mDefaultValue( defaultValue ), mChoices( choices ),
00226         mSignalList(signalList), mHidden( hidden )
00227     {
00228     }
00229 
00230     void setGroup( const QString &group ) { mGroup = group; }
00231     QString group() const { return mGroup; }
00232 
00233     void setType( const QString &type ) { mType = type; }
00234     QString type() const { return mType; }
00235 
00236     void setKey( const QString &key ) { mKey = key; }
00237     QString key() const { return mKey; }
00238 
00239     void setName( const QString &name ) { mName = name; }
00240     QString name() const { return mName; }
00241 
00242     void setContext( const QString &context ) { mContext = context; }
00243     QString context() const { return mContext; }
00244 
00245     void setLabel( const QString &label ) { mLabel = label; }
00246     QString label() const { return mLabel; }
00247 
00248     void setToolTip( const QString &toolTip ) { mToolTip = toolTip; }
00249     QString toolTip() const { return mToolTip; }
00250 
00251     void setWhatsThis( const QString &whatsThis ) { mWhatsThis = whatsThis; }
00252     QString whatsThis() const { return mWhatsThis; }
00253 
00254     void setDefaultValue( const QString &d ) { mDefaultValue = d; }
00255     QString defaultValue() const { return mDefaultValue; }
00256 
00257     void setCode( const QString &d ) { mCode = d; }
00258     QString code() const { return mCode; }
00259 
00260     void setMinValue( const QString &d ) { mMin = d; }
00261     QString minValue() const { return mMin; }
00262 
00263     void setMaxValue( const QString &d ) { mMax = d; }
00264     QString maxValue() const { return mMax; }
00265 
00266     void setParam( const QString &d ) { mParam = d; }
00267     QString param() const { return mParam; }
00268 
00269     void setParamName( const QString &d ) { mParamName = d; }
00270     QString paramName() const { return mParamName; }
00271 
00272     void setParamType( const QString &d ) { mParamType = d; }
00273     QString paramType() const { return mParamType; }
00274 
00275     void setChoices( const QList<Choice> &d, const QString &n, const QString &p ) { mChoices = Choices( d, n, p ); }
00276     Choices choices() const { return mChoices; }
00277 
00278     void setParamValues( const QStringList &d ) { mParamValues = d; }
00279     QStringList paramValues() const { return mParamValues; }
00280 
00281     void setParamDefaultValues( const QStringList &d ) { mParamDefaultValues = d; }
00282     QString paramDefaultValue(int i) const { return mParamDefaultValues[i]; }
00283 
00284     void setParamMax( int d ) { mParamMax = d; }
00285     int paramMax() const { return mParamMax; }
00286 
00287     void setSignalList( const QList<Signal> &value ) { mSignalList = value; }
00288     QList<Signal> signalList() const { return mSignalList; }
00289 
00290     bool hidden() const { return mHidden; }
00291 
00292     void dump() const
00293     {
00294       cerr << "<entry>" << endl;
00295       cerr << "  group: " << mGroup << endl;
00296       cerr << "  type: " << mType << endl;
00297       cerr << "  key: " << mKey << endl;
00298       cerr << "  name: " << mName << endl;
00299       cerr << "  context: " << mContext << endl;
00300       cerr << "  label: " << mLabel << endl;
00301 // whatsthis
00302       cerr << "  code: " << mCode << endl;
00303 //      cerr << "  values: " << mValues.join(":") << endl;
00304 
00305       if (!param().isEmpty())
00306       {
00307         cerr << "  param name: "<< mParamName << endl;
00308         cerr << "  param type: "<< mParamType << endl;
00309         cerr << "  paramvalues: " << mParamValues.join(QChar::fromLatin1(':')) << endl;
00310       }
00311       cerr << "  default: " << mDefaultValue << endl;
00312       cerr << "  hidden: " << mHidden << endl;
00313       cerr << "  min: " << mMin << endl;
00314       cerr << "  max: " << mMax << endl;
00315       cerr << "</entry>" << endl;
00316     }
00317 
00318   private:
00319     QString mGroup;
00320     QString mType;
00321     QString mKey;
00322     QString mName;
00323     QString mContext;
00324     QString mLabel;
00325     QString mToolTip;
00326     QString mWhatsThis;
00327     QString mCode;
00328     QString mDefaultValue;
00329     QString mParam;
00330     QString mParamName;
00331     QString mParamType;
00332     Choices mChoices;
00333     QList<Signal> mSignalList;
00334     QStringList mParamValues;
00335     QStringList mParamDefaultValues;
00336     int mParamMax;
00337     bool mHidden;
00338     QString mMin;
00339     QString mMax;
00340 };
00341 
00342 class Param {
00343 public:
00344   QString name;
00345   QString type;
00346 };
00347 
00348 // returns the name of an member variable
00349 // use itemPath to know the full path
00350 // like using d-> in case of dpointer
00351 static QString varName(const QString &n, const CfgConfig &cfg)
00352 {
00353   QString result;
00354   if ( !cfg.dpointer ) {
00355     result = QChar::fromLatin1('m') + n;
00356     result[1] = result[1].toUpper();
00357   }
00358   else {
00359     result = n;
00360     result[0] = result[0].toLower();
00361   }
00362   return result;
00363 }
00364 
00365 static QString varPath(const QString &n, const CfgConfig &cfg)
00366 {
00367   QString result;
00368   if ( cfg.dpointer ) {
00369     result = "d->"+varName(n, cfg);
00370   }
00371   else {
00372     result = varName(n, cfg);
00373   }
00374   return result;
00375 }
00376 
00377 static QString enumName(const QString &n)
00378 {
00379   QString result = QString::fromLatin1("Enum") + n;
00380   result[4] = result[4].toUpper();
00381   return result;
00382 }
00383 
00384 static QString enumName(const QString &n, const CfgEntry::Choices &c)
00385 {
00386   QString result = c.name();
00387   if ( result.isEmpty() )
00388   {
00389     result = QString::fromLatin1("Enum") + n;
00390     result[4] = result[4].toUpper();
00391   }
00392   return result;
00393 }
00394 
00395 static QString enumType(const CfgEntry *e, bool globalEnums)
00396 {
00397   QString result = e->choices().name();
00398   if ( result.isEmpty() )
00399   {
00400     result = QString::fromLatin1("Enum") + e->name();
00401     if( !globalEnums )
00402         result += QString::fromLatin1("::type");
00403     result[4] = result[4].toUpper();
00404   }
00405   return result;
00406 }
00407 
00408 static QString enumTypeQualifier(const QString &n, const CfgEntry::Choices &c)
00409 {
00410   QString result = c.name();
00411   if ( result.isEmpty() )
00412   {
00413     result = QString::fromLatin1("Enum") + n + QString::fromLatin1("::");
00414     result[4] = result[4].toUpper();
00415   }
00416   else if ( c.external() )
00417     result = c.externalQualifier();
00418   else
00419     result.clear();
00420   return result;
00421 }
00422 
00423 static QString setFunction(const QString &n, const QString &className = QString())
00424 {
00425   QString result = QString::fromLatin1("set") + n;
00426   result[3] = result[3].toUpper();
00427 
00428   if ( !className.isEmpty() )
00429     result = className + QString::fromLatin1("::") + result;
00430   return result;
00431 }
00432 
00433 static QString getDefaultFunction(const QString &n, const QString &className = QString())
00434 {
00435   QString result = QString::fromLatin1("default") +  n + QString::fromLatin1("Value");
00436   result[7] = result[7].toUpper();
00437 
00438   if ( !className.isEmpty() )
00439     result = className + QString::fromLatin1("::") + result;
00440   return result;
00441 }
00442 
00443 static QString getFunction(const QString &n, const QString &className = QString())
00444 {
00445   QString result = n;
00446   result[0] = result[0].toLower();
00447 
00448   if ( !className.isEmpty() )
00449     result = className + QString::fromLatin1("::") + result;
00450   return result;
00451 }
00452 
00453 
00454 static void addQuotes( QString &s )
00455 {
00456   if ( !s.startsWith( QLatin1Char('"') ) )
00457     s.prepend( QLatin1Char('"') );
00458   if ( !s.endsWith( QLatin1Char('"') ) )
00459     s.append( QLatin1Char('"') );
00460 }
00461 
00462 static QString quoteString( const QString &s )
00463 {
00464   QString r = s;
00465   r.replace( QLatin1Char('\\'), QLatin1String("\\\\") );
00466   r.replace( QLatin1Char('\"'), QLatin1String("\\\"") );
00467   r.remove( QLatin1Char('\r') );
00468   r.replace( QLatin1Char('\n'), QLatin1String("\\n\"\n\"") );
00469   return QLatin1Char('\"') + r + QLatin1Char('\"');
00470 }
00471 
00472 static QString literalString( const QString &s )
00473 {
00474   bool isAscii = true;
00475   for(int i = s.length(); i--;)
00476      if (s[i].unicode() > 127) isAscii = false;
00477 
00478   if (isAscii)
00479      return QString::fromLatin1("QLatin1String( ") + quoteString(s) + QString::fromLatin1(" )");
00480   else
00481      return QString::fromLatin1("QString::fromUtf8( ") + quoteString(s) + QString::fromLatin1(" )");
00482 }
00483 
00484 static QString dumpNode(const QDomNode &node)
00485 {
00486   QString msg;
00487   QTextStream s(&msg, QIODevice::WriteOnly );
00488   node.save(s, 0);
00489 
00490   msg = msg.simplified();
00491   if (msg.length() > 40)
00492     return msg.left(37) + QString::fromLatin1("...");
00493   return msg;
00494 }
00495 
00496 static QString filenameOnly(const QString& path)
00497 {
00498    int i = path.lastIndexOf(QRegExp(QLatin1String("[/\\]")));
00499    if (i >= 0)
00500       return path.mid(i+1);
00501    return path;
00502 }
00503 
00504 static QString signalEnumName(const QString &signalName)
00505 {
00506   QString result;
00507   result = QString::fromLatin1("signal") + signalName;
00508   result[6] = result[6].toUpper();
00509 
00510   return result;
00511 }
00512 
00513 static void preProcessDefault( QString &defaultValue, const QString &name,
00514                                const QString &type,
00515                                const CfgEntry::Choices &choices,
00516                                QString &code, const CfgConfig &cfg )
00517 {
00518     if ( type == QLatin1String("String") && !defaultValue.isEmpty() ) {
00519       defaultValue = literalString(defaultValue);
00520 
00521     } else if ( type == QLatin1String("Path") && !defaultValue.isEmpty() ) {
00522       defaultValue = literalString( defaultValue );
00523     } else if ( type == QLatin1String("Url") && !defaultValue.isEmpty() ) {
00524       defaultValue = QString::fromLatin1("KUrl( ") + literalString(defaultValue) + QLatin1Char(')');
00525     } else if ( ( type == QLatin1String("UrlList") || type == QLatin1String("StringList") || type == QLatin1String("PathList")) && !defaultValue.isEmpty() ) {
00526       QTextStream cpp( &code, QIODevice::WriteOnly | QIODevice::Append );
00527       if (!code.isEmpty())
00528          cpp << endl;
00529 
00530       cpp << "  QStringList default" << name << ";" << endl;
00531       const QStringList defaults = defaultValue.split(QLatin1Char(','));
00532       QStringList::ConstIterator it;
00533       for( it = defaults.constBegin(); it != defaults.constEnd(); ++it ) {
00534         cpp << "  default" << name << ".append( ";
00535         if( type == "UrlList" ) {
00536           cpp << "KUrl(";
00537         }
00538         cpp << "QString::fromUtf8( \"" << *it << "\" ) ";
00539         if( type == QLatin1String("UrlList") ) {
00540           cpp << ") ";
00541         }
00542         cpp << ");" << endl;
00543       }
00544       defaultValue = QString::fromLatin1("default") + name;
00545 
00546     } else if ( type == QLatin1String("Color") && !defaultValue.isEmpty() ) {
00547       QRegExp colorRe(QLatin1String("\\d+,\\s*\\d+,\\s*\\d+(,\\s*\\d+)?"));
00548       if (colorRe.exactMatch(defaultValue))
00549       {
00550         defaultValue = QLatin1String("QColor( ") + defaultValue + QLatin1String(" )");
00551       }
00552       else
00553       {
00554         defaultValue = QLatin1String("QColor( \"") + defaultValue + QLatin1String("\" )");
00555       }
00556 
00557     } else if ( type == QLatin1String("Enum") ) {
00558       QList<CfgEntry::Choice>::ConstIterator it;
00559       for( it = choices.choices.constBegin(); it != choices.choices.constEnd(); ++it ) {
00560         if ( (*it).name == defaultValue ) {
00561           if ( cfg.globalEnums && choices.name().isEmpty() )
00562             defaultValue.prepend( choices.prefix );
00563           else
00564             defaultValue.prepend( enumTypeQualifier(name, choices) + choices.prefix );
00565           break;
00566         }
00567       }
00568 
00569     } else if ( type == QLatin1String("IntList") ) {
00570       QTextStream cpp( &code, QIODevice::WriteOnly | QIODevice::Append );
00571       if (!code.isEmpty())
00572          cpp << endl;
00573 
00574       cpp << "  QList<int> default" << name << ";" << endl;
00575       if (!defaultValue.isEmpty())
00576       {
00577         const QStringList defaults = defaultValue.split( QLatin1Char(',') );
00578         QStringList::ConstIterator it;
00579         for( it = defaults.constBegin(); it != defaults.constEnd(); ++it ) {
00580           cpp << "  default" << name << ".append( " << *it << " );"
00581               << endl;
00582         }
00583       }
00584       defaultValue = QString::fromLatin1("default") + name;
00585     }
00586 }
00587 
00588 
00589 CfgEntry *parseEntry( const QString &group, const QDomElement &element, const CfgConfig &cfg )
00590 {
00591   bool defaultCode = false;
00592   QString type = element.attribute( "type" );
00593   QString name = element.attribute( "name" );
00594   QString key = element.attribute( "key" );
00595   QString hidden = element.attribute( "hidden" );
00596   QString context = element.attribute( "context" );
00597   QString label;
00598   QString toolTip;
00599   QString whatsThis;
00600   QString defaultValue;
00601   QString code;
00602   QString param;
00603   QString paramName;
00604   QString paramType;
00605   CfgEntry::Choices choices;
00606   QList<Signal> signalList;
00607   QStringList paramValues;
00608   QStringList paramDefaultValues;
00609   QString minValue;
00610   QString maxValue;
00611   int paramMax = 0;
00612 
00613   for ( QDomElement e = element.firstChildElement(); !e.isNull(); e = e.nextSiblingElement() ) {
00614     QString tag = e.tagName();
00615     if ( tag == "label" ) {
00616       label = e.text();
00617       context = e.attribute( "context" );
00618     }
00619     else if ( tag == "tooltip" ) {
00620       toolTip = e.text();
00621       context = e.attribute( "context" );
00622     }
00623     else if ( tag == "whatsthis" ) {
00624       whatsThis = e.text();
00625       context = e.attribute( "context" );
00626     }
00627     else if ( tag == "min" ) minValue = e.text();
00628     else if ( tag == "max" ) maxValue = e.text();
00629     else if ( tag == "code" ) code = e.text();
00630     else if ( tag == "parameter" )
00631     {
00632       param = e.attribute( "name" );
00633       paramType = e.attribute( "type" );
00634       if ( param.isEmpty() ) {
00635         cerr << "Parameter must have a name: " << dumpNode(e) << endl;
00636         return 0;
00637       }
00638       if ( paramType.isEmpty() ) {
00639         cerr << "Parameter must have a type: " << dumpNode(e) << endl;
00640         return 0;
00641       }
00642       if ((paramType == "Int") || (paramType == "UInt"))
00643       {
00644          bool ok;
00645          paramMax = e.attribute("max").toInt(&ok);
00646          if (!ok)
00647          {
00648            cerr << "Integer parameter must have a maximum (e.g. max=\"0\"): "
00649                        << dumpNode(e) << endl;
00650            return 0;
00651          }
00652       }
00653       else if (paramType == "Enum")
00654       {
00655          for ( QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement() ) {
00656            if (e2.tagName() == "values")
00657            {
00658              for ( QDomElement e3 = e2.firstChildElement(); !e3.isNull(); e3 = e3.nextSiblingElement() ) {
00659                if (e3.tagName() == "value")
00660                {
00661                   paramValues.append( e3.text() );
00662                }
00663              }
00664              break;
00665            }
00666          }
00667          if (paramValues.isEmpty())
00668          {
00669            cerr << "No values specified for parameter '" << param
00670                        << "'." << endl;
00671            return 0;
00672          }
00673          paramMax = paramValues.count()-1;
00674       }
00675       else
00676       {
00677         cerr << "Parameter '" << param << "' has type " << paramType
00678                     << " but must be of type int, uint or Enum." << endl;
00679         return 0;
00680       }
00681     }
00682     else if ( tag == "default" )
00683     {
00684       if (e.attribute("param").isEmpty())
00685       {
00686         defaultValue = e.text();
00687         if (e.attribute( "code" ) == "true")
00688           defaultCode = true;
00689       }
00690     }
00691     else if ( tag == "choices" ) {
00692       QString name = e.attribute( "name" );
00693       QString prefix = e.attribute( "prefix" );
00694       QList<CfgEntry::Choice> chlist;
00695       for( QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement() ) {
00696         if ( e2.tagName() == "choice" ) {
00697           CfgEntry::Choice choice;
00698           choice.name = e2.attribute( "name" );
00699           if ( choice.name.isEmpty() ) {
00700             cerr << "Tag <choice> requires attribute 'name'." << endl;
00701           }
00702           for( QDomElement e3 = e2.firstChildElement(); !e3.isNull(); e3 = e3.nextSiblingElement() ) {
00703             if ( e3.tagName() == "label" ) {
00704               choice.label = e3.text();
00705               choice.context = e3.attribute( "context" );
00706             }
00707             if ( e3.tagName() == "tooltip" ) {
00708               choice.toolTip = e3.text();
00709               choice.context = e3.attribute( "context" );
00710             }
00711             if ( e3.tagName() == "whatsthis" ) {
00712               choice.whatsThis = e3.text();
00713               choice.context = e3.attribute( "context" );
00714             }
00715           }
00716           chlist.append( choice );
00717         }
00718       }
00719       choices = CfgEntry::Choices( chlist, name, prefix );
00720     }
00721    else if ( tag == "emit" ) {
00722     QDomNode signalNode;
00723     Signal signal;
00724     signal.name = e.attribute( "signal" );
00725     signalList.append( signal);
00726    }
00727   }
00728 
00729 
00730   bool nameIsEmpty = name.isEmpty();
00731   if ( nameIsEmpty && key.isEmpty() ) {
00732     cerr << "Entry must have a name or a key: " << dumpNode(element) << endl;
00733     return 0;
00734   }
00735 
00736   if ( key.isEmpty() ) {
00737     key = name;
00738   }
00739 
00740   if ( nameIsEmpty ) {
00741     name = key;
00742     name.remove( ' ' );
00743   } else if ( name.contains( ' ' ) ) {
00744     cout<<"Entry '"<<name<<"' contains spaces! <name> elements can not contain spaces!"<<endl;
00745     name.remove( ' ' );
00746   }
00747 
00748   if (name.contains("$("))
00749   {
00750     if (param.isEmpty())
00751     {
00752       cerr << "Name may not be parameterized: " << name << endl;
00753       return 0;
00754     }
00755   }
00756   else
00757   {
00758     if (!param.isEmpty())
00759     {
00760       cerr << "Name must contain '$(" << param << ")': " << name << endl;
00761       return 0;
00762     }
00763   }
00764 
00765   if ( label.isEmpty() ) {
00766     label = key;
00767   }
00768 
00769   if ( type.isEmpty() ) type = "String"; // XXX : implicit type might be bad
00770 
00771   if (!param.isEmpty())
00772   {
00773     // Adjust name
00774     paramName = name;
00775     name.remove("$("+param+')');
00776     // Lookup defaults for indexed entries
00777     for(int i = 0; i <= paramMax; i++)
00778     {
00779       paramDefaultValues.append(QString());
00780     }
00781 
00782     for ( QDomElement e = element.firstChildElement(); !e.isNull(); e = e.nextSiblingElement() ) {
00783       QString tag = e.tagName();
00784       if ( tag == "default" )
00785       {
00786         QString index = e.attribute("param");
00787         if (index.isEmpty())
00788            continue;
00789 
00790         bool ok;
00791         int i = index.toInt(&ok);
00792         if (!ok)
00793         {
00794           i = paramValues.indexOf(index);
00795           if (i == -1)
00796           {
00797             cerr << "Index '" << index << "' for default value is unknown." << endl;
00798             return 0;
00799           }
00800         }
00801 
00802         if ((i < 0) || (i > paramMax))
00803         {
00804           cerr << "Index '" << i << "' for default value is out of range [0, "<< paramMax<<"]." << endl;
00805           return 0;
00806         }
00807 
00808         QString tmpDefaultValue = e.text();
00809 
00810         if (e.attribute( "code" ) != "true")
00811            preProcessDefault(tmpDefaultValue, name, type, choices, code, cfg);
00812 
00813         paramDefaultValues[i] = tmpDefaultValue;
00814       }
00815     }
00816   }
00817 
00818   if (!validNameRegexp->exactMatch(name))
00819   {
00820     if (nameIsEmpty)
00821       cerr << "The key '" << key << "' can not be used as name for the entry because "
00822                    "it is not a valid name. You need to specify a valid name for this entry." << endl;
00823     else
00824       cerr << "The name '" << name << "' is not a valid name for an entry." << endl;
00825     return 0;
00826   }
00827 
00828   if (allNames.contains(name))
00829   {
00830     if (nameIsEmpty)
00831       cerr << "The key '" << key << "' can not be used as name for the entry because "
00832                    "it does not result in a unique name. You need to specify a unique name for this entry." << endl;
00833     else
00834       cerr << "The name '" << name << "' is not unique." << endl;
00835     return 0;
00836   }
00837   allNames.append(name);
00838 
00839   if (!defaultCode)
00840   {
00841     preProcessDefault(defaultValue, name, type, choices, code, cfg);
00842   }
00843 
00844   CfgEntry *result = new CfgEntry( group, type, key, name, context, label, toolTip, whatsThis,
00845                                    code, defaultValue, choices, signalList,
00846                                    hidden == "true" );
00847   if (!param.isEmpty())
00848   {
00849     result->setParam(param);
00850     result->setParamName(paramName);
00851     result->setParamType(paramType);
00852     result->setParamValues(paramValues);
00853     result->setParamDefaultValues(paramDefaultValues);
00854     result->setParamMax(paramMax);
00855   }
00856   result->setMinValue(minValue);
00857   result->setMaxValue(maxValue);
00858 
00859   return result;
00860 }
00861 
00862 static bool isUnsigned(const QString& type)
00863 {
00864     if ( type == "UInt" )        return true;
00865     if ( type == "ULongLong" )   return true;
00866     return false;
00867 }
00868 
00872 QString param( const QString &t )
00873 {
00874     const QString type = t.toLower();
00875     if ( type == "string" )           return "const QString &";
00876     else if ( type == "stringlist" )  return "const QStringList &";
00877     else if ( type == "font" )        return "const QFont &";
00878     else if ( type == "rect" )        return "const QRect &";
00879     else if ( type == "size" )        return "const QSize &";
00880     else if ( type == "color" )       return "const QColor &";
00881     else if ( type == "point" )       return "const QPoint &";
00882     else if ( type == "int" )         return "int";
00883     else if ( type == "uint" )        return "uint";
00884     else if ( type == "bool" )        return "bool";
00885     else if ( type == "double" )      return "double";
00886     else if ( type == "datetime" )    return "const QDateTime &";
00887     else if ( type == "longlong" )    return "qint64";
00888     else if ( type == "ulonglong" )   return "quint64";
00889     else if ( type == "intlist" )     return "const QList<int> &";
00890     else if ( type == "enum" )        return "int";
00891     else if ( type == "path" )        return "const QString &";
00892     else if ( type == "pathlist" )    return "const QStringList &";
00893     else if ( type == "password" )    return "const QString &";
00894     else if ( type == "url" )         return "const KUrl &";
00895     else if ( type == "urllist" )     return "const KUrl::List &";
00896     else {
00897         cerr <<"kconfig_compiler does not support type \""<< type <<"\""<<endl;
00898         return "QString"; //For now, but an assert would be better
00899     }
00900 }
00901 
00905 QString cppType( const QString &t )
00906 {
00907     const QString type = t.toLower();
00908     if ( type == "string" )           return "QString";
00909     else if ( type == "stringlist" )  return "QStringList";
00910     else if ( type == "font" )        return "QFont";
00911     else if ( type == "rect" )        return "QRect";
00912     else if ( type == "size" )        return "QSize";
00913     else if ( type == "color" )       return "QColor";
00914     else if ( type == "point" )       return "QPoint";
00915     else if ( type == "int" )         return "int";
00916     else if ( type == "uint" )        return "uint";
00917     else if ( type == "bool" )        return "bool";
00918     else if ( type == "double" )      return "double";
00919     else if ( type == "datetime" )    return "QDateTime";
00920     else if ( type == "longlong" )    return "qint64";
00921     else if ( type == "ulonglong" )   return "quint64";
00922     else if ( type == "intlist" )     return "QList<int>";
00923     else if ( type == "enum" )        return "int";
00924     else if ( type == "path" )        return "QString";
00925     else if ( type == "pathlist" )    return "QStringList";
00926     else if ( type == "password" )    return "QString";
00927     else if ( type == "url" )         return "KUrl";
00928     else if ( type == "urllist" )     return "KUrl::List";
00929     else {
00930         cerr<<"kconfig_compiler does not support type \""<< type <<"\""<<endl;
00931         return "QString"; //For now, but an assert would be better
00932     }
00933 }
00934 
00935 QString defaultValue( const QString &t )
00936 {
00937     const QString type = t.toLower();
00938     if ( type == "string" )           return "\"\""; // Use empty string, not null string!
00939     else if ( type == "stringlist" )  return "QStringList()";
00940     else if ( type == "font" )        return "QFont()";
00941     else if ( type == "rect" )        return "QRect()";
00942     else if ( type == "size" )        return "QSize()";
00943     else if ( type == "color" )       return "QColor(128, 128, 128)";
00944     else if ( type == "point" )       return "QPoint()";
00945     else if ( type == "int" )         return "0";
00946     else if ( type == "uint" )        return "0";
00947     else if ( type == "bool" )        return "false";
00948     else if ( type == "double" )      return "0.0";
00949     else if ( type == "datedime" )    return "QDateTime()";
00950     else if ( type == "longlong" )    return "0";
00951     else if ( type == "ulonglong" )   return "0";
00952     else if ( type == "intlist" )     return "QList<int>()";
00953     else if ( type == "enum" )        return "0";
00954     else if ( type == "path" )        return "\"\""; // Use empty string, not null string!
00955     else if ( type == "pathlist" )    return "QStringList()";
00956     else if ( type == "password" )    return "\"\""; // Use empty string, not null string!
00957     else if ( type == "url" )         return "KUrl()";
00958     else if ( type == "urllist" )     return "KUrl::List()";
00959     else {
00960         cerr<<"Error, kconfig_compiler does not support the \""<< type <<"\" type!"<<endl;
00961         return "QString"; //For now, but an assert would be better
00962     }
00963 }
00964 
00965 QString itemType( const QString &type )
00966 {
00967   QString t;
00968 
00969   t = type;
00970   t.replace( 0, 1, t.left( 1 ).toUpper() );
00971 
00972   return t;
00973 }
00974 
00975 static QString itemDeclaration(const CfgEntry *e, const CfgConfig &cfg)
00976 {
00977   if (cfg.itemAccessors)
00978      return QString();
00979 
00980   QString fCap = e->name();
00981   fCap[0] = fCap[0].toUpper();
00982   return "  "+cfg.inherits+"::Item"+itemType( e->type() ) +
00983          "  *item" + fCap +
00984          ( (!e->param().isEmpty())?(QString("[%1]").arg(e->paramMax()+1)) : QString()) +
00985          ";\n";
00986 }
00987 
00988 // returns the name of an item variable
00989 // use itemPath to know the full path
00990 // like using d-> in case of dpointer
00991 static QString itemVar(const CfgEntry *e, const CfgConfig &cfg)
00992 {
00993   QString result;
00994   if (cfg.itemAccessors)
00995   {
00996     if ( !cfg.dpointer )
00997     {
00998       result = 'm' + e->name() + "Item";
00999       result[1] = result[1].toUpper();
01000     }
01001     else
01002     {
01003       result = e->name() + "Item";
01004       result[0] = result[0].toLower();
01005     }
01006   }
01007   else
01008   {
01009     result = "item" + e->name();
01010     result[4] = result[4].toUpper();
01011   }
01012   return result;
01013 }
01014 
01015 static QString itemPath(const CfgEntry *e, const CfgConfig &cfg)
01016 {
01017   QString result;
01018   if ( cfg.dpointer ) {
01019     result = "d->"+itemVar(e, cfg);
01020   }
01021   else {
01022     result = itemVar(e, cfg);
01023   }
01024   return result;
01025 }
01026 
01027 QString newItem( const QString &type, const QString &name, const QString &key,
01028                  const QString &defaultValue, const CfgConfig &cfg, const QString &param = QString())
01029 {
01030   QString t = "new "+cfg.inherits+"::Item" + itemType( type ) +
01031               "( currentGroup(), " + key + ", " + varPath( name, cfg ) + param;
01032   if ( type == "Enum" ) t += ", values" + name;
01033   if ( !defaultValue.isEmpty() ) {
01034     t += ", ";
01035     if ( type == "String" ) t += defaultValue;
01036     else t+= defaultValue;
01037   }
01038   t += " );";
01039 
01040   return t;
01041 }
01042 
01043 QString paramString(const QString &s, const CfgEntry *e, int i)
01044 {
01045   QString result = s;
01046   QString needle = "$("+e->param()+')';
01047   if (result.contains(needle))
01048   {
01049     QString tmp;
01050     if (e->paramType() == "Enum")
01051     {
01052       tmp = e->paramValues()[i];
01053     }
01054     else
01055     {
01056       tmp = QString::number(i);
01057     }
01058 
01059     result.replace(needle, tmp);
01060   }
01061   return result;
01062 }
01063 
01064 QString paramString(const QString &group, const QList<Param> &parameters)
01065 {
01066   QString paramString = group;
01067   QString arguments;
01068   int i = 1;
01069   for (QList<Param>::ConstIterator it = parameters.constBegin();
01070        it != parameters.constEnd(); ++it)
01071   {
01072      if (paramString.contains("$("+(*it).name+')'))
01073      {
01074        QString tmp;
01075        tmp.sprintf("%%%d", i++);
01076        paramString.replace("$("+(*it).name+')', tmp);
01077        arguments += ".arg( mParam"+(*it).name+" )";
01078      }
01079   }
01080   if (arguments.isEmpty())
01081     return "QLatin1String( \""+group+"\" )";
01082 
01083   return "QString( QLatin1String( \""+paramString+"\" ) )"+arguments;
01084 }
01085 
01086 /* int i is the value of the parameter */
01087 QString userTextsFunctions( CfgEntry *e, const CfgConfig &cfg, QString itemVarStr=QString(), QString i=QString() )
01088 {
01089   QString txt;
01090   if (itemVarStr.isNull()) itemVarStr=itemPath(e, cfg);
01091   if ( !e->label().isEmpty() ) {
01092     txt += "  " + itemVarStr + "->setLabel( ";
01093     if ( !e->context().isEmpty() )
01094       txt += "i18nc(" + quoteString(e->context()) + ", ";
01095     else
01096       txt += "i18n(";
01097     if ( !e->param().isEmpty() )
01098       txt += quoteString(e->label().replace("$("+e->param()+')', i));
01099     else
01100       txt+= quoteString(e->label());
01101     txt+= ") );\n";
01102   }
01103   if ( !e->toolTip().isEmpty() ) {
01104     txt += "  " + itemVarStr + "->setToolTip( ";
01105     if ( !e->context().isEmpty() )
01106       txt += "i18nc(" + quoteString(e->context()) + ", ";
01107     else
01108       txt += "i18n(";
01109     if ( !e->param().isEmpty() )
01110       txt += quoteString(e->toolTip().replace("$("+e->param()+')', i));
01111     else
01112       txt+= quoteString(e->toolTip());
01113     txt+=") );\n";
01114   }
01115   if ( !e->whatsThis().isEmpty() ) {
01116     txt += "  " + itemVarStr + "->setWhatsThis( ";
01117     if ( !e->context().isEmpty() )
01118       txt += "i18nc(" + quoteString(e->context()) + ", ";
01119     else
01120       txt += "i18n(";
01121     if ( !e->param().isEmpty() )
01122       txt += quoteString(e->whatsThis().replace("$("+e->param()+')', i));
01123     else
01124       txt+= quoteString(e->whatsThis());
01125     txt+=") );\n";
01126   }
01127   return txt;
01128 }
01129 
01130 // returns the member accesor implementation
01131 // which should go in the h file if inline
01132 // or the cpp file if not inline
01133 QString memberAccessorBody( CfgEntry *e, bool globalEnums, const CfgConfig &cfg )
01134 {
01135     QString result;
01136     QTextStream out(&result, QIODevice::WriteOnly);
01137     QString n = e->name();
01138     QString t = e->type();
01139     bool useEnumType = cfg.useEnumTypes && t == "Enum";
01140 
01141     out << "return ";
01142     if (useEnumType)
01143       out << "static_cast<" << enumType(e, globalEnums) << ">(";
01144     out << This << varPath(n, cfg);
01145     if (!e->param().isEmpty())
01146       out << "[i]";
01147     if (useEnumType)
01148       out << ")";
01149     out << ";" << endl;
01150 
01151     return result;
01152 }
01153 
01154 // returns the member mutator implementation
01155 // which should go in the h file if inline
01156 // or the cpp file if not inline
01157 QString memberMutatorBody( CfgEntry *e, const CfgConfig &cfg )
01158 {
01159   QString result;
01160   QTextStream out(&result, QIODevice::WriteOnly);
01161   QString n = e->name();
01162   QString t = e->type();
01163 
01164   if (!e->minValue().isEmpty())
01165   {
01166     if (e->minValue() != "0" || !isUnsigned(t)) { // skip writing "if uint<0" (#187579)
01167       out << "if (v < " << e->minValue() << ")" << endl;
01168       out << "{" << endl;
01169       out << "  kDebug() << \"" << setFunction(n);
01170       out << ": value \" << v << \" is less than the minimum value of ";
01171       out << e->minValue()<< "\";" << endl;
01172       out << "  v = " << e->minValue() << ";" << endl;
01173       out << "}" << endl;
01174     }
01175   }
01176 
01177   if (!e->maxValue().isEmpty())
01178   {
01179     out << endl << "if (v > " << e->maxValue() << ")" << endl;
01180     out << "{" << endl;
01181     out << "  kDebug() << \"" << setFunction(n);
01182     out << ": value \" << v << \" is greater than the maximum value of ";
01183     out << e->maxValue()<< "\";" << endl;
01184     out << "  v = " << e->maxValue() << ";" << endl;
01185     out << "}" << endl << endl;
01186   }
01187 
01188   out << "if (!" << This << "isImmutable( QString::fromLatin1( \"";
01189   if (!e->param().isEmpty())
01190   {
01191     out << e->paramName().replace("$("+e->param()+")", "%1") << "\" ).arg( ";
01192     if ( e->paramType() == "Enum" ) {
01193       out << "QLatin1String( ";
01194 
01195       if (cfg.globalEnums)
01196         out << enumName(e->param()) << "ToString[i]";
01197       else
01198         out << enumName(e->param()) << "::enumToString[i]";
01199 
01200         out << " )";
01201     }
01202     else
01203     {
01204       out << "i";
01205     }
01206     out << " )";
01207   }
01208   else
01209   {
01210     out << n << "\" )";
01211   }
01212   out << " ))" << (!e->signalList().empty() ? " {" : "") << endl;
01213   out << "  " << This << varPath(n, cfg);
01214   if (!e->param().isEmpty())
01215     out << "[i]";
01216   out << " = v;" << endl;
01217 
01218   if ( !e->signalList().empty() ) {
01219     foreach(const Signal &signal, e->signalList()) {
01220       out << "  " << This << varPath("settingsChanged", cfg) << " |= " << signalEnumName(signal.name) << ";" << endl;
01221     }
01222     out << "}" << endl;
01223   }
01224 
01225   return result;
01226 }
01227 
01228 // returns the member get default implementation
01229 // which should go in the h file if inline
01230 // or the cpp file if not inline
01231 QString memberGetDefaultBody( CfgEntry *e )
01232 {
01233   QString result = e->code();
01234   QTextStream out(&result, QIODevice::WriteOnly);
01235   out << endl;
01236 
01237   if (!e->param().isEmpty()) {
01238     out << "  switch (i) {" << endl;
01239     for (int i = 0; i <= e->paramMax(); ++i) {
01240       if (!e->paramDefaultValue(i).isEmpty()) {
01241         out << "  case " << i << ": return " << e->paramDefaultValue(i) << ';' << endl;
01242       }
01243     }
01244     out << "  default:" << endl;
01245     out << "    return " << e->defaultValue().replace("$("+e->param()+')', "i") << ';' << endl;
01246     out << "  }" << endl;
01247   } else {
01248     out << "  return " << e->defaultValue() << ';';
01249   }
01250 
01251   return result;
01252 }
01253 
01254 // returns the item accesor implementation
01255 // which should go in the h file if inline
01256 // or the cpp file if not inline
01257 QString itemAccessorBody( CfgEntry *e, const CfgConfig &cfg )
01258 {
01259     QString result;
01260     QTextStream out(&result, QIODevice::WriteOnly);
01261 
01262     out << "return " << itemPath(e, cfg);
01263     if (!e->param().isEmpty()) out << "[i]";
01264     out << ";" << endl;
01265 
01266     return result;
01267 }
01268 
01269 //indents text adding X spaces per line
01270 QString indent(QString text, int spaces)
01271 {
01272     QString result;
01273     QTextStream out(&result, QIODevice::WriteOnly);
01274     QTextStream in(&text, QIODevice::ReadOnly);
01275     QString currLine;
01276     while ( !in.atEnd() )
01277     {
01278       currLine = in.readLine();
01279       if (!currLine.isEmpty())
01280         for (int i=0; i < spaces; i++)
01281           out << " ";
01282       out << currLine << endl;
01283     }
01284     return result;
01285 }
01286 
01287 // adds as many 'namespace foo {' lines to p_out as
01288 // there are namespaces in p_ns
01289 void beginNamespaces(const QString &p_ns, QTextStream &p_out)
01290 {
01291   if ( !p_ns.isEmpty() ) {
01292     const QStringList nameSpaces = p_ns.split( "::" );
01293     foreach (const QString &ns, nameSpaces )
01294       p_out << "namespace " << ns << " {" << endl;
01295     p_out << endl;
01296   }
01297 }
01298 
01299 // adds as many '}' lines to p_out as
01300 // there are namespaces in p_ns
01301 void endNamespaces(const QString &p_ns, QTextStream &p_out)
01302 {
01303   if ( !p_ns.isEmpty() ) {
01304     const int namespaceCount = p_ns.count( "::" ) + 1;
01305     for ( int i = 0; i < namespaceCount; ++i )
01306       p_out << "}" << endl;
01307     p_out << endl;
01308   }
01309 }
01310 
01311 
01312 int main( int argc, char **argv )
01313 {
01314   QCoreApplication app(argc, argv);
01315 
01316   validNameRegexp = new QRegExp("[a-zA-Z_][a-zA-Z0-9_]*");
01317 
01318   QString directoryName, inputFilename, codegenFilename;
01319   parseArgs(app.arguments(), directoryName, inputFilename, codegenFilename);
01320 
01321   QString baseDir = directoryName;
01322 #ifdef Q_OS_WIN
01323   if (!baseDir.endsWith('/') && !baseDir.endsWith('\\'))
01324 #else
01325   if (!baseDir.endsWith('/'))
01326 #endif
01327     baseDir.append("/");
01328 
01329   if (!codegenFilename.endsWith(".kcfgc"))
01330   {
01331     cerr << "Codegen options file must have extension .kcfgc" << endl;
01332     return 1;
01333   }
01334   QString baseName = QFileInfo(codegenFilename).fileName();
01335   baseName = baseName.left(baseName.length() - 6);
01336 
01337   CfgConfig cfg = CfgConfig( codegenFilename );
01338 
01339   QFile input( inputFilename );
01340 
01341   QDomDocument doc;
01342   QString errorMsg;
01343   int errorRow;
01344   int errorCol;
01345   if ( !doc.setContent( &input, &errorMsg, &errorRow, &errorCol ) ) {
01346     cerr << "Unable to load document." << endl;
01347     cerr << "Parse error in " << inputFilename << ", line " << errorRow << ", col " << errorCol << ": " << errorMsg << endl;
01348     return 1;
01349   }
01350 
01351   QDomElement cfgElement = doc.documentElement();
01352 
01353   if ( cfgElement.isNull() ) {
01354     cerr << "No document in kcfg file" << endl;
01355     return 1;
01356   }
01357 
01358   QString cfgFileName;
01359   bool cfgFileNameArg = false;
01360   QList<Param> parameters;
01361   QList<Signal> signalList;
01362   QStringList includes;
01363   bool hasSignals = false;
01364 
01365   QList<CfgEntry*> entries;
01366 
01367   for ( QDomElement e = cfgElement.firstChildElement(); !e.isNull(); e = e.nextSiblingElement() ) {
01368     QString tag = e.tagName();
01369 
01370     if ( tag == "include" ) {
01371       QString includeFile = e.text();
01372       if (!includeFile.isEmpty())
01373         includes.append(includeFile);
01374 
01375     } else if ( tag == "kcfgfile" ) {
01376       cfgFileName = e.attribute( "name" );
01377       cfgFileNameArg = e.attribute( "arg" ).toLower() == "true";
01378       for( QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement() ) {
01379         if ( e2.tagName() == "parameter" ) {
01380           Param p;
01381           p.name = e2.attribute( "name" );
01382           p.type = e2.attribute( "type" );
01383           if (p.type.isEmpty())
01384              p.type = "String";
01385           parameters.append( p );
01386         }
01387       }
01388 
01389     } else if ( tag == "group" ) {
01390       QString group = e.attribute( "name" );
01391       if ( group.isEmpty() ) {
01392         cerr << "Group without name" << endl;
01393         return 1;
01394       }
01395       for( QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement() ) {
01396         if ( e2.tagName() != "entry" ) continue;
01397         CfgEntry *entry = parseEntry( group, e2, cfg );
01398         if ( entry ) entries.append( entry );
01399         else {
01400           cerr << "Can not parse entry." << endl;
01401           return 1;
01402         }
01403       }
01404     }
01405     else if ( tag == "signal" ) {
01406       QString signalName = e.attribute( "name" );
01407       if ( signalName.isEmpty() ) {
01408         cerr << "Signal without name." << endl;
01409         return 1;
01410       }
01411       Signal theSignal;
01412       theSignal.name = signalName;
01413 
01414       for( QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement() ) {
01415         if ( e2.tagName() == "argument") {
01416           SignalArguments argument;
01417           argument.type = e2.attribute("type");
01418           if ( argument.type.isEmpty() ) {
01419             cerr << "Signal argument without type." << endl;
01420             return 1;
01421           }
01422           argument.variableName = e2.text();
01423           theSignal.arguments.append(argument);
01424         }
01425         else if( e2.tagName() == "label") {
01426           theSignal.label = e2.text();
01427         }
01428       }
01429       signalList.append(theSignal);
01430     }
01431   }
01432 
01433   if ( cfg.className.isEmpty() ) {
01434     cerr << "Class name missing" << endl;
01435     return 1;
01436   }
01437 
01438   if ( cfg.singleton && !parameters.isEmpty() ) {
01439     cerr << "Singleton class can not have parameters" << endl;
01440     return 1;
01441   }
01442 
01443   if ( !cfgFileName.isEmpty() && cfgFileNameArg)
01444   {
01445     cerr << "Having both a fixed filename and a filename as argument is not possible." << endl;
01446     return 1;
01447   }
01448 
01449   if ( entries.isEmpty() ) {
01450     cerr << "No entries." << endl;
01451   }
01452 
01453 #if 0
01454   CfgEntry *cfg;
01455   for( cfg = entries.first(); cfg; cfg = entries.next() ) {
01456     cfg->dump();
01457   }
01458 #endif
01459 
01460   hasSignals = !signalList.empty();
01461   QString headerFileName = baseName + ".h";
01462   QString implementationFileName = baseName + ".cpp";
01463   QString mocFileName = baseName + ".moc";
01464   QString cppPreamble; // code to be inserted at the beginnin of the cpp file, e.g. initialization of static values
01465 
01466   QFile header( baseDir + headerFileName );
01467   if ( !header.open( QIODevice::WriteOnly ) ) {
01468     cerr << "Can not open '" << baseDir  << headerFileName << "for writing." << endl;
01469     return 1;
01470   }
01471 
01472   QTextStream h( &header );
01473 
01474   h << "// This file is generated by kconfig_compiler from " << QFileInfo(inputFilename).fileName() << "." << endl;
01475   h << "// All changes you do to this file will be lost." << endl;
01476 
01477   h << "#ifndef " << ( !cfg.nameSpace.isEmpty() ? QString (QString(cfg.nameSpace).replace( "::", "_" ).toUpper() + '_') : "" )
01478     << cfg.className.toUpper() << "_H" << endl;
01479   h << "#define " << ( !cfg.nameSpace.isEmpty() ? QString (QString(cfg.nameSpace).replace( "::", "_" ).toUpper() + '_') : "" )
01480     << cfg.className.toUpper() << "_H" << endl << endl;
01481 
01482   // Includes
01483   QStringList::ConstIterator it;
01484   for( it = cfg.headerIncludes.constBegin(); it != cfg.headerIncludes.constEnd(); ++it ) {
01485     if ( (*it).startsWith('"') )
01486       h << "#include " << *it << endl;
01487     else
01488       h << "#include <" << *it << ">" << endl;
01489   }
01490 
01491   if ( cfg.headerIncludes.count() > 0 ) h << endl;
01492 
01493   if ( !cfg.singleton && parameters.isEmpty() )
01494     h << "#include <kglobal.h>" << endl;
01495 
01496   if ( cfg.inherits=="KCoreConfigSkeleton" ) {
01497     h << "#include <kcoreconfigskeleton.h>" << endl;
01498   } else {
01499     h << "#include <kconfigskeleton.h>" << endl;
01500   }
01501 
01502   h << "#include <kdebug.h>" << endl << endl;
01503 
01504   // Includes
01505   for( it = includes.constBegin(); it != includes.constEnd(); ++it ) {
01506     if ( (*it).startsWith('"') )
01507       h << "#include " << *it << endl;
01508     else
01509       h << "#include <" << *it << ">" << endl;
01510   }
01511 
01512   beginNamespaces(cfg.nameSpace, h);
01513 
01514   // Private class declaration
01515   if ( cfg.dpointer )
01516     h << "class " << cfg.className << "Private;" << endl << endl;
01517 
01518   // Class declaration header
01519   h << "class " << cfg.visibility << cfg.className << " : public " << cfg.inherits << endl;
01520 
01521   h << "{" << endl;
01522   // Add Q_OBJECT macro if the config need signals.
01523   if( hasSignals )
01524    h << "  Q_OBJECT" << endl;
01525   h << "  public:" << endl;
01526 
01527   // enums
01528   QList<CfgEntry*>::ConstIterator itEntry;
01529   for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) {
01530     const CfgEntry::Choices &choices = (*itEntry)->choices();
01531     const QList<CfgEntry::Choice> chlist = choices.choices;
01532     if ( !chlist.isEmpty() ) {
01533       QStringList values;
01534       QList<CfgEntry::Choice>::ConstIterator itChoice;
01535       for( itChoice = chlist.constBegin(); itChoice != chlist.constEnd(); ++itChoice ) {
01536         values.append( choices.prefix + (*itChoice).name );
01537       }
01538       if ( choices.name().isEmpty() ) {
01539         if ( cfg.globalEnums ) {
01540           h << "    enum " << enumName( (*itEntry)->name(), (*itEntry)->choices() ) << " { " << values.join( ", " ) << " };" << endl;
01541         } else {
01542           // Create an automatically named enum
01543           h << "    class " << enumName( (*itEntry)->name(), (*itEntry)->choices() ) << endl;
01544           h << "    {" << endl;
01545           h << "      public:" << endl;
01546           h << "      enum type { " << values.join( ", " ) << ", COUNT };" << endl;
01547           h << "    };" << endl;
01548         }
01549       } else if ( !choices.external() ) {
01550         // Create a named enum
01551         h << "    enum " << enumName( (*itEntry)->name(), (*itEntry)->choices() ) << " { " << values.join( ", " ) << " };" << endl;
01552       }
01553     }
01554     const QStringList values = (*itEntry)->paramValues();
01555     if ( !values.isEmpty() ) {
01556       if ( cfg.globalEnums ) {
01557         // ### FIXME!!
01558         // make the following string table an index-based string search!
01559         // ###
01560         h << "    enum " << enumName( (*itEntry)->param() ) << " { " << values.join( ", " ) << " };" << endl;
01561         h << "    static const char* const " << enumName( (*itEntry)->param() ) << "ToString[];" << endl;
01562         cppPreamble += "const char* const " + cfg.className + "::" + enumName( (*itEntry)->param() ) +
01563            "ToString[] = { \"" + values.join( "\", \"" ) + "\" };\n";
01564       } else {
01565         h << "    class " << enumName( (*itEntry)->param() ) << endl;
01566         h << "    {" << endl;
01567         h << "      public:" << endl;
01568         h << "      enum type { " << values.join( ", " ) << ", COUNT };" << endl;
01569         h << "      static const char* const enumToString[];" << endl;
01570         h << "    };" << endl;
01571         cppPreamble += "const char* const " + cfg.className + "::" + enumName( (*itEntry)->param() ) +
01572            "::enumToString[] = { \"" + values.join( "\", \"" ) + "\" };\n";
01573       }
01574     }
01575   }
01576   if ( hasSignals ) {
01577    h << "\n    enum {" << endl;
01578    unsigned val = 1;
01579    QList<Signal>::ConstIterator it, itEnd = signalList.constEnd();
01580    for ( it = signalList.constBegin(); it != itEnd; val <<= 1) {
01581      if ( !val ) {
01582        cerr << "Too many signals to create unique bit masks" << endl;
01583        exit(1);
01584      }
01585      Signal signal = *it;
01586      h << "      " << signalEnumName(signal.name) << " = 0x" << hex << val;
01587      if ( ++it != itEnd )
01588       h << ",";
01589      h << endl;
01590    }
01591    h << " };" << dec << endl;
01592   }
01593   h << endl;
01594   // Constructor or singleton accessor
01595   if ( !cfg.singleton ) {
01596     h << "    " << cfg.className << "(";
01597     if (cfgFileNameArg)
01598     {
01599         if(cfg.forceStringFilename)
01600             h << " const QString &cfgfilename"
01601                 << (parameters.isEmpty() ? " = QString()" : ", ");
01602         else
01603             h << " KSharedConfig::Ptr config"
01604                 << (parameters.isEmpty() ? " = KGlobal::config()" : ", ");
01605     }
01606     for (QList<Param>::ConstIterator it = parameters.constBegin();
01607          it != parameters.constEnd(); ++it)
01608     {
01609        if (it != parameters.constBegin())
01610          h << ",";
01611        h << " " << param((*it).type) << " " << (*it).name;
01612     }
01613     h << " );" << endl;
01614   } else {
01615     h << "    static " << cfg.className << " *self();" << endl;
01616     if (cfgFileNameArg)
01617     {
01618       h << "    static void instance(const QString& cfgfilename);" << endl;
01619     }
01620   }
01621 
01622   // Destructor
01623   h << "    ~" << cfg.className << "();" << endl << endl;
01624 
01625   // global variables
01626   if (cfg.staticAccessors)
01627     This = "self()->";
01628   else
01629     Const = " const";
01630 
01631   for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) {
01632     QString n = (*itEntry)->name();
01633     QString t = (*itEntry)->type();
01634 
01635     // Manipulator
01636     if (cfg.allMutators || cfg.mutators.contains(n))
01637     {
01638       h << "    /**" << endl;
01639       h << "      Set " << (*itEntry)->label() << endl;
01640       h << "    */" << endl;
01641       if (cfg.staticAccessors)
01642         h << "    static" << endl;
01643       h << "    void " << setFunction(n) << "( ";
01644       if (!(*itEntry)->param().isEmpty())
01645         h << cppType((*itEntry)->paramType()) << " i, ";
01646       if (cfg.useEnumTypes && t == "Enum")
01647         h << enumType(*itEntry, cfg.globalEnums);
01648       else
01649         h << param( t );
01650       h << " v )";
01651       // function body inline only if not using dpointer
01652       // for BC mode
01653       if ( !cfg.dpointer )
01654       {
01655         h << endl << "    {" << endl;
01656         h << indent(memberMutatorBody(*itEntry, cfg), 6 );
01657         h << "    }" << endl;
01658       }
01659       else
01660       {
01661         h << ";" << endl;
01662       }
01663     }
01664     h << endl;
01665     // Accessor
01666     h << "    /**" << endl;
01667     h << "      Get " << (*itEntry)->label() << endl;
01668     h << "    */" << endl;
01669     if (cfg.staticAccessors)
01670       h << "    static" << endl;
01671     h << "    ";
01672     if (cfg.useEnumTypes && t == "Enum")
01673       h << enumType(*itEntry, cfg.globalEnums);
01674     else
01675       h << cppType(t);
01676     h << " " << getFunction(n) << "(";
01677     if (!(*itEntry)->param().isEmpty())
01678       h << " " << cppType((*itEntry)->paramType()) <<" i ";
01679     h << ")" << Const;
01680     // function body inline only if not using dpointer
01681     // for BC mode
01682     if ( !cfg.dpointer )
01683     {
01684        h << endl << "    {" << endl;
01685       h << indent(memberAccessorBody(*itEntry, cfg.globalEnums, cfg), 6 );
01686        h << "    }" << endl;
01687     }
01688     else
01689     {
01690       h << ";" << endl;
01691     }
01692 
01693     // Default value Accessor
01694     if ((cfg.allDefaultGetters || cfg.defaultGetters.contains(n)) && !(*itEntry)->defaultValue().isEmpty()) {
01695       h << endl;
01696       h << "    /**" << endl;
01697       h << "      Get " << (*itEntry)->label() << " default value" << endl;
01698       h << "    */" << endl;
01699       if (cfg.staticAccessors)
01700         h << "    static" << endl;
01701       h << "    ";
01702       if (cfg.useEnumTypes && t == "Enum")
01703         h << enumType(*itEntry, cfg.globalEnums);
01704       else
01705         h << cppType(t);
01706       h << " " << getDefaultFunction(n) << "(";
01707       if ( !(*itEntry)->param().isEmpty() )
01708           h << " " << cppType( (*itEntry)->paramType() ) <<" i ";
01709       h << ")" << Const << endl;
01710       h << "    {" << endl;
01711       h << "        return ";
01712       if (cfg.useEnumTypes && t == "Enum")
01713         h << "static_cast<" << enumType(*itEntry, cfg.globalEnums) << ">(";
01714       h << getDefaultFunction(n) << "_helper(";
01715       if ( !(*itEntry)->param().isEmpty() )
01716           h << " i ";
01717       h << ")";
01718       if (cfg.useEnumTypes && t == "Enum")
01719         h << ")";
01720       h << ";" << endl;
01721       h << "    }" << endl;
01722     }
01723 
01724     // Item accessor
01725     if ( cfg.itemAccessors ) {
01726       h << endl;
01727       h << "    /**" << endl;
01728       h << "      Get Item object corresponding to " << n << "()"
01729         << endl;
01730       h << "    */" << endl;
01731       h << "    Item" << itemType( (*itEntry)->type() ) << " *"
01732         << getFunction( n ) << "Item(";
01733       if (!(*itEntry)->param().isEmpty()) {
01734         h << " " << cppType((*itEntry)->paramType()) << " i ";
01735       }
01736       h << ")";
01737       if ( !cfg.dpointer )
01738       {
01739         h << endl << "    {" << endl;
01740         h << indent( itemAccessorBody((*itEntry), cfg), 6);
01741         h << "    }" << endl;
01742       }
01743       else
01744       {
01745         h << ";" << endl;
01746       }
01747     }
01748 
01749     h << endl;
01750   }
01751 
01752 
01753   // Signal definition.
01754   if( hasSignals ) {
01755     h << endl;
01756     h << "  Q_SIGNALS:";
01757     foreach(const Signal &signal, signalList) {
01758       h << endl;
01759       if ( !signal.label.isEmpty() ) {
01760         h << "    /**" << endl;
01761         h << "      " << signal.label << endl;
01762         h << "    */" << endl;
01763       }
01764       h << "    void " << signal.name << "(";
01765       QList<SignalArguments>::ConstIterator it, itEnd = signal.arguments.constEnd();
01766       for ( it = signal.arguments.constBegin(); it != itEnd; ) {
01767         SignalArguments argument = *it;
01768         QString type = param(argument.type);
01769         if ( cfg.useEnumTypes && argument.type == "Enum" ) {
01770           for ( int i = 0, end = entries.count(); i < end; ++i ) {
01771             if ( entries[i]->name() == argument.variableName ) {
01772               type = enumType(entries[i], cfg.globalEnums);
01773               break;
01774             }
01775           }
01776         }
01777         h << type << " " << argument.variableName;
01778         if ( ++it != itEnd ) {
01779          h << ", ";
01780         }
01781       }
01782       h << ");" << endl;
01783     }
01784     h << endl;
01785   }
01786 
01787   h << "  protected:" << endl;
01788 
01789   // Private constructor for singleton
01790   if ( cfg.singleton ) {
01791     h << "    " << cfg.className << "(";
01792     if ( cfgFileNameArg )
01793       h << "const QString& arg";
01794     h << ");" << endl;
01795     h << "    friend class " << cfg.className << "Helper;" << endl << endl;
01796   }
01797 
01798   if ( hasSignals ) {
01799     h << "    virtual void usrWriteConfig();" << endl;
01800   }
01801 
01802   // Member variables
01803   if ( !cfg.memberVariables.isEmpty() && cfg.memberVariables != "private" && cfg.memberVariables != "dpointer") {
01804     h << "  " << cfg.memberVariables << ":" << endl;
01805   }
01806 
01807   // Class Parameters
01808   for (QList<Param>::ConstIterator it = parameters.constBegin();
01809        it != parameters.constEnd(); ++it)
01810   {
01811      h << "    " << cppType((*it).type) << " mParam" << (*it).name << ";" << endl;
01812   }
01813 
01814   if ( cfg.memberVariables != "dpointer" )
01815   {
01816     QString group;
01817     for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) {
01818       if ( (*itEntry)->group() != group ) {
01819         group = (*itEntry)->group();
01820         h << endl;
01821         h << "    // " << group << endl;
01822       }
01823       h << "    " << cppType( (*itEntry)->type() ) << " " << varName( (*itEntry)->name(), cfg );
01824       if ( !(*itEntry)->param().isEmpty() )
01825       {
01826         h << QString("[%1]").arg( (*itEntry)->paramMax()+1 );
01827       }
01828       h << ";" << endl;
01829 
01830       if ( cfg.allDefaultGetters || cfg.defaultGetters.contains((*itEntry)->name()) )
01831       {
01832         h << "    ";
01833         if (cfg.staticAccessors)
01834           h << "static ";
01835         h << cppType((*itEntry)->type()) << " " << getDefaultFunction((*itEntry)->name()) << "_helper(";
01836         if ( !(*itEntry)->param().isEmpty() )
01837             h << " " << cppType( (*itEntry)->paramType() ) <<" i ";
01838         h << ")" << Const << ";" << endl;
01839       }
01840     }
01841 
01842     h << endl << "  private:" << endl;
01843     if ( cfg.itemAccessors ) {
01844        for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) {
01845         h << "    Item" << itemType( (*itEntry)->type() ) << " *" << itemVar( *itEntry, cfg );
01846         if ( !(*itEntry)->param().isEmpty() ) h << QString("[%1]").arg( (*itEntry)->paramMax()+1 );
01847         h << ";" << endl;
01848       }
01849     }
01850     if ( hasSignals )
01851      h << "    uint " << varName("settingsChanged", cfg) << ";" << endl;
01852 
01853   }
01854   else
01855   {
01856     // use a private class for both member variables and items
01857     h << "  private:" << endl;
01858     for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) {
01859       if ( cfg.allDefaultGetters || cfg.defaultGetters.contains((*itEntry)->name()) ) {
01860         h << "    ";
01861         if (cfg.staticAccessors)
01862           h << "static ";
01863         h << cppType((*itEntry)->type()) << " " << getDefaultFunction((*itEntry)->name()) << "_helper(";
01864         if ( !(*itEntry)->param().isEmpty() )
01865             h << " " << cppType( (*itEntry)->paramType() ) <<" i ";
01866         h << ")" << Const << ";" << endl;
01867       }
01868     }
01869     h << "    " + cfg.className + "Private *d;" << endl;
01870   }
01871 
01872   if (cfg.customAddons)
01873   {
01874      h << "    // Include custom additions" << endl;
01875      h << "    #include \"" << filenameOnly(baseName) << "_addons.h\"" <<endl;
01876   }
01877 
01878   h << "};" << endl << endl;
01879 
01880   endNamespaces(cfg.nameSpace, h);
01881 
01882   h << "#endif" << endl << endl;
01883 
01884 
01885   header.close();
01886 
01887   QFile implementation( baseDir + implementationFileName );
01888   if ( !implementation.open( QIODevice::WriteOnly ) ) {
01889     cerr << "Can not open '" << implementationFileName << "for writing."
01890               << endl;
01891     return 1;
01892   }
01893 
01894   QTextStream cpp( &implementation );
01895 
01896 
01897   cpp << "// This file is generated by kconfig_compiler from " << QFileInfo(inputFilename).fileName() << "." << endl;
01898   cpp << "// All changes you do to this file will be lost." << endl << endl;
01899 
01900   cpp << "#include \"" << headerFileName << "\"" << endl << endl;
01901 
01902   for( it = cfg.sourceIncludes.constBegin(); it != cfg.sourceIncludes.constEnd(); ++it ) {
01903     if ( (*it).startsWith('"') )
01904       cpp << "#include " << *it << endl;
01905     else
01906       cpp << "#include <" << *it << ">" << endl;
01907   }
01908 
01909   if ( cfg.sourceIncludes.count() > 0 ) cpp << endl;
01910 
01911   if ( cfg.setUserTexts ) cpp << "#include <klocale.h>" << endl << endl;
01912 
01913   // Header required by singleton implementation
01914   if ( cfg.singleton )
01915     cpp << "#include <kglobal.h>" << endl << "#include <QtCore/QFile>" << endl << endl;
01916   if ( cfg.singleton && cfgFileNameArg )
01917     cpp << "#include <kdebug.h>" << endl << endl;
01918 
01919   if ( !cfg.nameSpace.isEmpty() )
01920     cpp << "using namespace " << cfg.nameSpace << ";" << endl << endl;
01921 
01922   QString group;
01923 
01924   // private class implementation
01925   if ( cfg.dpointer )
01926   {
01927     beginNamespaces(cfg.nameSpace, cpp);
01928     cpp << "class " << cfg.className << "Private" << endl;
01929     cpp << "{" << endl;
01930     cpp << "  public:" << endl;
01931     for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) {
01932       if ( (*itEntry)->group() != group ) {
01933         group = (*itEntry)->group();
01934         cpp << endl;
01935         cpp << "    // " << group << endl;
01936       }
01937       cpp << "    " << cppType( (*itEntry)->type() ) << " " << varName( (*itEntry)->name(), cfg );
01938       if ( !(*itEntry)->param().isEmpty() )
01939       {
01940         cpp << QString("[%1]").arg( (*itEntry)->paramMax()+1 );
01941       }
01942       cpp << ";" << endl;
01943     }
01944     cpp << endl << "    // items" << endl;
01945     for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) {
01946       cpp << "    "+cfg.inherits+"::Item" << itemType( (*itEntry)->type() ) << " *" << itemVar( *itEntry, cfg );
01947       if ( !(*itEntry)->param().isEmpty() ) cpp << QString("[%1]").arg( (*itEntry)->paramMax()+1 );
01948         cpp << ";" << endl;
01949     }
01950     if ( hasSignals ) {
01951       cpp << "    uint " << varName("settingsChanged", cfg) << ";" << endl;
01952     }
01953 
01954     cpp << "};" << endl << endl;
01955     endNamespaces(cfg.nameSpace, cpp);
01956   }
01957 
01958   // Singleton implementation
01959   if ( cfg.singleton ) {
01960     beginNamespaces(cfg.nameSpace, cpp);
01961     cpp << "class " << cfg.className << "Helper" << endl;
01962     cpp << '{' << endl;
01963     cpp << "  public:" << endl;
01964     cpp << "    " << cfg.className << "Helper() : q(0) {}" << endl;
01965     cpp << "    ~" << cfg.className << "Helper() { delete q; }" << endl;
01966     cpp << "    " << cfg.className << " *q;" << endl;
01967     cpp << "};" << endl;
01968     endNamespaces(cfg.nameSpace, cpp);
01969     cpp << "K_GLOBAL_STATIC(" << cfg.className << "Helper, s_global" << cfg.className << ")" << endl;
01970 
01971     cpp << cfg.className << " *" << cfg.className << "::self()" << endl;
01972     cpp << "{" << endl;
01973     if ( cfgFileNameArg ) {
01974       cpp << "  if (!s_global" << cfg.className << "->q)" << endl;
01975       cpp << "     kFatal() << \"you need to call " << cfg.className << "::instance before using\";" << endl;
01976     } else {
01977       cpp << "  if (!s_global" << cfg.className << "->q) {" << endl;
01978       cpp << "    new " << cfg.className << ';' << endl;
01979       cpp << "    s_global" << cfg.className << "->q->readConfig();" << endl;
01980       cpp << "  }" << endl << endl;
01981     }
01982     cpp << "  return s_global" << cfg.className << "->q;" << endl;
01983     cpp << "}" << endl << endl;
01984 
01985     if ( cfgFileNameArg ) {
01986       cpp << "void " << cfg.className << "::instance(const QString& cfgfilename)" << endl;
01987       cpp << "{" << endl;
01988       cpp << "  if (s_global" << cfg.className << "->q) {" << endl;
01989       cpp << "     kDebug() << \"" << cfg.className << "::instance called after the first use - ignoring\";" << endl;
01990       cpp << "     return;" << endl;
01991       cpp << "  }" << endl;
01992       cpp << "  new " << cfg.className << "(cfgfilename);" << endl;
01993       cpp << "  s_global" << cfg.className << "->q->readConfig();" << endl;
01994       cpp << "}" << endl << endl;
01995     }
01996   }
01997 
01998   if ( !cppPreamble.isEmpty() )
01999     cpp << cppPreamble << endl;
02000 
02001   // Constructor
02002   cpp << cfg.className << "::" << cfg.className << "( ";
02003   if ( cfgFileNameArg ) {
02004     if ( !cfg.singleton && ! cfg.forceStringFilename)
02005       cpp << " KSharedConfig::Ptr config";
02006     else
02007       cpp << " const QString& config";
02008     cpp << (parameters.isEmpty() ? " " : ", ");
02009   }
02010 
02011   for (QList<Param>::ConstIterator it = parameters.constBegin();
02012        it != parameters.constEnd(); ++it)
02013   {
02014      if (it != parameters.constBegin())
02015        cpp << ",";
02016      cpp << " " << param((*it).type) << " " << (*it).name;
02017   }
02018   cpp << " )" << endl;
02019 
02020   cpp << "  : " << cfg.inherits << "(";
02021   if ( !cfgFileName.isEmpty() ) cpp << " QLatin1String( \"" << cfgFileName << "\" ";
02022   if ( cfgFileNameArg ) cpp << " config ";
02023   if ( !cfgFileName.isEmpty() ) cpp << ") ";
02024   cpp << ")" << endl;
02025 
02026   // Store parameters
02027   for (QList<Param>::ConstIterator it = parameters.constBegin();
02028        it != parameters.constEnd(); ++it)
02029   {
02030      cpp << "  , mParam" << (*it).name << "(" << (*it).name << ")" << endl;
02031   }
02032 
02033   if ( hasSignals && !cfg.dpointer )
02034     cpp << "  , " << varName("settingsChanged", cfg) << "(0)" << endl;
02035 
02036   cpp << "{" << endl;
02037 
02038   if (cfg.dpointer)
02039   {
02040     cpp << "  d = new " + cfg.className + "Private;" << endl;
02041     if (hasSignals)
02042       cpp << "  " << varPath("settingsChanged", cfg) << " = 0;" << endl;
02043   }
02044   // Needed in case the singleton class is used as baseclass for
02045   // another singleton.
02046   if (cfg.singleton) {
02047     cpp << "  Q_ASSERT(!s_global" << cfg.className << "->q);" << endl;
02048     cpp << "  s_global" << cfg.className << "->q = this;" << endl;
02049   }
02050 
02051   group.clear();
02052 
02053   for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) {
02054     if ( (*itEntry)->group() != group ) {
02055       if ( !group.isEmpty() ) cpp << endl;
02056       group = (*itEntry)->group();
02057       cpp << "  setCurrentGroup( " << paramString(group, parameters) << " );" << endl << endl;
02058     }
02059 
02060     QString key = paramString( (*itEntry)->key(), parameters );
02061     if ( !(*itEntry)->code().isEmpty() ) {
02062       cpp << (*itEntry)->code() << endl;
02063     }
02064     if ( (*itEntry)->type() == "Enum" ) {
02065       cpp << "  QList<"+cfg.inherits+"::ItemEnum::Choice2> values"
02066           << (*itEntry)->name() << ";" << endl;
02067       const QList<CfgEntry::Choice> choices = (*itEntry)->choices().choices;
02068       QList<CfgEntry::Choice>::ConstIterator it;
02069       for( it = choices.constBegin(); it != choices.constEnd(); ++it ) {
02070         cpp << "  {" << endl;
02071         cpp << "    "+cfg.inherits+"::ItemEnum::Choice2 choice;" << endl;
02072         cpp << "    choice.name = QLatin1String(\"" << (*it).name << "\");" << endl;
02073         if ( cfg.setUserTexts ) {
02074           if ( !(*it).label.isEmpty() ) {
02075             cpp << "    choice.label = ";
02076             if ( !(*it).context.isEmpty() )
02077               cpp << "i18nc(" + quoteString((*it).context) + ", ";
02078             else
02079               cpp << "i18n(";
02080             cpp << quoteString((*it).label) << ");" << endl;
02081           }
02082           if ( !(*it).toolTip.isEmpty() ) {
02083             cpp << "    choice.toolTip = ";
02084             if ( !(*it).context.isEmpty() )
02085               cpp << "i18nc(" + quoteString((*it).context) + ", ";
02086             else
02087               cpp << "i18n(";
02088             cpp << quoteString((*it).toolTip) << ");" << endl;
02089           }
02090           if ( !(*it).whatsThis.isEmpty() ) {
02091             cpp << "    choice.whatsThis = ";
02092             if ( !(*it).context.isEmpty() )
02093               cpp << "i18nc(" + quoteString((*it).context) + ", ";
02094             else
02095               cpp << "i18n(";
02096             cpp << quoteString((*it).whatsThis) << ");" << endl;
02097           }
02098         }
02099         cpp << "    values" << (*itEntry)->name() << ".append( choice );" << endl;
02100         cpp << "  }" << endl;
02101       }
02102     }
02103 
02104     if (!cfg.dpointer)
02105       cpp << itemDeclaration( *itEntry, cfg );
02106 
02107     if ( (*itEntry)->param().isEmpty() )
02108     {
02109       // Normal case
02110       cpp << "  " << itemPath( *itEntry, cfg ) << " = "
02111           << newItem( (*itEntry)->type(), (*itEntry)->name(), key, (*itEntry)->defaultValue(), cfg ) << endl;
02112 
02113       if ( !(*itEntry)->minValue().isEmpty() )
02114         cpp << "  " << itemPath( *itEntry, cfg ) << "->setMinValue(" << (*itEntry)->minValue() << ");" << endl;
02115       if ( !(*itEntry)->maxValue().isEmpty() )
02116         cpp << "  " << itemPath( *itEntry, cfg ) << "->setMaxValue(" << (*itEntry)->maxValue() << ");" << endl;
02117 
02118       if ( cfg.setUserTexts )
02119         cpp << userTextsFunctions( (*itEntry), cfg );
02120 
02121       cpp << "  addItem( " << itemPath( *itEntry, cfg );
02122       QString quotedName = (*itEntry)->name();
02123       addQuotes( quotedName );
02124       if ( quotedName != key ) cpp << ", QLatin1String( \"" << (*itEntry)->name() << "\" )";
02125       cpp << " );" << endl;
02126     }
02127     else
02128     {
02129       // Indexed
02130       for(int i = 0; i <= (*itEntry)->paramMax(); i++)
02131       {
02132         QString defaultStr;
02133         QString itemVarStr(itemPath( *itEntry, cfg )+QString("[%1]").arg(i));
02134 
02135         if ( !(*itEntry)->paramDefaultValue(i).isEmpty() )
02136           defaultStr = (*itEntry)->paramDefaultValue(i);
02137         else if ( !(*itEntry)->defaultValue().isEmpty() )
02138           defaultStr = paramString( (*itEntry)->defaultValue(), (*itEntry), i );
02139         else
02140           defaultStr = defaultValue( (*itEntry)->type() );
02141 
02142         cpp << "  " << itemVarStr << " = "
02143             << newItem( (*itEntry)->type(), (*itEntry)->name(), paramString(key, *itEntry, i), defaultStr,cfg,  QString("[%1]").arg(i) )
02144             << endl;
02145 
02146         if ( cfg.setUserTexts )
02147           cpp << userTextsFunctions( *itEntry, cfg, itemVarStr, (*itEntry)->paramName() );
02148 
02149         // Make mutators for enum parameters work by adding them with $(..) replaced by the
02150         // param name. The check for isImmutable in the set* functions doesn't have the param
02151         // name available, just the corresponding enum value (int), so we need to store the
02152         // param names in a separate static list!.
02153         cpp << "  addItem( " << itemVarStr << ", QLatin1String( \"";
02154         if ( (*itEntry)->paramType()=="Enum" )
02155           cpp << (*itEntry)->paramName().replace( "$("+(*itEntry)->param()+')', "%1").arg((*itEntry)->paramValues()[i] );
02156         else
02157           cpp << (*itEntry)->paramName().replace( "$("+(*itEntry)->param()+')', "%1").arg(i);
02158         cpp << "\" ) );" << endl;
02159       }
02160     }
02161   }
02162 
02163   cpp << "}" << endl << endl;
02164 
02165   if (cfg.dpointer)
02166   {
02167     // setters and getters go in Cpp if in dpointer mode
02168     for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) {
02169       QString n = (*itEntry)->name();
02170       QString t = (*itEntry)->type();
02171 
02172       // Manipulator
02173       if (cfg.allMutators || cfg.mutators.contains(n))
02174       {
02175         cpp << "void " << setFunction(n, cfg.className) << "( ";
02176         if ( !(*itEntry)->param().isEmpty() )
02177           cpp << cppType( (*itEntry)->paramType() ) << " i, ";
02178         if (cfg.useEnumTypes && t == "Enum")
02179           cpp << enumType(*itEntry, cfg.globalEnums);
02180         else
02181           cpp << param( t );
02182         cpp << " v )" << endl;
02183         // function body inline only if not using dpointer
02184         // for BC mode
02185         cpp << "{" << endl;
02186         cpp << indent(memberMutatorBody( *itEntry, cfg ), 6);
02187         cpp << "}" << endl << endl;
02188       }
02189 
02190       // Accessor
02191       if (cfg.useEnumTypes && t == "Enum")
02192         cpp << enumType(*itEntry, cfg.globalEnums);
02193       else
02194         cpp << cppType(t);
02195       cpp << " " << getFunction(n, cfg.className) << "(";
02196       if ( !(*itEntry)->param().isEmpty() )
02197         cpp << " " << cppType( (*itEntry)->paramType() ) <<" i ";
02198       cpp << ")" << Const << endl;
02199       // function body inline only if not using dpointer
02200       // for BC mode
02201       cpp << "{" << endl;
02202       cpp << indent(memberAccessorBody( *itEntry, cfg.globalEnums, cfg ), 2);
02203       cpp << "}" << endl << endl;
02204 
02205       // Default value Accessor -- written by the loop below
02206 
02207       // Item accessor
02208       if ( cfg.itemAccessors )
02209       {
02210         cpp << endl;
02211         cpp << cfg.inherits+"::Item" << itemType( (*itEntry)->type() ) << " *"
02212           << getFunction( n, cfg.className ) << "Item(";
02213         if ( !(*itEntry)->param().isEmpty() ) {
02214           cpp << " " << cppType( (*itEntry)->paramType() ) << " i ";
02215         }
02216         cpp << ")" << endl;
02217         cpp << "{" << endl;
02218         cpp << indent(itemAccessorBody( *itEntry, cfg ), 2);
02219         cpp << "}" << endl;
02220       }
02221 
02222       cpp << endl;
02223     }
02224   }
02225 
02226   // default value getters always go in Cpp
02227   for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) {
02228     QString n = (*itEntry)->name();
02229     QString t = (*itEntry)->type();
02230 
02231     // Default value Accessor, as "helper" function
02232     if (( cfg.allDefaultGetters || cfg.defaultGetters.contains(n) ) && !(*itEntry)->defaultValue().isEmpty() ) {
02233       cpp << cppType(t) << " " << getDefaultFunction(n, cfg.className) << "_helper(";
02234       if ( !(*itEntry)->param().isEmpty() )
02235         cpp << " " << cppType( (*itEntry)->paramType() ) <<" i ";
02236       cpp << ")" << Const << endl;
02237       cpp << "{" << endl;
02238       cpp << memberGetDefaultBody(*itEntry) << endl;
02239       cpp << "}" << endl << endl;
02240     }
02241   }
02242 
02243   // Destructor
02244   cpp << cfg.className << "::~" << cfg.className << "()" << endl;
02245   cpp << "{" << endl;
02246   if ( cfg.singleton ) {
02247     if ( cfg.dpointer )
02248       cpp << "  delete d;" << endl;
02249     cpp << "  if (!s_global" << cfg.className << ".isDestroyed()) {" << endl;
02250     cpp << "    s_global" << cfg.className << "->q = 0;" << endl;
02251     cpp << "  }" << endl;
02252   }
02253   cpp << "}" << endl << endl;
02254 
02255   if ( hasSignals ) {
02256     cpp << "void " << cfg.className << "::" << "usrWriteConfig()" << endl;
02257     cpp << "{" << endl;
02258     cpp << "  " << cfg.inherits << "::usrWriteConfig();" << endl << endl;
02259     foreach(const Signal &signal, signalList) {
02260       cpp << "  if ( " << varPath("settingsChanged", cfg) << " & " << signalEnumName(signal.name) << " ) " << endl;
02261       cpp << "    emit " << signal.name << "(";
02262       QList<SignalArguments>::ConstIterator it, itEnd = signal.arguments.constEnd();
02263       for ( it = signal.arguments.constBegin(); it != itEnd; ) {
02264         SignalArguments argument = *it;
02265         bool cast = false;
02266         if ( cfg.useEnumTypes && argument.type == "Enum" ) {
02267           for ( int i = 0, end = entries.count(); i < end; ++i ) {
02268             if ( entries[i]->name() == argument.variableName ) {
02269               cpp << "static_cast<" << enumType(entries[i], cfg.globalEnums) << ">(";
02270               cast = true;
02271               break;
02272             }
02273           }
02274         }
02275         cpp << varPath(argument.variableName, cfg);
02276         if ( cast )
02277           cpp << ")";
02278         if ( ++it != itEnd )
02279           cpp << ", ";
02280       }
02281       cpp << ");" << endl << endl;
02282     }
02283     cpp << "  " << varPath("settingsChanged", cfg) << " = 0;" << endl;
02284     cpp << "}" << endl;
02285   }
02286 
02287   // Add includemoc if they are signals defined.
02288   if( hasSignals ) {
02289     cpp << endl;
02290     cpp << "#include \"" << mocFileName << "\"" << endl;
02291     cpp << endl;
02292   }
02293 
02294   // clear entries list
02295   qDeleteAll( entries );
02296 
02297   implementation.close();
02298 }

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal