|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the QtCore module of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include <qdebug.h> |
|
43 #include "qplatformdefs.h" |
|
44 #include "qsettings.h" |
|
45 |
|
46 #ifndef QT_NO_SETTINGS |
|
47 |
|
48 #include "qsettings_p.h" |
|
49 #include "qcache.h" |
|
50 #include "qfile.h" |
|
51 #include "qdir.h" |
|
52 #include "qfileinfo.h" |
|
53 #include "qmutex.h" |
|
54 #include "qlibraryinfo.h" |
|
55 #include "qtemporaryfile.h" |
|
56 |
|
57 #ifndef QT_NO_TEXTCODEC |
|
58 # include "qtextcodec.h" |
|
59 #endif |
|
60 |
|
61 #ifndef QT_NO_GEOM_VARIANT |
|
62 #include "qsize.h" |
|
63 #include "qpoint.h" |
|
64 #include "qrect.h" |
|
65 #endif // !QT_NO_GEOM_VARIANT |
|
66 |
|
67 #ifndef QT_NO_QOBJECT |
|
68 #include "qcoreapplication.h" |
|
69 |
|
70 #ifdef Q_OS_WIN // for homedirpath reading from registry |
|
71 #include "qt_windows.h" |
|
72 #include "qlibrary.h" |
|
73 |
|
74 #endif // Q_OS_WIN |
|
75 #endif // QT_NO_QOBJECT |
|
76 |
|
77 #ifdef Q_OS_VXWORKS |
|
78 # include <ioLib.h> |
|
79 #endif |
|
80 |
|
81 #include <stdlib.h> |
|
82 |
|
83 #ifndef CSIDL_COMMON_APPDATA |
|
84 #define CSIDL_COMMON_APPDATA 0x0023 // All Users\Application Data |
|
85 #endif |
|
86 |
|
87 #ifndef CSIDL_APPDATA |
|
88 #define CSIDL_APPDATA 0x001a // <username>\Application Data |
|
89 #endif |
|
90 |
|
91 // ************************************************************************ |
|
92 // QConfFile |
|
93 |
|
94 /* |
|
95 QConfFile objects are explicitly shared within the application. |
|
96 This ensures that modification to the settings done through one |
|
97 QSettings object are immediately reflected in other setting |
|
98 objects of the same application. |
|
99 */ |
|
100 |
|
101 QT_BEGIN_NAMESPACE |
|
102 |
|
103 struct QConfFileCustomFormat |
|
104 { |
|
105 QString extension; |
|
106 QSettings::ReadFunc readFunc; |
|
107 QSettings::WriteFunc writeFunc; |
|
108 Qt::CaseSensitivity caseSensitivity; |
|
109 }; |
|
110 |
|
111 typedef QHash<QString, QConfFile *> ConfFileHash; |
|
112 typedef QCache<QString, QConfFile> ConfFileCache; |
|
113 typedef QHash<int, QString> PathHash; |
|
114 typedef QVector<QConfFileCustomFormat> CustomFormatVector; |
|
115 |
|
116 Q_GLOBAL_STATIC(ConfFileHash, usedHashFunc) |
|
117 Q_GLOBAL_STATIC(ConfFileCache, unusedCacheFunc) |
|
118 Q_GLOBAL_STATIC(PathHash, pathHashFunc) |
|
119 Q_GLOBAL_STATIC(CustomFormatVector, customFormatVectorFunc) |
|
120 Q_GLOBAL_STATIC(QMutex, globalMutex) |
|
121 static QSettings::Format globalDefaultFormat = QSettings::NativeFormat; |
|
122 |
|
123 #ifndef Q_OS_WIN |
|
124 inline bool qt_isEvilFsTypeName(const char *name) |
|
125 { |
|
126 return (qstrncmp(name, "nfs", 3) == 0 |
|
127 || qstrncmp(name, "autofs", 6) == 0 |
|
128 || qstrncmp(name, "cachefs", 7) == 0); |
|
129 } |
|
130 |
|
131 #if defined(Q_OS_BSD4) && !defined(Q_OS_NETBSD) |
|
132 QT_BEGIN_INCLUDE_NAMESPACE |
|
133 # include <sys/param.h> |
|
134 # include <sys/mount.h> |
|
135 QT_END_INCLUDE_NAMESPACE |
|
136 |
|
137 static bool isLikelyToBeNfs(int handle) |
|
138 { |
|
139 struct statfs buf; |
|
140 if (fstatfs(handle, &buf) != 0) |
|
141 return false; |
|
142 return qt_isEvilFsTypeName(buf.f_fstypename); |
|
143 } |
|
144 |
|
145 #elif defined(Q_OS_LINUX) || defined(Q_OS_HURD) |
|
146 QT_BEGIN_INCLUDE_NAMESPACE |
|
147 # include <sys/vfs.h> |
|
148 # ifdef QT_LINUXBASE |
|
149 // LSB 3.2 has fstatfs in sys/statfs.h, sys/vfs.h is just an empty dummy header |
|
150 # include <sys/statfs.h> |
|
151 # endif |
|
152 QT_END_INCLUDE_NAMESPACE |
|
153 # ifndef NFS_SUPER_MAGIC |
|
154 # define NFS_SUPER_MAGIC 0x00006969 |
|
155 # endif |
|
156 # ifndef AUTOFS_SUPER_MAGIC |
|
157 # define AUTOFS_SUPER_MAGIC 0x00000187 |
|
158 # endif |
|
159 # ifndef AUTOFSNG_SUPER_MAGIC |
|
160 # define AUTOFSNG_SUPER_MAGIC 0x7d92b1a0 |
|
161 # endif |
|
162 |
|
163 static bool isLikelyToBeNfs(int handle) |
|
164 { |
|
165 struct statfs buf; |
|
166 if (fstatfs(handle, &buf) != 0) |
|
167 return false; |
|
168 return buf.f_type == NFS_SUPER_MAGIC |
|
169 || buf.f_type == AUTOFS_SUPER_MAGIC |
|
170 || buf.f_type == AUTOFSNG_SUPER_MAGIC; |
|
171 } |
|
172 |
|
173 #elif defined(Q_OS_SOLARIS) || defined(Q_OS_IRIX) || defined(Q_OS_AIX) || defined(Q_OS_HPUX) \ |
|
174 || defined(Q_OS_OSF) || defined(Q_OS_QNX) || defined(Q_OS_SCO) \ |
|
175 || defined(Q_OS_UNIXWARE) || defined(Q_OS_RELIANT) || defined(Q_OS_NETBSD) |
|
176 QT_BEGIN_INCLUDE_NAMESPACE |
|
177 # include <sys/statvfs.h> |
|
178 QT_END_INCLUDE_NAMESPACE |
|
179 |
|
180 static bool isLikelyToBeNfs(int handle) |
|
181 { |
|
182 struct statvfs buf; |
|
183 if (fstatvfs(handle, &buf) != 0) |
|
184 return false; |
|
185 #if defined(Q_OS_NETBSD) |
|
186 return qt_isEvilFsTypeName(buf.f_fstypename); |
|
187 #else |
|
188 return qt_isEvilFsTypeName(buf.f_basetype); |
|
189 #endif |
|
190 } |
|
191 #else |
|
192 static inline bool isLikelyToBeNfs(int /* handle */) |
|
193 { |
|
194 return true; |
|
195 } |
|
196 #endif |
|
197 |
|
198 static bool unixLock(int handle, int lockType) |
|
199 { |
|
200 /* |
|
201 NFS hangs on the fcntl() call below when statd or lockd isn't |
|
202 running. There's no way to detect this. Our work-around for |
|
203 now is to disable locking when we detect NFS (or AutoFS or |
|
204 CacheFS, which are probably wrapping NFS). |
|
205 */ |
|
206 if (isLikelyToBeNfs(handle)) |
|
207 return false; |
|
208 |
|
209 struct flock fl; |
|
210 fl.l_whence = SEEK_SET; |
|
211 fl.l_start = 0; |
|
212 fl.l_len = 0; |
|
213 fl.l_type = lockType; |
|
214 return fcntl(handle, F_SETLKW, &fl) == 0; |
|
215 } |
|
216 #endif |
|
217 |
|
218 QConfFile::QConfFile(const QString &fileName, bool _userPerms) |
|
219 : name(fileName), size(0), ref(1), userPerms(_userPerms) |
|
220 { |
|
221 usedHashFunc()->insert(name, this); |
|
222 } |
|
223 |
|
224 QConfFile::~QConfFile() |
|
225 { |
|
226 if (usedHashFunc()) |
|
227 usedHashFunc()->remove(name); |
|
228 } |
|
229 |
|
230 ParsedSettingsMap QConfFile::mergedKeyMap() const |
|
231 { |
|
232 ParsedSettingsMap result = originalKeys; |
|
233 ParsedSettingsMap::const_iterator i; |
|
234 |
|
235 for (i = removedKeys.begin(); i != removedKeys.end(); ++i) |
|
236 result.remove(i.key()); |
|
237 for (i = addedKeys.begin(); i != addedKeys.end(); ++i) |
|
238 result.insert(i.key(), i.value()); |
|
239 return result; |
|
240 } |
|
241 |
|
242 bool QConfFile::isWritable() const |
|
243 { |
|
244 QFileInfo fileInfo(name); |
|
245 |
|
246 #ifndef QT_NO_TEMPORARYFILE |
|
247 if (fileInfo.exists()) { |
|
248 #endif |
|
249 QFile file(name); |
|
250 return file.open(QFile::ReadWrite); |
|
251 #ifndef QT_NO_TEMPORARYFILE |
|
252 } else { |
|
253 // Create the directories to the file. |
|
254 QDir dir(fileInfo.absolutePath()); |
|
255 if (dir.exists() && dir.isReadable()) { |
|
256 return true; |
|
257 } else { |
|
258 if (!dir.mkpath(dir.absolutePath())) |
|
259 return false; |
|
260 } |
|
261 |
|
262 // we use a temporary file to avoid race conditions |
|
263 QTemporaryFile file(name); |
|
264 return file.open(); |
|
265 } |
|
266 #endif |
|
267 } |
|
268 |
|
269 QConfFile *QConfFile::fromName(const QString &fileName, bool _userPerms) |
|
270 { |
|
271 QString absPath = QFileInfo(fileName).absoluteFilePath(); |
|
272 |
|
273 ConfFileHash *usedHash = usedHashFunc(); |
|
274 ConfFileCache *unusedCache = unusedCacheFunc(); |
|
275 |
|
276 QConfFile *confFile = 0; |
|
277 QMutexLocker locker(globalMutex()); |
|
278 |
|
279 if (!(confFile = usedHash->value(absPath))) { |
|
280 if ((confFile = unusedCache->take(absPath))) |
|
281 usedHash->insert(absPath, confFile); |
|
282 } |
|
283 if (confFile) { |
|
284 confFile->ref.ref(); |
|
285 return confFile; |
|
286 } |
|
287 return new QConfFile(absPath, _userPerms); |
|
288 } |
|
289 |
|
290 void QConfFile::clearCache() |
|
291 { |
|
292 QMutexLocker locker(globalMutex()); |
|
293 unusedCacheFunc()->clear(); |
|
294 } |
|
295 |
|
296 // ************************************************************************ |
|
297 // QSettingsPrivate |
|
298 |
|
299 QSettingsPrivate::QSettingsPrivate(QSettings::Format format) |
|
300 : format(format), scope(QSettings::UserScope /* nothing better to put */), iniCodec(0), spec(0), fallbacks(true), |
|
301 pendingChanges(false), status(QSettings::NoError) |
|
302 { |
|
303 } |
|
304 |
|
305 QSettingsPrivate::QSettingsPrivate(QSettings::Format format, QSettings::Scope scope, |
|
306 const QString &organization, const QString &application) |
|
307 : format(format), scope(scope), organizationName(organization), applicationName(application), |
|
308 iniCodec(0), spec(0), fallbacks(true), pendingChanges(false), status(QSettings::NoError) |
|
309 { |
|
310 } |
|
311 |
|
312 QSettingsPrivate::~QSettingsPrivate() |
|
313 { |
|
314 } |
|
315 |
|
316 QString QSettingsPrivate::actualKey(const QString &key) const |
|
317 { |
|
318 QString n = normalizedKey(key); |
|
319 Q_ASSERT_X(!n.isEmpty(), "QSettings", "empty key"); |
|
320 n.prepend(groupPrefix); |
|
321 return n; |
|
322 } |
|
323 |
|
324 /* |
|
325 Returns a string that never starts nor ends with a slash (or an |
|
326 empty string). Examples: |
|
327 |
|
328 "foo" becomes "foo" |
|
329 "/foo//bar///" becomes "foo/bar" |
|
330 "///" becomes "" |
|
331 |
|
332 This function is optimized to avoid a QString deep copy in the |
|
333 common case where the key is already normalized. |
|
334 */ |
|
335 QString QSettingsPrivate::normalizedKey(const QString &key) |
|
336 { |
|
337 QString result = key; |
|
338 |
|
339 int i = 0; |
|
340 while (i < result.size()) { |
|
341 while (result.at(i) == QLatin1Char('/')) { |
|
342 result.remove(i, 1); |
|
343 if (i == result.size()) |
|
344 goto after_loop; |
|
345 } |
|
346 while (result.at(i) != QLatin1Char('/')) { |
|
347 ++i; |
|
348 if (i == result.size()) |
|
349 return result; |
|
350 } |
|
351 ++i; // leave the slash alone |
|
352 } |
|
353 |
|
354 after_loop: |
|
355 if (!result.isEmpty()) |
|
356 result.truncate(i - 1); // remove the trailing slash |
|
357 return result; |
|
358 } |
|
359 |
|
360 // see also qsettings_win.cpp and qsettings_mac.cpp |
|
361 |
|
362 #if !defined(Q_OS_WIN) && !defined(Q_OS_MAC) |
|
363 QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, QSettings::Scope scope, |
|
364 const QString &organization, const QString &application) |
|
365 { |
|
366 return new QConfFileSettingsPrivate(format, scope, organization, application); |
|
367 } |
|
368 #endif |
|
369 |
|
370 #if !defined(Q_OS_WIN) |
|
371 QSettingsPrivate *QSettingsPrivate::create(const QString &fileName, QSettings::Format format) |
|
372 { |
|
373 return new QConfFileSettingsPrivate(fileName, format); |
|
374 } |
|
375 #endif |
|
376 |
|
377 void QSettingsPrivate::processChild(QString key, ChildSpec spec, QMap<QString, QString> &result) |
|
378 { |
|
379 if (spec != AllKeys) { |
|
380 int slashPos = key.indexOf(QLatin1Char('/')); |
|
381 if (slashPos == -1) { |
|
382 if (spec != ChildKeys) |
|
383 return; |
|
384 } else { |
|
385 if (spec != ChildGroups) |
|
386 return; |
|
387 key.truncate(slashPos); |
|
388 } |
|
389 } |
|
390 result.insert(key, QString()); |
|
391 } |
|
392 |
|
393 void QSettingsPrivate::beginGroupOrArray(const QSettingsGroup &group) |
|
394 { |
|
395 groupStack.push(group); |
|
396 if (!group.name().isEmpty()) { |
|
397 groupPrefix += group.name(); |
|
398 groupPrefix += QLatin1Char('/'); |
|
399 } |
|
400 } |
|
401 |
|
402 /* |
|
403 We only set an error if there isn't one set already. This way the user always gets the |
|
404 first error that occurred. We always allow clearing errors. |
|
405 */ |
|
406 |
|
407 void QSettingsPrivate::setStatus(QSettings::Status status) const |
|
408 { |
|
409 if (status == QSettings::NoError || this->status == QSettings::NoError) |
|
410 this->status = status; |
|
411 } |
|
412 |
|
413 void QSettingsPrivate::update() |
|
414 { |
|
415 flush(); |
|
416 pendingChanges = false; |
|
417 } |
|
418 |
|
419 void QSettingsPrivate::requestUpdate() |
|
420 { |
|
421 if (!pendingChanges) { |
|
422 pendingChanges = true; |
|
423 #ifndef QT_NO_QOBJECT |
|
424 Q_Q(QSettings); |
|
425 QCoreApplication::postEvent(q, new QEvent(QEvent::UpdateRequest)); |
|
426 #else |
|
427 update(); |
|
428 #endif |
|
429 } |
|
430 } |
|
431 |
|
432 QStringList QSettingsPrivate::variantListToStringList(const QVariantList &l) |
|
433 { |
|
434 QStringList result; |
|
435 QVariantList::const_iterator it = l.constBegin(); |
|
436 for (; it != l.constEnd(); ++it) |
|
437 result.append(variantToString(*it)); |
|
438 return result; |
|
439 } |
|
440 |
|
441 QVariant QSettingsPrivate::stringListToVariantList(const QStringList &l) |
|
442 { |
|
443 QStringList outStringList = l; |
|
444 for (int i = 0; i < outStringList.count(); ++i) { |
|
445 const QString &str = outStringList.at(i); |
|
446 |
|
447 if (str.startsWith(QLatin1Char('@'))) { |
|
448 if (str.length() >= 2 && str.at(1) == QLatin1Char('@')) { |
|
449 outStringList[i].remove(0, 1); |
|
450 } else { |
|
451 QVariantList variantList; |
|
452 for (int j = 0; j < l.count(); ++j) |
|
453 variantList.append(stringToVariant(l.at(j))); |
|
454 return variantList; |
|
455 } |
|
456 } |
|
457 } |
|
458 return outStringList; |
|
459 } |
|
460 |
|
461 QString QSettingsPrivate::variantToString(const QVariant &v) |
|
462 { |
|
463 QString result; |
|
464 |
|
465 switch (v.type()) { |
|
466 case QVariant::Invalid: |
|
467 result = QLatin1String("@Invalid()"); |
|
468 break; |
|
469 |
|
470 case QVariant::ByteArray: { |
|
471 QByteArray a = v.toByteArray(); |
|
472 result = QLatin1String("@ByteArray("); |
|
473 result += QString::fromLatin1(a.constData(), a.size()); |
|
474 result += QLatin1Char(')'); |
|
475 break; |
|
476 } |
|
477 |
|
478 case QVariant::String: |
|
479 case QVariant::LongLong: |
|
480 case QVariant::ULongLong: |
|
481 case QVariant::Int: |
|
482 case QVariant::UInt: |
|
483 case QVariant::Bool: |
|
484 case QVariant::Double: |
|
485 case QVariant::KeySequence: { |
|
486 result = v.toString(); |
|
487 if (result.startsWith(QLatin1Char('@'))) |
|
488 result.prepend(QLatin1Char('@')); |
|
489 break; |
|
490 } |
|
491 #ifndef QT_NO_GEOM_VARIANT |
|
492 case QVariant::Rect: { |
|
493 QRect r = qvariant_cast<QRect>(v); |
|
494 result += QLatin1String("@Rect("); |
|
495 result += QString::number(r.x()); |
|
496 result += QLatin1Char(' '); |
|
497 result += QString::number(r.y()); |
|
498 result += QLatin1Char(' '); |
|
499 result += QString::number(r.width()); |
|
500 result += QLatin1Char(' '); |
|
501 result += QString::number(r.height()); |
|
502 result += QLatin1Char(')'); |
|
503 break; |
|
504 } |
|
505 case QVariant::Size: { |
|
506 QSize s = qvariant_cast<QSize>(v); |
|
507 result += QLatin1String("@Size("); |
|
508 result += QString::number(s.width()); |
|
509 result += QLatin1Char(' '); |
|
510 result += QString::number(s.height()); |
|
511 result += QLatin1Char(')'); |
|
512 break; |
|
513 } |
|
514 case QVariant::Point: { |
|
515 QPoint p = qvariant_cast<QPoint>(v); |
|
516 result += QLatin1String("@Point("); |
|
517 result += QString::number(p.x()); |
|
518 result += QLatin1Char(' '); |
|
519 result += QString::number(p.y()); |
|
520 result += QLatin1Char(')'); |
|
521 break; |
|
522 } |
|
523 #endif // !QT_NO_GEOM_VARIANT |
|
524 |
|
525 default: { |
|
526 #ifndef QT_NO_DATASTREAM |
|
527 QByteArray a; |
|
528 { |
|
529 QDataStream s(&a, QIODevice::WriteOnly); |
|
530 s.setVersion(QDataStream::Qt_4_0); |
|
531 s << v; |
|
532 } |
|
533 |
|
534 result = QLatin1String("@Variant("); |
|
535 result += QString::fromLatin1(a.constData(), a.size()); |
|
536 result += QLatin1Char(')'); |
|
537 #else |
|
538 Q_ASSERT(!"QSettings: Cannot save custom types without QDataStream support"); |
|
539 #endif |
|
540 break; |
|
541 } |
|
542 } |
|
543 |
|
544 return result; |
|
545 } |
|
546 |
|
547 |
|
548 QVariant QSettingsPrivate::stringToVariant(const QString &s) |
|
549 { |
|
550 if (s.startsWith(QLatin1Char('@'))) { |
|
551 if (s.endsWith(QLatin1Char(')'))) { |
|
552 if (s.startsWith(QLatin1String("@ByteArray("))) { |
|
553 return QVariant(s.toLatin1().mid(11, s.size() - 12)); |
|
554 } else if (s.startsWith(QLatin1String("@Variant("))) { |
|
555 #ifndef QT_NO_DATASTREAM |
|
556 QByteArray a(s.toLatin1().mid(9)); |
|
557 QDataStream stream(&a, QIODevice::ReadOnly); |
|
558 stream.setVersion(QDataStream::Qt_4_0); |
|
559 QVariant result; |
|
560 stream >> result; |
|
561 return result; |
|
562 #else |
|
563 Q_ASSERT(!"QSettings: Cannot load custom types without QDataStream support"); |
|
564 #endif |
|
565 #ifndef QT_NO_GEOM_VARIANT |
|
566 } else if (s.startsWith(QLatin1String("@Rect("))) { |
|
567 QStringList args = QSettingsPrivate::splitArgs(s, 5); |
|
568 if (args.size() == 4) |
|
569 return QVariant(QRect(args[0].toInt(), args[1].toInt(), args[2].toInt(), args[3].toInt())); |
|
570 } else if (s.startsWith(QLatin1String("@Size("))) { |
|
571 QStringList args = QSettingsPrivate::splitArgs(s, 5); |
|
572 if (args.size() == 2) |
|
573 return QVariant(QSize(args[0].toInt(), args[1].toInt())); |
|
574 } else if (s.startsWith(QLatin1String("@Point("))) { |
|
575 QStringList args = QSettingsPrivate::splitArgs(s, 6); |
|
576 if (args.size() == 2) |
|
577 return QVariant(QPoint(args[0].toInt(), args[1].toInt())); |
|
578 #endif |
|
579 } else if (s == QLatin1String("@Invalid()")) { |
|
580 return QVariant(); |
|
581 } |
|
582 |
|
583 } |
|
584 if (s.startsWith(QLatin1String("@@"))) |
|
585 return QVariant(s.mid(1)); |
|
586 } |
|
587 |
|
588 return QVariant(s); |
|
589 } |
|
590 |
|
591 static const char hexDigits[] = "0123456789ABCDEF"; |
|
592 |
|
593 void QSettingsPrivate::iniEscapedKey(const QString &key, QByteArray &result) |
|
594 { |
|
595 result.reserve(result.length() + key.length() * 3 / 2); |
|
596 for (int i = 0; i < key.size(); ++i) { |
|
597 uint ch = key.at(i).unicode(); |
|
598 |
|
599 if (ch == '/') { |
|
600 result += '\\'; |
|
601 } else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') |
|
602 || ch == '_' || ch == '-' || ch == '.') { |
|
603 result += (char)ch; |
|
604 } else if (ch <= 0xFF) { |
|
605 result += '%'; |
|
606 result += hexDigits[ch / 16]; |
|
607 result += hexDigits[ch % 16]; |
|
608 } else { |
|
609 result += "%U"; |
|
610 QByteArray hexCode; |
|
611 for (int i = 0; i < 4; ++i) { |
|
612 hexCode.prepend(hexDigits[ch % 16]); |
|
613 ch >>= 4; |
|
614 } |
|
615 result += hexCode; |
|
616 } |
|
617 } |
|
618 } |
|
619 |
|
620 bool QSettingsPrivate::iniUnescapedKey(const QByteArray &key, int from, int to, QString &result) |
|
621 { |
|
622 bool lowercaseOnly = true; |
|
623 int i = from; |
|
624 result.reserve(result.length() + (to - from)); |
|
625 while (i < to) { |
|
626 int ch = (uchar)key.at(i); |
|
627 |
|
628 if (ch == '\\') { |
|
629 result += QLatin1Char('/'); |
|
630 ++i; |
|
631 continue; |
|
632 } |
|
633 |
|
634 if (ch != '%' || i == to - 1) { |
|
635 if (uint(ch - 'A') <= 'Z' - 'A') // only for ASCII |
|
636 lowercaseOnly = false; |
|
637 result += QLatin1Char(ch); |
|
638 ++i; |
|
639 continue; |
|
640 } |
|
641 |
|
642 int numDigits = 2; |
|
643 int firstDigitPos = i + 1; |
|
644 |
|
645 ch = key.at(i + 1); |
|
646 if (ch == 'U') { |
|
647 ++firstDigitPos; |
|
648 numDigits = 4; |
|
649 } |
|
650 |
|
651 if (firstDigitPos + numDigits > to) { |
|
652 result += QLatin1Char('%'); |
|
653 // ### missing U |
|
654 ++i; |
|
655 continue; |
|
656 } |
|
657 |
|
658 bool ok; |
|
659 ch = key.mid(firstDigitPos, numDigits).toInt(&ok, 16); |
|
660 if (!ok) { |
|
661 result += QLatin1Char('%'); |
|
662 // ### missing U |
|
663 ++i; |
|
664 continue; |
|
665 } |
|
666 |
|
667 QChar qch(ch); |
|
668 if (qch.isUpper()) |
|
669 lowercaseOnly = false; |
|
670 result += qch; |
|
671 i = firstDigitPos + numDigits; |
|
672 } |
|
673 return lowercaseOnly; |
|
674 } |
|
675 |
|
676 void QSettingsPrivate::iniEscapedString(const QString &str, QByteArray &result, QTextCodec *codec) |
|
677 { |
|
678 bool needsQuotes = false; |
|
679 bool escapeNextIfDigit = false; |
|
680 int i; |
|
681 int startPos = result.size(); |
|
682 |
|
683 result.reserve(startPos + str.size() * 3 / 2); |
|
684 for (i = 0; i < str.size(); ++i) { |
|
685 uint ch = str.at(i).unicode(); |
|
686 if (ch == ';' || ch == ',' || ch == '=') |
|
687 needsQuotes = true; |
|
688 |
|
689 if (escapeNextIfDigit |
|
690 && ((ch >= '0' && ch <= '9') |
|
691 || (ch >= 'a' && ch <= 'f') |
|
692 || (ch >= 'A' && ch <= 'F'))) { |
|
693 result += "\\x"; |
|
694 result += QByteArray::number(ch, 16); |
|
695 continue; |
|
696 } |
|
697 |
|
698 escapeNextIfDigit = false; |
|
699 |
|
700 switch (ch) { |
|
701 case '\0': |
|
702 result += "\\0"; |
|
703 escapeNextIfDigit = true; |
|
704 break; |
|
705 case '\a': |
|
706 result += "\\a"; |
|
707 break; |
|
708 case '\b': |
|
709 result += "\\b"; |
|
710 break; |
|
711 case '\f': |
|
712 result += "\\f"; |
|
713 break; |
|
714 case '\n': |
|
715 result += "\\n"; |
|
716 break; |
|
717 case '\r': |
|
718 result += "\\r"; |
|
719 break; |
|
720 case '\t': |
|
721 result += "\\t"; |
|
722 break; |
|
723 case '\v': |
|
724 result += "\\v"; |
|
725 break; |
|
726 case '"': |
|
727 case '\\': |
|
728 result += '\\'; |
|
729 result += (char)ch; |
|
730 break; |
|
731 default: |
|
732 if (ch <= 0x1F || (ch >= 0x7F && !codec)) { |
|
733 result += "\\x"; |
|
734 result += QByteArray::number(ch, 16); |
|
735 escapeNextIfDigit = true; |
|
736 #ifndef QT_NO_TEXTCODEC |
|
737 } else if (codec) { |
|
738 // slow |
|
739 result += codec->fromUnicode(str.at(i)); |
|
740 #endif |
|
741 } else { |
|
742 result += (char)ch; |
|
743 } |
|
744 } |
|
745 } |
|
746 |
|
747 if (needsQuotes |
|
748 || (startPos < result.size() && (result.at(startPos) == ' ' |
|
749 || result.at(result.size() - 1) == ' '))) { |
|
750 result.insert(startPos, '"'); |
|
751 result += '"'; |
|
752 } |
|
753 } |
|
754 |
|
755 inline static void iniChopTrailingSpaces(QString &str) |
|
756 { |
|
757 int n = str.size() - 1; |
|
758 QChar ch; |
|
759 while (n >= 0 && ((ch = str.at(n)) == QLatin1Char(' ') || ch == QLatin1Char('\t'))) |
|
760 str.truncate(n--); |
|
761 } |
|
762 |
|
763 void QSettingsPrivate::iniEscapedStringList(const QStringList &strs, QByteArray &result, QTextCodec *codec) |
|
764 { |
|
765 if (strs.isEmpty()) { |
|
766 /* |
|
767 We need to distinguish between empty lists and one-item |
|
768 lists that contain an empty string. Ideally, we'd have a |
|
769 @EmptyList() symbol but that would break compatibility |
|
770 with Qt 4.0. @Invalid() stands for QVariant(), and |
|
771 QVariant().toStringList() returns an empty QStringList, |
|
772 so we're in good shape. |
|
773 |
|
774 ### Qt 5: Use a nicer syntax, e.g. @List, for variant lists |
|
775 */ |
|
776 result += "@Invalid()"; |
|
777 } else { |
|
778 for (int i = 0; i < strs.size(); ++i) { |
|
779 if (i != 0) |
|
780 result += ", "; |
|
781 iniEscapedString(strs.at(i), result, codec); |
|
782 } |
|
783 } |
|
784 } |
|
785 |
|
786 bool QSettingsPrivate::iniUnescapedStringList(const QByteArray &str, int from, int to, |
|
787 QString &stringResult, QStringList &stringListResult, |
|
788 QTextCodec *codec) |
|
789 { |
|
790 static const char escapeCodes[][2] = |
|
791 { |
|
792 { 'a', '\a' }, |
|
793 { 'b', '\b' }, |
|
794 { 'f', '\f' }, |
|
795 { 'n', '\n' }, |
|
796 { 'r', '\r' }, |
|
797 { 't', '\t' }, |
|
798 { 'v', '\v' }, |
|
799 { '"', '"' }, |
|
800 { '?', '?' }, |
|
801 { '\'', '\'' }, |
|
802 { '\\', '\\' } |
|
803 }; |
|
804 static const int numEscapeCodes = sizeof(escapeCodes) / sizeof(escapeCodes[0]); |
|
805 |
|
806 bool isStringList = false; |
|
807 bool inQuotedString = false; |
|
808 bool currentValueIsQuoted = false; |
|
809 int escapeVal = 0; |
|
810 int i = from; |
|
811 char ch; |
|
812 |
|
813 StSkipSpaces: |
|
814 while (i < to && ((ch = str.at(i)) == ' ' || ch == '\t')) |
|
815 ++i; |
|
816 // fallthrough |
|
817 |
|
818 StNormal: |
|
819 while (i < to) { |
|
820 switch (str.at(i)) { |
|
821 case '\\': |
|
822 ++i; |
|
823 if (i >= to) |
|
824 goto end; |
|
825 |
|
826 ch = str.at(i++); |
|
827 for (int j = 0; j < numEscapeCodes; ++j) { |
|
828 if (ch == escapeCodes[j][0]) { |
|
829 stringResult += QLatin1Char(escapeCodes[j][1]); |
|
830 goto StNormal; |
|
831 } |
|
832 } |
|
833 |
|
834 if (ch == 'x') { |
|
835 escapeVal = 0; |
|
836 |
|
837 if (i >= to) |
|
838 goto end; |
|
839 |
|
840 ch = str.at(i); |
|
841 if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) |
|
842 goto StHexEscape; |
|
843 } else if (ch >= '0' && ch <= '7') { |
|
844 escapeVal = ch - '0'; |
|
845 goto StOctEscape; |
|
846 } else if (ch == '\n' || ch == '\r') { |
|
847 if (i < to) { |
|
848 char ch2 = str.at(i); |
|
849 // \n, \r, \r\n, and \n\r are legitimate line terminators in INI files |
|
850 if ((ch2 == '\n' || ch2 == '\r') && ch2 != ch) |
|
851 ++i; |
|
852 } |
|
853 } else { |
|
854 // the character is skipped |
|
855 } |
|
856 break; |
|
857 case '"': |
|
858 ++i; |
|
859 currentValueIsQuoted = true; |
|
860 inQuotedString = !inQuotedString; |
|
861 if (!inQuotedString) |
|
862 goto StSkipSpaces; |
|
863 break; |
|
864 case ',': |
|
865 if (!inQuotedString) { |
|
866 if (!currentValueIsQuoted) |
|
867 iniChopTrailingSpaces(stringResult); |
|
868 if (!isStringList) { |
|
869 isStringList = true; |
|
870 stringListResult.clear(); |
|
871 stringResult.squeeze(); |
|
872 } |
|
873 stringListResult.append(stringResult); |
|
874 stringResult.clear(); |
|
875 currentValueIsQuoted = false; |
|
876 ++i; |
|
877 goto StSkipSpaces; |
|
878 } |
|
879 // fallthrough |
|
880 default: { |
|
881 int j = i + 1; |
|
882 while (j < to) { |
|
883 ch = str.at(j); |
|
884 if (ch == '\\' || ch == '"' || ch == ',') |
|
885 break; |
|
886 ++j; |
|
887 } |
|
888 |
|
889 #ifndef QT_NO_TEXTCODEC |
|
890 if (codec) { |
|
891 stringResult += codec->toUnicode(str.constData() + i, j - i); |
|
892 } else |
|
893 #endif |
|
894 { |
|
895 int n = stringResult.size(); |
|
896 stringResult.resize(n + (j - i)); |
|
897 QChar *resultData = stringResult.data() + n; |
|
898 for (int k = i; k < j; ++k) |
|
899 *resultData++ = QLatin1Char(str.at(k)); |
|
900 } |
|
901 i = j; |
|
902 } |
|
903 } |
|
904 } |
|
905 goto end; |
|
906 |
|
907 StHexEscape: |
|
908 if (i >= to) { |
|
909 stringResult += QChar(escapeVal); |
|
910 goto end; |
|
911 } |
|
912 |
|
913 ch = str.at(i); |
|
914 if (ch >= 'a') |
|
915 ch -= 'a' - 'A'; |
|
916 if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F')) { |
|
917 escapeVal <<= 4; |
|
918 escapeVal += strchr(hexDigits, ch) - hexDigits; |
|
919 ++i; |
|
920 goto StHexEscape; |
|
921 } else { |
|
922 stringResult += QChar(escapeVal); |
|
923 goto StNormal; |
|
924 } |
|
925 |
|
926 StOctEscape: |
|
927 if (i >= to) { |
|
928 stringResult += QChar(escapeVal); |
|
929 goto end; |
|
930 } |
|
931 |
|
932 ch = str.at(i); |
|
933 if (ch >= '0' && ch <= '7') { |
|
934 escapeVal <<= 3; |
|
935 escapeVal += ch - '0'; |
|
936 ++i; |
|
937 goto StOctEscape; |
|
938 } else { |
|
939 stringResult += QChar(escapeVal); |
|
940 goto StNormal; |
|
941 } |
|
942 |
|
943 end: |
|
944 if (!currentValueIsQuoted) |
|
945 iniChopTrailingSpaces(stringResult); |
|
946 if (isStringList) |
|
947 stringListResult.append(stringResult); |
|
948 return isStringList; |
|
949 } |
|
950 |
|
951 QStringList QSettingsPrivate::splitArgs(const QString &s, int idx) |
|
952 { |
|
953 int l = s.length(); |
|
954 Q_ASSERT(l > 0); |
|
955 Q_ASSERT(s.at(idx) == QLatin1Char('(')); |
|
956 Q_ASSERT(s.at(l - 1) == QLatin1Char(')')); |
|
957 |
|
958 QStringList result; |
|
959 QString item; |
|
960 |
|
961 for (++idx; idx < l; ++idx) { |
|
962 QChar c = s.at(idx); |
|
963 if (c == QLatin1Char(')')) { |
|
964 Q_ASSERT(idx == l - 1); |
|
965 result.append(item); |
|
966 } else if (c == QLatin1Char(' ')) { |
|
967 result.append(item); |
|
968 item.clear(); |
|
969 } else { |
|
970 item.append(c); |
|
971 } |
|
972 } |
|
973 |
|
974 return result; |
|
975 } |
|
976 |
|
977 // ************************************************************************ |
|
978 // QConfFileSettingsPrivate |
|
979 |
|
980 /* |
|
981 If we don't have the permission to read the file, returns false. |
|
982 If the file doesn't exist, returns true. |
|
983 */ |
|
984 static bool checkAccess(const QString &name) |
|
985 { |
|
986 QFileInfo fileInfo(name); |
|
987 |
|
988 if (fileInfo.exists()) { |
|
989 QFile file(name); |
|
990 // if the file exists but we can't open it, report an error |
|
991 return file.open(QFile::ReadOnly); |
|
992 } else { |
|
993 return true; |
|
994 } |
|
995 } |
|
996 |
|
997 void QConfFileSettingsPrivate::initFormat() |
|
998 { |
|
999 extension = (format == QSettings::NativeFormat) ? QLatin1String(".conf") : QLatin1String(".ini"); |
|
1000 readFunc = 0; |
|
1001 writeFunc = 0; |
|
1002 #if defined(Q_OS_MAC) |
|
1003 caseSensitivity = (format == QSettings::NativeFormat) ? Qt::CaseSensitive : Qt::CaseInsensitive; |
|
1004 #else |
|
1005 caseSensitivity = IniCaseSensitivity; |
|
1006 #endif |
|
1007 |
|
1008 if (format > QSettings::IniFormat) { |
|
1009 QMutexLocker locker(globalMutex()); |
|
1010 const CustomFormatVector *customFormatVector = customFormatVectorFunc(); |
|
1011 |
|
1012 int i = (int)format - (int)QSettings::CustomFormat1; |
|
1013 if (i >= 0 && i < customFormatVector->size()) { |
|
1014 QConfFileCustomFormat info = customFormatVector->at(i); |
|
1015 extension = info.extension; |
|
1016 readFunc = info.readFunc; |
|
1017 writeFunc = info.writeFunc; |
|
1018 caseSensitivity = info.caseSensitivity; |
|
1019 } |
|
1020 } |
|
1021 } |
|
1022 |
|
1023 void QConfFileSettingsPrivate::initAccess() |
|
1024 { |
|
1025 bool readAccess = false; |
|
1026 if (confFiles[spec]) { |
|
1027 readAccess = checkAccess(confFiles[spec]->name); |
|
1028 if (format > QSettings::IniFormat) { |
|
1029 if (!readFunc) |
|
1030 readAccess = false; |
|
1031 } |
|
1032 } |
|
1033 |
|
1034 if (!readAccess) |
|
1035 setStatus(QSettings::AccessError); |
|
1036 |
|
1037 sync(); // loads the files the first time |
|
1038 } |
|
1039 |
|
1040 #ifdef Q_OS_WIN |
|
1041 static QString windowsConfigPath(int type) |
|
1042 { |
|
1043 QString result; |
|
1044 |
|
1045 #ifndef QT_NO_QOBJECT |
|
1046 // We can't use QLibrary if there is QT_NO_QOBJECT is defined |
|
1047 // This only happens when bootstrapping qmake. |
|
1048 #ifndef Q_OS_WINCE |
|
1049 QLibrary library(QLatin1String("shell32")); |
|
1050 #else |
|
1051 QLibrary library(QLatin1String("coredll")); |
|
1052 #endif // Q_OS_WINCE |
|
1053 typedef BOOL (WINAPI*GetSpecialFolderPath)(HWND, LPWSTR, int, BOOL); |
|
1054 GetSpecialFolderPath SHGetSpecialFolderPath = (GetSpecialFolderPath)library.resolve("SHGetSpecialFolderPathW"); |
|
1055 if (SHGetSpecialFolderPath) { |
|
1056 wchar_t path[MAX_PATH]; |
|
1057 SHGetSpecialFolderPath(0, path, type, FALSE); |
|
1058 result = QString::fromWCharArray(path); |
|
1059 } |
|
1060 |
|
1061 #endif // QT_NO_QOBJECT |
|
1062 |
|
1063 if (result.isEmpty()) { |
|
1064 switch (type) { |
|
1065 #ifndef Q_OS_WINCE |
|
1066 case CSIDL_COMMON_APPDATA: |
|
1067 result = QLatin1String("C:\\temp\\qt-common"); |
|
1068 break; |
|
1069 case CSIDL_APPDATA: |
|
1070 result = QLatin1String("C:\\temp\\qt-user"); |
|
1071 break; |
|
1072 #else |
|
1073 case CSIDL_COMMON_APPDATA: |
|
1074 result = QLatin1String("\\Temp\\qt-common"); |
|
1075 break; |
|
1076 case CSIDL_APPDATA: |
|
1077 result = QLatin1String("\\Temp\\qt-user"); |
|
1078 break; |
|
1079 #endif |
|
1080 default: |
|
1081 ; |
|
1082 } |
|
1083 } |
|
1084 |
|
1085 return result; |
|
1086 } |
|
1087 #endif // Q_OS_WIN |
|
1088 |
|
1089 static inline int pathHashKey(QSettings::Format format, QSettings::Scope scope) |
|
1090 { |
|
1091 return int((uint(format) << 1) | uint(scope == QSettings::SystemScope)); |
|
1092 } |
|
1093 |
|
1094 static QString getPath(QSettings::Format format, QSettings::Scope scope) |
|
1095 { |
|
1096 Q_ASSERT((int)QSettings::NativeFormat == 0); |
|
1097 Q_ASSERT((int)QSettings::IniFormat == 1); |
|
1098 |
|
1099 QString homePath = QDir::homePath(); |
|
1100 QString systemPath; |
|
1101 |
|
1102 QMutexLocker locker(globalMutex()); |
|
1103 PathHash *pathHash = pathHashFunc(); |
|
1104 bool loadSystemPath = pathHash->isEmpty(); |
|
1105 locker.unlock(); |
|
1106 |
|
1107 if (loadSystemPath) { |
|
1108 /* |
|
1109 QLibraryInfo::location() uses QSettings, so in order to |
|
1110 avoid a dead-lock, we can't hold the global mutex while |
|
1111 calling it. |
|
1112 */ |
|
1113 systemPath = QLibraryInfo::location(QLibraryInfo::SettingsPath); |
|
1114 systemPath += QLatin1Char('/'); |
|
1115 } |
|
1116 |
|
1117 locker.relock(); |
|
1118 if (pathHash->isEmpty()) { |
|
1119 /* |
|
1120 Lazy initialization of pathHash. We initialize the |
|
1121 IniFormat paths and (on Unix) the NativeFormat paths. |
|
1122 (The NativeFormat paths are not configurable for the |
|
1123 Windows registry and the Mac CFPreferences.) |
|
1124 */ |
|
1125 #ifdef Q_OS_WIN |
|
1126 pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope), |
|
1127 windowsConfigPath(CSIDL_APPDATA) + QDir::separator()); |
|
1128 pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope), |
|
1129 windowsConfigPath(CSIDL_COMMON_APPDATA) + QDir::separator()); |
|
1130 #else |
|
1131 QString userPath; |
|
1132 char *env = getenv("XDG_CONFIG_HOME"); |
|
1133 if (env == 0) { |
|
1134 userPath = homePath; |
|
1135 userPath += QLatin1Char('/'); |
|
1136 #ifdef Q_WS_QWS |
|
1137 userPath += QLatin1String("Settings"); |
|
1138 #else |
|
1139 userPath += QLatin1String(".config"); |
|
1140 #endif |
|
1141 } else if (*env == '/') { |
|
1142 userPath = QLatin1String(env); |
|
1143 } else { |
|
1144 userPath = homePath; |
|
1145 userPath += QLatin1Char('/'); |
|
1146 userPath += QLatin1String(env); |
|
1147 } |
|
1148 userPath += QLatin1Char('/'); |
|
1149 |
|
1150 pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope), userPath); |
|
1151 pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope), systemPath); |
|
1152 #ifndef Q_OS_MAC |
|
1153 pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::UserScope), userPath); |
|
1154 pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::SystemScope), systemPath); |
|
1155 #endif |
|
1156 #endif |
|
1157 } |
|
1158 |
|
1159 QString result = pathHash->value(pathHashKey(format, scope)); |
|
1160 if (!result.isEmpty()) |
|
1161 return result; |
|
1162 |
|
1163 // fall back on INI path |
|
1164 return pathHash->value(pathHashKey(QSettings::IniFormat, scope)); |
|
1165 } |
|
1166 |
|
1167 QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format, |
|
1168 QSettings::Scope scope, |
|
1169 const QString &organization, |
|
1170 const QString &application) |
|
1171 : QSettingsPrivate(format, scope, organization, application), |
|
1172 nextPosition(0x40000000) // big positive number |
|
1173 { |
|
1174 int i; |
|
1175 initFormat(); |
|
1176 |
|
1177 QString org = organization; |
|
1178 if (org.isEmpty()) { |
|
1179 setStatus(QSettings::AccessError); |
|
1180 org = QLatin1String("Unknown Organization"); |
|
1181 } |
|
1182 |
|
1183 QString appFile = org + QDir::separator() + application + extension; |
|
1184 QString orgFile = org + extension; |
|
1185 |
|
1186 if (scope == QSettings::UserScope) { |
|
1187 QString userPath = getPath(format, QSettings::UserScope); |
|
1188 if (!application.isEmpty()) |
|
1189 confFiles[F_User | F_Application].reset(QConfFile::fromName(userPath + appFile, true)); |
|
1190 confFiles[F_User | F_Organization].reset(QConfFile::fromName(userPath + orgFile, true)); |
|
1191 } |
|
1192 |
|
1193 QString systemPath = getPath(format, QSettings::SystemScope); |
|
1194 if (!application.isEmpty()) |
|
1195 confFiles[F_System | F_Application].reset(QConfFile::fromName(systemPath + appFile, false)); |
|
1196 confFiles[F_System | F_Organization].reset(QConfFile::fromName(systemPath + orgFile, false)); |
|
1197 |
|
1198 for (i = 0; i < NumConfFiles; ++i) { |
|
1199 if (confFiles[i]) { |
|
1200 spec = i; |
|
1201 break; |
|
1202 } |
|
1203 } |
|
1204 |
|
1205 initAccess(); |
|
1206 } |
|
1207 |
|
1208 QConfFileSettingsPrivate::QConfFileSettingsPrivate(const QString &fileName, |
|
1209 QSettings::Format format) |
|
1210 : QSettingsPrivate(format), |
|
1211 nextPosition(0x40000000) // big positive number |
|
1212 { |
|
1213 initFormat(); |
|
1214 |
|
1215 confFiles[0].reset(QConfFile::fromName(fileName, true)); |
|
1216 |
|
1217 initAccess(); |
|
1218 } |
|
1219 |
|
1220 QConfFileSettingsPrivate::~QConfFileSettingsPrivate() |
|
1221 { |
|
1222 QMutexLocker locker(globalMutex()); |
|
1223 ConfFileHash *usedHash = usedHashFunc(); |
|
1224 ConfFileCache *unusedCache = unusedCacheFunc(); |
|
1225 |
|
1226 for (int i = 0; i < NumConfFiles; ++i) { |
|
1227 if (confFiles[i] && !confFiles[i]->ref.deref()) { |
|
1228 if (confFiles[i]->size == 0) { |
|
1229 delete confFiles[i].take(); |
|
1230 } else if (unusedCache) { |
|
1231 if (usedHash) |
|
1232 usedHash->remove(confFiles[i]->name); |
|
1233 QT_TRY { |
|
1234 // compute a better size? |
|
1235 unusedCache->insert(confFiles[i]->name, confFiles[i].data(), |
|
1236 10 + (confFiles[i]->originalKeys.size() / 4)); |
|
1237 confFiles[i].take(); |
|
1238 } QT_CATCH(...) { |
|
1239 // out of memory. Do not cache the file. |
|
1240 delete confFiles[i].take(); |
|
1241 } |
|
1242 } |
|
1243 } |
|
1244 // prevent the ScopedPointer to deref it again. |
|
1245 confFiles[i].take(); |
|
1246 } |
|
1247 } |
|
1248 |
|
1249 void QConfFileSettingsPrivate::remove(const QString &key) |
|
1250 { |
|
1251 QConfFile *confFile = confFiles[spec].data(); |
|
1252 if (!confFile) |
|
1253 return; |
|
1254 |
|
1255 QSettingsKey theKey(key, caseSensitivity); |
|
1256 QSettingsKey prefix(key + QLatin1Char('/'), caseSensitivity); |
|
1257 QMutexLocker locker(&confFile->mutex); |
|
1258 |
|
1259 ensureSectionParsed(confFile, theKey); |
|
1260 ensureSectionParsed(confFile, prefix); |
|
1261 |
|
1262 ParsedSettingsMap::iterator i = confFile->addedKeys.lowerBound(prefix); |
|
1263 while (i != confFile->addedKeys.end() && i.key().startsWith(prefix)) |
|
1264 i = confFile->addedKeys.erase(i); |
|
1265 confFile->addedKeys.remove(theKey); |
|
1266 |
|
1267 ParsedSettingsMap::const_iterator j = const_cast<const ParsedSettingsMap *>(&confFile->originalKeys)->lowerBound(prefix); |
|
1268 while (j != confFile->originalKeys.constEnd() && j.key().startsWith(prefix)) { |
|
1269 confFile->removedKeys.insert(j.key(), QVariant()); |
|
1270 ++j; |
|
1271 } |
|
1272 if (confFile->originalKeys.contains(theKey)) |
|
1273 confFile->removedKeys.insert(theKey, QVariant()); |
|
1274 } |
|
1275 |
|
1276 void QConfFileSettingsPrivate::set(const QString &key, const QVariant &value) |
|
1277 { |
|
1278 QConfFile *confFile = confFiles[spec].data(); |
|
1279 if (!confFile) |
|
1280 return; |
|
1281 |
|
1282 QSettingsKey theKey(key, caseSensitivity, nextPosition++); |
|
1283 QMutexLocker locker(&confFile->mutex); |
|
1284 confFile->removedKeys.remove(theKey); |
|
1285 confFile->addedKeys.insert(theKey, value); |
|
1286 } |
|
1287 |
|
1288 bool QConfFileSettingsPrivate::get(const QString &key, QVariant *value) const |
|
1289 { |
|
1290 QSettingsKey theKey(key, caseSensitivity); |
|
1291 ParsedSettingsMap::const_iterator j; |
|
1292 bool found = false; |
|
1293 |
|
1294 for (int i = 0; i < NumConfFiles; ++i) { |
|
1295 if (QConfFile *confFile = confFiles[i].data()) { |
|
1296 QMutexLocker locker(&confFile->mutex); |
|
1297 |
|
1298 if (!confFile->addedKeys.isEmpty()) { |
|
1299 j = confFile->addedKeys.constFind(theKey); |
|
1300 found = (j != confFile->addedKeys.constEnd()); |
|
1301 } |
|
1302 if (!found) { |
|
1303 ensureSectionParsed(confFile, theKey); |
|
1304 j = confFile->originalKeys.constFind(theKey); |
|
1305 found = (j != confFile->originalKeys.constEnd() |
|
1306 && !confFile->removedKeys.contains(theKey)); |
|
1307 } |
|
1308 |
|
1309 if (found && value) |
|
1310 *value = *j; |
|
1311 |
|
1312 if (found) |
|
1313 return true; |
|
1314 if (!fallbacks) |
|
1315 break; |
|
1316 } |
|
1317 } |
|
1318 return false; |
|
1319 } |
|
1320 |
|
1321 QStringList QConfFileSettingsPrivate::children(const QString &prefix, ChildSpec spec) const |
|
1322 { |
|
1323 QMap<QString, QString> result; |
|
1324 ParsedSettingsMap::const_iterator j; |
|
1325 |
|
1326 QSettingsKey thePrefix(prefix, caseSensitivity); |
|
1327 int startPos = prefix.size(); |
|
1328 |
|
1329 for (int i = 0; i < NumConfFiles; ++i) { |
|
1330 if (QConfFile *confFile = confFiles[i].data()) { |
|
1331 QMutexLocker locker(&confFile->mutex); |
|
1332 |
|
1333 if (thePrefix.isEmpty()) { |
|
1334 ensureAllSectionsParsed(confFile); |
|
1335 } else { |
|
1336 ensureSectionParsed(confFile, thePrefix); |
|
1337 } |
|
1338 |
|
1339 j = const_cast<const ParsedSettingsMap *>( |
|
1340 &confFile->originalKeys)->lowerBound( thePrefix); |
|
1341 while (j != confFile->originalKeys.constEnd() && j.key().startsWith(thePrefix)) { |
|
1342 if (!confFile->removedKeys.contains(j.key())) |
|
1343 processChild(j.key().originalCaseKey().mid(startPos), spec, result); |
|
1344 ++j; |
|
1345 } |
|
1346 |
|
1347 j = const_cast<const ParsedSettingsMap *>( |
|
1348 &confFile->addedKeys)->lowerBound(thePrefix); |
|
1349 while (j != confFile->addedKeys.constEnd() && j.key().startsWith(thePrefix)) { |
|
1350 processChild(j.key().originalCaseKey().mid(startPos), spec, result); |
|
1351 ++j; |
|
1352 } |
|
1353 |
|
1354 if (!fallbacks) |
|
1355 break; |
|
1356 } |
|
1357 } |
|
1358 return result.keys(); |
|
1359 } |
|
1360 |
|
1361 void QConfFileSettingsPrivate::clear() |
|
1362 { |
|
1363 QConfFile *confFile = confFiles[spec].data(); |
|
1364 if (!confFile) |
|
1365 return; |
|
1366 |
|
1367 QMutexLocker locker(&confFile->mutex); |
|
1368 ensureAllSectionsParsed(confFile); |
|
1369 confFile->addedKeys.clear(); |
|
1370 confFile->removedKeys = confFile->originalKeys; |
|
1371 } |
|
1372 |
|
1373 void QConfFileSettingsPrivate::sync() |
|
1374 { |
|
1375 // people probably won't be checking the status a whole lot, so in case of |
|
1376 // error we just try to go on and make the best of it |
|
1377 |
|
1378 for (int i = 0; i < NumConfFiles; ++i) { |
|
1379 QConfFile *confFile = confFiles[i].data(); |
|
1380 if (confFile) { |
|
1381 QMutexLocker locker(&confFile->mutex); |
|
1382 syncConfFile(i); |
|
1383 } |
|
1384 } |
|
1385 } |
|
1386 |
|
1387 void QConfFileSettingsPrivate::flush() |
|
1388 { |
|
1389 sync(); |
|
1390 } |
|
1391 |
|
1392 QString QConfFileSettingsPrivate::fileName() const |
|
1393 { |
|
1394 QConfFile *confFile = confFiles[spec].data(); |
|
1395 if (!confFile) |
|
1396 return QString(); |
|
1397 return confFile->name; |
|
1398 } |
|
1399 |
|
1400 bool QConfFileSettingsPrivate::isWritable() const |
|
1401 { |
|
1402 if (format > QSettings::IniFormat && !writeFunc) |
|
1403 return false; |
|
1404 |
|
1405 QConfFile *confFile = confFiles[spec].data(); |
|
1406 if (!confFile) |
|
1407 return false; |
|
1408 |
|
1409 return confFile->isWritable(); |
|
1410 } |
|
1411 |
|
1412 void QConfFileSettingsPrivate::syncConfFile(int confFileNo) |
|
1413 { |
|
1414 QConfFile *confFile = confFiles[confFileNo].data(); |
|
1415 bool readOnly = confFile->addedKeys.isEmpty() && confFile->removedKeys.isEmpty(); |
|
1416 bool ok; |
|
1417 |
|
1418 /* |
|
1419 We can often optimize the read-only case, if the file on disk |
|
1420 hasn't changed. |
|
1421 */ |
|
1422 if (readOnly) { |
|
1423 QFileInfo fileInfo(confFile->name); |
|
1424 if (confFile->size == fileInfo.size() && confFile->timeStamp == fileInfo.lastModified()) |
|
1425 return; |
|
1426 } |
|
1427 |
|
1428 /* |
|
1429 Open the configuration file and try to use it using a named |
|
1430 semaphore on Windows and an advisory lock on Unix-based |
|
1431 systems. This protect us against other QSettings instances |
|
1432 trying to access the same file from other threads or |
|
1433 processes. |
|
1434 |
|
1435 As it stands now, the locking mechanism doesn't work for |
|
1436 .plist files. |
|
1437 */ |
|
1438 QFile file(confFile->name); |
|
1439 bool createFile = !file.exists(); |
|
1440 if (!readOnly && confFile->isWritable()) |
|
1441 file.open(QFile::ReadWrite); |
|
1442 if (!file.isOpen()) |
|
1443 file.open(QFile::ReadOnly); |
|
1444 |
|
1445 #ifdef Q_OS_WIN |
|
1446 HANDLE readSemaphore = 0; |
|
1447 HANDLE writeSemaphore = 0; |
|
1448 static const int FileLockSemMax = 50; |
|
1449 int numReadLocks = readOnly ? 1 : FileLockSemMax; |
|
1450 |
|
1451 if (file.isOpen()) { |
|
1452 // Acquire the write lock if we will be writing |
|
1453 if (!readOnly) { |
|
1454 QString writeSemName = QLatin1String("QSettingsWriteSem "); |
|
1455 writeSemName.append(file.fileName()); |
|
1456 |
|
1457 writeSemaphore = CreateSemaphore(0, 1, 1, reinterpret_cast<const wchar_t *>(writeSemName.utf16())); |
|
1458 |
|
1459 if (writeSemaphore) { |
|
1460 WaitForSingleObject(writeSemaphore, INFINITE); |
|
1461 } else { |
|
1462 setStatus(QSettings::AccessError); |
|
1463 return; |
|
1464 } |
|
1465 } |
|
1466 |
|
1467 // Acquire all the read locks if we will be writing, to make sure nobody |
|
1468 // reads while we're writing. If we are only reading, acquire a single |
|
1469 // read lock. |
|
1470 QString readSemName(QLatin1String("QSettingsReadSem ")); |
|
1471 readSemName.append(file.fileName()); |
|
1472 |
|
1473 readSemaphore = CreateSemaphore(0, FileLockSemMax, FileLockSemMax, reinterpret_cast<const wchar_t *>(readSemName.utf16())); |
|
1474 |
|
1475 if (readSemaphore) { |
|
1476 for (int i = 0; i < numReadLocks; ++i) |
|
1477 WaitForSingleObject(readSemaphore, INFINITE); |
|
1478 } else { |
|
1479 setStatus(QSettings::AccessError); |
|
1480 if (writeSemaphore != 0) { |
|
1481 ReleaseSemaphore(writeSemaphore, 1, 0); |
|
1482 CloseHandle(writeSemaphore); |
|
1483 } |
|
1484 return; |
|
1485 } |
|
1486 } |
|
1487 #else |
|
1488 if (file.isOpen()) |
|
1489 unixLock(file.handle(), readOnly ? F_RDLCK : F_WRLCK); |
|
1490 #endif |
|
1491 |
|
1492 // If we have created the file, apply the file perms |
|
1493 if (file.isOpen()) { |
|
1494 if (createFile) { |
|
1495 QFile::Permissions perms = file.permissions() | QFile::ReadOwner | QFile::WriteOwner; |
|
1496 if (!confFile->userPerms) |
|
1497 perms |= QFile::ReadGroup | QFile::ReadOther; |
|
1498 file.setPermissions(perms); |
|
1499 } |
|
1500 } |
|
1501 |
|
1502 /* |
|
1503 We hold the lock. Let's reread the file if it has changed |
|
1504 since last time we read it. |
|
1505 */ |
|
1506 QFileInfo fileInfo(confFile->name); |
|
1507 bool mustReadFile = true; |
|
1508 |
|
1509 if (!readOnly) |
|
1510 mustReadFile = (confFile->size != fileInfo.size() |
|
1511 || (confFile->size != 0 && confFile->timeStamp != fileInfo.lastModified())); |
|
1512 |
|
1513 if (mustReadFile) { |
|
1514 confFile->unparsedIniSections.clear(); |
|
1515 confFile->originalKeys.clear(); |
|
1516 |
|
1517 /* |
|
1518 Files that we can't read (because of permissions or |
|
1519 because they don't exist) are treated as empty files. |
|
1520 */ |
|
1521 if (file.isReadable() && fileInfo.size() != 0) { |
|
1522 #ifdef Q_OS_MAC |
|
1523 if (format == QSettings::NativeFormat) { |
|
1524 ok = readPlistFile(confFile->name, &confFile->originalKeys); |
|
1525 } else |
|
1526 #endif |
|
1527 { |
|
1528 if (format <= QSettings::IniFormat) { |
|
1529 QByteArray data = file.readAll(); |
|
1530 ok = readIniFile(data, &confFile->unparsedIniSections); |
|
1531 } else { |
|
1532 if (readFunc) { |
|
1533 QSettings::SettingsMap tempNewKeys; |
|
1534 ok = readFunc(file, tempNewKeys); |
|
1535 |
|
1536 if (ok) { |
|
1537 QSettings::SettingsMap::const_iterator i = tempNewKeys.constBegin(); |
|
1538 while (i != tempNewKeys.constEnd()) { |
|
1539 confFile->originalKeys.insert(QSettingsKey(i.key(), |
|
1540 caseSensitivity), |
|
1541 i.value()); |
|
1542 ++i; |
|
1543 } |
|
1544 } |
|
1545 } else { |
|
1546 ok = false; |
|
1547 } |
|
1548 } |
|
1549 } |
|
1550 |
|
1551 if (!ok) |
|
1552 setStatus(QSettings::FormatError); |
|
1553 } |
|
1554 |
|
1555 confFile->size = fileInfo.size(); |
|
1556 confFile->timeStamp = fileInfo.lastModified(); |
|
1557 } |
|
1558 |
|
1559 /* |
|
1560 We also need to save the file. We still hold the file lock, |
|
1561 so everything is under control. |
|
1562 */ |
|
1563 if (!readOnly) { |
|
1564 ensureAllSectionsParsed(confFile); |
|
1565 ParsedSettingsMap mergedKeys = confFile->mergedKeyMap(); |
|
1566 |
|
1567 if (file.isWritable()) { |
|
1568 #ifdef Q_OS_MAC |
|
1569 if (format == QSettings::NativeFormat) { |
|
1570 ok = writePlistFile(confFile->name, mergedKeys); |
|
1571 } else |
|
1572 #endif |
|
1573 { |
|
1574 file.seek(0); |
|
1575 file.resize(0); |
|
1576 |
|
1577 if (format <= QSettings::IniFormat) { |
|
1578 ok = writeIniFile(file, mergedKeys); |
|
1579 if (!ok) { |
|
1580 // try to restore old data; might work if the disk was full and the new data |
|
1581 // was larger than the old data |
|
1582 file.seek(0); |
|
1583 file.resize(0); |
|
1584 writeIniFile(file, confFile->originalKeys); |
|
1585 } |
|
1586 } else { |
|
1587 if (writeFunc) { |
|
1588 QSettings::SettingsMap tempOriginalKeys; |
|
1589 |
|
1590 ParsedSettingsMap::const_iterator i = mergedKeys.constBegin(); |
|
1591 while (i != mergedKeys.constEnd()) { |
|
1592 tempOriginalKeys.insert(i.key(), i.value()); |
|
1593 ++i; |
|
1594 } |
|
1595 ok = writeFunc(file, tempOriginalKeys); |
|
1596 } else { |
|
1597 ok = false; |
|
1598 } |
|
1599 } |
|
1600 } |
|
1601 } else { |
|
1602 ok = false; |
|
1603 } |
|
1604 |
|
1605 if (ok) { |
|
1606 confFile->unparsedIniSections.clear(); |
|
1607 confFile->originalKeys = mergedKeys; |
|
1608 confFile->addedKeys.clear(); |
|
1609 confFile->removedKeys.clear(); |
|
1610 |
|
1611 QFileInfo fileInfo(confFile->name); |
|
1612 confFile->size = fileInfo.size(); |
|
1613 confFile->timeStamp = fileInfo.lastModified(); |
|
1614 } else { |
|
1615 setStatus(QSettings::AccessError); |
|
1616 } |
|
1617 } |
|
1618 |
|
1619 /* |
|
1620 Release the file lock. |
|
1621 */ |
|
1622 #ifdef Q_OS_WIN |
|
1623 if (readSemaphore != 0) { |
|
1624 ReleaseSemaphore(readSemaphore, numReadLocks, 0); |
|
1625 CloseHandle(readSemaphore); |
|
1626 } |
|
1627 if (writeSemaphore != 0) { |
|
1628 ReleaseSemaphore(writeSemaphore, 1, 0); |
|
1629 CloseHandle(writeSemaphore); |
|
1630 } |
|
1631 #endif |
|
1632 } |
|
1633 |
|
1634 enum { Space = 0x1, Special = 0x2 }; |
|
1635 |
|
1636 static const char charTraits[256] = |
|
1637 { |
|
1638 // Space: '\t', '\n', '\r', ' ' |
|
1639 // Special: '\n', '\r', '"', ';', '=', '\\' |
|
1640 |
|
1641 0, 0, 0, 0, 0, 0, 0, 0, 0, Space, Space | Special, 0, 0, Space | Special, 0, 0, |
|
1642 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
1643 Space, 0, Special, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
1644 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Special, 0, Special, 0, 0, |
|
1645 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
1646 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Special, 0, 0, 0, |
|
1647 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
1648 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
1649 |
|
1650 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
1651 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
1652 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
1653 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
1654 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
1655 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
1656 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
1657 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 |
|
1658 }; |
|
1659 |
|
1660 bool QConfFileSettingsPrivate::readIniLine(const QByteArray &data, int &dataPos, |
|
1661 int &lineStart, int &lineLen, int &equalsPos) |
|
1662 { |
|
1663 int dataLen = data.length(); |
|
1664 bool inQuotes = false; |
|
1665 |
|
1666 equalsPos = -1; |
|
1667 |
|
1668 lineStart = dataPos; |
|
1669 while (lineStart < dataLen && (charTraits[uint(uchar(data.at(lineStart)))] & Space)) |
|
1670 ++lineStart; |
|
1671 |
|
1672 int i = lineStart; |
|
1673 while (i < dataLen) { |
|
1674 while (!(charTraits[uint(uchar(data.at(i)))] & Special)) { |
|
1675 if (++i == dataLen) |
|
1676 goto break_out_of_outer_loop; |
|
1677 } |
|
1678 |
|
1679 char ch = data.at(i++); |
|
1680 if (ch == '=') { |
|
1681 if (!inQuotes && equalsPos == -1) |
|
1682 equalsPos = i - 1; |
|
1683 } else if (ch == '\n' || ch == '\r') { |
|
1684 if (i == lineStart + 1) { |
|
1685 ++lineStart; |
|
1686 } else if (!inQuotes) { |
|
1687 --i; |
|
1688 goto break_out_of_outer_loop; |
|
1689 } |
|
1690 } else if (ch == '\\') { |
|
1691 if (i < dataLen) { |
|
1692 char ch = data.at(i++); |
|
1693 if (i < dataLen) { |
|
1694 char ch2 = data.at(i); |
|
1695 // \n, \r, \r\n, and \n\r are legitimate line terminators in INI files |
|
1696 if ((ch == '\n' && ch2 == '\r') || (ch == '\r' && ch2 == '\n')) |
|
1697 ++i; |
|
1698 } |
|
1699 } |
|
1700 } else if (ch == '"') { |
|
1701 inQuotes = !inQuotes; |
|
1702 } else { |
|
1703 Q_ASSERT(ch == ';'); |
|
1704 |
|
1705 if (i == lineStart + 1) { |
|
1706 char ch; |
|
1707 while (i < dataLen && ((ch = data.at(i) != '\n') && ch != '\r')) |
|
1708 ++i; |
|
1709 lineStart = i; |
|
1710 } else if (!inQuotes) { |
|
1711 --i; |
|
1712 goto break_out_of_outer_loop; |
|
1713 } |
|
1714 } |
|
1715 } |
|
1716 |
|
1717 break_out_of_outer_loop: |
|
1718 dataPos = i; |
|
1719 lineLen = i - lineStart; |
|
1720 return lineLen > 0; |
|
1721 } |
|
1722 |
|
1723 /* |
|
1724 Returns false on parse error. However, as many keys are read as |
|
1725 possible, so if the user doesn't check the status he will get the |
|
1726 most out of the file anyway. |
|
1727 */ |
|
1728 bool QConfFileSettingsPrivate::readIniFile(const QByteArray &data, |
|
1729 UnparsedSettingsMap *unparsedIniSections) |
|
1730 { |
|
1731 #define FLUSH_CURRENT_SECTION() \ |
|
1732 { \ |
|
1733 QByteArray §ionData = (*unparsedIniSections)[QSettingsKey(currentSection, \ |
|
1734 IniCaseSensitivity, \ |
|
1735 sectionPosition)]; \ |
|
1736 if (!sectionData.isEmpty()) \ |
|
1737 sectionData.append('\n'); \ |
|
1738 sectionData += data.mid(currentSectionStart, lineStart - currentSectionStart); \ |
|
1739 sectionPosition = ++position; \ |
|
1740 } |
|
1741 |
|
1742 QString currentSection; |
|
1743 int currentSectionStart = 0; |
|
1744 int dataPos = 0; |
|
1745 int lineStart; |
|
1746 int lineLen; |
|
1747 int equalsPos; |
|
1748 int position = 0; |
|
1749 int sectionPosition = 0; |
|
1750 bool ok = true; |
|
1751 |
|
1752 while (readIniLine(data, dataPos, lineStart, lineLen, equalsPos)) { |
|
1753 char ch = data.at(lineStart); |
|
1754 if (ch == '[') { |
|
1755 FLUSH_CURRENT_SECTION(); |
|
1756 |
|
1757 // this is a section |
|
1758 QByteArray iniSection; |
|
1759 int idx = data.indexOf(']', lineStart); |
|
1760 if (idx == -1 || idx >= lineStart + lineLen) { |
|
1761 ok = false; |
|
1762 iniSection = data.mid(lineStart + 1, lineLen - 1); |
|
1763 } else { |
|
1764 iniSection = data.mid(lineStart + 1, idx - lineStart - 1); |
|
1765 } |
|
1766 |
|
1767 iniSection = iniSection.trimmed(); |
|
1768 |
|
1769 if (qstricmp(iniSection, "general") == 0) { |
|
1770 currentSection.clear(); |
|
1771 } else { |
|
1772 if (qstricmp(iniSection, "%general") == 0) { |
|
1773 currentSection = QLatin1String(iniSection.constData() + 1); |
|
1774 } else { |
|
1775 currentSection.clear(); |
|
1776 iniUnescapedKey(iniSection, 0, iniSection.size(), currentSection); |
|
1777 } |
|
1778 currentSection += QLatin1Char('/'); |
|
1779 } |
|
1780 currentSectionStart = dataPos; |
|
1781 } |
|
1782 ++position; |
|
1783 } |
|
1784 |
|
1785 Q_ASSERT(lineStart == data.length()); |
|
1786 FLUSH_CURRENT_SECTION(); |
|
1787 |
|
1788 return ok; |
|
1789 |
|
1790 #undef FLUSH_CURRENT_SECTION |
|
1791 } |
|
1792 |
|
1793 bool QConfFileSettingsPrivate::readIniSection(const QSettingsKey §ion, const QByteArray &data, |
|
1794 ParsedSettingsMap *settingsMap, QTextCodec *codec) |
|
1795 { |
|
1796 QStringList strListValue; |
|
1797 bool sectionIsLowercase = (section == section.originalCaseKey()); |
|
1798 int equalsPos; |
|
1799 |
|
1800 bool ok = true; |
|
1801 int dataPos = 0; |
|
1802 int lineStart; |
|
1803 int lineLen; |
|
1804 int position = section.originalKeyPosition(); |
|
1805 |
|
1806 while (readIniLine(data, dataPos, lineStart, lineLen, equalsPos)) { |
|
1807 char ch = data.at(lineStart); |
|
1808 Q_ASSERT(ch != '['); |
|
1809 |
|
1810 if (equalsPos == -1) { |
|
1811 if (ch != ';') |
|
1812 ok = false; |
|
1813 continue; |
|
1814 } |
|
1815 |
|
1816 int keyEnd = equalsPos; |
|
1817 while (keyEnd > lineStart && ((ch = data.at(keyEnd - 1)) == ' ' || ch == '\t')) |
|
1818 --keyEnd; |
|
1819 int valueStart = equalsPos + 1; |
|
1820 |
|
1821 QString key = section.originalCaseKey(); |
|
1822 bool keyIsLowercase = (iniUnescapedKey(data, lineStart, keyEnd, key) && sectionIsLowercase); |
|
1823 |
|
1824 QString strValue; |
|
1825 strValue.reserve(lineLen - (valueStart - lineStart)); |
|
1826 bool isStringList = iniUnescapedStringList(data, valueStart, lineStart + lineLen, |
|
1827 strValue, strListValue, codec); |
|
1828 QVariant variant; |
|
1829 if (isStringList) { |
|
1830 variant = stringListToVariantList(strListValue); |
|
1831 } else { |
|
1832 variant = stringToVariant(strValue); |
|
1833 } |
|
1834 |
|
1835 /* |
|
1836 We try to avoid the expensive toLower() call in |
|
1837 QSettingsKey by passing Qt::CaseSensitive when the |
|
1838 key is already in lowercase. |
|
1839 */ |
|
1840 settingsMap->insert(QSettingsKey(key, keyIsLowercase ? Qt::CaseSensitive |
|
1841 : IniCaseSensitivity, |
|
1842 position), |
|
1843 variant); |
|
1844 ++position; |
|
1845 } |
|
1846 |
|
1847 return ok; |
|
1848 } |
|
1849 |
|
1850 class QSettingsIniKey : public QString |
|
1851 { |
|
1852 public: |
|
1853 inline QSettingsIniKey() : position(-1) {} |
|
1854 inline QSettingsIniKey(const QString &str, int pos = -1) : QString(str), position(pos) {} |
|
1855 |
|
1856 int position; |
|
1857 }; |
|
1858 |
|
1859 static bool operator<(const QSettingsIniKey &k1, const QSettingsIniKey &k2) |
|
1860 { |
|
1861 if (k1.position != k2.position) |
|
1862 return k1.position < k2.position; |
|
1863 return static_cast<const QString &>(k1) < static_cast<const QString &>(k2); |
|
1864 } |
|
1865 |
|
1866 typedef QMap<QSettingsIniKey, QVariant> IniKeyMap; |
|
1867 |
|
1868 struct QSettingsIniSection |
|
1869 { |
|
1870 int position; |
|
1871 IniKeyMap keyMap; |
|
1872 |
|
1873 inline QSettingsIniSection() : position(-1) {} |
|
1874 }; |
|
1875 |
|
1876 typedef QMap<QString, QSettingsIniSection> IniMap; |
|
1877 |
|
1878 /* |
|
1879 This would be more straightforward if we didn't try to remember the original |
|
1880 key order in the .ini file, but we do. |
|
1881 */ |
|
1882 bool QConfFileSettingsPrivate::writeIniFile(QIODevice &device, const ParsedSettingsMap &map) |
|
1883 { |
|
1884 IniMap iniMap; |
|
1885 IniMap::const_iterator i; |
|
1886 |
|
1887 #ifdef Q_OS_WIN |
|
1888 const char * const eol = "\r\n"; |
|
1889 #else |
|
1890 const char eol = '\n'; |
|
1891 #endif |
|
1892 |
|
1893 for (ParsedSettingsMap::const_iterator j = map.constBegin(); j != map.constEnd(); ++j) { |
|
1894 QString section; |
|
1895 QSettingsIniKey key(j.key().originalCaseKey(), j.key().originalKeyPosition()); |
|
1896 int slashPos; |
|
1897 |
|
1898 if ((slashPos = key.indexOf(QLatin1Char('/'))) != -1) { |
|
1899 section = key.left(slashPos); |
|
1900 key.remove(0, slashPos + 1); |
|
1901 } |
|
1902 |
|
1903 QSettingsIniSection &iniSection = iniMap[section]; |
|
1904 |
|
1905 // -1 means infinity |
|
1906 if (uint(key.position) < uint(iniSection.position)) |
|
1907 iniSection.position = key.position; |
|
1908 iniSection.keyMap[key] = j.value(); |
|
1909 } |
|
1910 |
|
1911 const int sectionCount = iniMap.size(); |
|
1912 QVector<QSettingsIniKey> sections; |
|
1913 sections.reserve(sectionCount); |
|
1914 for (i = iniMap.constBegin(); i != iniMap.constEnd(); ++i) |
|
1915 sections.append(QSettingsIniKey(i.key(), i.value().position)); |
|
1916 qSort(sections); |
|
1917 |
|
1918 bool writeError = false; |
|
1919 for (int j = 0; !writeError && j < sectionCount; ++j) { |
|
1920 i = iniMap.constFind(sections.at(j)); |
|
1921 Q_ASSERT(i != iniMap.constEnd()); |
|
1922 |
|
1923 QByteArray realSection; |
|
1924 |
|
1925 iniEscapedKey(i.key(), realSection); |
|
1926 |
|
1927 if (realSection.isEmpty()) { |
|
1928 realSection = "[General]"; |
|
1929 } else if (qstricmp(realSection, "general") == 0) { |
|
1930 realSection = "[%General]"; |
|
1931 } else { |
|
1932 realSection.prepend('['); |
|
1933 realSection.append(']'); |
|
1934 } |
|
1935 |
|
1936 if (j != 0) |
|
1937 realSection.prepend(eol); |
|
1938 realSection += eol; |
|
1939 |
|
1940 device.write(realSection); |
|
1941 |
|
1942 const IniKeyMap &ents = i.value().keyMap; |
|
1943 for (IniKeyMap::const_iterator j = ents.constBegin(); j != ents.constEnd(); ++j) { |
|
1944 QByteArray block; |
|
1945 iniEscapedKey(j.key(), block); |
|
1946 block += '='; |
|
1947 |
|
1948 const QVariant &value = j.value(); |
|
1949 |
|
1950 /* |
|
1951 The size() != 1 trick is necessary because |
|
1952 QVariant(QString("foo")).toList() returns an empty |
|
1953 list, not a list containing "foo". |
|
1954 */ |
|
1955 if (value.type() == QVariant::StringList |
|
1956 || (value.type() == QVariant::List && value.toList().size() != 1)) { |
|
1957 iniEscapedStringList(variantListToStringList(value.toList()), block, iniCodec); |
|
1958 } else { |
|
1959 iniEscapedString(variantToString(value), block, iniCodec); |
|
1960 } |
|
1961 block += eol; |
|
1962 if (device.write(block) == -1) { |
|
1963 writeError = true; |
|
1964 break; |
|
1965 } |
|
1966 } |
|
1967 } |
|
1968 return !writeError; |
|
1969 } |
|
1970 |
|
1971 void QConfFileSettingsPrivate::ensureAllSectionsParsed(QConfFile *confFile) const |
|
1972 { |
|
1973 UnparsedSettingsMap::const_iterator i = confFile->unparsedIniSections.constBegin(); |
|
1974 const UnparsedSettingsMap::const_iterator end = confFile->unparsedIniSections.constEnd(); |
|
1975 |
|
1976 for (; i != end; ++i) { |
|
1977 if (!QConfFileSettingsPrivate::readIniSection(i.key(), i.value(), &confFile->originalKeys, iniCodec)) |
|
1978 setStatus(QSettings::FormatError); |
|
1979 } |
|
1980 confFile->unparsedIniSections.clear(); |
|
1981 } |
|
1982 |
|
1983 void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile, |
|
1984 const QSettingsKey &key) const |
|
1985 { |
|
1986 if (confFile->unparsedIniSections.isEmpty()) |
|
1987 return; |
|
1988 |
|
1989 UnparsedSettingsMap::iterator i; |
|
1990 |
|
1991 int indexOfSlash = key.indexOf(QLatin1Char('/')); |
|
1992 if (indexOfSlash != -1) { |
|
1993 i = confFile->unparsedIniSections.upperBound(key); |
|
1994 if (i == confFile->unparsedIniSections.begin()) |
|
1995 return; |
|
1996 --i; |
|
1997 if (i.key().isEmpty() || !key.startsWith(i.key())) |
|
1998 return; |
|
1999 } else { |
|
2000 i = confFile->unparsedIniSections.begin(); |
|
2001 if (i == confFile->unparsedIniSections.end() || !i.key().isEmpty()) |
|
2002 return; |
|
2003 } |
|
2004 |
|
2005 if (!QConfFileSettingsPrivate::readIniSection(i.key(), i.value(), &confFile->originalKeys, iniCodec)) |
|
2006 setStatus(QSettings::FormatError); |
|
2007 confFile->unparsedIniSections.erase(i); |
|
2008 } |
|
2009 |
|
2010 /*! |
|
2011 \class QSettings |
|
2012 \brief The QSettings class provides persistent platform-independent application settings. |
|
2013 |
|
2014 \ingroup io |
|
2015 |
|
2016 \reentrant |
|
2017 |
|
2018 Users normally expect an application to remember its settings |
|
2019 (window sizes and positions, options, etc.) across sessions. This |
|
2020 information is often stored in the system registry on Windows, |
|
2021 and in XML preferences files on Mac OS X. On Unix systems, in the |
|
2022 absence of a standard, many applications (including the KDE |
|
2023 applications) use INI text files. |
|
2024 |
|
2025 QSettings is an abstraction around these technologies, enabling |
|
2026 you to save and restore application settings in a portable |
|
2027 manner. It also supports \l{registerFormat()}{custom storage |
|
2028 formats}. |
|
2029 |
|
2030 QSettings's API is based on QVariant, allowing you to save |
|
2031 most value-based types, such as QString, QRect, and QImage, |
|
2032 with the minimum of effort. |
|
2033 |
|
2034 If all you need is a non-persistent memory-based structure, |
|
2035 consider using QMap<QString, QVariant> instead. |
|
2036 |
|
2037 \tableofcontents section1 |
|
2038 |
|
2039 \section1 Basic Usage |
|
2040 |
|
2041 When creating a QSettings object, you must pass the name of your |
|
2042 company or organization as well as the name of your application. |
|
2043 For example, if your product is called Star Runner and your |
|
2044 company is called MySoft, you would construct the QSettings |
|
2045 object as follows: |
|
2046 |
|
2047 \snippet doc/src/snippets/settings/settings.cpp 0 |
|
2048 |
|
2049 QSettings objects can be created either on the stack or on |
|
2050 the heap (i.e. using \c new). Constructing and destroying a |
|
2051 QSettings object is very fast. |
|
2052 |
|
2053 If you use QSettings from many places in your application, you |
|
2054 might want to specify the organization name and the application |
|
2055 name using QCoreApplication::setOrganizationName() and |
|
2056 QCoreApplication::setApplicationName(), and then use the default |
|
2057 QSettings constructor: |
|
2058 |
|
2059 \snippet doc/src/snippets/settings/settings.cpp 1 |
|
2060 \snippet doc/src/snippets/settings/settings.cpp 2 |
|
2061 \snippet doc/src/snippets/settings/settings.cpp 3 |
|
2062 \dots |
|
2063 \snippet doc/src/snippets/settings/settings.cpp 4 |
|
2064 |
|
2065 (Here, we also specify the organization's Internet domain. When |
|
2066 the Internet domain is set, it is used on Mac OS X instead of the |
|
2067 organization name, since Mac OS X applications conventionally use |
|
2068 Internet domains to identify themselves. If no domain is set, a |
|
2069 fake domain is derived from the organization name. See the |
|
2070 \l{Platform-Specific Notes} below for details.) |
|
2071 |
|
2072 QSettings stores settings. Each setting consists of a QString |
|
2073 that specifies the setting's name (the \e key) and a QVariant |
|
2074 that stores the data associated with the key. To write a setting, |
|
2075 use setValue(). For example: |
|
2076 |
|
2077 \snippet doc/src/snippets/settings/settings.cpp 5 |
|
2078 |
|
2079 If there already exists a setting with the same key, the existing |
|
2080 value is overwritten by the new value. For efficiency, the |
|
2081 changes may not be saved to permanent storage immediately. (You |
|
2082 can always call sync() to commit your changes.) |
|
2083 |
|
2084 You can get a setting's value back using value(): |
|
2085 |
|
2086 \snippet doc/src/snippets/settings/settings.cpp 6 |
|
2087 |
|
2088 If there is no setting with the specified name, QSettings |
|
2089 returns a null QVariant (which can be converted to the integer 0). |
|
2090 You can specify another default value by passing a second |
|
2091 argument to value(): |
|
2092 |
|
2093 \snippet doc/src/snippets/settings/settings.cpp 7 |
|
2094 |
|
2095 To test whether a given key exists, call contains(). To remove |
|
2096 the setting associated with a key, call remove(). To obtain the |
|
2097 list of all keys, call allKeys(). To remove all keys, call |
|
2098 clear(). |
|
2099 |
|
2100 \section1 QVariant and GUI Types |
|
2101 |
|
2102 Because QVariant is part of the \l QtCore library, it cannot provide |
|
2103 conversion functions to data types such as QColor, QImage, and |
|
2104 QPixmap, which are part of \l QtGui. In other words, there is no |
|
2105 \c toColor(), \c toImage(), or \c toPixmap() functions in QVariant. |
|
2106 |
|
2107 Instead, you can use the QVariant::value() or the qVariantValue() |
|
2108 template function. For example: |
|
2109 |
|
2110 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 0 |
|
2111 |
|
2112 The inverse conversion (e.g., from QColor to QVariant) is |
|
2113 automatic for all data types supported by QVariant, including |
|
2114 GUI-related types: |
|
2115 |
|
2116 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 1 |
|
2117 |
|
2118 Custom types registered using qRegisterMetaType() and |
|
2119 qRegisterMetaTypeStreamOperators() can be stored using QSettings. |
|
2120 |
|
2121 \section1 Section and Key Syntax |
|
2122 |
|
2123 Setting keys can contain any Unicode characters. The Windows |
|
2124 registry and INI files use case-insensitive keys, whereas the |
|
2125 Carbon Preferences API on Mac OS X uses case-sensitive keys. To |
|
2126 avoid portability problems, follow these simple rules: |
|
2127 |
|
2128 \list 1 |
|
2129 \o Always refer to the same key using the same case. For example, |
|
2130 if you refer to a key as "text fonts" in one place in your |
|
2131 code, don't refer to it as "Text Fonts" somewhere else. |
|
2132 |
|
2133 \o Avoid key names that are identical except for the case. For |
|
2134 example, if you have a key called "MainWindow", don't try to |
|
2135 save another key as "mainwindow". |
|
2136 |
|
2137 \o Do not use slashes ('/' and '\\') in section or key names; the |
|
2138 backslash character is used to separate sub keys (see below). On |
|
2139 windows '\\' are converted by QSettings to '/', which makes |
|
2140 them identical. |
|
2141 \endlist |
|
2142 |
|
2143 You can form hierarchical keys using the '/' character as a |
|
2144 separator, similar to Unix file paths. For example: |
|
2145 |
|
2146 \snippet doc/src/snippets/settings/settings.cpp 8 |
|
2147 \snippet doc/src/snippets/settings/settings.cpp 9 |
|
2148 \snippet doc/src/snippets/settings/settings.cpp 10 |
|
2149 |
|
2150 If you want to save or restore many settings with the same |
|
2151 prefix, you can specify the prefix using beginGroup() and call |
|
2152 endGroup() at the end. Here's the same example again, but this |
|
2153 time using the group mechanism: |
|
2154 |
|
2155 \snippet doc/src/snippets/settings/settings.cpp 11 |
|
2156 \codeline |
|
2157 \snippet doc/src/snippets/settings/settings.cpp 12 |
|
2158 |
|
2159 If a group is set using beginGroup(), the behavior of most |
|
2160 functions changes consequently. Groups can be set recursively. |
|
2161 |
|
2162 In addition to groups, QSettings also supports an "array" |
|
2163 concept. See beginReadArray() and beginWriteArray() for details. |
|
2164 |
|
2165 \section1 Fallback Mechanism |
|
2166 |
|
2167 Let's assume that you have created a QSettings object with the |
|
2168 organization name MySoft and the application name Star Runner. |
|
2169 When you look up a value, up to four locations are searched in |
|
2170 that order: |
|
2171 |
|
2172 \list 1 |
|
2173 \o a user-specific location for the Star Runner application |
|
2174 \o a user-specific location for all applications by MySoft |
|
2175 \o a system-wide location for the Star Runner application |
|
2176 \o a system-wide location for all applications by MySoft |
|
2177 \endlist |
|
2178 |
|
2179 (See \l{Platform-Specific Notes} below for information on what |
|
2180 these locations are on the different platforms supported by Qt.) |
|
2181 |
|
2182 If a key cannot be found in the first location, the search goes |
|
2183 on in the second location, and so on. This enables you to store |
|
2184 system-wide or organization-wide settings and to override them on |
|
2185 a per-user or per-application basis. To turn off this mechanism, |
|
2186 call setFallbacksEnabled(false). |
|
2187 |
|
2188 Although keys from all four locations are available for reading, |
|
2189 only the first file (the user-specific location for the |
|
2190 application at hand) is accessible for writing. To write to any |
|
2191 of the other files, omit the application name and/or specify |
|
2192 QSettings::SystemScope (as opposed to QSettings::UserScope, the |
|
2193 default). |
|
2194 |
|
2195 Let's see with an example: |
|
2196 |
|
2197 \snippet doc/src/snippets/settings/settings.cpp 13 |
|
2198 \snippet doc/src/snippets/settings/settings.cpp 14 |
|
2199 |
|
2200 The table below summarizes which QSettings objects access |
|
2201 which location. "\bold{X}" means that the location is the main |
|
2202 location associated to the QSettings object and is used both |
|
2203 for reading and for writing; "o" means that the location is used |
|
2204 as a fallback when reading. |
|
2205 |
|
2206 \table |
|
2207 \header \o Locations \o \c{obj1} \o \c{obj2} \o \c{obj3} \o \c{obj4} |
|
2208 \row \o 1. User, Application \o \bold{X} \o \o \o |
|
2209 \row \o 2. User, Organization \o o \o \bold{X} \o \o |
|
2210 \row \o 3. System, Application \o o \o \o \bold{X} \o |
|
2211 \row \o 4. System, Organization \o o \o o \o o \o \bold{X} |
|
2212 \endtable |
|
2213 |
|
2214 The beauty of this mechanism is that it works on all platforms |
|
2215 supported by Qt and that it still gives you a lot of flexibility, |
|
2216 without requiring you to specify any file names or registry |
|
2217 paths. |
|
2218 |
|
2219 If you want to use INI files on all platforms instead of the |
|
2220 native API, you can pass QSettings::IniFormat as the first |
|
2221 argument to the QSettings constructor, followed by the scope, the |
|
2222 organization name, and the application name: |
|
2223 |
|
2224 \snippet doc/src/snippets/settings/settings.cpp 15 |
|
2225 |
|
2226 The \l{tools/settingseditor}{Settings Editor} example lets you |
|
2227 experiment with different settings location and with fallbacks |
|
2228 turned on or off. |
|
2229 |
|
2230 \section1 Restoring the State of a GUI Application |
|
2231 |
|
2232 QSettings is often used to store the state of a GUI |
|
2233 application. The following example illustrates how to use QSettings |
|
2234 to save and restore the geometry of an application's main window. |
|
2235 |
|
2236 \snippet doc/src/snippets/settings/settings.cpp 16 |
|
2237 \codeline |
|
2238 \snippet doc/src/snippets/settings/settings.cpp 17 |
|
2239 |
|
2240 See \l{Window Geometry} for a discussion on why it is better to |
|
2241 call QWidget::resize() and QWidget::move() rather than QWidget::setGeometry() |
|
2242 to restore a window's geometry. |
|
2243 |
|
2244 The \c readSettings() and \c writeSettings() functions must be |
|
2245 called from the main window's constructor and close event handler |
|
2246 as follows: |
|
2247 |
|
2248 \snippet doc/src/snippets/settings/settings.cpp 18 |
|
2249 \dots |
|
2250 \snippet doc/src/snippets/settings/settings.cpp 19 |
|
2251 \snippet doc/src/snippets/settings/settings.cpp 20 |
|
2252 \codeline |
|
2253 \snippet doc/src/snippets/settings/settings.cpp 21 |
|
2254 |
|
2255 See the \l{mainwindows/application}{Application} example for a |
|
2256 self-contained example that uses QSettings. |
|
2257 |
|
2258 \section1 Accessing Settings from Multiple Threads or Processes Simultaneously |
|
2259 |
|
2260 QSettings is \l{reentrant}. This means that you can use |
|
2261 distinct QSettings object in different threads |
|
2262 simultaneously. This guarantee stands even when the QSettings |
|
2263 objects refer to the same files on disk (or to the same entries |
|
2264 in the system registry). If a setting is modified through one |
|
2265 QSettings object, the change will immediately be visible in |
|
2266 any other QSettings objects that operate on the same location |
|
2267 and that live in the same process. |
|
2268 |
|
2269 QSettings can safely be used from different processes (which can |
|
2270 be different instances of your application running at the same |
|
2271 time or different applications altogether) to read and write to |
|
2272 the same system locations. It uses advisory file locking and a |
|
2273 smart merging algorithm to ensure data integrity. Changes |
|
2274 performed by another process aren't visible in the current |
|
2275 process until sync() is called. |
|
2276 |
|
2277 \section1 Platform-Specific Notes |
|
2278 |
|
2279 \section2 Locations Where Application Settings Are Stored |
|
2280 |
|
2281 As mentioned in the \l{Fallback Mechanism} section, QSettings |
|
2282 stores settings for an application in up to four locations, |
|
2283 depending on whether the settings are user-specific or |
|
2284 system-wide and whether the settings are application-specific |
|
2285 or organization-wide. For simplicity, we're assuming the |
|
2286 organization is called MySoft and the application is called Star |
|
2287 Runner. |
|
2288 |
|
2289 On Unix systems, if the file format is NativeFormat, the |
|
2290 following files are used by default: |
|
2291 |
|
2292 \list 1 |
|
2293 \o \c{$HOME/.config/MySoft/Star Runner.conf} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft/Star Runner.conf}) |
|
2294 \o \c{$HOME/.config/MySoft.conf} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft.conf}) |
|
2295 \o \c{/etc/xdg/MySoft/Star Runner.conf} |
|
2296 \o \c{/etc/xdg/MySoft.conf} |
|
2297 \endlist |
|
2298 |
|
2299 On Mac OS X versions 10.2 and 10.3, these files are used by |
|
2300 default: |
|
2301 |
|
2302 \list 1 |
|
2303 \o \c{$HOME/Library/Preferences/com.MySoft.Star Runner.plist} |
|
2304 \o \c{$HOME/Library/Preferences/com.MySoft.plist} |
|
2305 \o \c{/Library/Preferences/com.MySoft.Star Runner.plist} |
|
2306 \o \c{/Library/Preferences/com.MySoft.plist} |
|
2307 \endlist |
|
2308 |
|
2309 On Windows, NativeFormat settings are stored in the following |
|
2310 registry paths: |
|
2311 |
|
2312 \list 1 |
|
2313 \o \c{HKEY_CURRENT_USER\Software\MySoft\Star Runner} |
|
2314 \o \c{HKEY_CURRENT_USER\Software\MySoft} |
|
2315 \o \c{HKEY_LOCAL_MACHINE\Software\MySoft\Star Runner} |
|
2316 \o \c{HKEY_LOCAL_MACHINE\Software\MySoft} |
|
2317 \endlist |
|
2318 |
|
2319 \note On Windows, for 32-bit programs running in WOW64 mode, settings are |
|
2320 stored in the following registry path: |
|
2321 \c{HKEY_LOCAL_MACHINE\Software\WOW6432node}. |
|
2322 |
|
2323 If the file format is IniFormat, the following files are |
|
2324 used on Unix and Mac OS X: |
|
2325 |
|
2326 \list 1 |
|
2327 \o \c{$HOME/.config/MySoft/Star Runner.ini} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft/Star Runner.ini}) |
|
2328 \o \c{$HOME/.config/MySoft.ini} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft.ini}) |
|
2329 \o \c{/etc/xdg/MySoft/Star Runner.ini} |
|
2330 \o \c{/etc/xdg/MySoft.ini} |
|
2331 \endlist |
|
2332 |
|
2333 On Windows, the following files are used: |
|
2334 |
|
2335 \list 1 |
|
2336 \o \c{%APPDATA%\MySoft\Star Runner.ini} |
|
2337 \o \c{%APPDATA%\MySoft.ini} |
|
2338 \o \c{%COMMON_APPDATA%\MySoft\Star Runner.ini} |
|
2339 \o \c{%COMMON_APPDATA%\MySoft.ini} |
|
2340 \endlist |
|
2341 |
|
2342 The \c %APPDATA% path is usually \tt{C:\\Documents and |
|
2343 Settings\\\e{User Name}\\Application Data}; the \c |
|
2344 %COMMON_APPDATA% path is usually \tt{C:\\Documents and |
|
2345 Settings\\All Users\\Application Data}. |
|
2346 |
|
2347 The paths for the \c .ini and \c .conf files can be changed using |
|
2348 setPath(). On Unix and Mac OS X, the user can override them by by |
|
2349 setting the \c XDG_CONFIG_HOME environment variable; see |
|
2350 setPath() for details. |
|
2351 |
|
2352 \section2 Accessing INI and .plist Files Directly |
|
2353 |
|
2354 Sometimes you do want to access settings stored in a specific |
|
2355 file or registry path. On all platforms, if you want to read an |
|
2356 INI file directly, you can use the QSettings constructor that |
|
2357 takes a file name as first argument and pass QSettings::IniFormat |
|
2358 as second argument. For example: |
|
2359 |
|
2360 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 2 |
|
2361 |
|
2362 You can then use the QSettings object to read and write settings |
|
2363 in the file. |
|
2364 |
|
2365 On Mac OS X, you can access XML-based \c .plist files by passing |
|
2366 QSettings::NativeFormat as second argument. For example: |
|
2367 |
|
2368 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 3 |
|
2369 |
|
2370 \section2 Accessing the Windows Registry Directly |
|
2371 |
|
2372 On Windows, QSettings lets you access settings that have been |
|
2373 written with QSettings (or settings in a supported format, e.g., string |
|
2374 data) in the system registry. This is done by constructing a QSettings |
|
2375 object with a path in the registry and QSettings::NativeFormat. |
|
2376 |
|
2377 For example: |
|
2378 |
|
2379 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 4 |
|
2380 |
|
2381 All the registry entries that appear under the specified path can |
|
2382 be read or written through the QSettings object as usual (using |
|
2383 forward slashes instead of backslashes). For example: |
|
2384 |
|
2385 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 5 |
|
2386 |
|
2387 Note that the backslash character is, as mentioned, used by |
|
2388 QSettings to separate subkeys. As a result, you cannot read or |
|
2389 write windows registry entries that contain slashes or |
|
2390 backslashes; you should use a native windows API if you need to do |
|
2391 so. |
|
2392 |
|
2393 \section2 Accessing Common Registry Settings on Windows |
|
2394 |
|
2395 On Windows, it is possible for a key to have both a value and subkeys. |
|
2396 Its default value is accessed by using "Default" or "." in |
|
2397 place of a subkey: |
|
2398 |
|
2399 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 6 |
|
2400 |
|
2401 On other platforms than Windows, "Default" and "." would be |
|
2402 treated as regular subkeys. |
|
2403 |
|
2404 \section2 Platform Limitations |
|
2405 |
|
2406 While QSettings attempts to smooth over the differences between |
|
2407 the different supported platforms, there are still a few |
|
2408 differences that you should be aware of when porting your |
|
2409 application: |
|
2410 |
|
2411 \list |
|
2412 \o The Windows system registry has the following limitations: A |
|
2413 subkey may not exceed 255 characters, an entry's value may |
|
2414 not exceed 16,383 characters, and all the values of a key may |
|
2415 not exceed 65,535 characters. One way to work around these |
|
2416 limitations is to store the settings using the IniFormat |
|
2417 instead of the NativeFormat. |
|
2418 |
|
2419 \o On Mac OS X, allKeys() will return some extra keys for global |
|
2420 settings that apply to all applications. These keys can be |
|
2421 read using value() but cannot be changed, only shadowed. |
|
2422 Calling setFallbacksEnabled(false) will hide these global |
|
2423 settings. |
|
2424 |
|
2425 \o On Mac OS X, the CFPreferences API used by QSettings expects |
|
2426 Internet domain names rather than organization names. To |
|
2427 provide a uniform API, QSettings derives a fake domain name |
|
2428 from the organization name (unless the organization name |
|
2429 already is a domain name, e.g. OpenOffice.org). The algorithm |
|
2430 appends ".com" to the company name and replaces spaces and |
|
2431 other illegal characters with hyphens. If you want to specify |
|
2432 a different domain name, call |
|
2433 QCoreApplication::setOrganizationDomain(), |
|
2434 QCoreApplication::setOrganizationName(), and |
|
2435 QCoreApplication::setApplicationName() in your \c main() |
|
2436 function and then use the default QSettings constructor. |
|
2437 Another solution is to use preprocessor directives, for |
|
2438 example: |
|
2439 |
|
2440 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 7 |
|
2441 |
|
2442 \o On Unix and Mac OS X systems, the advisory file locking is disabled |
|
2443 if NFS (or AutoFS or CacheFS) is detected to work around a bug in the |
|
2444 NFS fcntl() implementation, which hangs forever if statd or lockd aren't |
|
2445 running. Also, the locking isn't performed when accessing \c .plist |
|
2446 files. |
|
2447 |
|
2448 \endlist |
|
2449 |
|
2450 \sa QVariant, QSessionManager, {Settings Editor Example}, {Application Example} |
|
2451 */ |
|
2452 |
|
2453 /*! \enum QSettings::Status |
|
2454 |
|
2455 The following status values are possible: |
|
2456 |
|
2457 \value NoError No error occurred. |
|
2458 \value AccessError An access error occurred (e.g. trying to write to a read-only file). |
|
2459 \value FormatError A format error occurred (e.g. loading a malformed INI file). |
|
2460 |
|
2461 \sa status() |
|
2462 */ |
|
2463 |
|
2464 /*! \enum QSettings::Format |
|
2465 |
|
2466 This enum type specifies the storage format used by QSettings. |
|
2467 |
|
2468 \value NativeFormat Store the settings using the most |
|
2469 appropriate storage format for the platform. |
|
2470 On Windows, this means the system registry; |
|
2471 on Mac OS X, this means the CFPreferences |
|
2472 API; on Unix, this means textual |
|
2473 configuration files in INI format. |
|
2474 \value IniFormat Store the settings in INI files. |
|
2475 \value InvalidFormat Special value returned by registerFormat(). |
|
2476 \omitvalue CustomFormat1 |
|
2477 \omitvalue CustomFormat2 |
|
2478 \omitvalue CustomFormat3 |
|
2479 \omitvalue CustomFormat4 |
|
2480 \omitvalue CustomFormat5 |
|
2481 \omitvalue CustomFormat6 |
|
2482 \omitvalue CustomFormat7 |
|
2483 \omitvalue CustomFormat8 |
|
2484 \omitvalue CustomFormat9 |
|
2485 \omitvalue CustomFormat10 |
|
2486 \omitvalue CustomFormat11 |
|
2487 \omitvalue CustomFormat12 |
|
2488 \omitvalue CustomFormat13 |
|
2489 \omitvalue CustomFormat14 |
|
2490 \omitvalue CustomFormat15 |
|
2491 \omitvalue CustomFormat16 |
|
2492 |
|
2493 On Unix, NativeFormat and IniFormat mean the same thing, except |
|
2494 that the file extension is different (\c .conf for NativeFormat, |
|
2495 \c .ini for IniFormat). |
|
2496 |
|
2497 The INI file format is a Windows file format that Qt supports on |
|
2498 all platforms. In the absence of an INI standard, we try to |
|
2499 follow what Microsoft does, with the following exceptions: |
|
2500 |
|
2501 \list |
|
2502 \o If you store types that QVariant can't convert to QString |
|
2503 (e.g., QPoint, QRect, and QSize), Qt uses an \c{@}-based |
|
2504 syntax to encode the type. For example: |
|
2505 |
|
2506 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 8 |
|
2507 |
|
2508 To minimize compatibility issues, any \c @ that doesn't |
|
2509 appear at the first position in the value or that isn't |
|
2510 followed by a Qt type (\c Point, \c Rect, \c Size, etc.) is |
|
2511 treated as a normal character. |
|
2512 |
|
2513 \o Although backslash is a special character in INI files, most |
|
2514 Windows applications don't escape backslashes (\c{\}) in file |
|
2515 paths: |
|
2516 |
|
2517 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 9 |
|
2518 |
|
2519 QSettings always treats backslash as a special character and |
|
2520 provides no API for reading or writing such entries. |
|
2521 |
|
2522 \o The INI file format has severe restrictions on the syntax of |
|
2523 a key. Qt works around this by using \c % as an escape |
|
2524 character in keys. In addition, if you save a top-level |
|
2525 setting (a key with no slashes in it, e.g., "someKey"), it |
|
2526 will appear in the INI file's "General" section. To avoid |
|
2527 overwriting other keys, if you save something using the a key |
|
2528 such as "General/someKey", the key will be located in the |
|
2529 "%General" section, \e not in the "General" section. |
|
2530 |
|
2531 \o Following the philosophy that we should be liberal in what |
|
2532 we accept and conservative in what we generate, QSettings |
|
2533 will accept Latin-1 encoded INI files, but generate pure |
|
2534 ASCII files, where non-ASCII values are encoded using standard |
|
2535 INI escape sequences. To make the INI files more readable (but |
|
2536 potentially less compatible), call setIniCodec(). |
|
2537 \endlist |
|
2538 |
|
2539 \sa registerFormat(), setPath() |
|
2540 */ |
|
2541 |
|
2542 /*! \enum QSettings::Scope |
|
2543 |
|
2544 This enum specifies whether settings are user-specific or shared |
|
2545 by all users of the same system. |
|
2546 |
|
2547 \value UserScope Store settings in a location specific to the |
|
2548 current user (e.g., in the user's home |
|
2549 directory). |
|
2550 \value SystemScope Store settings in a global location, so that |
|
2551 all users on the same machine access the same |
|
2552 set of settings. |
|
2553 \omitvalue User |
|
2554 \omitvalue Global |
|
2555 |
|
2556 \sa setPath() |
|
2557 */ |
|
2558 |
|
2559 #ifndef QT_NO_QOBJECT |
|
2560 /*! |
|
2561 Constructs a QSettings object for accessing settings of the |
|
2562 application called \a application from the organization called \a |
|
2563 organization, and with parent \a parent. |
|
2564 |
|
2565 Example: |
|
2566 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 10 |
|
2567 |
|
2568 The scope is set to QSettings::UserScope, and the format is |
|
2569 set to QSettings::NativeFormat (i.e. calling setDefaultFormat() |
|
2570 before calling this constructor has no effect). |
|
2571 |
|
2572 \sa setDefaultFormat(), {Fallback Mechanism} |
|
2573 */ |
|
2574 QSettings::QSettings(const QString &organization, const QString &application, QObject *parent) |
|
2575 : QObject(*QSettingsPrivate::create(NativeFormat, UserScope, organization, application), |
|
2576 parent) |
|
2577 { |
|
2578 } |
|
2579 |
|
2580 /*! |
|
2581 Constructs a QSettings object for accessing settings of the |
|
2582 application called \a application from the organization called \a |
|
2583 organization, and with parent \a parent. |
|
2584 |
|
2585 If \a scope is QSettings::UserScope, the QSettings object searches |
|
2586 user-specific settings first, before it searches system-wide |
|
2587 settings as a fallback. If \a scope is QSettings::SystemScope, the |
|
2588 QSettings object ignores user-specific settings and provides |
|
2589 access to system-wide settings. |
|
2590 |
|
2591 The storage format is set to QSettings::NativeFormat (i.e. calling |
|
2592 setDefaultFormat() before calling this constructor has no effect). |
|
2593 |
|
2594 If no application name is given, the QSettings object will |
|
2595 only access the organization-wide \l{Fallback Mechanism}{locations}. |
|
2596 |
|
2597 \sa setDefaultFormat() |
|
2598 */ |
|
2599 QSettings::QSettings(Scope scope, const QString &organization, const QString &application, |
|
2600 QObject *parent) |
|
2601 : QObject(*QSettingsPrivate::create(NativeFormat, scope, organization, application), parent) |
|
2602 { |
|
2603 } |
|
2604 |
|
2605 /*! |
|
2606 Constructs a QSettings object for accessing settings of the |
|
2607 application called \a application from the organization called |
|
2608 \a organization, and with parent \a parent. |
|
2609 |
|
2610 If \a scope is QSettings::UserScope, the QSettings object searches |
|
2611 user-specific settings first, before it searches system-wide |
|
2612 settings as a fallback. If \a scope is |
|
2613 QSettings::SystemScope, the QSettings object ignores user-specific |
|
2614 settings and provides access to system-wide settings. |
|
2615 |
|
2616 If \a format is QSettings::NativeFormat, the native API is used for |
|
2617 storing settings. If \a format is QSettings::IniFormat, the INI format |
|
2618 is used. |
|
2619 |
|
2620 If no application name is given, the QSettings object will |
|
2621 only access the organization-wide \l{Fallback Mechanism}{locations}. |
|
2622 */ |
|
2623 QSettings::QSettings(Format format, Scope scope, const QString &organization, |
|
2624 const QString &application, QObject *parent) |
|
2625 : QObject(*QSettingsPrivate::create(format, scope, organization, application), parent) |
|
2626 { |
|
2627 } |
|
2628 |
|
2629 /*! |
|
2630 Constructs a QSettings object for accessing the settings |
|
2631 stored in the file called \a fileName, with parent \a parent. If |
|
2632 the file doesn't already exist, it is created. |
|
2633 |
|
2634 If \a format is QSettings::NativeFormat, the meaning of \a |
|
2635 fileName depends on the platform. On Unix, \a fileName is the |
|
2636 name of an INI file. On Mac OS X, \a fileName is the name of a |
|
2637 \c .plist file. On Windows, \a fileName is a path in the system |
|
2638 registry. |
|
2639 |
|
2640 If \a format is QSettings::IniFormat, \a fileName is the name of an INI |
|
2641 file. |
|
2642 |
|
2643 \warning This function is provided for convenience. It works well for |
|
2644 accessing INI or \c .plist files generated by Qt, but might fail on some |
|
2645 syntaxes found in such files originated by other programs. In particular, |
|
2646 be aware of the following limitations: |
|
2647 |
|
2648 \list |
|
2649 \o QSettings provides no way of reading INI "path" entries, i.e., entries |
|
2650 with unescaped slash characters. (This is because these entries are |
|
2651 ambiguous and cannot be resolved automatically.) |
|
2652 \o In INI files, QSettings uses the \c @ character as a metacharacter in some |
|
2653 contexts, to encode Qt-specific data types (e.g., \c @Rect), and might |
|
2654 therefore misinterpret it when it occurs in pure INI files. |
|
2655 \endlist |
|
2656 |
|
2657 \sa fileName() |
|
2658 */ |
|
2659 QSettings::QSettings(const QString &fileName, Format format, QObject *parent) |
|
2660 : QObject(*QSettingsPrivate::create(fileName, format), parent) |
|
2661 { |
|
2662 } |
|
2663 |
|
2664 /*! |
|
2665 Constructs a QSettings object for accessing settings of the |
|
2666 application and organization set previously with a call to |
|
2667 QCoreApplication::setOrganizationName(), |
|
2668 QCoreApplication::setOrganizationDomain(), and |
|
2669 QCoreApplication::setApplicationName(). |
|
2670 |
|
2671 The scope is QSettings::UserScope and the format is |
|
2672 defaultFormat() (QSettings::NativeFormat by default). |
|
2673 Use setDefaultFormat() before calling this constructor |
|
2674 to change the default format used by this constructor. |
|
2675 |
|
2676 The code |
|
2677 |
|
2678 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 11 |
|
2679 |
|
2680 is equivalent to |
|
2681 |
|
2682 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 12 |
|
2683 |
|
2684 If QCoreApplication::setOrganizationName() and |
|
2685 QCoreApplication::setApplicationName() has not been previously |
|
2686 called, the QSettings object will not be able to read or write |
|
2687 any settings, and status() will return AccessError. |
|
2688 |
|
2689 On Mac OS X, if both a name and an Internet domain are specified |
|
2690 for the organization, the domain is preferred over the name. On |
|
2691 other platforms, the name is preferred over the domain. |
|
2692 |
|
2693 \sa QCoreApplication::setOrganizationName(), |
|
2694 QCoreApplication::setOrganizationDomain(), |
|
2695 QCoreApplication::setApplicationName(), |
|
2696 setDefaultFormat() |
|
2697 */ |
|
2698 QSettings::QSettings(QObject *parent) |
|
2699 : QObject(*QSettingsPrivate::create(globalDefaultFormat, UserScope, |
|
2700 #ifdef Q_OS_MAC |
|
2701 QCoreApplication::organizationDomain().isEmpty() |
|
2702 ? QCoreApplication::organizationName() |
|
2703 : QCoreApplication::organizationDomain() |
|
2704 #else |
|
2705 QCoreApplication::organizationName().isEmpty() |
|
2706 ? QCoreApplication::organizationDomain() |
|
2707 : QCoreApplication::organizationName() |
|
2708 #endif |
|
2709 , QCoreApplication::applicationName()), |
|
2710 parent) |
|
2711 { |
|
2712 } |
|
2713 |
|
2714 #else |
|
2715 QSettings::QSettings(const QString &organization, const QString &application) |
|
2716 : d_ptr(QSettingsPrivate::create(globalDefaultFormat, QSettings::UserScope, organization, application)) |
|
2717 { |
|
2718 d_ptr->q_ptr = this; |
|
2719 } |
|
2720 |
|
2721 QSettings::QSettings(Scope scope, const QString &organization, const QString &application) |
|
2722 : d_ptr(QSettingsPrivate::create(globalDefaultFormat, scope, organization, application)) |
|
2723 { |
|
2724 d_ptr->q_ptr = this; |
|
2725 } |
|
2726 |
|
2727 QSettings::QSettings(Format format, Scope scope, const QString &organization, |
|
2728 const QString &application) |
|
2729 : d_ptr(QSettingsPrivate::create(format, scope, organization, application)) |
|
2730 { |
|
2731 d_ptr->q_ptr = this; |
|
2732 } |
|
2733 |
|
2734 QSettings::QSettings(const QString &fileName, Format format) |
|
2735 : d_ptr(QSettingsPrivate::create(fileName, format)) |
|
2736 { |
|
2737 d_ptr->q_ptr = this; |
|
2738 } |
|
2739 #endif |
|
2740 |
|
2741 /*! |
|
2742 Destroys the QSettings object. |
|
2743 |
|
2744 Any unsaved changes will eventually be written to permanent |
|
2745 storage. |
|
2746 |
|
2747 \sa sync() |
|
2748 */ |
|
2749 QSettings::~QSettings() |
|
2750 { |
|
2751 Q_D(QSettings); |
|
2752 if (d->pendingChanges) { |
|
2753 QT_TRY { |
|
2754 d->flush(); |
|
2755 } QT_CATCH(...) { |
|
2756 ; // ok. then don't flush but at least don't throw in the destructor |
|
2757 } |
|
2758 } |
|
2759 } |
|
2760 |
|
2761 /*! |
|
2762 Removes all entries in the primary location associated to this |
|
2763 QSettings object. |
|
2764 |
|
2765 Entries in fallback locations are not removed. |
|
2766 |
|
2767 If you only want to remove the entries in the current group(), |
|
2768 use remove("") instead. |
|
2769 |
|
2770 \sa remove(), setFallbacksEnabled() |
|
2771 */ |
|
2772 void QSettings::clear() |
|
2773 { |
|
2774 Q_D(QSettings); |
|
2775 d->clear(); |
|
2776 d->requestUpdate(); |
|
2777 } |
|
2778 |
|
2779 /*! |
|
2780 Writes any unsaved changes to permanent storage, and reloads any |
|
2781 settings that have been changed in the meantime by another |
|
2782 application. |
|
2783 |
|
2784 This function is called automatically from QSettings's destructor and |
|
2785 by the event loop at regular intervals, so you normally don't need to |
|
2786 call it yourself. |
|
2787 |
|
2788 \sa status() |
|
2789 */ |
|
2790 void QSettings::sync() |
|
2791 { |
|
2792 Q_D(QSettings); |
|
2793 d->sync(); |
|
2794 } |
|
2795 |
|
2796 /*! |
|
2797 Returns the path where settings written using this QSettings |
|
2798 object are stored. |
|
2799 |
|
2800 On Windows, if the format is QSettings::NativeFormat, the return value |
|
2801 is a system registry path, not a file path. |
|
2802 |
|
2803 \sa isWritable(), format() |
|
2804 */ |
|
2805 QString QSettings::fileName() const |
|
2806 { |
|
2807 Q_D(const QSettings); |
|
2808 return d->fileName(); |
|
2809 } |
|
2810 |
|
2811 /*! |
|
2812 \since 4.4 |
|
2813 |
|
2814 Returns the format used for storing the settings. |
|
2815 |
|
2816 \sa defaultFormat(), fileName(), scope(), organizationName(), applicationName() |
|
2817 */ |
|
2818 QSettings::Format QSettings::format() const |
|
2819 { |
|
2820 Q_D(const QSettings); |
|
2821 return d->format; |
|
2822 } |
|
2823 |
|
2824 /*! |
|
2825 \since 4.4 |
|
2826 |
|
2827 Returns the scope used for storing the settings. |
|
2828 |
|
2829 \sa format(), organizationName(), applicationName() |
|
2830 */ |
|
2831 QSettings::Scope QSettings::scope() const |
|
2832 { |
|
2833 Q_D(const QSettings); |
|
2834 return d->scope; |
|
2835 } |
|
2836 |
|
2837 /*! |
|
2838 \since 4.4 |
|
2839 |
|
2840 Returns the organization name used for storing the settings. |
|
2841 |
|
2842 \sa QCoreApplication::organizationName(), format(), scope(), applicationName() |
|
2843 */ |
|
2844 QString QSettings::organizationName() const |
|
2845 { |
|
2846 Q_D(const QSettings); |
|
2847 return d->organizationName; |
|
2848 } |
|
2849 |
|
2850 /*! |
|
2851 \since 4.4 |
|
2852 |
|
2853 Returns the application name used for storing the settings. |
|
2854 |
|
2855 \sa QCoreApplication::applicationName(), format(), scope(), organizationName() |
|
2856 */ |
|
2857 QString QSettings::applicationName() const |
|
2858 { |
|
2859 Q_D(const QSettings); |
|
2860 return d->applicationName; |
|
2861 } |
|
2862 |
|
2863 #ifndef QT_NO_TEXTCODEC |
|
2864 |
|
2865 /*! |
|
2866 \since 4.5 |
|
2867 |
|
2868 Sets the codec for accessing INI files (including \c .conf files on Unix) |
|
2869 to \a codec. The codec is used for decoding any data that is read from |
|
2870 the INI file, and for encoding any data that is written to the file. By |
|
2871 default, no codec is used, and non-ASCII characters are encoded using |
|
2872 standard INI escape sequences. |
|
2873 |
|
2874 \warning The codec must be set immediately after creating the QSettings |
|
2875 object, before accessing any data. |
|
2876 |
|
2877 \sa iniCodec() |
|
2878 */ |
|
2879 void QSettings::setIniCodec(QTextCodec *codec) |
|
2880 { |
|
2881 Q_D(QSettings); |
|
2882 d->iniCodec = codec; |
|
2883 } |
|
2884 |
|
2885 /*! |
|
2886 \since 4.5 |
|
2887 \overload |
|
2888 |
|
2889 Sets the codec for accessing INI files (including \c .conf files on Unix) |
|
2890 to the QTextCodec for the encoding specified by \a codecName. Common |
|
2891 values for \c codecName include "ISO 8859-1", "UTF-8", and "UTF-16". |
|
2892 If the encoding isn't recognized, nothing happens. |
|
2893 |
|
2894 \sa QTextCodec::codecForName() |
|
2895 */ |
|
2896 void QSettings::setIniCodec(const char *codecName) |
|
2897 { |
|
2898 Q_D(QSettings); |
|
2899 if (QTextCodec *codec = QTextCodec::codecForName(codecName)) |
|
2900 d->iniCodec = codec; |
|
2901 } |
|
2902 |
|
2903 /*! |
|
2904 \since 4.5 |
|
2905 |
|
2906 Returns the codec that is used for accessing INI files. By default, |
|
2907 no codec is used, so a null pointer is returned. |
|
2908 */ |
|
2909 |
|
2910 QTextCodec *QSettings::iniCodec() const |
|
2911 { |
|
2912 Q_D(const QSettings); |
|
2913 return d->iniCodec; |
|
2914 } |
|
2915 |
|
2916 #endif // QT_NO_TEXTCODEC |
|
2917 |
|
2918 /*! |
|
2919 Returns a status code indicating the first error that was met by |
|
2920 QSettings, or QSettings::NoError if no error occurred. |
|
2921 |
|
2922 Be aware that QSettings delays performing some operations. For this |
|
2923 reason, you might want to call sync() to ensure that the data stored |
|
2924 in QSettings is written to disk before calling status(). |
|
2925 |
|
2926 \sa sync() |
|
2927 */ |
|
2928 QSettings::Status QSettings::status() const |
|
2929 { |
|
2930 Q_D(const QSettings); |
|
2931 return d->status; |
|
2932 } |
|
2933 |
|
2934 /*! |
|
2935 Appends \a prefix to the current group. |
|
2936 |
|
2937 The current group is automatically prepended to all keys |
|
2938 specified to QSettings. In addition, query functions such as |
|
2939 childGroups(), childKeys(), and allKeys() are based on the group. |
|
2940 By default, no group is set. |
|
2941 |
|
2942 Groups are useful to avoid typing in the same setting paths over |
|
2943 and over. For example: |
|
2944 |
|
2945 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 13 |
|
2946 |
|
2947 This will set the value of three settings: |
|
2948 |
|
2949 \list |
|
2950 \o \c mainwindow/size |
|
2951 \o \c mainwindow/fullScreen |
|
2952 \o \c outputpanel/visible |
|
2953 \endlist |
|
2954 |
|
2955 Call endGroup() to reset the current group to what it was before |
|
2956 the corresponding beginGroup() call. Groups can be nested. |
|
2957 |
|
2958 \sa endGroup(), group() |
|
2959 */ |
|
2960 void QSettings::beginGroup(const QString &prefix) |
|
2961 { |
|
2962 Q_D(QSettings); |
|
2963 d->beginGroupOrArray(QSettingsGroup(d->normalizedKey(prefix))); |
|
2964 } |
|
2965 |
|
2966 /*! |
|
2967 Resets the group to what it was before the corresponding |
|
2968 beginGroup() call. |
|
2969 |
|
2970 Example: |
|
2971 |
|
2972 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 14 |
|
2973 |
|
2974 \sa beginGroup(), group() |
|
2975 */ |
|
2976 void QSettings::endGroup() |
|
2977 { |
|
2978 Q_D(QSettings); |
|
2979 if (d->groupStack.isEmpty()) { |
|
2980 qWarning("QSettings::endGroup: No matching beginGroup()"); |
|
2981 return; |
|
2982 } |
|
2983 |
|
2984 QSettingsGroup group = d->groupStack.pop(); |
|
2985 int len = group.toString().size(); |
|
2986 if (len > 0) |
|
2987 d->groupPrefix.truncate(d->groupPrefix.size() - (len + 1)); |
|
2988 |
|
2989 if (group.isArray()) |
|
2990 qWarning("QSettings::endGroup: Expected endArray() instead"); |
|
2991 } |
|
2992 |
|
2993 /*! |
|
2994 Returns the current group. |
|
2995 |
|
2996 \sa beginGroup(), endGroup() |
|
2997 */ |
|
2998 QString QSettings::group() const |
|
2999 { |
|
3000 Q_D(const QSettings); |
|
3001 return d->groupPrefix.left(d->groupPrefix.size() - 1); |
|
3002 } |
|
3003 |
|
3004 /*! |
|
3005 Adds \a prefix to the current group and starts reading from an |
|
3006 array. Returns the size of the array. |
|
3007 |
|
3008 Example: |
|
3009 |
|
3010 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 15 |
|
3011 |
|
3012 Use beginWriteArray() to write the array in the first place. |
|
3013 |
|
3014 \sa beginWriteArray(), endArray(), setArrayIndex() |
|
3015 */ |
|
3016 int QSettings::beginReadArray(const QString &prefix) |
|
3017 { |
|
3018 Q_D(QSettings); |
|
3019 d->beginGroupOrArray(QSettingsGroup(d->normalizedKey(prefix), false)); |
|
3020 return value(QLatin1String("size")).toInt(); |
|
3021 } |
|
3022 |
|
3023 /*! |
|
3024 Adds \a prefix to the current group and starts writing an array |
|
3025 of size \a size. If \a size is -1 (the default), it is automatically |
|
3026 determined based on the indexes of the entries written. |
|
3027 |
|
3028 If you have many occurrences of a certain set of keys, you can |
|
3029 use arrays to make your life easier. For example, let's suppose |
|
3030 that you want to save a variable-length list of user names and |
|
3031 passwords. You could then write: |
|
3032 |
|
3033 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 16 |
|
3034 |
|
3035 The generated keys will have the form |
|
3036 |
|
3037 \list |
|
3038 \o \c logins/size |
|
3039 \o \c logins/1/userName |
|
3040 \o \c logins/1/password |
|
3041 \o \c logins/2/userName |
|
3042 \o \c logins/2/password |
|
3043 \o \c logins/3/userName |
|
3044 \o \c logins/3/password |
|
3045 \o ... |
|
3046 \endlist |
|
3047 |
|
3048 To read back an array, use beginReadArray(). |
|
3049 |
|
3050 \sa beginReadArray(), endArray(), setArrayIndex() |
|
3051 */ |
|
3052 void QSettings::beginWriteArray(const QString &prefix, int size) |
|
3053 { |
|
3054 Q_D(QSettings); |
|
3055 d->beginGroupOrArray(QSettingsGroup(d->normalizedKey(prefix), size < 0)); |
|
3056 |
|
3057 if (size < 0) |
|
3058 remove(QLatin1String("size")); |
|
3059 else |
|
3060 setValue(QLatin1String("size"), size); |
|
3061 } |
|
3062 |
|
3063 /*! |
|
3064 Closes the array that was started using beginReadArray() or |
|
3065 beginWriteArray(). |
|
3066 |
|
3067 \sa beginReadArray(), beginWriteArray() |
|
3068 */ |
|
3069 void QSettings::endArray() |
|
3070 { |
|
3071 Q_D(QSettings); |
|
3072 if (d->groupStack.isEmpty()) { |
|
3073 qWarning("QSettings::endArray: No matching beginArray()"); |
|
3074 return; |
|
3075 } |
|
3076 |
|
3077 QSettingsGroup group = d->groupStack.top(); |
|
3078 int len = group.toString().size(); |
|
3079 d->groupStack.pop(); |
|
3080 if (len > 0) |
|
3081 d->groupPrefix.truncate(d->groupPrefix.size() - (len + 1)); |
|
3082 |
|
3083 if (group.arraySizeGuess() != -1) |
|
3084 setValue(group.name() + QLatin1String("/size"), group.arraySizeGuess()); |
|
3085 |
|
3086 if (!group.isArray()) |
|
3087 qWarning("QSettings::endArray: Expected endGroup() instead"); |
|
3088 } |
|
3089 |
|
3090 /*! |
|
3091 Sets the current array index to \a i. Calls to functions such as |
|
3092 setValue(), value(), remove(), and contains() will operate on the |
|
3093 array entry at that index. |
|
3094 |
|
3095 You must call beginReadArray() or beginWriteArray() before you |
|
3096 can call this function. |
|
3097 */ |
|
3098 void QSettings::setArrayIndex(int i) |
|
3099 { |
|
3100 Q_D(QSettings); |
|
3101 if (d->groupStack.isEmpty() || !d->groupStack.top().isArray()) { |
|
3102 qWarning("QSettings::setArrayIndex: Missing beginArray()"); |
|
3103 return; |
|
3104 } |
|
3105 |
|
3106 QSettingsGroup &top = d->groupStack.top(); |
|
3107 int len = top.toString().size(); |
|
3108 top.setArrayIndex(qMax(i, 0)); |
|
3109 d->groupPrefix.replace(d->groupPrefix.size() - len - 1, len, top.toString()); |
|
3110 } |
|
3111 |
|
3112 /*! |
|
3113 Returns a list of all keys, including subkeys, that can be read |
|
3114 using the QSettings object. |
|
3115 |
|
3116 Example: |
|
3117 |
|
3118 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 17 |
|
3119 |
|
3120 If a group is set using beginGroup(), only the keys in the group |
|
3121 are returned, without the group prefix: |
|
3122 |
|
3123 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 18 |
|
3124 |
|
3125 \sa childGroups(), childKeys() |
|
3126 */ |
|
3127 QStringList QSettings::allKeys() const |
|
3128 { |
|
3129 Q_D(const QSettings); |
|
3130 return d->children(d->groupPrefix, QSettingsPrivate::AllKeys); |
|
3131 } |
|
3132 |
|
3133 /*! |
|
3134 Returns a list of all top-level keys that can be read using the |
|
3135 QSettings object. |
|
3136 |
|
3137 Example: |
|
3138 |
|
3139 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 19 |
|
3140 |
|
3141 If a group is set using beginGroup(), the top-level keys in that |
|
3142 group are returned, without the group prefix: |
|
3143 |
|
3144 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 20 |
|
3145 |
|
3146 You can navigate through the entire setting hierarchy using |
|
3147 childKeys() and childGroups() recursively. |
|
3148 |
|
3149 \sa childGroups(), allKeys() |
|
3150 */ |
|
3151 QStringList QSettings::childKeys() const |
|
3152 { |
|
3153 Q_D(const QSettings); |
|
3154 return d->children(d->groupPrefix, QSettingsPrivate::ChildKeys); |
|
3155 } |
|
3156 |
|
3157 /*! |
|
3158 Returns a list of all key top-level groups that contain keys that |
|
3159 can be read using the QSettings object. |
|
3160 |
|
3161 Example: |
|
3162 |
|
3163 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 21 |
|
3164 |
|
3165 If a group is set using beginGroup(), the first-level keys in |
|
3166 that group are returned, without the group prefix. |
|
3167 |
|
3168 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 22 |
|
3169 |
|
3170 You can navigate through the entire setting hierarchy using |
|
3171 childKeys() and childGroups() recursively. |
|
3172 |
|
3173 \sa childKeys(), allKeys() |
|
3174 */ |
|
3175 QStringList QSettings::childGroups() const |
|
3176 { |
|
3177 Q_D(const QSettings); |
|
3178 return d->children(d->groupPrefix, QSettingsPrivate::ChildGroups); |
|
3179 } |
|
3180 |
|
3181 /*! |
|
3182 Returns true if settings can be written using this QSettings |
|
3183 object; returns false otherwise. |
|
3184 |
|
3185 One reason why isWritable() might return false is if |
|
3186 QSettings operates on a read-only file. |
|
3187 |
|
3188 \warning This function is not perfectly reliable, because the |
|
3189 file permissions can change at any time. |
|
3190 |
|
3191 \sa fileName(), status(), sync() |
|
3192 */ |
|
3193 bool QSettings::isWritable() const |
|
3194 { |
|
3195 Q_D(const QSettings); |
|
3196 return d->isWritable(); |
|
3197 } |
|
3198 |
|
3199 /*! |
|
3200 |
|
3201 Sets the value of setting \a key to \a value. If the \a key already |
|
3202 exists, the previous value is overwritten. |
|
3203 |
|
3204 Note that the Windows registry and INI files use case-insensitive |
|
3205 keys, whereas the Carbon Preferences API on Mac OS X uses |
|
3206 case-sensitive keys. To avoid portability problems, see the |
|
3207 \l{Section and Key Syntax} rules. |
|
3208 |
|
3209 Example: |
|
3210 |
|
3211 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 23 |
|
3212 |
|
3213 \sa value(), remove(), contains() |
|
3214 */ |
|
3215 void QSettings::setValue(const QString &key, const QVariant &value) |
|
3216 { |
|
3217 Q_D(QSettings); |
|
3218 QString k = d->actualKey(key); |
|
3219 d->set(k, value); |
|
3220 d->requestUpdate(); |
|
3221 } |
|
3222 |
|
3223 /*! |
|
3224 Removes the setting \a key and any sub-settings of \a key. |
|
3225 |
|
3226 Example: |
|
3227 |
|
3228 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 24 |
|
3229 |
|
3230 Be aware that if one of the fallback locations contains a setting |
|
3231 with the same key, that setting will be visible after calling |
|
3232 remove(). |
|
3233 |
|
3234 If \a key is an empty string, all keys in the current group() are |
|
3235 removed. For example: |
|
3236 |
|
3237 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 25 |
|
3238 |
|
3239 Note that the Windows registry and INI files use case-insensitive |
|
3240 keys, whereas the Carbon Preferences API on Mac OS X uses |
|
3241 case-sensitive keys. To avoid portability problems, see the |
|
3242 \l{Section and Key Syntax} rules. |
|
3243 |
|
3244 \sa setValue(), value(), contains() |
|
3245 */ |
|
3246 void QSettings::remove(const QString &key) |
|
3247 { |
|
3248 Q_D(QSettings); |
|
3249 /* |
|
3250 We cannot use actualKey(), because remove() supports empty |
|
3251 keys. The code is also tricky because of slash handling. |
|
3252 */ |
|
3253 QString theKey = d->normalizedKey(key); |
|
3254 if (theKey.isEmpty()) |
|
3255 theKey = group(); |
|
3256 else |
|
3257 theKey.prepend(d->groupPrefix); |
|
3258 |
|
3259 if (theKey.isEmpty()) { |
|
3260 d->clear(); |
|
3261 } else { |
|
3262 d->remove(theKey); |
|
3263 } |
|
3264 d->requestUpdate(); |
|
3265 } |
|
3266 |
|
3267 /*! |
|
3268 Returns true if there exists a setting called \a key; returns |
|
3269 false otherwise. |
|
3270 |
|
3271 If a group is set using beginGroup(), \a key is taken to be |
|
3272 relative to that group. |
|
3273 |
|
3274 Note that the Windows registry and INI files use case-insensitive |
|
3275 keys, whereas the Carbon Preferences API on Mac OS X uses |
|
3276 case-sensitive keys. To avoid portability problems, see the |
|
3277 \l{Section and Key Syntax} rules. |
|
3278 |
|
3279 \sa value(), setValue() |
|
3280 */ |
|
3281 bool QSettings::contains(const QString &key) const |
|
3282 { |
|
3283 Q_D(const QSettings); |
|
3284 QString k = d->actualKey(key); |
|
3285 return d->get(k, 0); |
|
3286 } |
|
3287 |
|
3288 /*! |
|
3289 Sets whether fallbacks are enabled to \a b. |
|
3290 |
|
3291 By default, fallbacks are enabled. |
|
3292 |
|
3293 \sa fallbacksEnabled() |
|
3294 */ |
|
3295 void QSettings::setFallbacksEnabled(bool b) |
|
3296 { |
|
3297 Q_D(QSettings); |
|
3298 d->fallbacks = !!b; |
|
3299 } |
|
3300 |
|
3301 /*! |
|
3302 Returns true if fallbacks are enabled; returns false otherwise. |
|
3303 |
|
3304 By default, fallbacks are enabled. |
|
3305 |
|
3306 \sa setFallbacksEnabled() |
|
3307 */ |
|
3308 bool QSettings::fallbacksEnabled() const |
|
3309 { |
|
3310 Q_D(const QSettings); |
|
3311 return d->fallbacks; |
|
3312 } |
|
3313 |
|
3314 #ifndef QT_NO_QOBJECT |
|
3315 /*! |
|
3316 \reimp |
|
3317 */ |
|
3318 bool QSettings::event(QEvent *event) |
|
3319 { |
|
3320 Q_D(QSettings); |
|
3321 if (event->type() == QEvent::UpdateRequest) { |
|
3322 d->update(); |
|
3323 return true; |
|
3324 } |
|
3325 return QObject::event(event); |
|
3326 } |
|
3327 #endif |
|
3328 |
|
3329 /*! |
|
3330 Returns the value for setting \a key. If the setting doesn't |
|
3331 exist, returns \a defaultValue. |
|
3332 |
|
3333 If no default value is specified, a default QVariant is |
|
3334 returned. |
|
3335 |
|
3336 Note that the Windows registry and INI files use case-insensitive |
|
3337 keys, whereas the Carbon Preferences API on Mac OS X uses |
|
3338 case-sensitive keys. To avoid portability problems, see the |
|
3339 \l{Section and Key Syntax} rules. |
|
3340 |
|
3341 Example: |
|
3342 |
|
3343 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 26 |
|
3344 |
|
3345 \sa setValue(), contains(), remove() |
|
3346 */ |
|
3347 QVariant QSettings::value(const QString &key, const QVariant &defaultValue) const |
|
3348 { |
|
3349 Q_D(const QSettings); |
|
3350 QVariant result = defaultValue; |
|
3351 QString k = d->actualKey(key); |
|
3352 d->get(k, &result); |
|
3353 return result; |
|
3354 } |
|
3355 |
|
3356 /*! |
|
3357 \since 4.4 |
|
3358 |
|
3359 Sets the default file format to the given \a format, which is used |
|
3360 for storing settings for the QSettings(QObject *) constructor. |
|
3361 |
|
3362 If no default format is set, QSettings::NativeFormat is used. See |
|
3363 the documentation for the QSettings constructor you are using to |
|
3364 see if that constructor will ignore this function. |
|
3365 |
|
3366 \sa format() |
|
3367 */ |
|
3368 void QSettings::setDefaultFormat(Format format) |
|
3369 { |
|
3370 globalDefaultFormat = format; |
|
3371 } |
|
3372 |
|
3373 /*! |
|
3374 \since 4.4 |
|
3375 |
|
3376 Returns default file format used for storing settings for the QSettings(QObject *) constructor. |
|
3377 If no default format is set, QSettings::NativeFormat is used. |
|
3378 |
|
3379 \sa format() |
|
3380 */ |
|
3381 QSettings::Format QSettings::defaultFormat() |
|
3382 { |
|
3383 return globalDefaultFormat; |
|
3384 } |
|
3385 |
|
3386 /*! |
|
3387 \obsolete |
|
3388 |
|
3389 Use setPath() instead. |
|
3390 |
|
3391 \oldcode |
|
3392 setSystemIniPath(path); |
|
3393 \newcode |
|
3394 setPath(QSettings::NativeFormat, QSettings::SystemScope, path); |
|
3395 setPath(QSettings::IniFormat, QSettings::SystemScope, path); |
|
3396 \endcode |
|
3397 */ |
|
3398 void QSettings::setSystemIniPath(const QString &dir) |
|
3399 { |
|
3400 setPath(IniFormat, SystemScope, dir); |
|
3401 #if !defined(Q_OS_WIN) && !defined(Q_OS_MAC) |
|
3402 setPath(NativeFormat, SystemScope, dir); |
|
3403 #endif |
|
3404 } |
|
3405 |
|
3406 /*! |
|
3407 \obsolete |
|
3408 |
|
3409 Use setPath() instead. |
|
3410 */ |
|
3411 |
|
3412 void QSettings::setUserIniPath(const QString &dir) |
|
3413 { |
|
3414 setPath(IniFormat, UserScope, dir); |
|
3415 #if !defined(Q_OS_WIN) && !defined(Q_OS_MAC) |
|
3416 setPath(NativeFormat, UserScope, dir); |
|
3417 #endif |
|
3418 } |
|
3419 |
|
3420 /*! |
|
3421 \since 4.1 |
|
3422 |
|
3423 Sets the path used for storing settings for the given \a format |
|
3424 and \a scope, to \a path. The \a format can be a custom format. |
|
3425 |
|
3426 The table below summarizes the default values: |
|
3427 |
|
3428 \table |
|
3429 \header \o Platform \o Format \o Scope \o Path |
|
3430 \row \o{1,2} Windows \o{1,2} IniFormat \o UserScope \o \c %APPDATA% |
|
3431 \row \o SystemScope \o \c %COMMON_APPDATA% |
|
3432 \row \o{1,2} Unix \o{1,2} NativeFormat, IniFormat \o UserScope \o \c $HOME/.config |
|
3433 \row \o SystemScope \o \c /etc/xdg |
|
3434 \row \o{1,2} Qt for Embedded Linux \o{1,2} NativeFormat, IniFormat \o UserScope \o \c $HOME/Settings |
|
3435 \row \o SystemScope \o \c /etc/xdg |
|
3436 \row \o{1,2} Mac OS X \o{1,2} IniFormat \o UserScope \o \c $HOME/.config |
|
3437 \row \o SystemScope \o \c /etc/xdg |
|
3438 \endtable |
|
3439 |
|
3440 The default UserScope paths on Unix and Mac OS X (\c |
|
3441 $HOME/.config or $HOME/Settings) can be overridden by the user by setting the |
|
3442 \c XDG_CONFIG_HOME environment variable. The default SystemScope |
|
3443 paths on Unix and Mac OS X (\c /etc/xdg) can be overridden when |
|
3444 building the Qt library using the \c configure script's \c |
|
3445 --sysconfdir flag (see QLibraryInfo for details). |
|
3446 |
|
3447 Setting the NativeFormat paths on Windows and Mac OS X has no |
|
3448 effect. |
|
3449 |
|
3450 \warning This function doesn't affect existing QSettings objects. |
|
3451 |
|
3452 \sa registerFormat() |
|
3453 */ |
|
3454 void QSettings::setPath(Format format, Scope scope, const QString &path) |
|
3455 { |
|
3456 QMutexLocker locker(globalMutex()); |
|
3457 PathHash *pathHash = pathHashFunc(); |
|
3458 pathHash->insert(pathHashKey(format, scope), path + QDir::separator()); |
|
3459 } |
|
3460 |
|
3461 /*! |
|
3462 \typedef QSettings::SettingsMap |
|
3463 |
|
3464 Typedef for QMap<QString, QVariant>. |
|
3465 |
|
3466 \sa registerFormat() |
|
3467 */ |
|
3468 |
|
3469 /*! |
|
3470 \typedef QSettings::ReadFunc |
|
3471 |
|
3472 Typedef for a pointer to a function with the following signature: |
|
3473 |
|
3474 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 27 |
|
3475 |
|
3476 \c ReadFunc is used in \c registerFormat() as a pointer to a function |
|
3477 that reads a set of key/value pairs. \c ReadFunc should read all the |
|
3478 options in one pass, and return all the settings in the \c SettingsMap |
|
3479 container, which is initially empty. |
|
3480 |
|
3481 \sa WriteFunc, registerFormat() |
|
3482 */ |
|
3483 |
|
3484 /*! |
|
3485 \typedef QSettings::WriteFunc |
|
3486 |
|
3487 Typedef for a pointer to a function with the following signature: |
|
3488 |
|
3489 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 28 |
|
3490 |
|
3491 \c WriteFunc is used in \c registerFormat() as a pointer to a function |
|
3492 that writes a set of key/value pairs. \c WriteFunc is only called once, |
|
3493 so you need to output the settings in one go. |
|
3494 |
|
3495 \sa ReadFunc, registerFormat() |
|
3496 */ |
|
3497 |
|
3498 /*! |
|
3499 \since 4.1 |
|
3500 \threadsafe |
|
3501 |
|
3502 Registers a custom storage format. On success, returns a special |
|
3503 Format value that can then be passed to the QSettings constuctor. |
|
3504 On failure, returns InvalidFormat. |
|
3505 |
|
3506 The \a extension is the file |
|
3507 extension associated to the format (without the '.'). |
|
3508 |
|
3509 The \a readFunc and \a writeFunc parameters are pointers to |
|
3510 functions that read and write a set of key/value pairs. The |
|
3511 QIODevice parameter to the read and write functions is always |
|
3512 opened in binary mode (i.e., without the QIODevice::Text flag). |
|
3513 |
|
3514 The \a caseSensitivity parameter specifies whether keys are case |
|
3515 sensitive or not. This makes a difference when looking up values |
|
3516 using QSettings. The default is case sensitive. |
|
3517 |
|
3518 By default, if you use one of the constructors that work in terms |
|
3519 of an organization name and an application name, the file system |
|
3520 locations used are the same as for IniFormat. Use setPath() to |
|
3521 specify other locations. |
|
3522 |
|
3523 Example: |
|
3524 |
|
3525 \snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 29 |
|
3526 |
|
3527 \sa setPath() |
|
3528 */ |
|
3529 QSettings::Format QSettings::registerFormat(const QString &extension, ReadFunc readFunc, |
|
3530 WriteFunc writeFunc, |
|
3531 Qt::CaseSensitivity caseSensitivity) |
|
3532 { |
|
3533 #ifdef QT_QSETTINGS_ALWAYS_CASE_SENSITIVE_AND_FORGET_ORIGINAL_KEY_ORDER |
|
3534 Q_ASSERT(caseSensitivity == Qt::CaseSensitive); |
|
3535 #endif |
|
3536 |
|
3537 QMutexLocker locker(globalMutex()); |
|
3538 CustomFormatVector *customFormatVector = customFormatVectorFunc(); |
|
3539 int index = customFormatVector->size(); |
|
3540 if (index == 16) // the QSettings::Format enum has room for 16 custom formats |
|
3541 return QSettings::InvalidFormat; |
|
3542 |
|
3543 QConfFileCustomFormat info; |
|
3544 info.extension = QLatin1Char('.'); |
|
3545 info.extension += extension; |
|
3546 info.readFunc = readFunc; |
|
3547 info.writeFunc = writeFunc; |
|
3548 info.caseSensitivity = caseSensitivity; |
|
3549 customFormatVector->append(info); |
|
3550 |
|
3551 return QSettings::Format((int)QSettings::CustomFormat1 + index); |
|
3552 } |
|
3553 |
|
3554 #ifdef QT3_SUPPORT |
|
3555 void QSettings::setPath_helper(Scope scope, const QString &organization, const QString &application) |
|
3556 { |
|
3557 Q_D(QSettings); |
|
3558 if (d->pendingChanges) |
|
3559 d->flush(); |
|
3560 QSettingsPrivate *oldPriv = d; |
|
3561 QSettingsPrivate *newPriv = QSettingsPrivate::create(oldPriv->format, scope, organization, application); |
|
3562 static_cast<QObjectPrivate &>(*newPriv) = static_cast<QObjectPrivate &>(*oldPriv); // copy the QObject stuff over (hack) |
|
3563 d_ptr.reset(newPriv); |
|
3564 } |
|
3565 |
|
3566 /*! \fn bool QSettings::writeEntry(const QString &key, bool value) |
|
3567 |
|
3568 Sets the value of setting \a key to \a value. |
|
3569 |
|
3570 Use setValue() instead. |
|
3571 */ |
|
3572 |
|
3573 /*! \fn bool QSettings::writeEntry(const QString &key, double value) |
|
3574 |
|
3575 \overload |
|
3576 */ |
|
3577 |
|
3578 /*! \fn bool QSettings::writeEntry(const QString &key, int value) |
|
3579 |
|
3580 \overload |
|
3581 */ |
|
3582 |
|
3583 /*! \fn bool QSettings::writeEntry(const QString &key, const char *value) |
|
3584 |
|
3585 \overload |
|
3586 */ |
|
3587 |
|
3588 /*! \fn bool QSettings::writeEntry(const QString &key, const QString &value) |
|
3589 |
|
3590 \overload |
|
3591 */ |
|
3592 |
|
3593 /*! \fn bool QSettings::writeEntry(const QString &key, const QStringList &value) |
|
3594 |
|
3595 \overload |
|
3596 */ |
|
3597 |
|
3598 /*! \fn bool QSettings::writeEntry(const QString &key, const QStringList &value, QChar separator) |
|
3599 |
|
3600 \overload |
|
3601 |
|
3602 Use setValue(\a key, \a value) instead. You don't need \a separator. |
|
3603 */ |
|
3604 |
|
3605 /*! \fn QStringList QSettings::readListEntry(const QString &key, bool *ok = 0) |
|
3606 |
|
3607 Returns the value of setting \a key converted to a QStringList. |
|
3608 |
|
3609 If \a ok is not 0, *\a{ok} is set to true if the key exists, |
|
3610 otherwise *\a{ok} is set to false. |
|
3611 |
|
3612 Use value() instead. |
|
3613 |
|
3614 \oldcode |
|
3615 bool ok; |
|
3616 QStringList list = settings.readListEntry("recentFiles", &ok); |
|
3617 \newcode |
|
3618 bool ok = settings.contains("recentFiles"); |
|
3619 QStringList list = settings.value("recentFiles").toStringList(); |
|
3620 \endcode |
|
3621 */ |
|
3622 |
|
3623 /*! \fn QStringList QSettings::readListEntry(const QString &key, QChar separator, bool *ok) |
|
3624 |
|
3625 Returns the value of setting \a key converted to a QStringList. |
|
3626 \a separator is ignored. |
|
3627 |
|
3628 If \a ok is not 0, *\a{ok} is set to true if the key exists, |
|
3629 otherwise *\a{ok} is set to false. |
|
3630 |
|
3631 Use value() instead. |
|
3632 |
|
3633 \oldcode |
|
3634 bool ok; |
|
3635 QStringList list = settings.readListEntry("recentFiles", ":", &ok); |
|
3636 \newcode |
|
3637 bool ok = settings.contains("recentFiles"); |
|
3638 QStringList list = settings.value("recentFiles").toStringList(); |
|
3639 \endcode |
|
3640 */ |
|
3641 |
|
3642 /*! \fn QString QSettings::readEntry(const QString &key, const QString &defaultValue, bool *ok) |
|
3643 |
|
3644 Returns the value for setting \a key converted to a QString. If |
|
3645 the setting doesn't exist, returns \a defaultValue. |
|
3646 |
|
3647 If \a ok is not 0, *\a{ok} is set to true if the key exists, |
|
3648 otherwise *\a{ok} is set to false. |
|
3649 |
|
3650 Use value() instead. |
|
3651 |
|
3652 \oldcode |
|
3653 bool ok; |
|
3654 QString str = settings.readEntry("userName", "administrator", &ok); |
|
3655 \newcode |
|
3656 bool ok = settings.contains("userName"); |
|
3657 QString str = settings.value("userName", "administrator").toString(); |
|
3658 \endcode |
|
3659 */ |
|
3660 |
|
3661 /*! \fn int QSettings::readNumEntry(const QString &key, int defaultValue, bool *ok) |
|
3662 |
|
3663 Returns the value for setting \a key converted to an \c int. If |
|
3664 the setting doesn't exist, returns \a defaultValue. |
|
3665 |
|
3666 If \a ok is not 0, *\a{ok} is set to true if the key exists, |
|
3667 otherwise *\a{ok} is set to false. |
|
3668 |
|
3669 Use value() instead. |
|
3670 |
|
3671 \oldcode |
|
3672 bool ok; |
|
3673 int max = settings.readNumEntry("maxConnections", 30, &ok); |
|
3674 \newcode |
|
3675 bool ok = settings.contains("maxConnections"); |
|
3676 int max = settings.value("maxConnections", 30).toInt(); |
|
3677 \endcode |
|
3678 */ |
|
3679 |
|
3680 /*! \fn double QSettings::readDoubleEntry(const QString &key, double defaultValue, bool *ok) |
|
3681 |
|
3682 Returns the value for setting \a key converted to a \c double. If |
|
3683 the setting doesn't exist, returns \a defaultValue. |
|
3684 |
|
3685 If \a ok is not 0, *\a{ok} is set to true if the key exists, |
|
3686 otherwise *\a{ok} is set to false. |
|
3687 |
|
3688 Use value() instead. |
|
3689 |
|
3690 \oldcode |
|
3691 bool ok; |
|
3692 double pi = settings.readDoubleEntry("pi", 3.141592, &ok); |
|
3693 \newcode |
|
3694 bool ok = settings.contains("pi"); |
|
3695 double pi = settings.value("pi", 3.141592).toDouble(); |
|
3696 \endcode |
|
3697 */ |
|
3698 |
|
3699 /*! \fn bool QSettings::readBoolEntry(const QString &key, bool defaultValue, bool *ok) |
|
3700 |
|
3701 Returns the value for setting \a key converted to a \c bool. If |
|
3702 the setting doesn't exist, returns \a defaultValue. |
|
3703 |
|
3704 If \a ok is not 0, *\a{ok} is set to true if the key exists, |
|
3705 otherwise *\a{ok} is set to false. |
|
3706 |
|
3707 Use value() instead. |
|
3708 |
|
3709 \oldcode |
|
3710 bool ok; |
|
3711 bool grid = settings.readBoolEntry("showGrid", true, &ok); |
|
3712 \newcode |
|
3713 bool ok = settings.contains("showGrid"); |
|
3714 bool grid = settings.value("showGrid", true).toBool(); |
|
3715 \endcode |
|
3716 */ |
|
3717 |
|
3718 /*! \fn bool QSettings::removeEntry(const QString &key) |
|
3719 |
|
3720 Use remove() instead. |
|
3721 */ |
|
3722 |
|
3723 /*! \enum QSettings::System |
|
3724 \compat |
|
3725 |
|
3726 \value Unix Unix systems (X11 and Embedded Linux) |
|
3727 \value Windows Microsoft Windows systems |
|
3728 \value Mac Mac OS X systems |
|
3729 |
|
3730 \sa insertSearchPath(), removeSearchPath() |
|
3731 */ |
|
3732 |
|
3733 /*! \fn void QSettings::insertSearchPath(System system, const QString &path) |
|
3734 |
|
3735 This function is implemented as a no-op. It is provided for |
|
3736 source compatibility with Qt 3. The new QSettings class has no |
|
3737 concept of "search path". |
|
3738 */ |
|
3739 |
|
3740 /*! \fn void QSettings::removeSearchPath(System system, const QString &path) |
|
3741 |
|
3742 This function is implemented as a no-op. It is provided for |
|
3743 source compatibility with Qt 3. The new QSettings class has no |
|
3744 concept of "search path". |
|
3745 */ |
|
3746 |
|
3747 /*! \fn void QSettings::setPath(const QString &organization, const QString &application, \ |
|
3748 Scope scope) |
|
3749 |
|
3750 Specifies the \a organization, \a application, and \a scope to |
|
3751 use by the QSettings object. |
|
3752 |
|
3753 Use the appropriate constructor instead, with QSettings::UserScope |
|
3754 instead of QSettings::User and QSettings::SystemScope instead of |
|
3755 QSettings::Global. |
|
3756 |
|
3757 \oldcode |
|
3758 QSettings settings; |
|
3759 settings.setPath("twikimaster.com", "Kanooth", QSettings::Global); |
|
3760 \newcode |
|
3761 QSettings settings(QSettings::SystemScope, "twikimaster.com", "Kanooth"); |
|
3762 \endcode |
|
3763 */ |
|
3764 |
|
3765 /*! \fn void QSettings::resetGroup() |
|
3766 |
|
3767 Sets the current group to be the empty string. |
|
3768 |
|
3769 Use endGroup() instead (possibly multiple times). |
|
3770 |
|
3771 \oldcode |
|
3772 QSettings settings; |
|
3773 settings.beginGroup("mainWindow"); |
|
3774 settings.beginGroup("leftPanel"); |
|
3775 ... |
|
3776 settings.resetGroup(); |
|
3777 \newcode |
|
3778 QSettings settings; |
|
3779 settings.beginGroup("mainWindow"); |
|
3780 settings.beginGroup("leftPanel"); |
|
3781 ... |
|
3782 settings.endGroup(); |
|
3783 settings.endGroup(); |
|
3784 \endcode |
|
3785 */ |
|
3786 |
|
3787 /*! \fn QStringList QSettings::entryList(const QString &key) const |
|
3788 |
|
3789 Returns a list of all sub-keys of \a key. |
|
3790 |
|
3791 Use childKeys() instead. |
|
3792 |
|
3793 \oldcode |
|
3794 QSettings settings; |
|
3795 QStringList keys = settings.entryList("cities"); |
|
3796 ... |
|
3797 \newcode |
|
3798 QSettings settings; |
|
3799 settings.beginGroup("cities"); |
|
3800 QStringList keys = settings.childKeys(); |
|
3801 ... |
|
3802 settings.endGroup(); |
|
3803 \endcode |
|
3804 */ |
|
3805 |
|
3806 /*! \fn QStringList QSettings::subkeyList(const QString &key) const |
|
3807 |
|
3808 Returns a list of all sub-keys of \a key. |
|
3809 |
|
3810 Use childGroups() instead. |
|
3811 |
|
3812 \oldcode |
|
3813 QSettings settings; |
|
3814 QStringList groups = settings.entryList("cities"); |
|
3815 ... |
|
3816 \newcode |
|
3817 QSettings settings; |
|
3818 settings.beginGroup("cities"); |
|
3819 QStringList groups = settings.childKeys(); |
|
3820 ... |
|
3821 settings.endGroup(); |
|
3822 \endcode |
|
3823 */ |
|
3824 #endif |
|
3825 |
|
3826 QT_END_NAMESPACE |
|
3827 |
|
3828 #endif // QT_NO_SETTINGS |