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

Skip menu "kdelibs-4.8.5 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