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 ¶m = 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> ¶meters) 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 }
KDE 4.6 API Reference