• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • 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 
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., 51 Franklin Street, Fifth Floor,
00022     Boston, MA 02110-1301, 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 bool dpointer;
00055 QStringList allNames;
00056 QRegExp *validNameRegexp;
00057 QString This;
00058 QString Const;  
00059 
00060 class CfgEntry
00061 {
00062   public:
00063     struct Choice
00064     {
00065       QString name;
00066       QString label;
00067       QString whatsThis;
00068     };
00069 
00070     CfgEntry( const QString &group, const QString &type, const QString &key,
00071               const QString &name, const QString &label,
00072               const QString &whatsThis, const QString &code,
00073               const QString &defaultValue, const QValueList<Choice> &choices,
00074               bool hidden )
00075       : mGroup( group ), mType( type ), mKey( key ), mName( name ),
00076         mLabel( label ), mWhatsThis( whatsThis ), mCode( code ),
00077         mDefaultValue( defaultValue ),
00078         mChoices( choices ), mHidden( hidden )
00079     {
00080     }
00081 
00082     void setGroup( const QString &group ) { mGroup = group; }
00083     QString group() const { return mGroup; }
00084 
00085     void setType( const QString &type ) { mType = type; }
00086     QString type() const { return mType; }
00087 
00088     void setKey( const QString &key ) { mKey = key; }
00089     QString key() const { return mKey; }
00090 
00091     void setName( const QString &name ) { mName = name; }
00092     QString name() const { return mName; }
00093 
00094     void setLabel( const QString &label ) { mLabel = label; }
00095     QString label() const { return mLabel; }
00096 
00097     void setWhatsThis( const QString &whatsThis ) { mWhatsThis = whatsThis; }
00098     QString whatsThis() const { return mWhatsThis; }
00099 
00100     void setDefaultValue( const QString &d ) { mDefaultValue = d; }
00101     QString defaultValue() const { return mDefaultValue; }
00102 
00103     void setCode( const QString &d ) { mCode = d; }
00104     QString code() const { return mCode; }
00105 
00106     void setMinValue( const QString &d ) { mMin = d; }
00107     QString minValue() const { return mMin; }
00108 
00109     void setMaxValue( const QString &d ) { mMax = d; }
00110     QString maxValue() const { return mMax; }
00111 
00112     void setParam( const QString &d ) { mParam = d; }
00113     QString param() const { return mParam; }
00114 
00115     void setParamName( const QString &d ) { mParamName = d; }
00116     QString paramName() const { return mParamName; }
00117 
00118     void setParamType( const QString &d ) { mParamType = d; }
00119     QString paramType() const { return mParamType; }
00120 
00121     void setChoices( const QValueList<Choice> &d ) { mChoices = d; }
00122     QValueList<Choice> choices() const { return mChoices; }
00123 
00124     void setParamValues( const QStringList &d ) { mParamValues = d; }
00125     QStringList paramValues() const { return mParamValues; }
00126 
00127     void setParamDefaultValues( const QStringList &d ) { mParamDefaultValues = d; }
00128     QString paramDefaultValue(int i) const { return mParamDefaultValues[i]; }
00129 
00130     void setParamMax( int d ) { mParamMax = d; }
00131     int paramMax() const { return mParamMax; }
00132 
00133     bool hidden() const { return mHidden; }
00134 
00135     void dump() const
00136     {
00137       kdDebug() << "<entry>" << endl;
00138       kdDebug() << "  group: " << mGroup << endl;
00139       kdDebug() << "  type: " << mType << endl;
00140       kdDebug() << "  key: " << mKey << endl;
00141       kdDebug() << "  name: " << mName << endl;
00142       kdDebug() << "  label: " << mLabel << endl;
00143 // whatsthis
00144       kdDebug() << "  code: " << mCode << endl;
00145 //      kdDebug() << "  values: " << mValues.join(":") << endl;
00146 
00147       if (!param().isEmpty())
00148       {
00149         kdDebug() << "  param name: "<< mParamName << endl;
00150         kdDebug() << "  param type: "<< mParamType << endl;
00151         kdDebug() << "  paramvalues: " << mParamValues.join(":") << endl;
00152       }
00153       kdDebug() << "  default: " << mDefaultValue << endl;
00154       kdDebug() << "  hidden: " << mHidden << endl;
00155       kdDebug() << "  min: " << mMin << endl;
00156       kdDebug() << "  max: " << mMax << endl;
00157       kdDebug() << "</entry>" << endl;
00158     }
00159 
00160   private:
00161     QString mGroup;
00162     QString mType;
00163     QString mKey;
00164     QString mName;
00165     QString mLabel;
00166     QString mWhatsThis;
00167     QString mCode;
00168     QString mDefaultValue;
00169     QString mParam;
00170     QString mParamName;
00171     QString mParamType;
00172     QValueList<Choice> mChoices;
00173     QStringList mParamValues;
00174     QStringList mParamDefaultValues;
00175     int mParamMax;
00176     bool mHidden;
00177     QString mMin;
00178     QString mMax;
00179 };
00180 
00181 class Param {
00182 public:
00183   QString name;
00184   QString type;
00185 };
00186 
00187 // returns the name of an member variable
00188 // use itemPath to know the full path
00189 // like using d-> in case of dpointer
00190 static QString varName(const QString &n)
00191 {
00192   QString result;
00193   if ( !dpointer ) {
00194     result = "m"+n;
00195     result[1] = result[1].upper();
00196   }
00197   else {
00198     result = n;
00199     result[0] = result[0].lower();
00200   }
00201   return result;
00202 }
00203 
00204 static QString varPath(const QString &n)
00205 {
00206   QString result;
00207   if ( dpointer ) {
00208     result = "d->"+varName(n);
00209   }
00210   else {
00211     result = varName(n);
00212   }
00213   return result;
00214 }
00215 
00216 static QString enumName(const QString &n)
00217 {
00218   QString result = "Enum"+n;
00219   result[4] = result[4].upper();
00220   return result;
00221 }
00222 
00223 static QString setFunction(const QString &n, const QString &className = QString::null)
00224 {
00225   QString result = "set"+n;
00226   result[3] = result[3].upper();
00227 
00228   if ( !className.isEmpty() )
00229     result = className + "::" + result;
00230   return result;
00231 }
00232 
00233 
00234 static QString getFunction(const QString &n, const QString &className = QString::null)
00235 {
00236   QString result = n;
00237   result[0] = result[0].lower();
00238 
00239   if ( !className.isEmpty() )
00240     result = className + "::" + result;
00241   return result;
00242 }
00243 
00244 
00245 static void addQuotes( QString &s )
00246 {
00247   if ( s.left( 1 ) != "\"" ) s.prepend( "\"" );
00248   if ( s.right( 1 ) != "\"" ) s.append( "\"" );
00249 }
00250 
00251 static QString quoteString( const QString &s )
00252 {
00253   QString r = s;
00254   r.replace( "\\", "\\\\" );
00255   r.replace( "\"", "\\\"" );
00256   r.replace( "\r", "" );
00257   r.replace( "\n", "\\n\"\n\"" );
00258   return "\"" + r + "\"";
00259 }
00260 
00261 static QString literalString( const QString &s )
00262 {
00263   bool isAscii = true;
00264   for(int i = s.length(); i--;)
00265      if (s[i].unicode() > 127) isAscii = false;
00266 
00267   if (isAscii)
00268      return "QString::fromLatin1( " + quoteString(s) + " )";
00269   else
00270      return "QString::fromUtf8( " + quoteString(s) + " )";
00271 }
00272 
00273 static QString dumpNode(const QDomNode &node)
00274 {
00275   QString msg;
00276   QTextStream s(&msg, IO_WriteOnly );
00277   node.save(s, 0);
00278 
00279   msg = msg.simplifyWhiteSpace();
00280   if (msg.length() > 40)
00281     return msg.left(37)+"...";
00282   return msg;
00283 }
00284 
00285 static QString filenameOnly(QString path)
00286 {
00287    int i = path.findRev('/');
00288    if (i >= 0)
00289       return path.mid(i+1);
00290    return path;
00291 }
00292 
00293 static void preProcessDefault( QString &defaultValue, const QString &name,
00294                                const QString &type,
00295                                const QValueList<CfgEntry::Choice> &choices,
00296                                QString &code )
00297 {
00298     if ( type == "String" && !defaultValue.isEmpty() ) {
00299       defaultValue = literalString(defaultValue);
00300 
00301     } else if ( type == "Path" && !defaultValue.isEmpty() ) {
00302       defaultValue = literalString( defaultValue );
00303 
00304     } else if ( (type == "StringList" || type == "PathList") && !defaultValue.isEmpty() ) {
00305       QTextStream cpp( &code, IO_WriteOnly | IO_Append );
00306       if (!code.isEmpty())
00307          cpp << endl;
00308 
00309       cpp << "  QStringList default" << name << ";" << endl;
00310       QStringList defaults = QStringList::split( ",", defaultValue );
00311       QStringList::ConstIterator it;
00312       for( it = defaults.begin(); it != defaults.end(); ++it ) {
00313         cpp << "  default" << name << ".append( QString::fromUtf8( \"" << *it << "\" ) );"
00314             << endl;
00315       }
00316       defaultValue = "default" + name;
00317 
00318     } else if ( type == "Color" && !defaultValue.isEmpty() ) {
00319       QRegExp colorRe("\\d+,\\s*\\d+,\\s*\\d+");
00320       if (colorRe.exactMatch(defaultValue))
00321       {
00322         defaultValue = "QColor( " + defaultValue + " )";
00323       }
00324       else
00325       {
00326         defaultValue = "QColor( \"" + defaultValue + "\" )";
00327       }
00328 
00329     } else if ( type == "Enum" ) {
00330       if ( !globalEnums ) {
00331         QValueList<CfgEntry::Choice>::ConstIterator it;
00332         for( it = choices.begin(); it != choices.end(); ++it ) {
00333           if ( (*it).name == defaultValue ) {
00334             defaultValue.prepend( enumName(name) + "::");
00335             break;
00336           }
00337         }
00338       }
00339 
00340     } else if ( type == "IntList" ) {
00341       QTextStream cpp( &code, IO_WriteOnly | IO_Append );
00342       if (!code.isEmpty())
00343          cpp << endl;
00344 
00345       cpp << "  QValueList<int> default" << name << ";" << endl;
00346       QStringList defaults = QStringList::split( ",", defaultValue );
00347       QStringList::ConstIterator it;
00348       for( it = defaults.begin(); it != defaults.end(); ++it ) {
00349         cpp << "  default" << name << ".append( " << *it << " );"
00350             << endl;
00351       }
00352       defaultValue = "default" + name;
00353     }
00354 }
00355 
00356 
00357 CfgEntry *parseEntry( const QString &group, const QDomElement &element )
00358 {
00359   bool defaultCode = false;
00360   QString type = element.attribute( "type" );
00361   QString name = element.attribute( "name" );
00362   QString key = element.attribute( "key" );
00363   QString hidden = element.attribute( "hidden" );
00364   QString label;
00365   QString whatsThis;
00366   QString defaultValue;
00367   QString code;
00368   QString param;
00369   QString paramName;
00370   QString paramType;
00371   QValueList<CfgEntry::Choice> choices;
00372   QStringList paramValues;
00373   QStringList paramDefaultValues;
00374   QString minValue;
00375   QString maxValue;
00376   int paramMax = 0;
00377 
00378   QDomNode n;
00379   for ( n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
00380     QDomElement e = n.toElement();
00381     QString tag = e.tagName();
00382     if ( tag == "label" ) label = e.text();
00383     else if ( tag == "whatsthis" ) whatsThis = e.text();
00384     else if ( tag == "min" ) minValue = e.text();
00385     else if ( tag == "max" ) maxValue = e.text();
00386     else if ( tag == "code" ) code = e.text();
00387     else if ( tag == "parameter" )
00388     {
00389       param = e.attribute( "name" );
00390       paramType = e.attribute( "type" );
00391       if ( param.isEmpty() ) {
00392         kdError() << "Parameter must have a name: " << dumpNode(e) << endl;
00393         return 0;
00394       }
00395       if ( paramType.isEmpty() ) {
00396         kdError() << "Parameter must have a type: " << dumpNode(e) << endl;
00397         return 0;
00398       }
00399       if ((paramType == "Int") || (paramType == "UInt"))
00400       {
00401          bool ok;
00402          paramMax = e.attribute("max").toInt(&ok);
00403          if (!ok)
00404          {
00405            kdError() << "Integer parameter must have a maximum (e.g. max=\"0\"): " << dumpNode(e) << endl;
00406            return 0;
00407          }
00408       }
00409       else if (paramType == "Enum")
00410       {
00411          QDomNode n2;
00412          for ( n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) {
00413            QDomElement e2 = n2.toElement();
00414            if (e2.tagName() == "values")
00415            {
00416              QDomNode n3;
00417              for ( n3 = e2.firstChild(); !n3.isNull(); n3 = n3.nextSibling() ) {
00418                QDomElement e3 = n3.toElement();
00419                if (e3.tagName() == "value")
00420                {
00421                   paramValues.append( e3.text() );
00422                }
00423              }
00424              break;
00425            }
00426          }
00427          if (paramValues.isEmpty())
00428          {
00429            kdError() << "No values specified for parameter '" << param << "'." << endl;
00430            return 0;
00431          }
00432          paramMax = paramValues.count()-1;
00433       }
00434       else
00435       {
00436         kdError() << "Parameter '" << param << "' has type " << paramType << " but must be of type int, uint or Enum." << endl;
00437         return 0;
00438       }
00439     }
00440     else if ( tag == "default" )
00441     {
00442       if (e.attribute("param").isEmpty())
00443       {
00444         defaultValue = e.text();
00445         if (e.attribute( "code" ) == "true")
00446           defaultCode = true;
00447       }
00448     }
00449     else if ( tag == "choices" ) {
00450       QDomNode n2;
00451       for( n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) {
00452         QDomElement e2 = n2.toElement();
00453         if ( e2.tagName() == "choice" ) {
00454           QDomNode n3;
00455           CfgEntry::Choice choice;
00456           choice.name = e2.attribute( "name" );
00457           if ( choice.name.isEmpty() ) {
00458             kdError() << "Tag <choice> requires attribute 'name'." << endl;
00459           }
00460           for( n3 = e2.firstChild(); !n3.isNull(); n3 = n3.nextSibling() ) {
00461             QDomElement e3 = n3.toElement();
00462             if ( e3.tagName() == "label" ) choice.label = e3.text();
00463             if ( e3.tagName() == "whatsthis" ) choice.whatsThis = e3.text();
00464           }
00465           choices.append( choice );
00466         }
00467       }
00468     }
00469   }
00470 
00471   bool nameIsEmpty = name.isEmpty();
00472   if ( nameIsEmpty && key.isEmpty() ) {
00473     kdError() << "Entry must have a name or a key: " << dumpNode(element) << endl;
00474     return 0;
00475   }
00476 
00477   if ( key.isEmpty() ) {
00478     key = name;
00479   }
00480 
00481   if ( nameIsEmpty ) {
00482     name = key;
00483     name.replace( " ", QString::null );
00484   } else if ( name.contains( ' ' ) ) {
00485     kdWarning()<<"Entry '"<<name<<"' contains spaces! <name> elements can't contain speces!"<<endl;
00486     name.remove( ' ' );
00487   }
00488 
00489   if (name.contains("$("))
00490   {
00491     if (param.isEmpty())
00492     {
00493       kdError() << "Name may not be parameterized: " << name << endl;
00494       return 0;
00495     }
00496   }
00497   else
00498   {
00499     if (!param.isEmpty())
00500     {
00501       kdError() << "Name must contain '$(" << param << ")': " << name << endl;
00502       return 0;
00503     }
00504   }
00505 
00506   if ( label.isEmpty() ) {
00507     label = key;
00508   }
00509 
00510   if ( type.isEmpty() ) type = "String"; // XXX : implicit type might be bad
00511 
00512   if (!param.isEmpty())
00513   {
00514     // Adjust name
00515     paramName = name;
00516     name.replace("$("+param+")", QString::null);
00517     // Lookup defaults for indexed entries
00518     for(int i = 0; i <= paramMax; i++)
00519     {
00520       paramDefaultValues.append(QString::null);
00521     }
00522 
00523     QDomNode n;
00524     for ( n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
00525       QDomElement e = n.toElement();
00526       QString tag = e.tagName();
00527       if ( tag == "default" )
00528       {
00529         QString index = e.attribute("param");
00530         if (index.isEmpty())
00531            continue;
00532 
00533         bool ok;
00534         int i = index.toInt(&ok);
00535         if (!ok)
00536         {
00537           i = paramValues.findIndex(index);
00538           if (i == -1)
00539           {
00540             kdError() << "Index '" << index << "' for default value is unknown." << endl;
00541             return 0;
00542           }
00543         }
00544 
00545         if ((i < 0) || (i > paramMax))
00546         {
00547           kdError() << "Index '" << i << "' for default value is out of range [0, "<< paramMax<<"]." << endl;
00548           return 0;
00549         }
00550 
00551         QString tmpDefaultValue = e.text();
00552 
00553         if (e.attribute( "code" ) != "true")
00554            preProcessDefault(tmpDefaultValue, name, type, choices, code);
00555 
00556         paramDefaultValues[i] = tmpDefaultValue;
00557       }
00558     }
00559   }
00560 
00561   if (!validNameRegexp->exactMatch(name))
00562   {
00563     if (nameIsEmpty)
00564       kdError() << "The key '" << key << "' can not be used as name for the entry because "
00565                    "it is not a valid name. You need to specify a valid name for this entry." << endl;
00566     else
00567       kdError() << "The name '" << name << "' is not a valid name for an entry." << endl;
00568     return 0;
00569   }
00570 
00571   if (allNames.contains(name))
00572   {
00573     if (nameIsEmpty)
00574       kdError() << "The key '" << key << "' can not be used as name for the entry because "
00575                    "it does not result in a unique name. You need to specify a unique name for this entry." << endl;
00576     else
00577       kdError() << "The name '" << name << "' is not unique." << endl;
00578     return 0;
00579   }
00580   allNames.append(name);
00581 
00582   if (!defaultCode)
00583   {
00584     preProcessDefault(defaultValue, name, type, choices, code);
00585   }
00586 
00587   CfgEntry *result = new CfgEntry( group, type, key, name, label, whatsThis,
00588                                    code, defaultValue, choices,
00589                                    hidden == "true" );
00590   if (!param.isEmpty())
00591   {
00592     result->setParam(param);
00593     result->setParamName(paramName);
00594     result->setParamType(paramType);
00595     result->setParamValues(paramValues);
00596     result->setParamDefaultValues(paramDefaultValues);
00597     result->setParamMax(paramMax);
00598   }
00599   result->setMinValue(minValue);
00600   result->setMaxValue(maxValue);
00601 
00602   return result;
00603 }
00604 
00608 QString param( const QString &type )
00609 {
00610     if ( type == "String" )           return "const QString &";
00611     else if ( type == "StringList" )  return "const QStringList &";
00612     else if ( type == "Font" )        return "const QFont &";
00613     else if ( type == "Rect" )        return "const QRect &";
00614     else if ( type == "Size" )        return "const QSize &";
00615     else if ( type == "Color" )       return "const QColor &";
00616     else if ( type == "Point" )       return "const QPoint &";
00617     else if ( type == "Int" )         return "int";
00618     else if ( type == "UInt" )        return "uint";
00619     else if ( type == "Bool" )        return "bool";
00620     else if ( type == "Double" )      return "double";
00621     else if ( type == "DateTime" )    return "const QDateTime &";
00622     else if ( type == "Int64" )       return "Q_INT64";
00623     else if ( type == "UInt64" )      return "Q_UINT64";
00624     else if ( type == "IntList" )     return "const QValueList<int> &";
00625     else if ( type == "Enum" )        return "int";
00626     else if ( type == "Path" )        return "const QString &";
00627     else if ( type == "PathList" )    return "const QStringList &";
00628     else if ( type == "Password" )    return "const QString &";
00629     else {
00630         kdError() <<"kconfig_compiler does not support type \""<< type <<"\""<<endl;
00631         return "QString"; //For now, but an assert would be better
00632     }
00633 }
00634 
00638 QString cppType( const QString &type )
00639 {
00640     if ( type == "String" )           return "QString";
00641     else if ( type == "StringList" )  return "QStringList";
00642     else if ( type == "Font" )        return "QFont";
00643     else if ( type == "Rect" )        return "QRect";
00644     else if ( type == "Size" )        return "QSize";
00645     else if ( type == "Color" )       return "QColor";
00646     else if ( type == "Point" )       return "QPoint";
00647     else if ( type == "Int" )         return "int";
00648     else if ( type == "UInt" )        return "uint";
00649     else if ( type == "Bool" )        return "bool";
00650     else if ( type == "Double" )      return "double";
00651     else if ( type == "DateTime" )    return "QDateTime";
00652     else if ( type == "Int64" )       return "Q_INT64";
00653     else if ( type == "UInt64" )      return "Q_UINT64";
00654     else if ( type == "IntList" )     return "QValueList<int>";
00655     else if ( type == "Enum" )        return "int";
00656     else if ( type == "Path" )        return "QString";
00657     else if ( type == "PathList" )    return "QStringList";
00658     else if ( type == "Password" )    return "QString";
00659     else {
00660         kdError()<<"kconfig_compiler does not support type \""<< type <<"\""<<endl;
00661         return "QString"; //For now, but an assert would be better
00662     }
00663 }
00664 
00665 QString defaultValue( const QString &type )
00666 {
00667     if ( type == "String" )           return "\"\""; // Use empty string, not null string!
00668     else if ( type == "StringList" )  return "QStringList()";
00669     else if ( type == "Font" )        return "KGlobalSettings::generalFont()";
00670     else if ( type == "Rect" )        return "QRect()";
00671     else if ( type == "Size" )        return "QSize()";
00672     else if ( type == "Color" )       return "QColor(128, 128, 128)";
00673     else if ( type == "Point" )       return "QPoint()";
00674     else if ( type == "Int" )         return "0";
00675     else if ( type == "UInt" )        return "0";
00676     else if ( type == "Bool" )        return "false";
00677     else if ( type == "Double" )      return "0.0";
00678     else if ( type == "DateTime" )    return "QDateTime()";
00679     else if ( type == "Int64" )       return "0";
00680     else if ( type == "UInt64" )      return "0";
00681     else if ( type == "IntList" )     return "QValueList<int>()";
00682     else if ( type == "Enum" )        return "0";
00683     else if ( type == "Path" )        return "\"\""; // Use empty string, not null string!
00684     else if ( type == "PathList" )    return "QStringList()";
00685     else if ( type == "Password" )    return "\"\""; // Use empty string, not null string!
00686     else {
00687         kdWarning()<<"Error, kconfig_compiler doesn't support the \""<< type <<"\" type!"<<endl;
00688         return "QString"; //For now, but an assert would be better
00689     }
00690 }
00691 
00692 QString itemType( const QString &type )
00693 {
00694   QString t;
00695 
00696   t = type;
00697   t.replace( 0, 1, t.left( 1 ).upper() );
00698 
00699   return t;
00700 }
00701 
00702 static QString itemDeclaration(const CfgEntry *e)
00703 {
00704   if (itemAccessors)
00705      return QString::null;
00706 
00707   QString fCap = e->name();
00708   fCap[0] = fCap[0].upper();
00709   return "  KConfigSkeleton::Item"+itemType( e->type() ) +
00710          "  *item" + fCap +
00711          ( (!e->param().isEmpty())?(QString("[%1]").arg(e->paramMax()+1)) : QString::null) +
00712          ";\n";
00713 }
00714 
00715 // returns the name of an item variable
00716 // use itemPath to know the full path
00717 // like using d-> in case of dpointer
00718 static QString itemVar(const CfgEntry *e)
00719 {
00720   QString result;
00721   if (itemAccessors)
00722   {
00723     if ( !dpointer )  
00724     {
00725       result = "m" + e->name() + "Item";
00726       result[1] = result[1].upper();
00727     }
00728     else
00729     {
00730       result = e->name() + "Item";
00731       result[0] = result[0].lower();
00732     }
00733   }
00734   else
00735   {
00736     result = "item" + e->name();
00737     result[4] = result[4].upper();
00738   }
00739   return result;
00740 }
00741 
00742 static QString itemPath(const CfgEntry *e)
00743 {
00744   QString result;
00745   if ( dpointer ) {
00746     result = "d->"+itemVar(e);
00747   }
00748   else {
00749     result = itemVar(e);
00750   }
00751   return result;
00752 }
00753 
00754 QString newItem( const QString &type, const QString &name, const QString &key,
00755                  const QString &defaultValue, const QString &param = QString::null)
00756 {
00757   QString t = "new KConfigSkeleton::Item" + itemType( type ) +
00758               "( currentGroup(), " + key + ", " + varPath( name ) + param;
00759   if ( type == "Enum" ) t += ", values" + name;
00760   if ( !defaultValue.isEmpty() ) {
00761     t += ", ";
00762     if ( type == "String" ) t += defaultValue;
00763     else t+= defaultValue;
00764   }
00765   t += " );";
00766 
00767   return t;
00768 }
00769 
00770 QString paramString(const QString &s, const CfgEntry *e, int i)
00771 {
00772   QString result = s;
00773   QString needle = "$("+e->param()+")";
00774   if (result.contains(needle))
00775   {
00776     QString tmp;
00777     if (e->paramType() == "Enum")
00778     {
00779       tmp = e->paramValues()[i];
00780     }
00781     else
00782     {
00783       tmp = QString::number(i);
00784     }
00785 
00786     result.replace(needle, tmp);
00787   }
00788   return result;
00789 }
00790 
00791 QString paramString(const QString &group, const QValueList<Param> &parameters)
00792 {
00793   QString paramString = group;
00794   QString arguments;
00795   int i = 1;
00796   for (QValueList<Param>::ConstIterator it = parameters.begin();
00797        it != parameters.end(); ++it)
00798   {
00799      if (paramString.contains("$("+(*it).name+")"))
00800      {
00801        QString tmp;
00802        tmp.sprintf("%%%d", i++);
00803        paramString.replace("$("+(*it).name+")", tmp);
00804        arguments += ".arg( mParam"+(*it).name+" )";
00805      }
00806   }
00807   if (arguments.isEmpty())
00808     return "QString::fromLatin1( \""+group+"\" )";
00809 
00810   return "QString::fromLatin1( \""+paramString+"\" )"+arguments;
00811 }
00812 
00813 /* int i is the value of the parameter */
00814 QString userTextsFunctions( CfgEntry *e, QString itemVarStr=QString::null, QString i=QString::null )
00815 {
00816   QString txt;
00817   if (itemVarStr.isNull()) itemVarStr=itemPath(e);
00818   if ( !e->label().isEmpty() ) {
00819     txt += "  " + itemVarStr + "->setLabel( i18n(";
00820     if ( !e->param().isEmpty() )
00821       txt += quoteString(e->label().replace("$("+e->param()+")", i));
00822     else
00823       txt+= quoteString(e->label());
00824     txt+= ") );\n";
00825   }
00826   if ( !e->whatsThis().isEmpty() ) {
00827     txt += "  " + itemVarStr + "->setWhatsThis( i18n(";
00828     if ( !e->param().isEmpty() )
00829       txt += quoteString(e->whatsThis().replace("$("+e->param()+")", i));
00830     else
00831       txt+= quoteString(e->whatsThis());
00832     txt+=") );\n";
00833   }
00834   return txt;
00835 }
00836 
00837 // returns the member accesor implementation
00838 // which should go in the h file if inline
00839 // or the cpp file if not inline
00840 QString memberAccessorBody( CfgEntry *e )
00841 {    
00842     QString result;
00843     QTextStream out(&result, IO_WriteOnly);
00844     QString n = e->name();
00845     QString t = e->type();
00846 
00847     out << "return " << This << varPath(n);
00848     if (!e->param().isEmpty()) out << "[i]";
00849     out << ";" << endl;
00850    
00851     return result;
00852 }
00853 
00854 // returns the member mutator implementation
00855 // which should go in the h file if inline
00856 // or the cpp file if not inline
00857 QString memberMutatorBody( CfgEntry *e )
00858 {
00859   QString result;
00860   QTextStream out(&result, IO_WriteOnly);
00861   QString n = e->name();
00862   QString t = e->type();
00863 
00864   if (!e->minValue().isEmpty())
00865   {
00866     out << "if (v < " << e->minValue() << ")" << endl;
00867     out << "{" << endl;
00868     out << "  kdDebug() << \"" << setFunction(n);
00869     out << ": value \" << v << \" is less than the minimum value of ";
00870     out << e->minValue()<< "\" << endl;" << endl;
00871     out << "  v = " << e->minValue() << ";" << endl;
00872     out << "}" << endl;
00873   }
00874   
00875   if (!e->maxValue().isEmpty())
00876   {
00877     out << endl << "if (v > " << e->maxValue() << ")" << endl;
00878     out << "{" << endl;
00879     out << "  kdDebug() << \"" << setFunction(n);
00880     out << ": value \" << v << \" is greater than the maximum value of ";
00881     out << e->maxValue()<< "\" << endl;" << endl;
00882     out << "  v = " << e->maxValue() << ";" << endl;
00883     out << "}" << endl << endl;
00884   }
00885 
00886   out << "if (!" << This << "isImmutable( QString::fromLatin1( \"";
00887   if (!e->param().isEmpty())
00888   {
00889     out << e->paramName().replace("$("+e->param()+")", "%1") << "\" ).arg( ";
00890     if ( e->paramType() == "Enum" ) {
00891       out << "QString::fromLatin1( ";
00892 
00893       if (globalEnums)
00894         out << enumName(e->param()) << "ToString[i]";
00895       else
00896         out << enumName(e->param()) << "::enumToString[i]";
00897         
00898         out << " )";
00899     }
00900     else
00901     {
00902       out << "i";
00903     }
00904     out << " )";
00905   }
00906   else
00907   {
00908     out << n << "\" )";
00909   }
00910   out << " ))" << endl;
00911   out << "  " << This << varPath(n);
00912   if (!e->param().isEmpty())
00913     out << "[i]";
00914   out << " = v;" << endl;    
00915 
00916   return result;
00917 }
00918 
00919 // returns the item accesor implementation
00920 // which should go in the h file if inline
00921 // or the cpp file if not inline
00922 QString itemAccessorBody( CfgEntry *e )
00923 {    
00924     QString result;
00925     QTextStream out(&result, IO_WriteOnly);
00926 
00927     out << "return " << itemPath(e);
00928     if (!e->param().isEmpty()) out << "[i]";
00929     out << ";" << endl;
00930 
00931     return result;
00932 }
00933 
00934 //indents text adding X spaces per line
00935 QString indent(QString text, int spaces)
00936 {    
00937     QString result;
00938     QTextStream out(&result, IO_WriteOnly);
00939     QTextStream in(&text, IO_ReadOnly);
00940     QString currLine;
00941     while ( !in.atEnd() )
00942     {
00943       currLine = in.readLine();
00944       if (!currLine.isEmpty())
00945         for (int i=0; i < spaces; i++)
00946           out << " ";
00947       out << currLine << endl;
00948     }
00949     return result;
00950 }
00951 
00952 
00953 int main( int argc, char **argv )
00954 {
00955   KAboutData aboutData( "kconfig_compiler", I18N_NOOP("KDE .kcfg compiler"), "0.3",
00956     I18N_NOOP("KConfig Compiler") , KAboutData::License_LGPL );
00957   aboutData.addAuthor( "Cornelius Schumacher", 0, "schumacher@kde.org" );
00958   aboutData.addAuthor( "Waldo Bastian", 0, "bastian@kde.org" );
00959   aboutData.addAuthor( "Zack Rusin", 0, "zack@kde.org" );
00960   aboutData.addCredit( "Reinhold Kainhofer", "Fix for parametrized entries",
00961       "reinhold@kainhofer.com", "http://reinhold.kainhofer.com" );
00962   aboutData.addCredit( "Duncan Mac-Vicar P.", "dpointer support",
00963       "duncan@kde.org", "http://www.mac-vicar.com/~duncan" );
00964 
00965   KCmdLineArgs::init( argc, argv, &aboutData );
00966   KCmdLineArgs::addCmdLineOptions( options );
00967 
00968   KInstance app( &aboutData );
00969 
00970   KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
00971 
00972   if ( args->count() < 2 ) {
00973     kdError() << "Too few arguments." << endl;
00974     return 1;
00975   }
00976   if ( args->count() > 2 ) {
00977     kdError() << "Too many arguments." << endl;
00978     return 1;
00979   }
00980 
00981   validNameRegexp = new QRegExp("[a-zA-Z_][a-zA-Z0-9_]*");
00982 
00983   QString baseDir = QFile::decodeName(args->getOption("directory"));
00984   if (!baseDir.endsWith("/"))
00985     baseDir.append("/");
00986 
00987   QString inputFilename = args->url( 0 ).path();
00988   QString codegenFilename = args->url( 1 ).path();
00989 
00990   if (!codegenFilename.endsWith(".kcfgc"))
00991   {
00992     kdError() << "Codegen options file must have extension .kcfgc" << endl;
00993     return 1;
00994   }
00995   QString baseName = args->url( 1 ).fileName();
00996   baseName = baseName.left(baseName.length() - 6);
00997 
00998   KSimpleConfig codegenConfig( codegenFilename, true );
00999 
01000   QString nameSpace = codegenConfig.readEntry("NameSpace");
01001   QString className = codegenConfig.readEntry("ClassName");
01002   QString inherits = codegenConfig.readEntry("Inherits");
01003   QString visibility = codegenConfig.readEntry("Visibility");
01004   if (!visibility.isEmpty()) visibility+=" ";
01005   bool singleton = codegenConfig.readBoolEntry("Singleton", false);
01006   bool staticAccessors = singleton;
01007   //bool useDPointer = codegenConfig.readBoolEntry("DPointer", false);
01008   bool customAddons = codegenConfig.readBoolEntry("CustomAdditions");
01009   QString memberVariables = codegenConfig.readEntry("MemberVariables");
01010   QStringList headerIncludes = codegenConfig.readListEntry("IncludeFiles");
01011   QStringList mutators = codegenConfig.readListEntry("Mutators");
01012   bool allMutators = false;
01013   if ((mutators.count() == 1) && (mutators[0].lower() == "true"))
01014      allMutators = true;
01015   itemAccessors = codegenConfig.readBoolEntry( "ItemAccessors", false );
01016   bool setUserTexts = codegenConfig.readBoolEntry( "SetUserTexts", false );
01017 
01018   globalEnums = codegenConfig.readBoolEntry( "GlobalEnums", false );
01019 
01020   dpointer = (memberVariables == "dpointer");
01021 
01022   QFile input( inputFilename );
01023 
01024   QDomDocument doc;
01025   QString errorMsg;
01026   int errorRow;
01027   int errorCol;
01028   if ( !doc.setContent( &input, &errorMsg, &errorRow, &errorCol ) ) {
01029     kdError() << "Unable to load document." << endl;
01030     kdError() << "Parse error in " << args->url( 0 ).fileName() << ", line " << errorRow << ", col " << errorCol << ": " << errorMsg << endl;
01031     return 1;
01032   }
01033 
01034   QDomElement cfgElement = doc.documentElement();
01035 
01036   if ( cfgElement.isNull() ) {
01037     kdError() << "No document in kcfg file" << endl;
01038     return 1;
01039   }
01040 
01041   QString cfgFileName;
01042   bool cfgFileNameArg = false;
01043   QValueList<Param> parameters;
01044   QStringList includes;
01045 
01046   QPtrList<CfgEntry> entries;
01047   entries.setAutoDelete( true );
01048 
01049   QDomNode n;
01050   for ( n = cfgElement.firstChild(); !n.isNull(); n = n.nextSibling() ) {
01051     QDomElement e = n.toElement();
01052 
01053     QString tag = e.tagName();
01054 
01055     if ( tag == "include" ) {
01056       QString includeFile = e.text();
01057       if (!includeFile.isEmpty())
01058         includes.append(includeFile);
01059 
01060     } else if ( tag == "kcfgfile" ) {
01061       cfgFileName = e.attribute( "name" );
01062       cfgFileNameArg = e.attribute( "arg" ).lower() == "true";
01063       QDomNode n2;
01064       for( n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) {
01065         QDomElement e2 = n2.toElement();
01066         if ( e2.tagName() == "parameter" ) {
01067           Param p;
01068           p.name = e2.attribute( "name" );
01069           p.type = e2.attribute( "type" );
01070           if (p.type.isEmpty())
01071              p.type = "String";
01072           parameters.append( p );
01073         }
01074       }
01075 
01076     } else if ( tag == "group" ) {
01077       QString group = e.attribute( "name" );
01078       if ( group.isEmpty() ) {
01079         kdError() << "Group without name" << endl;
01080         return 1;
01081       }
01082       QDomNode n2;
01083       for( n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) {
01084         QDomElement e2 = n2.toElement();
01085         if ( e2.tagName() != "entry" ) continue;
01086         CfgEntry *entry = parseEntry( group, e2 );
01087         if ( entry ) entries.append( entry );
01088         else {
01089           kdError() << "Can't parse entry." << endl;
01090           return 1;
01091         }
01092       }
01093     }
01094   }
01095 
01096   if ( inherits.isEmpty() ) inherits = "KConfigSkeleton";
01097 
01098   if ( className.isEmpty() ) {
01099     kdError() << "Class name missing" << endl;
01100     return 1;
01101   }
01102 
01103   if ( singleton && !parameters.isEmpty() ) {
01104     kdError() << "Singleton class can not have parameters" << endl;
01105     return 1;
01106   }
01107 
01108   if ( !cfgFileName.isEmpty() && cfgFileNameArg)
01109   {
01110     kdError() << "Having both a fixed filename and a filename as argument is not possible." << endl;
01111     return 1;
01112   }
01113 
01114   if ( entries.isEmpty() ) {
01115     kdWarning() << "No entries." << endl;
01116   }
01117 
01118 #if 0
01119   CfgEntry *cfg;
01120   for( cfg = entries.first(); cfg; cfg = entries.next() ) {
01121     cfg->dump();
01122   }
01123 #endif
01124 
01125   QString headerFileName = baseName + ".h";
01126   QString implementationFileName = baseName + ".cpp";
01127   QString cppPreamble; // code to be inserted at the beginnin of the cpp file, e.g. initialization of static values
01128 
01129   QFile header( baseDir + headerFileName );
01130   if ( !header.open( IO_WriteOnly ) ) {
01131     kdError() << "Can't open '" << headerFileName << "' for writing." << endl;
01132     return 1;
01133   }
01134 
01135   QTextStream h( &header );
01136 
01137   h << "// This file is generated by kconfig_compiler from " << args->url(0).fileName() << "." << endl;
01138   h << "// All changes you do to this file will be lost." << endl;
01139 
01140   h << "#ifndef " << ( !nameSpace.isEmpty() ? nameSpace.upper() + "_" : "" )
01141     << className.upper() << "_H" << endl;
01142   h << "#define " << ( !nameSpace.isEmpty() ? nameSpace.upper() + "_" : "" )
01143     << className.upper() << "_H" << endl << endl;
01144 
01145   // Includes
01146   QStringList::ConstIterator it;
01147   for( it = headerIncludes.begin(); it != headerIncludes.end(); ++it ) {
01148     h << "#include <" << *it << ">" << endl;
01149   }
01150 
01151   if ( headerIncludes.count() > 0 ) h << endl;
01152 
01153   if ( !singleton && cfgFileNameArg && parameters.isEmpty() )
01154     h << "#include <kglobal.h>" << endl;
01155 
01156   h << "#include <kconfigskeleton.h>" << endl;
01157   h << "#include <kdebug.h>" << endl << endl;
01158 
01159   // Includes
01160   for( it = includes.begin(); it != includes.end(); ++it ) {
01161     h << "#include <" << *it << ">" << endl;
01162   }
01163 
01164 
01165   if ( !nameSpace.isEmpty() )
01166     h << "namespace " << nameSpace << " {" << endl << endl;
01167 
01168   // Private class declaration
01169   if ( dpointer )
01170     h << "class " << className << "Private;" << endl << endl;
01171 
01172   // Class declaration header
01173   h << "class " << visibility << className << " : public " << inherits << endl;
01174   h << "{" << endl;
01175   h << "  public:" << endl;
01176 
01177   // enums
01178   CfgEntry *e;
01179   for( e = entries.first(); e; e = entries.next() ) {
01180     QValueList<CfgEntry::Choice> choices = e->choices();
01181     if ( !choices.isEmpty() ) {
01182       QStringList values;
01183       QValueList<CfgEntry::Choice>::ConstIterator itChoice;
01184       for( itChoice = choices.begin(); itChoice != choices.end(); ++itChoice ) {
01185         values.append( (*itChoice).name );
01186       }
01187       if ( globalEnums ) {
01188         h << "    enum { " << values.join( ", " ) << " };" << endl;
01189       } else {
01190         h << "    class " << enumName(e->name()) << endl;
01191         h << "    {" << endl;
01192         h << "      public:" << endl;
01193         h << "      enum type { " << values.join( ", " ) << ", COUNT };" << endl;
01194         h << "    };" << endl;
01195       }
01196     }
01197     QStringList values = e->paramValues();
01198     if ( !values.isEmpty() ) {
01199       if ( globalEnums ) {
01200         h << "    enum { " << values.join( ", " ) << " };" << endl;
01201         h << "    static const char* const " << enumName(e->param()) << "ToString[];" << endl;
01202         cppPreamble += "const char* const " + className + "::" + enumName(e->param()) + "ToString[] = " +
01203             "{ \"" + values.join( "\", \"" ) + "\" };\n";
01204       } else {
01205         h << "    class " << enumName(e->param()) << endl;
01206         h << "    {" << endl;
01207         h << "      public:" << endl;
01208         h << "      enum type { " << values.join( ", " ) << ", COUNT };" << endl;
01209         h << "      static const char* const enumToString[];" << endl;
01210         h << "    };" << endl;
01211         cppPreamble += "const char* const " + className + "::" + enumName(e->param()) + "::enumToString[] = " +
01212             "{ \"" + values.join( "\", \"" ) + "\" };\n";
01213       }
01214     }
01215   }
01216 
01217   h << endl;
01218 
01219   // Constructor or singleton accessor
01220   if ( !singleton ) {
01221     h << "    " << className << "(";
01222     if (cfgFileNameArg)
01223        h << " KSharedConfig::Ptr config" << (parameters.isEmpty() ? " = KGlobal::sharedConfig()" : ", ");
01224     for (QValueList<Param>::ConstIterator it = parameters.begin();
01225          it != parameters.end(); ++it)
01226     {
01227        if (it != parameters.begin())
01228          h << ",";
01229        h << " " << param((*it).type) << " " << (*it).name;
01230     }
01231     h << " );" << endl;
01232   } else {
01233     h << "    static " << className << " *self();" << endl;
01234     if (cfgFileNameArg)
01235       h << "    static void instance(const char * cfgfilename);" << endl;
01236   }
01237 
01238   // Destructor
01239   h << "    ~" << className << "();" << endl << endl;
01240 
01241   // global variables
01242   if (staticAccessors)
01243     This = "self()->";
01244   else
01245     Const = " const";
01246 
01247   for( e = entries.first(); e; e = entries.next() ) {
01248     QString n = e->name();
01249     QString t = e->type();
01250 
01251     // Manipulator
01252     if (allMutators || mutators.contains(n))
01253     {
01254       h << "    /**" << endl;
01255       h << "      Set " << e->label() << endl;
01256       h << "    */" << endl;
01257       if (staticAccessors)
01258         h << "    static" << endl;
01259       h << "    void " << setFunction(n) << "( ";
01260       if (!e->param().isEmpty())
01261         h << cppType(e->paramType()) << " i, ";
01262       h << param( t ) << " v )";
01263       // function body inline only if not using dpointer
01264       // for BC mode
01265       if ( !dpointer )
01266       {
01267         h << endl << "    {" << endl;
01268         h << indent(memberMutatorBody(e), 6 );      
01269         h << "    }" << endl;
01270       }
01271       else
01272       {
01273         h << ";" << endl;
01274       }
01275     }
01276     h << endl;
01277     // Accessor
01278     h << "    /**" << endl;
01279     h << "      Get " << e->label() << endl;
01280     h << "    */" << endl;
01281     if (staticAccessors)
01282       h << "    static" << endl;
01283     h << "    " << cppType(t) << " " << getFunction(n) << "(";
01284     if (!e->param().isEmpty())
01285       h << " " << cppType(e->paramType()) <<" i ";
01286     h << ")" << Const;
01287     // function body inline only if not using dpointer
01288     // for BC mode
01289     if ( !dpointer )
01290     {
01291        h << endl << "    {" << endl;
01292       h << indent(memberAccessorBody(e), 6 );      
01293        h << "    }" << endl;
01294     }
01295     else
01296     {
01297       h << ";" << endl;
01298     }
01299 
01300     // Item accessor
01301     if ( itemAccessors ) {
01302       h << endl;
01303       h << "    /**" << endl;
01304       h << "      Get Item object corresponding to " << n << "()"
01305         << endl;
01306       h << "    */" << endl;
01307       h << "    Item" << itemType( e->type() ) << " *"
01308         << getFunction( n ) << "Item(";
01309       if (!e->param().isEmpty()) {
01310         h << " " << cppType(e->paramType()) << " i ";
01311       }
01312       h << ")";
01313       if (! dpointer )
01314       {
01315         h << endl << "    {" << endl;
01316         h << indent( itemAccessorBody(e), 6);
01317         h << "    }" << endl;
01318       }
01319       else
01320       {
01321         h << ";" << endl;
01322       }
01323     }
01324 
01325     h << endl;
01326   }
01327 
01328   // Static writeConfig method for singleton
01329   if ( singleton ) {
01330     h << "    static" << endl;
01331     h << "    void writeConfig()" << endl;
01332     h << "    {" << endl;
01333     h << "      static_cast<KConfigSkeleton*>(self())->writeConfig();" << endl;
01334     h << "    }" << endl;
01335   }
01336 
01337   h << "  protected:" << endl;
01338 
01339   // Private constructor for singleton
01340   if ( singleton ) {
01341     h << "    " << className << "(";
01342     if ( cfgFileNameArg )
01343       h << "const char *arg";
01344     h << ");" << endl;
01345     h << "    static " << className << " *mSelf;" << endl << endl;
01346   }
01347 
01348   // Member variables
01349   if ( !memberVariables.isEmpty() && memberVariables != "private" && memberVariables != "dpointer") {
01350     h << "  " << memberVariables << ":" << endl;
01351   }
01352 
01353   // Class Parameters
01354   for (QValueList<Param>::ConstIterator it = parameters.begin();
01355        it != parameters.end(); ++it)
01356   {
01357      h << "    " << cppType((*it).type) << " mParam" << (*it).name << ";" << endl;
01358   }
01359 
01360   if ( memberVariables != "dpointer" )
01361   {
01362     QString group;
01363     for( e = entries.first(); e; e = entries.next() ) {
01364       if ( e->group() != group ) {
01365         group = e->group();
01366         h << endl;
01367         h << "    // " << group << endl;
01368       }
01369       h << "    " << cppType(e->type()) << " " << varName(e->name());
01370       if (!e->param().isEmpty())
01371       {
01372         h << QString("[%1]").arg(e->paramMax()+1);
01373       }
01374       h << ";" << endl;
01375     }
01376 
01377     h << endl << "  private:" << endl;
01378     if ( itemAccessors ) {
01379       for( e = entries.first(); e; e = entries.next() ) {
01380         h << "    Item" << itemType( e->type() ) << " *" << itemVar( e );
01381         if (!e->param().isEmpty() ) h << QString("[%1]").arg( e->paramMax()+1 );
01382         h << ";" << endl;
01383       }
01384     }
01385   
01386   }
01387   else
01388   {
01389     // use a private class for both member variables and items
01390     h << "  private:" << endl;
01391     h << "    " + className + "Private *d;" << endl;
01392   }
01393   
01394   if (customAddons)
01395   {
01396      h << "    // Include custom additions" << endl;
01397      h << "    #include \"" << filenameOnly(baseName) << "_addons.h\"" <<endl;
01398   }
01399 
01400   h << "};" << endl << endl;
01401 
01402   if ( !nameSpace.isEmpty() ) h << "}" << endl << endl;
01403 
01404   h << "#endif" << endl << endl;
01405 
01406 
01407   header.close();
01408 
01409   QFile implementation( baseDir + implementationFileName );
01410   if ( !implementation.open( IO_WriteOnly ) ) {
01411     kdError() << "Can't open '" << implementationFileName << "' for writing."
01412               << endl;
01413     return 1;
01414   }
01415 
01416   QTextStream cpp( &implementation );
01417 
01418 
01419   cpp << "// This file is generated by kconfig_compiler from " << args->url(0).fileName() << "." << endl;
01420   cpp << "// All changes you do to this file will be lost." << endl << endl;
01421 
01422   cpp << "#include \"" << headerFileName << "\"" << endl << endl;
01423 
01424   if ( setUserTexts ) cpp << "#include <klocale.h>" << endl << endl;
01425 
01426   // Header required by singleton implementation
01427   if ( singleton )
01428     cpp << "#include <kstaticdeleter.h>" << endl << endl;
01429   if ( singleton && cfgFileNameArg )
01430     cpp << "#include <kdebug.h>" << endl << endl;
01431 
01432   if ( !nameSpace.isEmpty() )
01433     cpp << "using namespace " << nameSpace << ";" << endl << endl;
01434 
01435   QString group;
01436 
01437   // private class implementation
01438   if ( dpointer )
01439   {
01440     cpp << "class " << className << "Private" << endl;
01441     cpp << "{" << endl;
01442     cpp << "  public:" << endl;
01443     for( e = entries.first(); e; e = entries.next() ) {
01444       if ( e->group() != group ) {
01445         group = e->group();
01446         cpp << endl;
01447         cpp << "    // " << group << endl;
01448       }
01449       cpp << "    " << cppType(e->type()) << " " << varName(e->name());
01450       if (!e->param().isEmpty())
01451       {
01452         cpp << QString("[%1]").arg(e->paramMax()+1);
01453       }
01454       cpp << ";" << endl;
01455     }
01456     cpp << endl << "    // items" << endl;
01457     for( e = entries.first(); e; e = entries.next() ) {
01458       cpp << "    KConfigSkeleton::Item" << itemType( e->type() ) << " *" << itemVar( e );
01459       if (!e->param().isEmpty() ) cpp << QString("[%1]").arg( e->paramMax()+1 );
01460         cpp << ";" << endl;
01461     }
01462 
01463     cpp << "};" << endl << endl;
01464   }
01465 
01466   // Singleton implementation
01467   if ( singleton ) {
01468     cpp << className << " *" << className << "::mSelf = 0;" << endl;
01469     cpp << "static KStaticDeleter<" << className << "> static" << className << "Deleter;" << endl << endl;
01470 
01471     cpp << className << " *" << className << "::self()" << endl;
01472     cpp << "{" << endl;
01473     if ( cfgFileNameArg ) {
01474       cpp << "  if (!mSelf)" << endl;
01475       cpp << "     kdFatal() << \"you need to call " << className << "::instance before using\" << endl;" << endl;
01476     } else {
01477     cpp << "  if ( !mSelf ) {" << endl;
01478     cpp << "    static" << className << "Deleter.setObject( mSelf, new " << className << "() );" << endl;
01479     cpp << "    mSelf->readConfig();" << endl;
01480     cpp << "  }" << endl << endl;
01481     }
01482     cpp << "  return mSelf;" << endl;
01483     cpp << "}" << endl << endl;
01484 
01485     if ( cfgFileNameArg ) {
01486       cpp << "void " << className << "::instance(const char *cfgfilename)" << endl;
01487       cpp << "{" << endl;
01488       cpp << "  if (mSelf) {" << endl;
01489       cpp << "     kdError() << \"" << className << "::instance called after the first use - ignoring\" << endl;" << endl;
01490       cpp << "     return;" << endl;
01491       cpp << "  }" << endl;
01492       cpp << "  static" << className << "Deleter.setObject( mSelf, new " << className << "(cfgfilename) );" << endl;
01493       cpp << "  mSelf->readConfig();" << endl;
01494       cpp << "}" << endl << endl;
01495     }
01496   }
01497 
01498   if ( !cppPreamble.isEmpty() )
01499     cpp << cppPreamble << endl;
01500 
01501   // Constructor
01502   cpp << className << "::" << className << "( ";
01503   if ( cfgFileNameArg ) {
01504     if ( !singleton )
01505       cpp << " KSharedConfig::Ptr config";
01506     else
01507       cpp << " const char *config";
01508     cpp << (parameters.isEmpty() ? " " : ", ");
01509   }
01510 
01511   for (QValueList<Param>::ConstIterator it = parameters.begin();
01512        it != parameters.end(); ++it)
01513   {
01514      if (it != parameters.begin())
01515        cpp << ",";
01516      cpp << " " << param((*it).type) << " " << (*it).name;
01517   }
01518   cpp << " )" << endl;
01519 
01520   cpp << "  : " << inherits << "(";
01521   if ( !cfgFileName.isEmpty() ) cpp << " QString::fromLatin1( \"" << cfgFileName << "\" ";
01522   if ( cfgFileNameArg ) cpp << " config ";
01523   if ( !cfgFileName.isEmpty() ) cpp << ") ";
01524   cpp << ")" << endl;
01525 
01526   // Store parameters
01527   for (QValueList<Param>::ConstIterator it = parameters.begin();
01528        it != parameters.end(); ++it)
01529   {
01530      cpp << "  , mParam" << (*it).name << "(" << (*it).name << ")" << endl;
01531   }
01532 
01533   cpp << "{" << endl;
01534 
01535   if (dpointer)
01536     cpp << "  d = new " + className + "Private;" << endl;
01537   // Needed in case the singleton class is used as baseclass for
01538   // another singleton.
01539   if ( singleton )
01540     cpp << "  mSelf = this;" << endl;
01541 
01542   group = QString::null;
01543   for( e = entries.first(); e; e = entries.next() ) {
01544     if ( e->group() != group ) {
01545       if ( !group.isEmpty() ) cpp << endl;
01546       group = e->group();
01547       cpp << "  setCurrentGroup( " << paramString(group, parameters) << " );" << endl << endl;
01548     }
01549 
01550     QString key = paramString(e->key(), parameters);
01551     if ( !e->code().isEmpty())
01552     {
01553       cpp << e->code() << endl;
01554     }
01555     if ( e->type() == "Enum" ) {
01556       cpp << "  QValueList<KConfigSkeleton::ItemEnum::Choice> values"
01557           << e->name() << ";" << endl;
01558       QValueList<CfgEntry::Choice> choices = e->choices();
01559       QValueList<CfgEntry::Choice>::ConstIterator it;
01560       for( it = choices.begin(); it != choices.end(); ++it ) {
01561         cpp << "  {" << endl;
01562         cpp << "    KConfigSkeleton::ItemEnum::Choice choice;" << endl;
01563         cpp << "    choice.name = QString::fromLatin1( \"" << (*it).name << "\" );" << endl;
01564         if ( setUserTexts ) {
01565           if ( !(*it).label.isEmpty() )
01566             cpp << "    choice.label = i18n(" << quoteString((*it).label) << ");" << endl;
01567           if ( !(*it).whatsThis.isEmpty() )
01568             cpp << "    choice.whatsThis = i18n(" << quoteString((*it).whatsThis) << ");" << endl;
01569         }
01570         cpp << "    values" << e->name() << ".append( choice );" << endl;
01571         cpp << "  }" << endl;
01572       }
01573     }
01574 
01575     if (!dpointer)
01576       cpp << itemDeclaration(e);
01577 
01578     if (e->param().isEmpty())
01579     {
01580       // Normal case
01581       cpp << "  " << itemPath(e) << " = "
01582           << newItem( e->type(), e->name(), key, e->defaultValue() ) << endl;
01583 
01584       if ( !e->minValue().isEmpty() )
01585         cpp << "  " << itemPath(e) << "->setMinValue(" << e->minValue() << ");" << endl;
01586       if ( !e->maxValue().isEmpty() )
01587         cpp << "  " << itemPath(e) << "->setMaxValue(" << e->maxValue() << ");" << endl;
01588 
01589       if ( setUserTexts )
01590         cpp << userTextsFunctions( e );
01591 
01592       cpp << "  addItem( " << itemPath(e);
01593       QString quotedName = e->name();
01594       addQuotes( quotedName );
01595       if ( quotedName != key ) cpp << ", QString::fromLatin1( \"" << e->name() << "\" )";
01596       cpp << " );" << endl;
01597     }
01598     else
01599     {
01600       // Indexed
01601       for(int i = 0; i <= e->paramMax(); i++)
01602       {
01603         QString defaultStr;
01604         QString itemVarStr(itemPath(e)+QString("[%1]").arg(i));
01605 
01606         if ( !e->paramDefaultValue(i).isEmpty() )
01607           defaultStr = e->paramDefaultValue(i);
01608         else if ( !e->defaultValue().isEmpty() )
01609           defaultStr = paramString(e->defaultValue(), e, i);
01610         else
01611           defaultStr = defaultValue( e->type() );
01612 
01613         cpp << "  " << itemVarStr << " = "
01614             << newItem( e->type(), e->name(), paramString(key, e, i), defaultStr, QString("[%1]").arg(i) )
01615             << endl;
01616 
01617         if ( setUserTexts )
01618           cpp << userTextsFunctions( e, itemVarStr, e->paramName() );
01619 
01620         // Make mutators for enum parameters work by adding them with $(..) replaced by the
01621         // param name. The check for isImmutable in the set* functions doesn't have the param
01622         // name available, just the corresponding enum value (int), so we need to store the
01623         // param names in a separate static list!.
01624         cpp << "  addItem( " << itemVarStr << ", QString::fromLatin1( \"";
01625         if ( e->paramType()=="Enum" )
01626           cpp << e->paramName().replace( "$("+e->param()+")", "%1").arg(e->paramValues()[i] );
01627         else
01628           cpp << e->paramName().replace( "$("+e->param()+")", "%1").arg(i);
01629         cpp << "\" ) );" << endl;
01630       }
01631     }
01632   }
01633 
01634   cpp << "}" << endl << endl;
01635 
01636   if (dpointer)
01637   {
01638     // setters and getters go in Cpp if in dpointer mode
01639     for( e = entries.first(); e; e = entries.next() )
01640     {
01641       QString n = e->name();
01642       QString t = e->type();
01643   
01644       // Manipulator
01645       if (allMutators || mutators.contains(n))
01646       {
01647         cpp << "void " << setFunction(n, className) << "( ";
01648         if (!e->param().isEmpty())
01649           cpp << cppType(e->paramType()) << " i, ";
01650         cpp << param( t ) << " v )" << endl;
01651         // function body inline only if not using dpointer
01652         // for BC mode
01653         cpp << "{" << endl;
01654         cpp << indent(memberMutatorBody(e), 6);      
01655         cpp << "}" << endl << endl;
01656       }
01657   
01658       // Accessor
01659       cpp << cppType(t) << " " << getFunction(n, className) << "(";
01660       if (!e->param().isEmpty())
01661         cpp << " " << cppType(e->paramType()) <<" i ";
01662       cpp << ")" << Const << endl;
01663       // function body inline only if not using dpointer
01664       // for BC mode
01665       cpp << "{" << endl;
01666       cpp << indent(memberAccessorBody(e), 2);      
01667       cpp << "}" << endl << endl;
01668   
01669       // Item accessor
01670       if ( itemAccessors )
01671       {
01672         cpp << endl;
01673         cpp << "KConfigSkeleton::Item" << itemType( e->type() ) << " *"
01674           << getFunction( n, className ) << "Item(";
01675         if (!e->param().isEmpty()) {
01676           cpp << " " << cppType(e->paramType()) << " i ";
01677         }
01678         cpp << ")" << endl;
01679         cpp << "{" << endl;
01680         cpp << indent(itemAccessorBody(e), 2);
01681         cpp << "}" << endl;
01682       }
01683   
01684       cpp << endl;
01685     }
01686   }
01687 
01688   // Destructor
01689   cpp << className << "::~" << className << "()" << endl;
01690   cpp << "{" << endl;
01691   if ( singleton ) {
01692     if ( dpointer )
01693       cpp << "  delete d;" << endl;
01694     cpp << "  if ( mSelf == this )" << endl;
01695     cpp << "    static" << className << "Deleter.setObject( mSelf, 0, false );" << endl;
01696   }
01697   cpp << "}" << endl << endl;
01698 
01699   implementation.close();
01700 }

KDECore

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

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
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