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

KDECore

  • kdecore
  • kconfig_compiler
kconfig_compiler.cpp
Go to the documentation of this file.
1 // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2 /*
3  This file is part of KDE.
4 
5  Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
6  Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
7  Copyright (c) 2003 Zack Rusin <zack@kde.org>
8  Copyright (c) 2006 MichaĆ«l Larouche <michael.larouche@kdemail.net>
9  Copyright (c) 2008 Allen Winter <winter@kde.org>
10 
11  This library is free software; you can redistribute it and/or
12  modify it under the terms of the GNU Library General Public
13  License as published by the Free Software Foundation; either
14  version 2 of the License, or (at your option) any later version.
15 
16  This library is distributed in the hope that it will be useful,
17  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  Library General Public License for more details.
20 
21  You should have received a copy of the GNU Library General Public License
22  along with this library; see the file COPYING.LIB. If not, write to
23  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24  Boston, MA 02110-1301, USA.
25 */
26 
27 // Compiling this file with this flag is just crazy
28 #undef QT_NO_CAST_FROM_ASCII
29 
30 #include <QtCore/QCoreApplication>
31 #include <QtCore/QFile>
32 #include <QtCore/QFileInfo>
33 #include <QtCore/QSettings>
34 #include <QtCore/QTextStream>
35 #include <QtXml/QDomAttr>
36 #include <QtCore/QRegExp>
37 #include <QtCore/QStringList>
38 
39 #include <ostream>
40 #include <iostream>
41 #include <stdlib.h>
42 
43 namespace
44 {
45  QTextStream cout(stdout);
46  QTextStream cerr(stderr);
47 }
48 
49 static void parseArgs(const QStringList &args, QString &directory, QString &file1, QString &file2)
50 {
51  int fileCount = 0;
52  directory = QChar::fromLatin1('.');
53 
54  for (int i = 1; i < args.count(); ++i) {
55  if (args.at(i) == QLatin1String("-d") || args.at(i) == QLatin1String("--directory")) {
56  if (i + 1 > args.count()) {
57  cerr << args.at(i) << " needs an argument" << endl;
58  exit(1);
59  }
60  directory = args.at(++i);
61  } else if (args.at(i).startsWith(QLatin1String("-d"))) {
62  directory = args.at(i).mid(2);
63  } else if (args.at(i) == QLatin1String("--help") || args.at(i) == QLatin1String("-h")) {
64  cout << "Options:" << endl;
65  cout << " -L --license Display software license" << endl;
66  cout << " -d, --directory <dir> Directory to generate files in [.]" << endl;
67  cout << " -h, --help Display this help" << endl;
68  cout << endl;
69  cout << "Arguments:" << endl;
70  cout << " file.kcfg Input kcfg XML file" << endl;
71  cout << " file.kcfgc Code generation options file" << endl;
72  exit(0);
73  } else if (args.at(i) == QLatin1String("--license") || args.at(i) == QLatin1String("-L")) {
74  cout << "Copyright 2003 Cornelius Schumacher, Waldo Bastian, Zack Rusin," << endl;
75  cout << " Reinhold Kainhofer, Duncan Mac-Vicar P., Harald Fernengel" << endl;
76  cout << "This program comes with ABSOLUTELY NO WARRANTY." << endl;
77  cout << "You may redistribute copies of this program" << endl;
78  cout << "under the terms of the GNU Library Public License." << endl;
79  cout << "For more information about these matters, see the file named COPYING." << endl;
80  exit(0);
81  } else if (args.at(i).startsWith(QLatin1Char('-'))) {
82  cerr << "Unknown option: " << args.at(i) << endl;
83  exit(1);
84  } else if (fileCount == 0) {
85  file1 = args.at(i);
86  ++fileCount;
87  } else if (fileCount == 1) {
88  file2 = args.at(i);
89  ++fileCount;
90  } else {
91  cerr << "Too many arguments" << endl;
92  exit(1);
93  }
94  }
95  if (fileCount < 2) {
96  cerr << "Too few arguments" << endl;
97  exit(1);
98  }
99 }
100 
101 QStringList allNames;
102 QRegExp *validNameRegexp;
103 QString This;
104 QString Const;
105 
109 class CfgConfig
110 {
111 public:
112  CfgConfig( const QString &codegenFilename )
113  {
114  // Configure the compiler with some settings
115  QSettings codegenConfig(codegenFilename, QSettings::IniFormat);
116 
117  nameSpace = codegenConfig.value("NameSpace").toString();
118  className = codegenConfig.value("ClassName").toString();
119  if ( className.isEmpty() ) {
120  cerr << "Class name missing" << endl;
121  exit(1);
122  }
123  inherits = codegenConfig.value("Inherits").toString();
124  if ( inherits.isEmpty() ) inherits = "KConfigSkeleton";
125  visibility = codegenConfig.value("Visibility").toString();
126  if ( !visibility.isEmpty() ) visibility += ' ';
127  forceStringFilename = codegenConfig.value("ForceStringFilename", false).toBool();
128  singleton = codegenConfig.value("Singleton", false).toBool();
129  staticAccessors = singleton;
130  customAddons = codegenConfig.value("CustomAdditions", false).toBool();
131  memberVariables = codegenConfig.value("MemberVariables").toString();
132  dpointer = (memberVariables == "dpointer");
133  headerIncludes = codegenConfig.value("IncludeFiles", QStringList()).toStringList();
134  sourceIncludes = codegenConfig.value("SourceIncludeFiles", QStringList()).toStringList();
135  mutators = codegenConfig.value("Mutators", QStringList()).toStringList();
136  allMutators = ((mutators.count() == 1) && (mutators.at(0).toLower() == "true"));
137  itemAccessors = codegenConfig.value("ItemAccessors", false).toBool();
138  setUserTexts = codegenConfig.value("SetUserTexts", false).toBool();
139  defaultGetters = codegenConfig.value("DefaultValueGetters", QStringList()).toStringList();
140  allDefaultGetters = (defaultGetters.count() == 1) && (defaultGetters.at(0).toLower() == "true");
141  globalEnums = codegenConfig.value("GlobalEnums", false).toBool();
142  useEnumTypes = codegenConfig.value("UseEnumTypes", false).toBool();
143  }
144 
145 public:
146  // These are read from the .kcfgc configuration file
147  QString nameSpace; // The namespace for the class to be generated
148  QString className; // The class name to be generated
149  QString inherits; // The class the generated class inherits (if empty, from KConfigSkeleton)
150  QString visibility;
151  bool forceStringFilename;
152  bool singleton; // The class will be a singleton
153  bool staticAccessors; // provide or not static accessors
154  bool customAddons;
155  QString memberVariables;
156  QStringList headerIncludes;
157  QStringList sourceIncludes;
158  QStringList mutators;
159  QStringList defaultGetters;
160  bool allMutators;
161  bool setUserTexts;
162  bool allDefaultGetters;
163  bool dpointer;
164  bool globalEnums;
165  bool useEnumTypes;
166  bool itemAccessors;
167 };
168 
169 
170 struct SignalArguments
171 {
172  QString type;
173  QString variableName;
174 };
175 
176 class Signal {
177 public:
178  QString name;
179  QString label;
180  QList<SignalArguments> arguments;
181 };
182 
183 
184 
185 
186 class CfgEntry
187 {
188  public:
189  struct Choice
190  {
191  QString name;
192  QString context;
193  QString label;
194  QString toolTip;
195  QString whatsThis;
196  };
197  class Choices
198  {
199  public:
200  Choices() {}
201  Choices( const QList<Choice> &d, const QString &n, const QString &p )
202  : prefix(p), choices(d), mName(n)
203  {
204  int i = n.indexOf(QLatin1String("::"));
205  if (i >= 0)
206  mExternalQual = n.left(i + 2);
207  }
208  QString prefix;
209  QList<Choice> choices;
210  const QString& name() const { return mName; }
211  const QString& externalQualifier() const { return mExternalQual; }
212  bool external() const { return !mExternalQual.isEmpty(); }
213  private:
214  QString mName;
215  QString mExternalQual;
216  };
217 
218  CfgEntry( const QString &group, const QString &type, const QString &key,
219  const QString &name, const QString &labelContext, const QString &label,
220  const QString &toolTipContext, const QString &toolTip, const QString &whatsThisContext, const QString &whatsThis, const QString &code,
221  const QString &defaultValue, const Choices &choices, const QList<Signal> signalList,
222  bool hidden )
223  : mGroup( group ), mType( type ), mKey( key ), mName( name ),
224  mLabelContext( labelContext ), mLabel( label ), mToolTipContext( toolTipContext ), mToolTip( toolTip ),
225  mWhatsThisContext( whatsThisContext ), mWhatsThis( whatsThis ),
226  mCode( code ), mDefaultValue( defaultValue ), mChoices( choices ),
227  mSignalList(signalList), mHidden( hidden )
228  {
229  }
230 
231  void setGroup( const QString &group ) { mGroup = group; }
232  QString group() const { return mGroup; }
233 
234  void setType( const QString &type ) { mType = type; }
235  QString type() const { return mType; }
236 
237  void setKey( const QString &key ) { mKey = key; }
238  QString key() const { return mKey; }
239 
240  void setName( const QString &name ) { mName = name; }
241  QString name() const { return mName; }
242 
243  void setLabelContext( const QString &labelContext ) { mLabelContext = labelContext; }
244  QString labelContext() const { return mLabelContext; }
245 
246  void setLabel( const QString &label ) { mLabel = label; }
247  QString label() const { return mLabel; }
248 
249  void setToolTipContext( const QString &toolTipContext ) { mToolTipContext = toolTipContext; }
250  QString toolTipContext() const { return mToolTipContext; }
251 
252  void setToolTip( const QString &toolTip ) { mToolTip = toolTip; }
253  QString toolTip() const { return mToolTip; }
254 
255  void setWhatsThisContext( const QString &whatsThisContext ) { mWhatsThisContext = whatsThisContext; }
256  QString whatsThisContext() const { return mWhatsThisContext; }
257 
258  void setWhatsThis( const QString &whatsThis ) { mWhatsThis = whatsThis; }
259  QString whatsThis() const { return mWhatsThis; }
260 
261  void setDefaultValue( const QString &d ) { mDefaultValue = d; }
262  QString defaultValue() const { return mDefaultValue; }
263 
264  void setCode( const QString &d ) { mCode = d; }
265  QString code() const { return mCode; }
266 
267  void setMinValue( const QString &d ) { mMin = d; }
268  QString minValue() const { return mMin; }
269 
270  void setMaxValue( const QString &d ) { mMax = d; }
271  QString maxValue() const { return mMax; }
272 
273  void setParam( const QString &d ) { mParam = d; }
274  QString param() const { return mParam; }
275 
276  void setParamName( const QString &d ) { mParamName = d; }
277  QString paramName() const { return mParamName; }
278 
279  void setParamType( const QString &d ) { mParamType = d; }
280  QString paramType() const { return mParamType; }
281 
282  void setChoices( const QList<Choice> &d, const QString &n, const QString &p ) { mChoices = Choices( d, n, p ); }
283  Choices choices() const { return mChoices; }
284 
285  void setParamValues( const QStringList &d ) { mParamValues = d; }
286  QStringList paramValues() const { return mParamValues; }
287 
288  void setParamDefaultValues( const QStringList &d ) { mParamDefaultValues = d; }
289  QString paramDefaultValue(int i) const { return mParamDefaultValues[i]; }
290 
291  void setParamMax( int d ) { mParamMax = d; }
292  int paramMax() const { return mParamMax; }
293 
294  void setSignalList( const QList<Signal> &value ) { mSignalList = value; }
295  QList<Signal> signalList() const { return mSignalList; }
296 
297  bool hidden() const { return mHidden; }
298 
299  void dump() const
300  {
301  cerr << "<entry>" << endl;
302  cerr << " group: " << mGroup << endl;
303  cerr << " type: " << mType << endl;
304  cerr << " key: " << mKey << endl;
305  cerr << " name: " << mName << endl;
306  cerr << " label context: " << mLabelContext << endl;
307  cerr << " label: " << mLabel << endl;
308 // whatsthis
309  cerr << " code: " << mCode << endl;
310 // cerr << " values: " << mValues.join(":") << endl;
311 
312  if (!param().isEmpty())
313  {
314  cerr << " param name: "<< mParamName << endl;
315  cerr << " param type: "<< mParamType << endl;
316  cerr << " paramvalues: " << mParamValues.join(QChar::fromLatin1(':')) << endl;
317  }
318  cerr << " default: " << mDefaultValue << endl;
319  cerr << " hidden: " << mHidden << endl;
320  cerr << " min: " << mMin << endl;
321  cerr << " max: " << mMax << endl;
322  cerr << "</entry>" << endl;
323  }
324 
325  private:
326  QString mGroup;
327  QString mType;
328  QString mKey;
329  QString mName;
330  QString mLabelContext;
331  QString mLabel;
332  QString mToolTipContext;
333  QString mToolTip;
334  QString mWhatsThisContext;
335  QString mWhatsThis;
336  QString mCode;
337  QString mDefaultValue;
338  QString mParam;
339  QString mParamName;
340  QString mParamType;
341  Choices mChoices;
342  QList<Signal> mSignalList;
343  QStringList mParamValues;
344  QStringList mParamDefaultValues;
345  int mParamMax;
346  bool mHidden;
347  QString mMin;
348  QString mMax;
349 };
350 
351 class Param {
352 public:
353  QString name;
354  QString type;
355 };
356 
357 // returns the name of an member variable
358 // use itemPath to know the full path
359 // like using d-> in case of dpointer
360 static QString varName(const QString &n, const CfgConfig &cfg)
361 {
362  QString result;
363  if ( !cfg.dpointer ) {
364  result = QChar::fromLatin1('m') + n;
365  result[1] = result[1].toUpper();
366  }
367  else {
368  result = n;
369  result[0] = result[0].toLower();
370  }
371  return result;
372 }
373 
374 static QString varPath(const QString &n, const CfgConfig &cfg)
375 {
376  QString result;
377  if ( cfg.dpointer ) {
378  result = "d->"+varName(n, cfg);
379  }
380  else {
381  result = varName(n, cfg);
382  }
383  return result;
384 }
385 
386 static QString enumName(const QString &n)
387 {
388  QString result = QString::fromLatin1("Enum") + n;
389  result[4] = result[4].toUpper();
390  return result;
391 }
392 
393 static QString enumName(const QString &n, const CfgEntry::Choices &c)
394 {
395  QString result = c.name();
396  if ( result.isEmpty() )
397  {
398  result = QString::fromLatin1("Enum") + n;
399  result[4] = result[4].toUpper();
400  }
401  return result;
402 }
403 
404 static QString enumType(const CfgEntry *e, bool globalEnums)
405 {
406  QString result = e->choices().name();
407  if ( result.isEmpty() )
408  {
409  result = QString::fromLatin1("Enum") + e->name();
410  if( !globalEnums )
411  result += QString::fromLatin1("::type");
412  result[4] = result[4].toUpper();
413  }
414  return result;
415 }
416 
417 static QString enumTypeQualifier(const QString &n, const CfgEntry::Choices &c)
418 {
419  QString result = c.name();
420  if ( result.isEmpty() )
421  {
422  result = QString::fromLatin1("Enum") + n + QString::fromLatin1("::");
423  result[4] = result[4].toUpper();
424  }
425  else if ( c.external() )
426  result = c.externalQualifier();
427  else
428  result.clear();
429  return result;
430 }
431 
432 static QString setFunction(const QString &n, const QString &className = QString())
433 {
434  QString result = QString::fromLatin1("set") + n;
435  result[3] = result[3].toUpper();
436 
437  if ( !className.isEmpty() )
438  result = className + QString::fromLatin1("::") + result;
439  return result;
440 }
441 
442 static QString getDefaultFunction(const QString &n, const QString &className = QString())
443 {
444  QString result = QString::fromLatin1("default") + n + QString::fromLatin1("Value");
445  result[7] = result[7].toUpper();
446 
447  if ( !className.isEmpty() )
448  result = className + QString::fromLatin1("::") + result;
449  return result;
450 }
451 
452 static QString getFunction(const QString &n, const QString &className = QString())
453 {
454  QString result = n;
455  result[0] = result[0].toLower();
456 
457  if ( !className.isEmpty() )
458  result = className + QString::fromLatin1("::") + result;
459  return result;
460 }
461 
462 
463 static void addQuotes( QString &s )
464 {
465  if ( !s.startsWith( QLatin1Char('"') ) )
466  s.prepend( QLatin1Char('"') );
467  if ( !s.endsWith( QLatin1Char('"') ) )
468  s.append( QLatin1Char('"') );
469 }
470 
471 static QString quoteString( const QString &s )
472 {
473  QString r = s;
474  r.replace( QLatin1Char('\\'), QLatin1String("\\\\") );
475  r.replace( QLatin1Char('\"'), QLatin1String("\\\"") );
476  r.remove( QLatin1Char('\r') );
477  r.replace( QLatin1Char('\n'), QLatin1String("\\n\"\n\"") );
478  return QLatin1Char('\"') + r + QLatin1Char('\"');
479 }
480 
481 static QString literalString( const QString &s )
482 {
483  bool isAscii = true;
484  for(int i = s.length(); i--;)
485  if (s[i].unicode() > 127) isAscii = false;
486 
487  if (isAscii)
488  return QString::fromLatin1("QLatin1String( ") + quoteString(s) + QString::fromLatin1(" )");
489  else
490  return QString::fromLatin1("QString::fromUtf8( ") + quoteString(s) + QString::fromLatin1(" )");
491 }
492 
493 static QString dumpNode(const QDomNode &node)
494 {
495  QString msg;
496  QTextStream s(&msg, QIODevice::WriteOnly );
497  node.save(s, 0);
498 
499  msg = msg.simplified();
500  if (msg.length() > 40)
501  return msg.left(37) + QString::fromLatin1("...");
502  return msg;
503 }
504 
505 static QString filenameOnly(const QString& path)
506 {
507  int i = path.lastIndexOf(QRegExp(QLatin1String("[/\\]")));
508  if (i >= 0)
509  return path.mid(i+1);
510  return path;
511 }
512 
513 static QString signalEnumName(const QString &signalName)
514 {
515  QString result;
516  result = QString::fromLatin1("signal") + signalName;
517  result[6] = result[6].toUpper();
518 
519  return result;
520 }
521 
522 static void preProcessDefault( QString &defaultValue, const QString &name,
523  const QString &type,
524  const CfgEntry::Choices &choices,
525  QString &code, const CfgConfig &cfg )
526 {
527  if ( type == QLatin1String("String") && !defaultValue.isEmpty() ) {
528  defaultValue = literalString(defaultValue);
529 
530  } else if ( type == QLatin1String("Path") && !defaultValue.isEmpty() ) {
531  defaultValue = literalString( defaultValue );
532  } else if ( type == QLatin1String("Url") && !defaultValue.isEmpty() ) {
533  defaultValue = QString::fromLatin1("KUrl( ") + literalString(defaultValue) + QLatin1Char(')');
534  } else if ( ( type == QLatin1String("UrlList") || type == QLatin1String("StringList") || type == QLatin1String("PathList")) && !defaultValue.isEmpty() ) {
535  QTextStream cpp( &code, QIODevice::WriteOnly | QIODevice::Append );
536  if (!code.isEmpty())
537  cpp << endl;
538 
539  cpp << " QStringList default" << name << ";" << endl;
540  const QStringList defaults = defaultValue.split(QLatin1Char(','));
541  QStringList::ConstIterator it;
542  for( it = defaults.constBegin(); it != defaults.constEnd(); ++it ) {
543  cpp << " default" << name << ".append( ";
544  if( type == "UrlList" ) {
545  cpp << "KUrl(";
546  }
547  cpp << "QString::fromUtf8( \"" << *it << "\" ) ";
548  if( type == QLatin1String("UrlList") ) {
549  cpp << ") ";
550  }
551  cpp << ");" << endl;
552  }
553  defaultValue = QString::fromLatin1("default") + name;
554 
555  } else if ( type == QLatin1String("Color") && !defaultValue.isEmpty() ) {
556  QRegExp colorRe(QLatin1String("\\d+,\\s*\\d+,\\s*\\d+(,\\s*\\d+)?"));
557  if (colorRe.exactMatch(defaultValue))
558  {
559  defaultValue = QLatin1String("QColor( ") + defaultValue + QLatin1String(" )");
560  }
561  else
562  {
563  defaultValue = QLatin1String("QColor( \"") + defaultValue + QLatin1String("\" )");
564  }
565 
566  } else if ( type == QLatin1String("Enum") ) {
567  QList<CfgEntry::Choice>::ConstIterator it;
568  for( it = choices.choices.constBegin(); it != choices.choices.constEnd(); ++it ) {
569  if ( (*it).name == defaultValue ) {
570  if ( cfg.globalEnums && choices.name().isEmpty() )
571  defaultValue.prepend( choices.prefix );
572  else
573  defaultValue.prepend( enumTypeQualifier(name, choices) + choices.prefix );
574  break;
575  }
576  }
577 
578  } else if ( type == QLatin1String("IntList") ) {
579  QTextStream cpp( &code, QIODevice::WriteOnly | QIODevice::Append );
580  if (!code.isEmpty())
581  cpp << endl;
582 
583  cpp << " QList<int> default" << name << ";" << endl;
584  if (!defaultValue.isEmpty())
585  {
586  const QStringList defaults = defaultValue.split( QLatin1Char(',') );
587  QStringList::ConstIterator it;
588  for( it = defaults.constBegin(); it != defaults.constEnd(); ++it ) {
589  cpp << " default" << name << ".append( " << *it << " );"
590  << endl;
591  }
592  }
593  defaultValue = QString::fromLatin1("default") + name;
594  }
595 }
596 
597 
598 CfgEntry *parseEntry( const QString &group, const QDomElement &element, const CfgConfig &cfg )
599 {
600  bool defaultCode = false;
601  QString type = element.attribute( "type" );
602  QString name = element.attribute( "name" );
603  QString key = element.attribute( "key" );
604  QString hidden = element.attribute( "hidden" );
605  QString labelContext;
606  QString label;
607  QString toolTipContext;
608  QString toolTip;
609  QString whatsThisContext;
610  QString whatsThis;
611  QString defaultValue;
612  QString code;
613  QString param;
614  QString paramName;
615  QString paramType;
616  CfgEntry::Choices choices;
617  QList<Signal> signalList;
618  QStringList paramValues;
619  QStringList paramDefaultValues;
620  QString minValue;
621  QString maxValue;
622  int paramMax = 0;
623 
624  for ( QDomElement e = element.firstChildElement(); !e.isNull(); e = e.nextSiblingElement() ) {
625  QString tag = e.tagName();
626  if ( tag == "label" ) {
627  label = e.text();
628  labelContext = e.attribute( "context" );
629  }
630  else if ( tag == "tooltip" ) {
631  toolTip = e.text();
632  toolTipContext = e.attribute( "context" );
633  }
634  else if ( tag == "whatsthis" ) {
635  whatsThis = e.text();
636  whatsThisContext = e.attribute( "context" );
637  }
638  else if ( tag == "min" ) minValue = e.text();
639  else if ( tag == "max" ) maxValue = e.text();
640  else if ( tag == "code" ) code = e.text();
641  else if ( tag == "parameter" )
642  {
643  param = e.attribute( "name" );
644  paramType = e.attribute( "type" );
645  if ( param.isEmpty() ) {
646  cerr << "Parameter must have a name: " << dumpNode(e) << endl;
647  return 0;
648  }
649  if ( paramType.isEmpty() ) {
650  cerr << "Parameter must have a type: " << dumpNode(e) << endl;
651  return 0;
652  }
653  if ((paramType == "Int") || (paramType == "UInt"))
654  {
655  bool ok;
656  paramMax = e.attribute("max").toInt(&ok);
657  if (!ok)
658  {
659  cerr << "Integer parameter must have a maximum (e.g. max=\"0\"): "
660  << dumpNode(e) << endl;
661  return 0;
662  }
663  }
664  else if (paramType == "Enum")
665  {
666  for ( QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement() ) {
667  if (e2.tagName() == "values")
668  {
669  for ( QDomElement e3 = e2.firstChildElement(); !e3.isNull(); e3 = e3.nextSiblingElement() ) {
670  if (e3.tagName() == "value")
671  {
672  paramValues.append( e3.text() );
673  }
674  }
675  break;
676  }
677  }
678  if (paramValues.isEmpty())
679  {
680  cerr << "No values specified for parameter '" << param
681  << "'." << endl;
682  return 0;
683  }
684  paramMax = paramValues.count()-1;
685  }
686  else
687  {
688  cerr << "Parameter '" << param << "' has type " << paramType
689  << " but must be of type int, uint or Enum." << endl;
690  return 0;
691  }
692  }
693  else if ( tag == "default" )
694  {
695  if (e.attribute("param").isEmpty())
696  {
697  defaultValue = e.text();
698  if (e.attribute( "code" ) == "true")
699  defaultCode = true;
700  }
701  }
702  else if ( tag == "choices" ) {
703  QString name = e.attribute( "name" );
704  QString prefix = e.attribute( "prefix" );
705  QList<CfgEntry::Choice> chlist;
706  for( QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement() ) {
707  if ( e2.tagName() == "choice" ) {
708  CfgEntry::Choice choice;
709  choice.name = e2.attribute( "name" );
710  if ( choice.name.isEmpty() ) {
711  cerr << "Tag <choice> requires attribute 'name'." << endl;
712  }
713  for( QDomElement e3 = e2.firstChildElement(); !e3.isNull(); e3 = e3.nextSiblingElement() ) {
714  if ( e3.tagName() == "label" ) {
715  choice.label = e3.text();
716  choice.context = e3.attribute( "context" );
717  }
718  if ( e3.tagName() == "tooltip" ) {
719  choice.toolTip = e3.text();
720  choice.context = e3.attribute( "context" );
721  }
722  if ( e3.tagName() == "whatsthis" ) {
723  choice.whatsThis = e3.text();
724  choice.context = e3.attribute( "context" );
725  }
726  }
727  chlist.append( choice );
728  }
729  }
730  choices = CfgEntry::Choices( chlist, name, prefix );
731  }
732  else if ( tag == "emit" ) {
733  QDomNode signalNode;
734  Signal signal;
735  signal.name = e.attribute( "signal" );
736  signalList.append( signal);
737  }
738  }
739 
740 
741  bool nameIsEmpty = name.isEmpty();
742  if ( nameIsEmpty && key.isEmpty() ) {
743  cerr << "Entry must have a name or a key: " << dumpNode(element) << endl;
744  return 0;
745  }
746 
747  if ( key.isEmpty() ) {
748  key = name;
749  }
750 
751  if ( nameIsEmpty ) {
752  name = key;
753  name.remove( ' ' );
754  } else if ( name.contains( ' ' ) ) {
755  cout<<"Entry '"<<name<<"' contains spaces! <name> elements can not contain spaces!"<<endl;
756  name.remove( ' ' );
757  }
758 
759  if (name.contains("$("))
760  {
761  if (param.isEmpty())
762  {
763  cerr << "Name may not be parameterized: " << name << endl;
764  return 0;
765  }
766  }
767  else
768  {
769  if (!param.isEmpty())
770  {
771  cerr << "Name must contain '$(" << param << ")': " << name << endl;
772  return 0;
773  }
774  }
775 
776  if ( label.isEmpty() ) {
777  label = key;
778  }
779 
780  if ( type.isEmpty() ) type = "String"; // XXX : implicit type might be bad
781 
782  if (!param.isEmpty())
783  {
784  // Adjust name
785  paramName = name;
786  name.remove("$("+param+')');
787  // Lookup defaults for indexed entries
788  for(int i = 0; i <= paramMax; i++)
789  {
790  paramDefaultValues.append(QString());
791  }
792 
793  for ( QDomElement e = element.firstChildElement(); !e.isNull(); e = e.nextSiblingElement() ) {
794  QString tag = e.tagName();
795  if ( tag == "default" )
796  {
797  QString index = e.attribute("param");
798  if (index.isEmpty())
799  continue;
800 
801  bool ok;
802  int i = index.toInt(&ok);
803  if (!ok)
804  {
805  i = paramValues.indexOf(index);
806  if (i == -1)
807  {
808  cerr << "Index '" << index << "' for default value is unknown." << endl;
809  return 0;
810  }
811  }
812 
813  if ((i < 0) || (i > paramMax))
814  {
815  cerr << "Index '" << i << "' for default value is out of range [0, "<< paramMax<<"]." << endl;
816  return 0;
817  }
818 
819  QString tmpDefaultValue = e.text();
820 
821  if (e.attribute( "code" ) != "true")
822  preProcessDefault(tmpDefaultValue, name, type, choices, code, cfg);
823 
824  paramDefaultValues[i] = tmpDefaultValue;
825  }
826  }
827  }
828 
829  if (!validNameRegexp->exactMatch(name))
830  {
831  if (nameIsEmpty)
832  cerr << "The key '" << key << "' can not be used as name for the entry because "
833  "it is not a valid name. You need to specify a valid name for this entry." << endl;
834  else
835  cerr << "The name '" << name << "' is not a valid name for an entry." << endl;
836  return 0;
837  }
838 
839  if (allNames.contains(name))
840  {
841  if (nameIsEmpty)
842  cerr << "The key '" << key << "' can not be used as name for the entry because "
843  "it does not result in a unique name. You need to specify a unique name for this entry." << endl;
844  else
845  cerr << "The name '" << name << "' is not unique." << endl;
846  return 0;
847  }
848  allNames.append(name);
849 
850  if (!defaultCode)
851  {
852  preProcessDefault(defaultValue, name, type, choices, code, cfg);
853  }
854 
855  CfgEntry *result = new CfgEntry( group, type, key, name, labelContext, label, toolTipContext, toolTip, whatsThisContext, whatsThis,
856  code, defaultValue, choices, signalList,
857  hidden == "true" );
858  if (!param.isEmpty())
859  {
860  result->setParam(param);
861  result->setParamName(paramName);
862  result->setParamType(paramType);
863  result->setParamValues(paramValues);
864  result->setParamDefaultValues(paramDefaultValues);
865  result->setParamMax(paramMax);
866  }
867  result->setMinValue(minValue);
868  result->setMaxValue(maxValue);
869 
870  return result;
871 }
872 
873 static bool isUnsigned(const QString& type)
874 {
875  if ( type == "UInt" ) return true;
876  if ( type == "ULongLong" ) return true;
877  return false;
878 }
879 
883 QString param( const QString &t )
884 {
885  const QString type = t.toLower();
886  if ( type == "string" ) return "const QString &";
887  else if ( type == "stringlist" ) return "const QStringList &";
888  else if ( type == "font" ) return "const QFont &";
889  else if ( type == "rect" ) return "const QRect &";
890  else if ( type == "size" ) return "const QSize &";
891  else if ( type == "color" ) return "const QColor &";
892  else if ( type == "point" ) return "const QPoint &";
893  else if ( type == "int" ) return "int";
894  else if ( type == "uint" ) return "uint";
895  else if ( type == "bool" ) return "bool";
896  else if ( type == "double" ) return "double";
897  else if ( type == "datetime" ) return "const QDateTime &";
898  else if ( type == "longlong" ) return "qint64";
899  else if ( type == "ulonglong" ) return "quint64";
900  else if ( type == "intlist" ) return "const QList<int> &";
901  else if ( type == "enum" ) return "int";
902  else if ( type == "path" ) return "const QString &";
903  else if ( type == "pathlist" ) return "const QStringList &";
904  else if ( type == "password" ) return "const QString &";
905  else if ( type == "url" ) return "const KUrl &";
906  else if ( type == "urllist" ) return "const KUrl::List &";
907  else {
908  cerr <<"kconfig_compiler does not support type \""<< type <<"\""<<endl;
909  return "QString"; //For now, but an assert would be better
910  }
911 }
912 
916 QString cppType( const QString &t )
917 {
918  const QString type = t.toLower();
919  if ( type == "string" ) return "QString";
920  else if ( type == "stringlist" ) return "QStringList";
921  else if ( type == "font" ) return "QFont";
922  else if ( type == "rect" ) return "QRect";
923  else if ( type == "size" ) return "QSize";
924  else if ( type == "color" ) return "QColor";
925  else if ( type == "point" ) return "QPoint";
926  else if ( type == "int" ) return "int";
927  else if ( type == "uint" ) return "uint";
928  else if ( type == "bool" ) return "bool";
929  else if ( type == "double" ) return "double";
930  else if ( type == "datetime" ) return "QDateTime";
931  else if ( type == "longlong" ) return "qint64";
932  else if ( type == "ulonglong" ) return "quint64";
933  else if ( type == "intlist" ) return "QList<int>";
934  else if ( type == "enum" ) return "int";
935  else if ( type == "path" ) return "QString";
936  else if ( type == "pathlist" ) return "QStringList";
937  else if ( type == "password" ) return "QString";
938  else if ( type == "url" ) return "KUrl";
939  else if ( type == "urllist" ) return "KUrl::List";
940  else {
941  cerr<<"kconfig_compiler does not support type \""<< type <<"\""<<endl;
942  return "QString"; //For now, but an assert would be better
943  }
944 }
945 
946 QString defaultValue( const QString &t )
947 {
948  const QString type = t.toLower();
949  if ( type == "string" ) return "\"\""; // Use empty string, not null string!
950  else if ( type == "stringlist" ) return "QStringList()";
951  else if ( type == "font" ) return "QFont()";
952  else if ( type == "rect" ) return "QRect()";
953  else if ( type == "size" ) return "QSize()";
954  else if ( type == "color" ) return "QColor(128, 128, 128)";
955  else if ( type == "point" ) return "QPoint()";
956  else if ( type == "int" ) return "0";
957  else if ( type == "uint" ) return "0";
958  else if ( type == "bool" ) return "false";
959  else if ( type == "double" ) return "0.0";
960  else if ( type == "datedime" ) return "QDateTime()";
961  else if ( type == "longlong" ) return "0";
962  else if ( type == "ulonglong" ) return "0";
963  else if ( type == "intlist" ) return "QList<int>()";
964  else if ( type == "enum" ) return "0";
965  else if ( type == "path" ) return "\"\""; // Use empty string, not null string!
966  else if ( type == "pathlist" ) return "QStringList()";
967  else if ( type == "password" ) return "\"\""; // Use empty string, not null string!
968  else if ( type == "url" ) return "KUrl()";
969  else if ( type == "urllist" ) return "KUrl::List()";
970  else {
971  cerr<<"Error, kconfig_compiler does not support the \""<< type <<"\" type!"<<endl;
972  return "QString"; //For now, but an assert would be better
973  }
974 }
975 
976 QString itemType( const QString &type )
977 {
978  QString t;
979 
980  t = type;
981  t.replace( 0, 1, t.left( 1 ).toUpper() );
982 
983  return t;
984 }
985 
986 static QString itemDeclaration(const CfgEntry *e, const CfgConfig &cfg)
987 {
988  if (cfg.itemAccessors)
989  return QString();
990 
991  QString fCap = e->name();
992  fCap[0] = fCap[0].toUpper();
993  return " "+cfg.inherits+"::Item"+itemType( e->type() ) +
994  " *item" + fCap +
995  ( (!e->param().isEmpty())?(QString("[%1]").arg(e->paramMax()+1)) : QString()) +
996  ";\n";
997 }
998 
999 // returns the name of an item variable
1000 // use itemPath to know the full path
1001 // like using d-> in case of dpointer
1002 static QString itemVar(const CfgEntry *e, const CfgConfig &cfg)
1003 {
1004  QString result;
1005  if (cfg.itemAccessors)
1006  {
1007  if ( !cfg.dpointer )
1008  {
1009  result = 'm' + e->name() + "Item";
1010  result[1] = result[1].toUpper();
1011  }
1012  else
1013  {
1014  result = e->name() + "Item";
1015  result[0] = result[0].toLower();
1016  }
1017  }
1018  else
1019  {
1020  result = "item" + e->name();
1021  result[4] = result[4].toUpper();
1022  }
1023  return result;
1024 }
1025 
1026 static QString itemPath(const CfgEntry *e, const CfgConfig &cfg)
1027 {
1028  QString result;
1029  if ( cfg.dpointer ) {
1030  result = "d->"+itemVar(e, cfg);
1031  }
1032  else {
1033  result = itemVar(e, cfg);
1034  }
1035  return result;
1036 }
1037 
1038 QString newItem( const QString &type, const QString &name, const QString &key,
1039  const QString &defaultValue, const CfgConfig &cfg, const QString &param = QString())
1040 {
1041  QString t = "new "+cfg.inherits+"::Item" + itemType( type ) +
1042  "( currentGroup(), " + key + ", " + varPath( name, cfg ) + param;
1043  if ( type == "Enum" ) t += ", values" + name;
1044  if ( !defaultValue.isEmpty() ) {
1045  t += ", ";
1046  if ( type == "String" ) t += defaultValue;
1047  else t+= defaultValue;
1048  }
1049  t += " );";
1050 
1051  return t;
1052 }
1053 
1054 QString paramString(const QString &s, const CfgEntry *e, int i)
1055 {
1056  QString result = s;
1057  QString needle = "$("+e->param()+')';
1058  if (result.contains(needle))
1059  {
1060  QString tmp;
1061  if (e->paramType() == "Enum")
1062  {
1063  tmp = e->paramValues()[i];
1064  }
1065  else
1066  {
1067  tmp = QString::number(i);
1068  }
1069 
1070  result.replace(needle, tmp);
1071  }
1072  return result;
1073 }
1074 
1075 QString paramString(const QString &group, const QList<Param> &parameters)
1076 {
1077  QString paramString = group;
1078  QString arguments;
1079  int i = 1;
1080  for (QList<Param>::ConstIterator it = parameters.constBegin();
1081  it != parameters.constEnd(); ++it)
1082  {
1083  if (paramString.contains("$("+(*it).name+')'))
1084  {
1085  QString tmp;
1086  tmp.sprintf("%%%d", i++);
1087  paramString.replace("$("+(*it).name+')', tmp);
1088  arguments += ".arg( mParam"+(*it).name+" )";
1089  }
1090  }
1091  if (arguments.isEmpty())
1092  return "QLatin1String( \""+group+"\" )";
1093 
1094  return "QString( QLatin1String( \""+paramString+"\" ) )"+arguments;
1095 }
1096 
1097 /* int i is the value of the parameter */
1098 QString userTextsFunctions( CfgEntry *e, const CfgConfig &cfg, QString itemVarStr=QString(), QString i=QString() )
1099 {
1100  QString txt;
1101  if (itemVarStr.isNull()) itemVarStr=itemPath(e, cfg);
1102  if ( !e->label().isEmpty() ) {
1103  txt += " " + itemVarStr + "->setLabel( ";
1104  if ( !e->labelContext().isEmpty() )
1105  txt += "i18nc(" + quoteString(e->labelContext()) + ", ";
1106  else
1107  txt += "i18n(";
1108  if ( !e->param().isEmpty() )
1109  txt += quoteString(e->label().replace("$("+e->param()+')', i));
1110  else
1111  txt+= quoteString(e->label());
1112  txt+= ") );\n";
1113  }
1114  if ( !e->toolTip().isEmpty() ) {
1115  txt += " " + itemVarStr + "->setToolTip( ";
1116  if ( !e->toolTipContext().isEmpty() )
1117  txt += "i18nc(" + quoteString(e->toolTipContext()) + ", ";
1118  else
1119  txt += "i18n(";
1120  if ( !e->param().isEmpty() )
1121  txt += quoteString(e->toolTip().replace("$("+e->param()+')', i));
1122  else
1123  txt+= quoteString(e->toolTip());
1124  txt+=") );\n";
1125  }
1126  if ( !e->whatsThis().isEmpty() ) {
1127  txt += " " + itemVarStr + "->setWhatsThis( ";
1128  if ( !e->whatsThisContext().isEmpty() )
1129  txt += "i18nc(" + quoteString(e->whatsThisContext()) + ", ";
1130  else
1131  txt += "i18n(";
1132  if ( !e->param().isEmpty() )
1133  txt += quoteString(e->whatsThis().replace("$("+e->param()+')', i));
1134  else
1135  txt+= quoteString(e->whatsThis());
1136  txt+=") );\n";
1137  }
1138  return txt;
1139 }
1140 
1141 // returns the member accesor implementation
1142 // which should go in the h file if inline
1143 // or the cpp file if not inline
1144 QString memberAccessorBody( CfgEntry *e, bool globalEnums, const CfgConfig &cfg )
1145 {
1146  QString result;
1147  QTextStream out(&result, QIODevice::WriteOnly);
1148  QString n = e->name();
1149  QString t = e->type();
1150  bool useEnumType = cfg.useEnumTypes && t == "Enum";
1151 
1152  out << "return ";
1153  if (useEnumType)
1154  out << "static_cast<" << enumType(e, globalEnums) << ">(";
1155  out << This << varPath(n, cfg);
1156  if (!e->param().isEmpty())
1157  out << "[i]";
1158  if (useEnumType)
1159  out << ")";
1160  out << ";" << endl;
1161 
1162  return result;
1163 }
1164 
1165 // returns the member mutator implementation
1166 // which should go in the h file if inline
1167 // or the cpp file if not inline
1168 QString memberMutatorBody( CfgEntry *e, const CfgConfig &cfg )
1169 {
1170  QString result;
1171  QTextStream out(&result, QIODevice::WriteOnly);
1172  QString n = e->name();
1173  QString t = e->type();
1174 
1175  if (!e->minValue().isEmpty())
1176  {
1177  if (e->minValue() != "0" || !isUnsigned(t)) { // skip writing "if uint<0" (#187579)
1178  out << "if (v < " << e->minValue() << ")" << endl;
1179  out << "{" << endl;
1180  out << " kDebug() << \"" << setFunction(n);
1181  out << ": value \" << v << \" is less than the minimum value of ";
1182  out << e->minValue()<< "\";" << endl;
1183  out << " v = " << e->minValue() << ";" << endl;
1184  out << "}" << endl;
1185  }
1186  }
1187 
1188  if (!e->maxValue().isEmpty())
1189  {
1190  out << endl << "if (v > " << e->maxValue() << ")" << endl;
1191  out << "{" << endl;
1192  out << " kDebug() << \"" << setFunction(n);
1193  out << ": value \" << v << \" is greater than the maximum value of ";
1194  out << e->maxValue()<< "\";" << endl;
1195  out << " v = " << e->maxValue() << ";" << endl;
1196  out << "}" << endl << endl;
1197  }
1198 
1199  out << "if (!" << This << "isImmutable( QString::fromLatin1( \"";
1200  if (!e->param().isEmpty())
1201  {
1202  out << e->paramName().replace("$("+e->param()+")", "%1") << "\" ).arg( ";
1203  if ( e->paramType() == "Enum" ) {
1204  out << "QLatin1String( ";
1205 
1206  if (cfg.globalEnums)
1207  out << enumName(e->param()) << "ToString[i]";
1208  else
1209  out << enumName(e->param()) << "::enumToString[i]";
1210 
1211  out << " )";
1212  }
1213  else
1214  {
1215  out << "i";
1216  }
1217  out << " )";
1218  }
1219  else
1220  {
1221  out << n << "\" )";
1222  }
1223  out << " ))" << (!e->signalList().empty() ? " {" : "") << endl;
1224  out << " " << This << varPath(n, cfg);
1225  if (!e->param().isEmpty())
1226  out << "[i]";
1227  out << " = v;" << endl;
1228 
1229  if ( !e->signalList().empty() ) {
1230  foreach(const Signal &signal, e->signalList()) {
1231  out << " " << This << varPath("settingsChanged", cfg) << " |= " << signalEnumName(signal.name) << ";" << endl;
1232  }
1233  out << "}" << endl;
1234  }
1235 
1236  return result;
1237 }
1238 
1239 // returns the member get default implementation
1240 // which should go in the h file if inline
1241 // or the cpp file if not inline
1242 QString memberGetDefaultBody( CfgEntry *e )
1243 {
1244  QString result = e->code();
1245  QTextStream out(&result, QIODevice::WriteOnly);
1246  out << endl;
1247 
1248  if (!e->param().isEmpty()) {
1249  out << " switch (i) {" << endl;
1250  for (int i = 0; i <= e->paramMax(); ++i) {
1251  if (!e->paramDefaultValue(i).isEmpty()) {
1252  out << " case " << i << ": return " << e->paramDefaultValue(i) << ';' << endl;
1253  }
1254  }
1255  out << " default:" << endl;
1256  out << " return " << e->defaultValue().replace("$("+e->param()+')', "i") << ';' << endl;
1257  out << " }" << endl;
1258  } else {
1259  out << " return " << e->defaultValue() << ';';
1260  }
1261 
1262  return result;
1263 }
1264 
1265 // returns the item accesor implementation
1266 // which should go in the h file if inline
1267 // or the cpp file if not inline
1268 QString itemAccessorBody( CfgEntry *e, const CfgConfig &cfg )
1269 {
1270  QString result;
1271  QTextStream out(&result, QIODevice::WriteOnly);
1272 
1273  out << "return " << itemPath(e, cfg);
1274  if (!e->param().isEmpty()) out << "[i]";
1275  out << ";" << endl;
1276 
1277  return result;
1278 }
1279 
1280 //indents text adding X spaces per line
1281 QString indent(QString text, int spaces)
1282 {
1283  QString result;
1284  QTextStream out(&result, QIODevice::WriteOnly);
1285  QTextStream in(&text, QIODevice::ReadOnly);
1286  QString currLine;
1287  while ( !in.atEnd() )
1288  {
1289  currLine = in.readLine();
1290  if (!currLine.isEmpty())
1291  for (int i=0; i < spaces; i++)
1292  out << " ";
1293  out << currLine << endl;
1294  }
1295  return result;
1296 }
1297 
1298 // adds as many 'namespace foo {' lines to p_out as
1299 // there are namespaces in p_ns
1300 void beginNamespaces(const QString &p_ns, QTextStream &p_out)
1301 {
1302  if ( !p_ns.isEmpty() ) {
1303  const QStringList nameSpaces = p_ns.split( "::" );
1304  foreach (const QString &ns, nameSpaces )
1305  p_out << "namespace " << ns << " {" << endl;
1306  p_out << endl;
1307  }
1308 }
1309 
1310 // adds as many '}' lines to p_out as
1311 // there are namespaces in p_ns
1312 void endNamespaces(const QString &p_ns, QTextStream &p_out)
1313 {
1314  if ( !p_ns.isEmpty() ) {
1315  const int namespaceCount = p_ns.count( "::" ) + 1;
1316  for ( int i = 0; i < namespaceCount; ++i )
1317  p_out << "}" << endl;
1318  p_out << endl;
1319  }
1320 }
1321 
1322 
1323 int main( int argc, char **argv )
1324 {
1325  QCoreApplication app(argc, argv);
1326 
1327  validNameRegexp = new QRegExp("[a-zA-Z_][a-zA-Z0-9_]*");
1328 
1329  QString directoryName, inputFilename, codegenFilename;
1330  parseArgs(app.arguments(), directoryName, inputFilename, codegenFilename);
1331 
1332  QString baseDir = directoryName;
1333 #ifdef Q_OS_WIN
1334  if (!baseDir.endsWith('/') && !baseDir.endsWith('\\'))
1335 #else
1336  if (!baseDir.endsWith('/'))
1337 #endif
1338  baseDir.append("/");
1339 
1340  if (!codegenFilename.endsWith(QLatin1String(".kcfgc")))
1341  {
1342  cerr << "Codegen options file must have extension .kcfgc" << endl;
1343  return 1;
1344  }
1345  QString baseName = QFileInfo(codegenFilename).fileName();
1346  baseName = baseName.left(baseName.length() - 6);
1347 
1348  CfgConfig cfg = CfgConfig( codegenFilename );
1349 
1350  QFile input( inputFilename );
1351 
1352  QDomDocument doc;
1353  QString errorMsg;
1354  int errorRow;
1355  int errorCol;
1356  if ( !doc.setContent( &input, &errorMsg, &errorRow, &errorCol ) ) {
1357  cerr << "Unable to load document." << endl;
1358  cerr << "Parse error in " << inputFilename << ", line " << errorRow << ", col " << errorCol << ": " << errorMsg << endl;
1359  return 1;
1360  }
1361 
1362  QDomElement cfgElement = doc.documentElement();
1363 
1364  if ( cfgElement.isNull() ) {
1365  cerr << "No document in kcfg file" << endl;
1366  return 1;
1367  }
1368 
1369  QString cfgFileName;
1370  bool cfgFileNameArg = false;
1371  QList<Param> parameters;
1372  QList<Signal> signalList;
1373  QStringList includes;
1374  bool hasSignals = false;
1375 
1376  QList<CfgEntry*> entries;
1377 
1378  for ( QDomElement e = cfgElement.firstChildElement(); !e.isNull(); e = e.nextSiblingElement() ) {
1379  QString tag = e.tagName();
1380 
1381  if ( tag == "include" ) {
1382  QString includeFile = e.text();
1383  if (!includeFile.isEmpty())
1384  includes.append(includeFile);
1385 
1386  } else if ( tag == "kcfgfile" ) {
1387  cfgFileName = e.attribute( "name" );
1388  cfgFileNameArg = e.attribute( "arg" ).toLower() == "true";
1389  for( QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement() ) {
1390  if ( e2.tagName() == "parameter" ) {
1391  Param p;
1392  p.name = e2.attribute( "name" );
1393  p.type = e2.attribute( "type" );
1394  if (p.type.isEmpty())
1395  p.type = "String";
1396  parameters.append( p );
1397  }
1398  }
1399 
1400  } else if ( tag == "group" ) {
1401  QString group = e.attribute( "name" );
1402  if ( group.isEmpty() ) {
1403  cerr << "Group without name" << endl;
1404  return 1;
1405  }
1406  for( QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement() ) {
1407  if ( e2.tagName() != "entry" ) continue;
1408  CfgEntry *entry = parseEntry( group, e2, cfg );
1409  if ( entry ) entries.append( entry );
1410  else {
1411  cerr << "Can not parse entry." << endl;
1412  return 1;
1413  }
1414  }
1415  }
1416  else if ( tag == "signal" ) {
1417  QString signalName = e.attribute( "name" );
1418  if ( signalName.isEmpty() ) {
1419  cerr << "Signal without name." << endl;
1420  return 1;
1421  }
1422  Signal theSignal;
1423  theSignal.name = signalName;
1424 
1425  for( QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement() ) {
1426  if ( e2.tagName() == "argument") {
1427  SignalArguments argument;
1428  argument.type = e2.attribute("type");
1429  if ( argument.type.isEmpty() ) {
1430  cerr << "Signal argument without type." << endl;
1431  return 1;
1432  }
1433  argument.variableName = e2.text();
1434  theSignal.arguments.append(argument);
1435  }
1436  else if( e2.tagName() == "label") {
1437  theSignal.label = e2.text();
1438  }
1439  }
1440  signalList.append(theSignal);
1441  }
1442  }
1443 
1444  if ( cfg.className.isEmpty() ) {
1445  cerr << "Class name missing" << endl;
1446  return 1;
1447  }
1448 
1449  if ( cfg.singleton && !parameters.isEmpty() ) {
1450  cerr << "Singleton class can not have parameters" << endl;
1451  return 1;
1452  }
1453 
1454  if ( !cfgFileName.isEmpty() && cfgFileNameArg)
1455  {
1456  cerr << "Having both a fixed filename and a filename as argument is not possible." << endl;
1457  return 1;
1458  }
1459 
1460  if ( entries.isEmpty() ) {
1461  cerr << "No entries." << endl;
1462  }
1463 
1464 #if 0
1465  CfgEntry *cfg;
1466  for( cfg = entries.first(); cfg; cfg = entries.next() ) {
1467  cfg->dump();
1468  }
1469 #endif
1470 
1471  hasSignals = !signalList.empty();
1472  QString headerFileName = baseName + ".h";
1473  QString implementationFileName = baseName + ".cpp";
1474  QString mocFileName = baseName + ".moc";
1475  QString cppPreamble; // code to be inserted at the beginnin of the cpp file, e.g. initialization of static values
1476 
1477  QFile header( baseDir + headerFileName );
1478  if ( !header.open( QIODevice::WriteOnly ) ) {
1479  cerr << "Can not open '" << baseDir << headerFileName << "for writing." << endl;
1480  return 1;
1481  }
1482 
1483  QTextStream h( &header );
1484 
1485  h << "// This file is generated by kconfig_compiler from " << QFileInfo(inputFilename).fileName() << "." << endl;
1486  h << "// All changes you do to this file will be lost." << endl;
1487 
1488  h << "#ifndef " << ( !cfg.nameSpace.isEmpty() ? QString (QString(cfg.nameSpace).replace( "::", "_" ).toUpper() + '_') : "" )
1489  << cfg.className.toUpper() << "_H" << endl;
1490  h << "#define " << ( !cfg.nameSpace.isEmpty() ? QString (QString(cfg.nameSpace).replace( "::", "_" ).toUpper() + '_') : "" )
1491  << cfg.className.toUpper() << "_H" << endl << endl;
1492 
1493  // Includes
1494  QStringList::ConstIterator it;
1495  for( it = cfg.headerIncludes.constBegin(); it != cfg.headerIncludes.constEnd(); ++it ) {
1496  if ( (*it).startsWith('"') )
1497  h << "#include " << *it << endl;
1498  else
1499  h << "#include <" << *it << ">" << endl;
1500  }
1501 
1502  if ( cfg.headerIncludes.count() > 0 ) h << endl;
1503 
1504  if ( !cfg.singleton && parameters.isEmpty() )
1505  h << "#include <kglobal.h>" << endl;
1506 
1507  if ( cfg.inherits=="KCoreConfigSkeleton" ) {
1508  h << "#include <kcoreconfigskeleton.h>" << endl;
1509  } else {
1510  h << "#include <kconfigskeleton.h>" << endl;
1511  }
1512 
1513  h << "#include <kdebug.h>" << endl << endl;
1514 
1515  // Includes
1516  for( it = includes.constBegin(); it != includes.constEnd(); ++it ) {
1517  if ( (*it).startsWith('"') )
1518  h << "#include " << *it << endl;
1519  else
1520  h << "#include <" << *it << ">" << endl;
1521  }
1522 
1523  beginNamespaces(cfg.nameSpace, h);
1524 
1525  // Private class declaration
1526  if ( cfg.dpointer )
1527  h << "class " << cfg.className << "Private;" << endl << endl;
1528 
1529  // Class declaration header
1530  h << "class " << cfg.visibility << cfg.className << " : public " << cfg.inherits << endl;
1531 
1532  h << "{" << endl;
1533  // Add Q_OBJECT macro if the config need signals.
1534  if( hasSignals )
1535  h << " Q_OBJECT" << endl;
1536  h << " public:" << endl;
1537 
1538  // enums
1539  QList<CfgEntry*>::ConstIterator itEntry;
1540  for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) {
1541  const CfgEntry::Choices &choices = (*itEntry)->choices();
1542  const QList<CfgEntry::Choice> chlist = choices.choices;
1543  if ( !chlist.isEmpty() ) {
1544  QStringList values;
1545  QList<CfgEntry::Choice>::ConstIterator itChoice;
1546  for( itChoice = chlist.constBegin(); itChoice != chlist.constEnd(); ++itChoice ) {
1547  values.append( choices.prefix + (*itChoice).name );
1548  }
1549  if ( choices.name().isEmpty() ) {
1550  if ( cfg.globalEnums ) {
1551  h << " enum " << enumName( (*itEntry)->name(), (*itEntry)->choices() ) << " { " << values.join( ", " ) << " };" << endl;
1552  } else {
1553  // Create an automatically named enum
1554  h << " class " << enumName( (*itEntry)->name(), (*itEntry)->choices() ) << endl;
1555  h << " {" << endl;
1556  h << " public:" << endl;
1557  h << " enum type { " << values.join( ", " ) << ", COUNT };" << endl;
1558  h << " };" << endl;
1559  }
1560  } else if ( !choices.external() ) {
1561  // Create a named enum
1562  h << " enum " << enumName( (*itEntry)->name(), (*itEntry)->choices() ) << " { " << values.join( ", " ) << " };" << endl;
1563  }
1564  }
1565  const QStringList values = (*itEntry)->paramValues();
1566  if ( !values.isEmpty() ) {
1567  if ( cfg.globalEnums ) {
1568  // ### FIXME!!
1569  // make the following string table an index-based string search!
1570  // ###
1571  h << " enum " << enumName( (*itEntry)->param() ) << " { " << values.join( ", " ) << " };" << endl;
1572  h << " static const char* const " << enumName( (*itEntry)->param() ) << "ToString[];" << endl;
1573  cppPreamble += "const char* const " + cfg.className + "::" + enumName( (*itEntry)->param() ) +
1574  "ToString[] = { \"" + values.join( "\", \"" ) + "\" };\n";
1575  } else {
1576  h << " class " << enumName( (*itEntry)->param() ) << endl;
1577  h << " {" << endl;
1578  h << " public:" << endl;
1579  h << " enum type { " << values.join( ", " ) << ", COUNT };" << endl;
1580  h << " static const char* const enumToString[];" << endl;
1581  h << " };" << endl;
1582  cppPreamble += "const char* const " + cfg.className + "::" + enumName( (*itEntry)->param() ) +
1583  "::enumToString[] = { \"" + values.join( "\", \"" ) + "\" };\n";
1584  }
1585  }
1586  }
1587  if ( hasSignals ) {
1588  h << "\n enum {" << endl;
1589  unsigned val = 1;
1590  QList<Signal>::ConstIterator it, itEnd = signalList.constEnd();
1591  for ( it = signalList.constBegin(); it != itEnd; val <<= 1) {
1592  if ( !val ) {
1593  cerr << "Too many signals to create unique bit masks" << endl;
1594  exit(1);
1595  }
1596  Signal signal = *it;
1597  h << " " << signalEnumName(signal.name) << " = 0x" << hex << val;
1598  if ( ++it != itEnd )
1599  h << ",";
1600  h << endl;
1601  }
1602  h << " };" << dec << endl;
1603  }
1604  h << endl;
1605  // Constructor or singleton accessor
1606  if ( !cfg.singleton ) {
1607  h << " " << cfg.className << "(";
1608  if (cfgFileNameArg)
1609  {
1610  if(cfg.forceStringFilename)
1611  h << " const QString &cfgfilename"
1612  << (parameters.isEmpty() ? " = QString()" : ", ");
1613  else
1614  h << " KSharedConfig::Ptr config"
1615  << (parameters.isEmpty() ? " = KGlobal::config()" : ", ");
1616  }
1617  for (QList<Param>::ConstIterator it = parameters.constBegin();
1618  it != parameters.constEnd(); ++it)
1619  {
1620  if (it != parameters.constBegin())
1621  h << ",";
1622  h << " " << param((*it).type) << " " << (*it).name;
1623  }
1624  h << " );" << endl;
1625  } else {
1626  h << " static " << cfg.className << " *self();" << endl;
1627  if (cfgFileNameArg)
1628  {
1629  h << " static void instance(const QString& cfgfilename);" << endl;
1630  }
1631  }
1632 
1633  // Destructor
1634  h << " ~" << cfg.className << "();" << endl << endl;
1635 
1636  // global variables
1637  if (cfg.staticAccessors)
1638  This = "self()->";
1639  else
1640  Const = " const";
1641 
1642  for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) {
1643  QString n = (*itEntry)->name();
1644  QString t = (*itEntry)->type();
1645 
1646  // Manipulator
1647  if (cfg.allMutators || cfg.mutators.contains(n))
1648  {
1649  h << " /**" << endl;
1650  h << " Set " << (*itEntry)->label() << endl;
1651  h << " */" << endl;
1652  if (cfg.staticAccessors)
1653  h << " static" << endl;
1654  h << " void " << setFunction(n) << "( ";
1655  if (!(*itEntry)->param().isEmpty())
1656  h << cppType((*itEntry)->paramType()) << " i, ";
1657  if (cfg.useEnumTypes && t == "Enum")
1658  h << enumType(*itEntry, cfg.globalEnums);
1659  else
1660  h << param( t );
1661  h << " v )";
1662  // function body inline only if not using dpointer
1663  // for BC mode
1664  if ( !cfg.dpointer )
1665  {
1666  h << endl << " {" << endl;
1667  h << indent(memberMutatorBody(*itEntry, cfg), 6 );
1668  h << " }" << endl;
1669  }
1670  else
1671  {
1672  h << ";" << endl;
1673  }
1674  }
1675  h << endl;
1676  // Accessor
1677  h << " /**" << endl;
1678  h << " Get " << (*itEntry)->label() << endl;
1679  h << " */" << endl;
1680  if (cfg.staticAccessors)
1681  h << " static" << endl;
1682  h << " ";
1683  if (cfg.useEnumTypes && t == "Enum")
1684  h << enumType(*itEntry, cfg.globalEnums);
1685  else
1686  h << cppType(t);
1687  h << " " << getFunction(n) << "(";
1688  if (!(*itEntry)->param().isEmpty())
1689  h << " " << cppType((*itEntry)->paramType()) <<" i ";
1690  h << ")" << Const;
1691  // function body inline only if not using dpointer
1692  // for BC mode
1693  if ( !cfg.dpointer )
1694  {
1695  h << endl << " {" << endl;
1696  h << indent(memberAccessorBody(*itEntry, cfg.globalEnums, cfg), 6 );
1697  h << " }" << endl;
1698  }
1699  else
1700  {
1701  h << ";" << endl;
1702  }
1703 
1704  // Default value Accessor
1705  if ((cfg.allDefaultGetters || cfg.defaultGetters.contains(n)) && !(*itEntry)->defaultValue().isEmpty()) {
1706  h << endl;
1707  h << " /**" << endl;
1708  h << " Get " << (*itEntry)->label() << " default value" << endl;
1709  h << " */" << endl;
1710  if (cfg.staticAccessors)
1711  h << " static" << endl;
1712  h << " ";
1713  if (cfg.useEnumTypes && t == "Enum")
1714  h << enumType(*itEntry, cfg.globalEnums);
1715  else
1716  h << cppType(t);
1717  h << " " << getDefaultFunction(n) << "(";
1718  if ( !(*itEntry)->param().isEmpty() )
1719  h << " " << cppType( (*itEntry)->paramType() ) <<" i ";
1720  h << ")" << Const << endl;
1721  h << " {" << endl;
1722  h << " return ";
1723  if (cfg.useEnumTypes && t == "Enum")
1724  h << "static_cast<" << enumType(*itEntry, cfg.globalEnums) << ">(";
1725  h << getDefaultFunction(n) << "_helper(";
1726  if ( !(*itEntry)->param().isEmpty() )
1727  h << " i ";
1728  h << ")";
1729  if (cfg.useEnumTypes && t == "Enum")
1730  h << ")";
1731  h << ";" << endl;
1732  h << " }" << endl;
1733  }
1734 
1735  // Item accessor
1736  if ( cfg.itemAccessors ) {
1737  h << endl;
1738  h << " /**" << endl;
1739  h << " Get Item object corresponding to " << n << "()"
1740  << endl;
1741  h << " */" << endl;
1742  h << " Item" << itemType( (*itEntry)->type() ) << " *"
1743  << getFunction( n ) << "Item(";
1744  if (!(*itEntry)->param().isEmpty()) {
1745  h << " " << cppType((*itEntry)->paramType()) << " i ";
1746  }
1747  h << ")";
1748  if ( !cfg.dpointer )
1749  {
1750  h << endl << " {" << endl;
1751  h << indent( itemAccessorBody((*itEntry), cfg), 6);
1752  h << " }" << endl;
1753  }
1754  else
1755  {
1756  h << ";" << endl;
1757  }
1758  }
1759 
1760  h << endl;
1761  }
1762 
1763 
1764  // Signal definition.
1765  if( hasSignals ) {
1766  h << endl;
1767  h << " Q_SIGNALS:";
1768  foreach(const Signal &signal, signalList) {
1769  h << endl;
1770  if ( !signal.label.isEmpty() ) {
1771  h << " /**" << endl;
1772  h << " " << signal.label << endl;
1773  h << " */" << endl;
1774  }
1775  h << " void " << signal.name << "(";
1776  QList<SignalArguments>::ConstIterator it, itEnd = signal.arguments.constEnd();
1777  for ( it = signal.arguments.constBegin(); it != itEnd; ) {
1778  SignalArguments argument = *it;
1779  QString type = param(argument.type);
1780  if ( cfg.useEnumTypes && argument.type == "Enum" ) {
1781  for ( int i = 0, end = entries.count(); i < end; ++i ) {
1782  if ( entries[i]->name() == argument.variableName ) {
1783  type = enumType(entries[i], cfg.globalEnums);
1784  break;
1785  }
1786  }
1787  }
1788  h << type << " " << argument.variableName;
1789  if ( ++it != itEnd ) {
1790  h << ", ";
1791  }
1792  }
1793  h << ");" << endl;
1794  }
1795  h << endl;
1796  }
1797 
1798  h << " protected:" << endl;
1799 
1800  // Private constructor for singleton
1801  if ( cfg.singleton ) {
1802  h << " " << cfg.className << "(";
1803  if ( cfgFileNameArg )
1804  h << "const QString& arg";
1805  h << ");" << endl;
1806  h << " friend class " << cfg.className << "Helper;" << endl << endl;
1807  }
1808 
1809  if ( hasSignals ) {
1810  h << " virtual void usrWriteConfig();" << endl;
1811  }
1812 
1813  // Member variables
1814  if ( !cfg.memberVariables.isEmpty() && cfg.memberVariables != "private" && cfg.memberVariables != "dpointer") {
1815  h << " " << cfg.memberVariables << ":" << endl;
1816  }
1817 
1818  // Class Parameters
1819  for (QList<Param>::ConstIterator it = parameters.constBegin();
1820  it != parameters.constEnd(); ++it)
1821  {
1822  h << " " << cppType((*it).type) << " mParam" << (*it).name << ";" << endl;
1823  }
1824 
1825  if ( cfg.memberVariables != "dpointer" )
1826  {
1827  QString group;
1828  for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) {
1829  if ( (*itEntry)->group() != group ) {
1830  group = (*itEntry)->group();
1831  h << endl;
1832  h << " // " << group << endl;
1833  }
1834  h << " " << cppType( (*itEntry)->type() ) << " " << varName( (*itEntry)->name(), cfg );
1835  if ( !(*itEntry)->param().isEmpty() )
1836  {
1837  h << QString("[%1]").arg( (*itEntry)->paramMax()+1 );
1838  }
1839  h << ";" << endl;
1840 
1841  if ( cfg.allDefaultGetters || cfg.defaultGetters.contains((*itEntry)->name()) )
1842  {
1843  h << " ";
1844  if (cfg.staticAccessors)
1845  h << "static ";
1846  h << cppType((*itEntry)->type()) << " " << getDefaultFunction((*itEntry)->name()) << "_helper(";
1847  if ( !(*itEntry)->param().isEmpty() )
1848  h << " " << cppType( (*itEntry)->paramType() ) <<" i ";
1849  h << ")" << Const << ";" << endl;
1850  }
1851  }
1852 
1853  h << endl << " private:" << endl;
1854  if ( cfg.itemAccessors ) {
1855  for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) {
1856  h << " Item" << itemType( (*itEntry)->type() ) << " *" << itemVar( *itEntry, cfg );
1857  if ( !(*itEntry)->param().isEmpty() ) h << QString("[%1]").arg( (*itEntry)->paramMax()+1 );
1858  h << ";" << endl;
1859  }
1860  }
1861  if ( hasSignals )
1862  h << " uint " << varName("settingsChanged", cfg) << ";" << endl;
1863 
1864  }
1865  else
1866  {
1867  // use a private class for both member variables and items
1868  h << " private:" << endl;
1869  for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) {
1870  if ( cfg.allDefaultGetters || cfg.defaultGetters.contains((*itEntry)->name()) ) {
1871  h << " ";
1872  if (cfg.staticAccessors)
1873  h << "static ";
1874  h << cppType((*itEntry)->type()) << " " << getDefaultFunction((*itEntry)->name()) << "_helper(";
1875  if ( !(*itEntry)->param().isEmpty() )
1876  h << " " << cppType( (*itEntry)->paramType() ) <<" i ";
1877  h << ")" << Const << ";" << endl;
1878  }
1879  }
1880  h << " " + cfg.className + "Private *d;" << endl;
1881  }
1882 
1883  if (cfg.customAddons)
1884  {
1885  h << " // Include custom additions" << endl;
1886  h << " #include \"" << filenameOnly(baseName) << "_addons.h\"" <<endl;
1887  }
1888 
1889  h << "};" << endl << endl;
1890 
1891  endNamespaces(cfg.nameSpace, h);
1892 
1893  h << "#endif" << endl << endl;
1894 
1895 
1896  header.close();
1897 
1898  QFile implementation( baseDir + implementationFileName );
1899  if ( !implementation.open( QIODevice::WriteOnly ) ) {
1900  cerr << "Can not open '" << implementationFileName << "for writing."
1901  << endl;
1902  return 1;
1903  }
1904 
1905  QTextStream cpp( &implementation );
1906 
1907 
1908  cpp << "// This file is generated by kconfig_compiler from " << QFileInfo(inputFilename).fileName() << "." << endl;
1909  cpp << "// All changes you do to this file will be lost." << endl << endl;
1910 
1911  cpp << "#include \"" << headerFileName << "\"" << endl << endl;
1912 
1913  for( it = cfg.sourceIncludes.constBegin(); it != cfg.sourceIncludes.constEnd(); ++it ) {
1914  if ( (*it).startsWith('"') )
1915  cpp << "#include " << *it << endl;
1916  else
1917  cpp << "#include <" << *it << ">" << endl;
1918  }
1919 
1920  if ( cfg.sourceIncludes.count() > 0 ) cpp << endl;
1921 
1922  if ( cfg.setUserTexts ) cpp << "#include <klocale.h>" << endl << endl;
1923 
1924  // Header required by singleton implementation
1925  if ( cfg.singleton )
1926  cpp << "#include <kglobal.h>" << endl << "#include <QtCore/QFile>" << endl << endl;
1927  if ( cfg.singleton && cfgFileNameArg )
1928  cpp << "#include <kdebug.h>" << endl << endl;
1929 
1930  if ( !cfg.nameSpace.isEmpty() )
1931  cpp << "using namespace " << cfg.nameSpace << ";" << endl << endl;
1932 
1933  QString group;
1934 
1935  // private class implementation
1936  if ( cfg.dpointer )
1937  {
1938  beginNamespaces(cfg.nameSpace, cpp);
1939  cpp << "class " << cfg.className << "Private" << endl;
1940  cpp << "{" << endl;
1941  cpp << " public:" << endl;
1942  for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) {
1943  if ( (*itEntry)->group() != group ) {
1944  group = (*itEntry)->group();
1945  cpp << endl;
1946  cpp << " // " << group << endl;
1947  }
1948  cpp << " " << cppType( (*itEntry)->type() ) << " " << varName( (*itEntry)->name(), cfg );
1949  if ( !(*itEntry)->param().isEmpty() )
1950  {
1951  cpp << QString("[%1]").arg( (*itEntry)->paramMax()+1 );
1952  }
1953  cpp << ";" << endl;
1954  }
1955  cpp << endl << " // items" << endl;
1956  for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) {
1957  cpp << " "+cfg.inherits+"::Item" << itemType( (*itEntry)->type() ) << " *" << itemVar( *itEntry, cfg );
1958  if ( !(*itEntry)->param().isEmpty() ) cpp << QString("[%1]").arg( (*itEntry)->paramMax()+1 );
1959  cpp << ";" << endl;
1960  }
1961  if ( hasSignals ) {
1962  cpp << " uint " << varName("settingsChanged", cfg) << ";" << endl;
1963  }
1964 
1965  cpp << "};" << endl << endl;
1966  endNamespaces(cfg.nameSpace, cpp);
1967  }
1968 
1969  // Singleton implementation
1970  if ( cfg.singleton ) {
1971  beginNamespaces(cfg.nameSpace, cpp);
1972  cpp << "class " << cfg.className << "Helper" << endl;
1973  cpp << '{' << endl;
1974  cpp << " public:" << endl;
1975  cpp << " " << cfg.className << "Helper() : q(0) {}" << endl;
1976  cpp << " ~" << cfg.className << "Helper() { delete q; }" << endl;
1977  cpp << " " << cfg.className << " *q;" << endl;
1978  cpp << "};" << endl;
1979  endNamespaces(cfg.nameSpace, cpp);
1980  cpp << "K_GLOBAL_STATIC(" << cfg.className << "Helper, s_global" << cfg.className << ")" << endl;
1981 
1982  cpp << cfg.className << " *" << cfg.className << "::self()" << endl;
1983  cpp << "{" << endl;
1984  if ( cfgFileNameArg ) {
1985  cpp << " if (!s_global" << cfg.className << "->q)" << endl;
1986  cpp << " kFatal() << \"you need to call " << cfg.className << "::instance before using\";" << endl;
1987  } else {
1988  cpp << " if (!s_global" << cfg.className << "->q) {" << endl;
1989  cpp << " new " << cfg.className << ';' << endl;
1990  cpp << " s_global" << cfg.className << "->q->readConfig();" << endl;
1991  cpp << " }" << endl << endl;
1992  }
1993  cpp << " return s_global" << cfg.className << "->q;" << endl;
1994  cpp << "}" << endl << endl;
1995 
1996  if ( cfgFileNameArg ) {
1997  cpp << "void " << cfg.className << "::instance(const QString& cfgfilename)" << endl;
1998  cpp << "{" << endl;
1999  cpp << " if (s_global" << cfg.className << "->q) {" << endl;
2000  cpp << " kDebug() << \"" << cfg.className << "::instance called after the first use - ignoring\";" << endl;
2001  cpp << " return;" << endl;
2002  cpp << " }" << endl;
2003  cpp << " new " << cfg.className << "(cfgfilename);" << endl;
2004  cpp << " s_global" << cfg.className << "->q->readConfig();" << endl;
2005  cpp << "}" << endl << endl;
2006  }
2007  }
2008 
2009  if ( !cppPreamble.isEmpty() )
2010  cpp << cppPreamble << endl;
2011 
2012  // Constructor
2013  cpp << cfg.className << "::" << cfg.className << "( ";
2014  if ( cfgFileNameArg ) {
2015  if ( !cfg.singleton && ! cfg.forceStringFilename)
2016  cpp << " KSharedConfig::Ptr config";
2017  else
2018  cpp << " const QString& config";
2019  cpp << (parameters.isEmpty() ? " " : ", ");
2020  }
2021 
2022  for (QList<Param>::ConstIterator it = parameters.constBegin();
2023  it != parameters.constEnd(); ++it)
2024  {
2025  if (it != parameters.constBegin())
2026  cpp << ",";
2027  cpp << " " << param((*it).type) << " " << (*it).name;
2028  }
2029  cpp << " )" << endl;
2030 
2031  cpp << " : " << cfg.inherits << "(";
2032  if ( !cfgFileName.isEmpty() ) cpp << " QLatin1String( \"" << cfgFileName << "\" ";
2033  if ( cfgFileNameArg ) cpp << " config ";
2034  if ( !cfgFileName.isEmpty() ) cpp << ") ";
2035  cpp << ")" << endl;
2036 
2037  // Store parameters
2038  for (QList<Param>::ConstIterator it = parameters.constBegin();
2039  it != parameters.constEnd(); ++it)
2040  {
2041  cpp << " , mParam" << (*it).name << "(" << (*it).name << ")" << endl;
2042  }
2043 
2044  if ( hasSignals && !cfg.dpointer )
2045  cpp << " , " << varName("settingsChanged", cfg) << "(0)" << endl;
2046 
2047  cpp << "{" << endl;
2048 
2049  if (cfg.dpointer)
2050  {
2051  cpp << " d = new " + cfg.className + "Private;" << endl;
2052  if (hasSignals)
2053  cpp << " " << varPath("settingsChanged", cfg) << " = 0;" << endl;
2054  }
2055  // Needed in case the singleton class is used as baseclass for
2056  // another singleton.
2057  if (cfg.singleton) {
2058  cpp << " Q_ASSERT(!s_global" << cfg.className << "->q);" << endl;
2059  cpp << " s_global" << cfg.className << "->q = this;" << endl;
2060  }
2061 
2062  group.clear();
2063 
2064  for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) {
2065  if ( (*itEntry)->group() != group ) {
2066  if ( !group.isEmpty() ) cpp << endl;
2067  group = (*itEntry)->group();
2068  cpp << " setCurrentGroup( " << paramString(group, parameters) << " );" << endl << endl;
2069  }
2070 
2071  QString key = paramString( (*itEntry)->key(), parameters );
2072  if ( !(*itEntry)->code().isEmpty() ) {
2073  cpp << (*itEntry)->code() << endl;
2074  }
2075  if ( (*itEntry)->type() == "Enum" ) {
2076  cpp << " QList<"+cfg.inherits+"::ItemEnum::Choice2> values"
2077  << (*itEntry)->name() << ";" << endl;
2078  const QList<CfgEntry::Choice> choices = (*itEntry)->choices().choices;
2079  QList<CfgEntry::Choice>::ConstIterator it;
2080  for( it = choices.constBegin(); it != choices.constEnd(); ++it ) {
2081  cpp << " {" << endl;
2082  cpp << " "+cfg.inherits+"::ItemEnum::Choice2 choice;" << endl;
2083  cpp << " choice.name = QLatin1String(\"" << (*it).name << "\");" << endl;
2084  if ( cfg.setUserTexts ) {
2085  if ( !(*it).label.isEmpty() ) {
2086  cpp << " choice.label = ";
2087  if ( !(*it).context.isEmpty() )
2088  cpp << "i18nc(" + quoteString((*it).context) + ", ";
2089  else
2090  cpp << "i18n(";
2091  cpp << quoteString((*it).label) << ");" << endl;
2092  }
2093  if ( !(*it).toolTip.isEmpty() ) {
2094  cpp << " choice.toolTip = ";
2095  if ( !(*it).context.isEmpty() )
2096  cpp << "i18nc(" + quoteString((*it).context) + ", ";
2097  else
2098  cpp << "i18n(";
2099  cpp << quoteString((*it).toolTip) << ");" << endl;
2100  }
2101  if ( !(*it).whatsThis.isEmpty() ) {
2102  cpp << " choice.whatsThis = ";
2103  if ( !(*it).context.isEmpty() )
2104  cpp << "i18nc(" + quoteString((*it).context) + ", ";
2105  else
2106  cpp << "i18n(";
2107  cpp << quoteString((*it).whatsThis) << ");" << endl;
2108  }
2109  }
2110  cpp << " values" << (*itEntry)->name() << ".append( choice );" << endl;
2111  cpp << " }" << endl;
2112  }
2113  }
2114 
2115  if (!cfg.dpointer)
2116  cpp << itemDeclaration( *itEntry, cfg );
2117 
2118  if ( (*itEntry)->param().isEmpty() )
2119  {
2120  // Normal case
2121  cpp << " " << itemPath( *itEntry, cfg ) << " = "
2122  << newItem( (*itEntry)->type(), (*itEntry)->name(), key, (*itEntry)->defaultValue(), cfg ) << endl;
2123 
2124  if ( !(*itEntry)->minValue().isEmpty() )
2125  cpp << " " << itemPath( *itEntry, cfg ) << "->setMinValue(" << (*itEntry)->minValue() << ");" << endl;
2126  if ( !(*itEntry)->maxValue().isEmpty() )
2127  cpp << " " << itemPath( *itEntry, cfg ) << "->setMaxValue(" << (*itEntry)->maxValue() << ");" << endl;
2128 
2129  if ( cfg.setUserTexts )
2130  cpp << userTextsFunctions( (*itEntry), cfg );
2131 
2132  cpp << " addItem( " << itemPath( *itEntry, cfg );
2133  QString quotedName = (*itEntry)->name();
2134  addQuotes( quotedName );
2135  if ( quotedName != key ) cpp << ", QLatin1String( \"" << (*itEntry)->name() << "\" )";
2136  cpp << " );" << endl;
2137  }
2138  else
2139  {
2140  // Indexed
2141  for(int i = 0; i <= (*itEntry)->paramMax(); i++)
2142  {
2143  QString defaultStr;
2144  QString itemVarStr(itemPath( *itEntry, cfg )+QString("[%1]").arg(i));
2145 
2146  if ( !(*itEntry)->paramDefaultValue(i).isEmpty() )
2147  defaultStr = (*itEntry)->paramDefaultValue(i);
2148  else if ( !(*itEntry)->defaultValue().isEmpty() )
2149  defaultStr = paramString( (*itEntry)->defaultValue(), (*itEntry), i );
2150  else
2151  defaultStr = defaultValue( (*itEntry)->type() );
2152 
2153  cpp << " " << itemVarStr << " = "
2154  << newItem( (*itEntry)->type(), (*itEntry)->name(), paramString(key, *itEntry, i), defaultStr,cfg, QString("[%1]").arg(i) )
2155  << endl;
2156 
2157  if ( cfg.setUserTexts )
2158  cpp << userTextsFunctions( *itEntry, cfg, itemVarStr, (*itEntry)->paramName() );
2159 
2160  // Make mutators for enum parameters work by adding them with $(..) replaced by the
2161  // param name. The check for isImmutable in the set* functions doesn't have the param
2162  // name available, just the corresponding enum value (int), so we need to store the
2163  // param names in a separate static list!.
2164  cpp << " addItem( " << itemVarStr << ", QLatin1String( \"";
2165  if ( (*itEntry)->paramType()=="Enum" )
2166  cpp << (*itEntry)->paramName().replace( "$("+(*itEntry)->param()+')', "%1").arg((*itEntry)->paramValues()[i] );
2167  else
2168  cpp << (*itEntry)->paramName().replace( "$("+(*itEntry)->param()+')', "%1").arg(i);
2169  cpp << "\" ) );" << endl;
2170  }
2171  }
2172  }
2173 
2174  cpp << "}" << endl << endl;
2175 
2176  if (cfg.dpointer)
2177  {
2178  // setters and getters go in Cpp if in dpointer mode
2179  for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) {
2180  QString n = (*itEntry)->name();
2181  QString t = (*itEntry)->type();
2182 
2183  // Manipulator
2184  if (cfg.allMutators || cfg.mutators.contains(n))
2185  {
2186  cpp << "void " << setFunction(n, cfg.className) << "( ";
2187  if ( !(*itEntry)->param().isEmpty() )
2188  cpp << cppType( (*itEntry)->paramType() ) << " i, ";
2189  if (cfg.useEnumTypes && t == "Enum")
2190  cpp << enumType(*itEntry, cfg.globalEnums);
2191  else
2192  cpp << param( t );
2193  cpp << " v )" << endl;
2194  // function body inline only if not using dpointer
2195  // for BC mode
2196  cpp << "{" << endl;
2197  cpp << indent(memberMutatorBody( *itEntry, cfg ), 6);
2198  cpp << "}" << endl << endl;
2199  }
2200 
2201  // Accessor
2202  if (cfg.useEnumTypes && t == "Enum")
2203  cpp << enumType(*itEntry, cfg.globalEnums);
2204  else
2205  cpp << cppType(t);
2206  cpp << " " << getFunction(n, cfg.className) << "(";
2207  if ( !(*itEntry)->param().isEmpty() )
2208  cpp << " " << cppType( (*itEntry)->paramType() ) <<" i ";
2209  cpp << ")" << Const << endl;
2210  // function body inline only if not using dpointer
2211  // for BC mode
2212  cpp << "{" << endl;
2213  cpp << indent(memberAccessorBody( *itEntry, cfg.globalEnums, cfg ), 2);
2214  cpp << "}" << endl << endl;
2215 
2216  // Default value Accessor -- written by the loop below
2217 
2218  // Item accessor
2219  if ( cfg.itemAccessors )
2220  {
2221  cpp << endl;
2222  cpp << cfg.inherits+"::Item" << itemType( (*itEntry)->type() ) << " *"
2223  << getFunction( n, cfg.className ) << "Item(";
2224  if ( !(*itEntry)->param().isEmpty() ) {
2225  cpp << " " << cppType( (*itEntry)->paramType() ) << " i ";
2226  }
2227  cpp << ")" << endl;
2228  cpp << "{" << endl;
2229  cpp << indent(itemAccessorBody( *itEntry, cfg ), 2);
2230  cpp << "}" << endl;
2231  }
2232 
2233  cpp << endl;
2234  }
2235  }
2236 
2237  // default value getters always go in Cpp
2238  for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) {
2239  QString n = (*itEntry)->name();
2240  QString t = (*itEntry)->type();
2241 
2242  // Default value Accessor, as "helper" function
2243  if (( cfg.allDefaultGetters || cfg.defaultGetters.contains(n) ) && !(*itEntry)->defaultValue().isEmpty() ) {
2244  cpp << cppType(t) << " " << getDefaultFunction(n, cfg.className) << "_helper(";
2245  if ( !(*itEntry)->param().isEmpty() )
2246  cpp << " " << cppType( (*itEntry)->paramType() ) <<" i ";
2247  cpp << ")" << Const << endl;
2248  cpp << "{" << endl;
2249  cpp << memberGetDefaultBody(*itEntry) << endl;
2250  cpp << "}" << endl << endl;
2251  }
2252  }
2253 
2254  // Destructor
2255  cpp << cfg.className << "::~" << cfg.className << "()" << endl;
2256  cpp << "{" << endl;
2257  if ( cfg.singleton ) {
2258  if ( cfg.dpointer )
2259  cpp << " delete d;" << endl;
2260  cpp << " if (!s_global" << cfg.className << ".isDestroyed()) {" << endl;
2261  cpp << " s_global" << cfg.className << "->q = 0;" << endl;
2262  cpp << " }" << endl;
2263  }
2264  cpp << "}" << endl << endl;
2265 
2266  if ( hasSignals ) {
2267  cpp << "void " << cfg.className << "::" << "usrWriteConfig()" << endl;
2268  cpp << "{" << endl;
2269  cpp << " " << cfg.inherits << "::usrWriteConfig();" << endl << endl;
2270  foreach(const Signal &signal, signalList) {
2271  cpp << " if ( " << varPath("settingsChanged", cfg) << " & " << signalEnumName(signal.name) << " ) " << endl;
2272  cpp << " emit " << signal.name << "(";
2273  QList<SignalArguments>::ConstIterator it, itEnd = signal.arguments.constEnd();
2274  for ( it = signal.arguments.constBegin(); it != itEnd; ) {
2275  SignalArguments argument = *it;
2276  bool cast = false;
2277  if ( cfg.useEnumTypes && argument.type == "Enum" ) {
2278  for ( int i = 0, end = entries.count(); i < end; ++i ) {
2279  if ( entries[i]->name() == argument.variableName ) {
2280  cpp << "static_cast<" << enumType(entries[i], cfg.globalEnums) << ">(";
2281  cast = true;
2282  break;
2283  }
2284  }
2285  }
2286  cpp << varPath(argument.variableName, cfg);
2287  if ( cast )
2288  cpp << ")";
2289  if ( ++it != itEnd )
2290  cpp << ", ";
2291  }
2292  cpp << ");" << endl << endl;
2293  }
2294  cpp << " " << varPath("settingsChanged", cfg) << " = 0;" << endl;
2295  cpp << "}" << endl;
2296  }
2297 
2298  // Add includemoc if they are signals defined.
2299  if( hasSignals ) {
2300  cpp << endl;
2301  cpp << "#include \"" << mocFileName << "\"" << endl;
2302  cpp << endl;
2303  }
2304 
2305  // clear entries list
2306  qDeleteAll( entries );
2307 
2308  implementation.close();
2309 }
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Wed Mar 20 2013 07:14:34 by doxygen 1.8.3.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDECore

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

kdelibs-4.10.1 API Reference

Skip menu "kdelibs-4.10.1 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal