KConfig

kconfigloader.cpp
1 /*
2  SPDX-FileCopyrightText: 2007 Aaron Seigo <aseigo@kde.org>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "kconfigloader.h"
8 #include "kconfigloader_p.h"
9 #include "kconfigloaderhandler_p.h"
10 
11 #include <QColor>
12 #include <QFont>
13 #include <QHash>
14 #include <QUrl>
15 
16 #include <QDebug>
17 
18 void ConfigLoaderPrivate::parse(KConfigLoader *loader, QIODevice *xml)
19 {
20  clearData();
21  loader->clearItems();
22 
23  if (xml) {
24  ConfigLoaderHandler handler(loader, this);
25  handler.parse(xml);
26  }
27 }
28 
29 ConfigLoaderHandler::ConfigLoaderHandler(KConfigLoader *config, ConfigLoaderPrivate *d)
30  : m_config(config)
31  , d(d)
32 {
33  resetState();
34 }
35 
36 bool ConfigLoaderHandler::parse(QIODevice *input)
37 {
38  if (!input->open(QIODevice::ReadOnly)) {
39  qWarning() << "Impossible to open device";
40  return false;
41  }
42  QXmlStreamReader reader(input);
43 
44  while (!reader.atEnd()) {
45  reader.readNext();
46  if (reader.hasError()) {
47  return false;
48  }
49 
50  switch (reader.tokenType()) {
52  startElement(reader.name(), reader.attributes());
53  break;
55  endElement(reader.name());
56  break;
58  if (!reader.isWhitespace() && !reader.text().trimmed().isEmpty()) {
59  m_cdata.append(reader.text());
60  }
61  break;
62  default:
63  break;
64  }
65  }
66 
67  if (!reader.isEndDocument()) {
68  return false;
69  }
70 
71  return true;
72 }
73 
74 static bool caseInsensitiveCompare(const QStringView a, const QLatin1String b)
75 {
76  return a.compare(b, Qt::CaseInsensitive) == 0;
77 }
78 
79 void ConfigLoaderHandler::startElement(const QStringView localName, const QXmlStreamAttributes &attrs)
80 {
81  // qDebug() << "ConfigLoaderHandler::startElement(" << localName << qName;
82  if (caseInsensitiveCompare(localName, QLatin1String("group"))) {
83  QString group;
84  for (const auto &attr : attrs) {
85  const auto attrName = attr.name();
86  if (caseInsensitiveCompare(attrName, QLatin1String("name"))) {
87  // qDebug() << "set group to" << attrs.value(i);
88  group = attr.value().toString();
89  }
90  }
91  if (group.isEmpty()) {
92  group = d->baseGroup;
93  } else {
94  d->groups.append(group);
95  if (!d->baseGroup.isEmpty()) {
96  group = d->baseGroup + QLatin1Char('\x1d') + group;
97  }
98  }
99 
100  if (m_config) {
101  m_config->setCurrentGroup(group);
102  }
103  } else if (caseInsensitiveCompare(localName, QLatin1String("entry"))) {
104  for (const auto &attr : attrs) {
105  const auto attrName = attr.name();
106  if (caseInsensitiveCompare(attrName, QLatin1String("name"))) {
107  m_name = attr.value().trimmed().toString();
108  } else if (caseInsensitiveCompare(attrName, QLatin1String("type"))) {
109  m_type = attr.value().toString().toLower();
110  } else if (caseInsensitiveCompare(attrName, QLatin1String("key"))) {
111  m_key = attr.value().trimmed().toString();
112  }
113  }
114  } else if (caseInsensitiveCompare(localName, QLatin1String("choice"))) {
115  m_choice.name.clear();
116  m_choice.label.clear();
117  m_choice.whatsThis.clear();
118  for (const auto &attr : attrs) {
119  const auto attrName = attr.name();
120  if (caseInsensitiveCompare(attrName, QLatin1String("name"))) {
121  m_choice.name = attr.value().toString();
122  }
123  }
124  m_inChoice = true;
125  }
126 }
127 
128 void ConfigLoaderHandler::endElement(const QStringView localName)
129 {
130  // qDebug() << "ConfigLoaderHandler::endElement(" << localName << qName;
131  if (caseInsensitiveCompare(localName, QLatin1String("entry"))) {
132  addItem();
133  resetState();
134  } else if (caseInsensitiveCompare(localName, QLatin1String("label"))) {
135  if (m_inChoice) {
136  m_choice.label = m_cdata.trimmed();
137  } else {
138  m_label = m_cdata.trimmed();
139  }
140  } else if (caseInsensitiveCompare(localName, QLatin1String("whatsthis"))) {
141  if (m_inChoice) {
142  m_choice.whatsThis = m_cdata.trimmed();
143  } else {
144  m_whatsThis = m_cdata.trimmed();
145  }
146  } else if (caseInsensitiveCompare(localName, QLatin1String("default"))) {
147  m_default = m_cdata.trimmed();
148  } else if (caseInsensitiveCompare(localName, QLatin1String("min"))) {
149  m_min = m_cdata.toInt(&m_haveMin);
150  } else if (caseInsensitiveCompare(localName, QLatin1String("max"))) {
151  m_max = m_cdata.toInt(&m_haveMax);
152  } else if (caseInsensitiveCompare(localName, QLatin1String("choice"))) {
153  m_enumChoices.append(m_choice);
154  m_inChoice = false;
155  }
156 
157  m_cdata.clear();
158 }
159 
160 void ConfigLoaderHandler::addItem()
161 {
162  if (m_name.isEmpty()) {
163  if (m_key.isEmpty()) {
164  return;
165  }
166 
167  m_name = m_key;
168  }
169 
170  m_name.remove(QLatin1Char(' '));
171 
172  KConfigSkeletonItem *item = nullptr;
173 
174  if (m_type == QLatin1String("bool")) {
175  const bool defaultValue = caseInsensitiveCompare(m_default, QLatin1String("true"));
176  item = m_config->addItemBool(m_name, *d->newBool(), defaultValue, m_key);
177  } else if (m_type == QLatin1String("color")) {
178  item = m_config->addItemColor(m_name, *d->newColor(), QColor(m_default), m_key);
179  } else if (m_type == QLatin1String("datetime")) {
180  item = m_config->addItemDateTime(m_name, *d->newDateTime(), QDateTime::fromString(m_default), m_key);
181  } else if (m_type == QLatin1String("enum")) {
182  m_key = (m_key.isEmpty()) ? m_name : m_key;
183 
184  bool ok = false;
185  int defaultValue = m_default.toInt(&ok);
186  if (!ok) {
187  for (int i = 0; i < m_enumChoices.size(); i++) {
188  if (m_default == m_enumChoices[i].name) {
189  defaultValue = i;
190  break;
191  }
192  }
193  }
194 
195  KConfigSkeleton::ItemEnum *enumItem = new KConfigSkeleton::ItemEnum(m_config->currentGroup(), m_key, *d->newInt(), m_enumChoices, defaultValue);
196  m_config->addItem(enumItem, m_name);
197  item = enumItem;
198  } else if (m_type == QLatin1String("font")) {
199  item = m_config->addItemFont(m_name, *d->newFont(), QFont(m_default), m_key);
200  } else if (m_type == QLatin1String("int")) {
201  KConfigSkeleton::ItemInt *intItem = m_config->addItemInt(m_name, *d->newInt(), m_default.toInt(), m_key);
202 
203  if (m_haveMin) {
204  intItem->setMinValue(m_min);
205  }
206 
207  if (m_haveMax) {
208  intItem->setMaxValue(m_max);
209  }
210 
211  item = intItem;
212  } else if (m_type == QLatin1String("password")) {
213  item = m_config->addItemPassword(m_name, *d->newString(), m_default, m_key);
214  } else if (m_type == QLatin1String("path")) {
215  item = m_config->addItemPath(m_name, *d->newString(), m_default, m_key);
216  } else if (m_type == QLatin1String("string")) {
217  item = m_config->addItemString(m_name, *d->newString(), m_default, m_key);
218  } else if (m_type == QLatin1String("stringlist")) {
219  // FIXME: the split() is naive and will break on lists with ,'s in them
220  // empty parts are not wanted in this case
221  item = m_config->addItemStringList(m_name, *d->newStringList(), m_default.split(QLatin1Char(','), Qt::SkipEmptyParts), m_key);
222  } else if (m_type == QLatin1String("uint")) {
223  KConfigSkeleton::ItemUInt *uintItem = m_config->addItemUInt(m_name, *d->newUint(), m_default.toUInt(), m_key);
224  if (m_haveMin) {
225  uintItem->setMinValue(m_min);
226  }
227  if (m_haveMax) {
228  uintItem->setMaxValue(m_max);
229  }
230  item = uintItem;
231  } else if (m_type == QLatin1String("url")) {
232  m_key = (m_key.isEmpty()) ? m_name : m_key;
233  KConfigSkeleton::ItemUrl *urlItem = new KConfigSkeleton::ItemUrl(m_config->currentGroup(), m_key, *d->newUrl(), QUrl::fromUserInput(m_default));
234  m_config->addItem(urlItem, m_name);
235  item = urlItem;
236  } else if (m_type == QLatin1String("double")) {
237  KConfigSkeleton::ItemDouble *doubleItem = m_config->addItemDouble(m_name, *d->newDouble(), m_default.toDouble(), m_key);
238  if (m_haveMin) {
239  doubleItem->setMinValue(m_min);
240  }
241  if (m_haveMax) {
242  doubleItem->setMaxValue(m_max);
243  }
244  item = doubleItem;
245  } else if (m_type == QLatin1String("intlist")) {
246  QList<int> defaultList;
247  const QStringList tmpList = m_default.split(QLatin1Char(','), Qt::SkipEmptyParts);
248  for (const QString &tmp : tmpList) {
249  defaultList.append(tmp.toInt());
250  }
251  item = m_config->addItemIntList(m_name, *d->newIntList(), defaultList, m_key);
252  } else if (m_type == QLatin1String("longlong")) {
253  KConfigSkeleton::ItemLongLong *longlongItem = m_config->addItemLongLong(m_name, *d->newLongLong(), m_default.toLongLong(), m_key);
254  if (m_haveMin) {
255  longlongItem->setMinValue(m_min);
256  }
257  if (m_haveMax) {
258  longlongItem->setMaxValue(m_max);
259  }
260  item = longlongItem;
261  /* No addItemPathList in KConfigSkeleton ?
262  } else if (m_type == "PathList") {
263  //FIXME: the split() is naive and will break on lists with ,'s in them
264  item = m_config->addItemPathList(m_name, *d->newStringList(), m_default.split(","), m_key);
265  */
266  } else if (m_type == QLatin1String("point")) {
267  QPoint defaultPoint;
268  const QStringList tmpList = m_default.split(QLatin1Char(','));
269  if (tmpList.size() >= 2) {
270  defaultPoint.setX(tmpList[0].toInt());
271  defaultPoint.setY(tmpList[1].toInt());
272  }
273  item = m_config->addItemPoint(m_name, *d->newPoint(), defaultPoint, m_key);
274  } else if (m_type == QLatin1String("pointf")) {
275  QPointF defaultPointF;
276  const auto tmpList = QStringView(m_default).split(u',');
277  if (tmpList.size() >= 2) {
278  defaultPointF.setX(tmpList[0].toDouble());
279  defaultPointF.setY(tmpList[1].toDouble());
280  }
281  item = m_config->addItemPointF(m_name, *d->newPointF(), defaultPointF, m_key);
282  } else if (m_type == QLatin1String("rect")) {
283  QRect defaultRect;
284  const QStringList tmpList = m_default.split(QLatin1Char(','));
285  if (tmpList.size() >= 4) {
286  defaultRect.setCoords(tmpList[0].toInt(), tmpList[1].toInt(), tmpList[2].toInt(), tmpList[3].toInt());
287  }
288  item = m_config->addItemRect(m_name, *d->newRect(), defaultRect, m_key);
289  } else if (m_type == QLatin1String("rectf")) {
290  QRectF defaultRectF;
291  const auto tmpList = QStringView(m_default).split(u',');
292  if (tmpList.size() >= 4) {
293  defaultRectF.setCoords(tmpList[0].toDouble(), tmpList[1].toDouble(), tmpList[2].toDouble(), tmpList[3].toDouble());
294  }
295  item = m_config->addItemRectF(m_name, *d->newRectF(), defaultRectF, m_key);
296  } else if (m_type == QLatin1String("size")) {
298  const QStringList tmpList = m_default.split(QLatin1Char(','));
299  if (tmpList.size() >= 2) {
300  defaultSize.setWidth(tmpList[0].toInt());
301  defaultSize.setHeight(tmpList[1].toInt());
302  }
303  item = m_config->addItemSize(m_name, *d->newSize(), defaultSize, m_key);
304  } else if (m_type == QLatin1String("sizef")) {
305  QSizeF defaultSizeF;
306  const auto tmpList = QStringView(m_default).split(u',');
307  if (tmpList.size() >= 2) {
308  defaultSizeF.setWidth(tmpList[0].toDouble());
309  defaultSizeF.setHeight(tmpList[1].toDouble());
310  }
311  item = m_config->addItemSizeF(m_name, *d->newSizeF(), defaultSizeF, m_key);
312  } else if (m_type == QLatin1String("ulonglong")) {
313  KConfigSkeleton::ItemULongLong *ulonglongItem = m_config->addItemULongLong(m_name, *d->newULongLong(), m_default.toULongLong(), m_key);
314  if (m_haveMin) {
315  ulonglongItem->setMinValue(m_min);
316  }
317  if (m_haveMax) {
318  ulonglongItem->setMaxValue(m_max);
319  }
320  item = ulonglongItem;
321  /* No addItemUrlList in KConfigSkeleton ?
322  } else if (m_type == "urllist") {
323  //FIXME: the split() is naive and will break on lists with ,'s in them
324  QStringList tmpList = m_default.split(",");
325  QList<QUrl> defaultList;
326  foreach (const QString& tmp, tmpList) {
327  defaultList.append(QUrl(tmp));
328  }
329  item = m_config->addItemUrlList(m_name, *d->newUrlList(), defaultList, m_key);*/
330  }
331 
332  if (item) {
333  item->setLabel(m_label);
334  item->setWhatsThis(m_whatsThis);
335  d->keysToNames.insert(item->group() + item->key(), item->name());
336  }
337 }
338 
339 void ConfigLoaderHandler::resetState()
340 {
341  m_haveMin = false;
342  m_min = 0;
343  m_haveMax = false;
344  m_max = 0;
345  m_name.clear();
346  m_type.clear();
347  m_label.clear();
348  m_default.clear();
349  m_key.clear();
350  m_whatsThis.clear();
351  m_enumChoices.clear();
352  m_inChoice = false;
353 }
354 
355 KConfigLoader::KConfigLoader(const QString &configFile, QIODevice *xml, QObject *parent)
356  : KConfigSkeleton(configFile, parent)
357  , d(new ConfigLoaderPrivate)
358 {
359  d->parse(this, xml);
360 }
361 
363  : KConfigSkeleton(std::move(config), parent)
364  , d(new ConfigLoaderPrivate)
365 {
366  d->parse(this, xml);
367 }
368 
369 // FIXME: obviously this is broken and should be using the group as the root,
370 // but KConfigSkeleton does not currently support this. it will eventually though,
371 // at which point this can be addressed properly
373  : KConfigSkeleton(KSharedConfig::openConfig(config.config()->name(), config.config()->openFlags(), config.config()->locationType()), parent)
374  , d(new ConfigLoaderPrivate)
375 {
376  KConfigGroup group = config.parent();
377  d->baseGroup = config.name();
378  while (group.isValid() && group.name() != QLatin1String("<default>")) {
379  d->baseGroup = group.name() + QLatin1Char('\x1d') + d->baseGroup;
380  group = group.parent();
381  }
382  d->parse(this, xml);
383 }
384 
385 KConfigLoader::~KConfigLoader()
386 {
387  delete d;
388 }
389 
391 {
392  return KConfigSkeleton::findItem(d->keysToNames[group + key]);
393 }
394 
396 {
397  return KConfigSkeleton::findItem(name);
398 }
399 
401 {
403 
404  if (item) {
405  return item->property();
406  }
407 
408  return QVariant();
409 }
410 
411 bool KConfigLoader::hasGroup(const QString &group) const
412 {
413  return d->groups.contains(group);
414 }
415 
417 {
418  return d->groups;
419 }
420 
422 {
423  if (d->saveDefaults) {
424  const auto listItems = items();
425  for (const auto &item : listItems) {
426  config()->group(item->group()).writeEntry(item->key(), "");
427  }
428  }
429  return true;
430 }
Class for handling a url preferences item.
void append(const T &value)
KConfigSkeletonItem * findItemByName(const QString &name) const
Finds an item by its name.
virtual QVariant property() const =0
Return item as property.
void writeEntry(const QString &key, const QVariant &value, WriteConfigFlags pFlags=Normal)
Writes a value to the configuration object.
void setMaxValue(double)
Set the maximum value for the item.
Class for handling preferences settings for an application.
Class for handling a floating point preference item.
CaseInsensitive
KConfigSkeletonItem::List items() const
Return list of items managed by this KCoreConfigSkeleton object.
void clearItems()
Removes and deletes all items.
void setCoords(qreal x1, qreal y1, qreal x2, qreal y2)
QString trimmed() const const
void clear()
QString name() const
Returns the filename used to store the configuration.
Definition: kconfig.cpp:564
void setMinValue(quint64)
Set the minimum value for the item.
Class for handling a 64-bit integer preferences item.
bool isValid() const
Whether the group is valid.
virtual bool open(QIODevice::OpenMode mode)
QString name() const
Return internal name of entry.
A KConfigSkeleton that populates itself based on KConfigXT XML.
Definition: kconfigloader.h:91
void setMinValue(qint32)
Set the minimum value for the item.
KConfigSkeletonItem * findItem(const QString &name) const
Lookup item by name.
QString group() const
Return name of config file group.
void setWhatsThis(const QString &w)
Set WhatsThis description of item.
void setCoords(int x1, int y1, int x2, int y2)
int size() const const
QVariant property(const QString &name) const
Returns the property (variantized value) of the named item.
void setX(qreal x)
void setY(qreal y)
KConfigSkeletonItem * findItem(const QString &group, const QString &key) const
Finds the item for the given group and key.
KConfigGroup parent() const
Returns the group that this group belongs to.
SkipEmptyParts
Class for handling unsigned 64-bit integer preferences item.
void setMaxValue(quint64)
Set the maximum value for the item.
void setX(int x)
void setY(int y)
bool isEmpty() const const
KREPORT_EXPORT QPageSize::PageSizeId defaultSize()
Class for handling an unsigned 32-bit integer preferences item.
KConfigLoader(const QString &configFile, QIODevice *xml, QObject *parent=nullptr)
Creates a KConfigSkeleton populated using the definition found in the XML data passed in.
int toInt(bool *ok, int base) const const
void setMinValue(double)
Set the minimum value for the item.
void setMinValue(qint64)
Set the minimum value for the item.
QDateTime fromString(const QString &string, Qt::DateFormat format)
QStringList groupList() const
QString key() const
Return config file key.
QString toLower() const const
void setMaxValue(qint32)
Set the maximum value for the item.
Class for handling a 32-bit integer preferences item.
Class for storing a preferences setting.
void setMaxValue(qint64)
Set the maximum value for the item.
KConfig * config()
Return the KConfig object used for reading and writing the settings.
int compare(QStringView str, Qt::CaseSensitivity cs) const const
void setLabel(const QString &l)
Set label providing a translated one-line description of the item.
QString name() const
The name of this group.
bool usrSave() override
Perform the actual writing of the configuration file.
KConfigGroup group(const QString &group)
Returns an object for the named subgroup.
Definition: kconfigbase.cpp:21
Class for handling enums.
void setWidth(qreal width)
bool hasGroup(const QString &group) const
Check to see if a group exists.
void setHeight(qreal height)
void setMinValue(quint32)
Set the minimum value for the item.
QString & append(QChar ch)
QUrl fromUserInput(const QString &userInput)
void setMaxValue(quint32)
Set the maximum value for the item.
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Thu Feb 15 2024 04:07:59 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.