KConfig

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

KDE's Doxygen guidelines are available online.