1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include "qsettings.h"
41
42 #include "qsettings_p.h"
43 #include "qvector.h"
44 #include "qmap.h"
45 #include "qdebug.h"
46 #include "qfunctions_winrt.h"
47
48 #include <wrl.h>
49 #include <wrl/event.h>
50 #include <Windows.ApplicationModel.h>
51 #include <windows.storage.h>
52
53 using namespace ABI::Windows::ApplicationModel;
54 using namespace ABI::Windows::Storage;
55 using namespace ABI::Windows::Foundation;
56 using namespace ABI::Windows::Foundation::Collections;
57 using namespace Microsoft::WRL;
58 using namespace Microsoft::WRL::Wrappers;
59
60 typedef ITypedEventHandler<ApplicationData*, IInspectable*> DataHandler;
61 typedef Collections::IKeyValuePair<HSTRING, ApplicationDataContainer*> ContainerItem;
62 typedef Collections::IIterable<ContainerItem*> ContainerIterable;
63 typedef Collections::IIterator<ContainerItem*> ContainerIterator;
64
65 typedef Collections::IKeyValuePair<HSTRING, IInspectable*> ValueItem;
66 typedef Collections::IIterable<ValueItem*> ValueIterable;
67 typedef Collections::IIterator<ValueItem*> ValueIterator;
68
69 QT_BEGIN_NAMESPACE
70
subContainer(IApplicationDataContainer * parent,const QString & name)71 static IApplicationDataContainer *subContainer(IApplicationDataContainer *parent, const QString &name)
72 {
73 ComPtr<IMapView<HSTRING, ApplicationDataContainer*>> childrenContainer;
74 HRESULT hr = parent->get_Containers(&childrenContainer);
75 if (FAILED(hr))
76 return 0;
77
78 ComPtr< ContainerIterable > iterable;
79 ComPtr< ContainerIterator > iterator;
80
81 hr = childrenContainer.As(&iterable);
82 if (FAILED(hr))
83 return 0;
84
85 hr = iterable->First(&iterator);
86 if (FAILED(hr))
87 return 0;
88 boolean current;
89 hr = iterator->get_HasCurrent(¤t);
90 if (FAILED(hr))
91 return 0;
92
93 while (SUCCEEDED(hr) && current) {
94 ComPtr<ContainerItem> item;
95 hr = iterator->get_Current(&item);
96 if (FAILED(hr))
97 return 0;
98
99 HString key;
100 hr = item->get_Key(key.GetAddressOf());
101 if (FAILED(hr))
102 continue;
103 QString subName = QString::fromWCharArray(key.GetRawBuffer(nullptr));
104 if (name == subName) {
105 IApplicationDataContainer *container;
106 hr = item->get_Value(&container);
107 return SUCCEEDED(hr) ? container : 0;
108 }
109 hr = iterator->MoveNext(¤t);
110 }
111
112 return 0;
113 }
114
subContainerNames(IApplicationDataContainer * container,bool recursive=false)115 static QStringList subContainerNames(IApplicationDataContainer *container, bool recursive = false)
116 {
117 QStringList result;
118 ComPtr<IMapView<HSTRING, ApplicationDataContainer*>> childrenContainer;
119 HRESULT hr = container->get_Containers(&childrenContainer);
120 if (FAILED(hr))
121 return result;
122
123 ComPtr< ContainerIterable > iterable;
124 ComPtr< ContainerIterator > iterator;
125
126 hr = childrenContainer.As(&iterable);
127 if (FAILED(hr))
128 return result;
129
130 hr = iterable->First(&iterator);
131 if (FAILED(hr))
132 return result;
133 boolean current;
134 hr = iterator->get_HasCurrent(¤t);
135 if (FAILED(hr))
136 return result;
137
138 while (SUCCEEDED(hr) && current) {
139 ComPtr<ContainerItem> item;
140 hr = iterator->get_Current(&item);
141 if (FAILED(hr))
142 return result;
143
144 HString key;
145 hr = item->get_Key(key.GetAddressOf());
146 if (SUCCEEDED(hr)) {
147 QString subName = QString::fromWCharArray(key.GetRawBuffer(nullptr));
148 result.append(subName);
149 if (recursive) {
150 ComPtr<IApplicationDataContainer> sub = subContainer(container, subName);
151 QStringList subSubNames = subContainerNames(sub.Get(), recursive);
152 for (int i = 0; i < subSubNames.size(); ++i)
153 subSubNames[i] = subName + QLatin1Char('/') + subSubNames[i];
154 result.append(subSubNames);
155 }
156 hr = iterator->MoveNext(¤t);
157 }
158 }
159 return result;
160 }
161
keyNames(IApplicationDataContainer * container)162 static QStringList keyNames(IApplicationDataContainer *container) {
163 HRESULT hr;
164 QStringList result;
165 ComPtr<IPropertySet> values;
166 hr = container->get_Values(&values);
167 if (FAILED(hr))
168 return result;
169
170 ComPtr<IMap<HSTRING, IInspectable*>> settingsMap;
171
172 hr = values.As(&settingsMap);
173 if (FAILED(hr))
174 return result;
175
176 ComPtr<IMapView<HSTRING, IInspectable*>> mapView;
177 hr = settingsMap->GetView(&mapView);
178 if (FAILED(hr))
179 return result;
180
181 ComPtr< ValueIterable > iterable;
182 ComPtr< ValueIterator > iterator;
183
184 hr = mapView.As(&iterable);
185 if (FAILED(hr))
186 return result;
187
188 boolean current = false;
189 hr = iterable->First(&iterator);
190 if (FAILED(hr))
191 return result;
192 hr = iterator->get_HasCurrent(¤t);
193 if (FAILED(hr))
194 return result;
195
196 while (SUCCEEDED(hr) && current){
197 ComPtr<ValueItem> item;
198 hr = iterator->get_Current(&item);
199 if (FAILED(hr))
200 return result;
201
202 HString key;
203 hr = item->get_Key(key.GetAddressOf());
204 if (SUCCEEDED(hr)) {
205 result += QString::fromWCharArray(key.GetRawBuffer(nullptr));
206 hr = iterator->MoveNext(¤t);
207 }
208 }
209 return result;
210 }
211
createSubContainer(IApplicationDataContainer * parent,const QString & name)212 static IApplicationDataContainer *createSubContainer(IApplicationDataContainer *parent, const QString &name)
213 {
214 HStringReference childGroupNativeName((const wchar_t*)name.utf16(), name.size());
215
216 IApplicationDataContainer *result = subContainer(parent, name);
217 if (!result)
218 parent->CreateContainer(childGroupNativeName.Get(), ApplicationDataCreateDisposition_Always, &result);
219 return result;
220 }
221
222 #define PROP_CASE_TO_VARIANT(TYPE, VARTYPE, QTYPE) \
223 case PropertyType_##TYPE: { \
224 VARTYPE v; \
225 value->Get##TYPE(&v); \
226 result.setValue( QTYPE(v) ); \
227 break; \
228 }
229
propertyValueToQVariant(IPropertyValue * value)230 static QVariant propertyValueToQVariant(IPropertyValue *value)
231 {
232 QVariant result;
233 PropertyType type;
234 value->get_Type(&type);
235 switch (type) {
236 PROP_CASE_TO_VARIANT(Boolean, boolean, bool)
237 PROP_CASE_TO_VARIANT(UInt8, UINT8, quint8)
238 PROP_CASE_TO_VARIANT(Int16, INT16, qint16)
239 PROP_CASE_TO_VARIANT(UInt16, UINT16, quint16)
240 PROP_CASE_TO_VARIANT(Int32, INT32, qint32)
241 PROP_CASE_TO_VARIANT(UInt32, UINT32, quint32)
242 PROP_CASE_TO_VARIANT(Int64, INT64, qint64)
243 PROP_CASE_TO_VARIANT(UInt64, UINT64, quint64)
244 PROP_CASE_TO_VARIANT(Single, FLOAT, float)
245 PROP_CASE_TO_VARIANT(Double, DOUBLE, double)
246 case PropertyType_StringArray: {
247 UINT32 size;
248 HSTRING *content;
249 value->GetStringArray(&size, &content);
250 QStringList list;
251 // The last item is assumed to be added by us
252 for (UINT32 i = 0; i < size - 1; ++i) {
253 QString s = QString::fromWCharArray(WindowsGetStringRawBuffer(content[i], nullptr));
254 list.append(s);
255 }
256 result = QSettingsPrivate::stringListToVariantList(list);
257 break;
258 }
259 case PropertyType_String: {
260 HString v;
261 value->GetString(v.GetAddressOf());
262 result = QSettingsPrivate::stringToVariant(QString::fromWCharArray(v.GetRawBuffer(nullptr)));
263 break;
264 }
265 default: {
266 UINT32 size;
267 BYTE *arr;
268 value->GetUInt8Array(&size, &arr);
269 QByteArray data = QByteArray::fromRawData((const char*)arr, size);
270 QString s;
271 if (size) {
272 // We assume this is our qt stored data like on other platforms
273 // as well. QList and others are converted to byte arrays
274 s = QString::fromWCharArray((const wchar_t *)data.constData(), data.size() / 2);
275 result = QSettingsPrivate::stringToVariant(s);
276 }
277 break;
278 }
279 }
280 return result;
281 }
282
283 class QWinRTSettingsPrivate : public QSettingsPrivate
284 {
285 public:
286 QWinRTSettingsPrivate(QSettings::Scope scope, const QString &organization,
287 const QString &application);
288 QWinRTSettingsPrivate(const QString &rKey);
289 ~QWinRTSettingsPrivate();
290
291 void remove(const QString &uKey) override;
292 void set(const QString &uKey, const QVariant &value) override;
293 bool get(const QString &uKey, QVariant *value) const override;
294 QStringList children(const QString &uKey, ChildSpec spec) const override;
295 void clear() override;
296 void sync() override;
297 void flush() override;
298 bool isWritable() const override;
299 QString fileName() const override;
300
301 private:
302 void init(QSettings::Scope scope);
303 IApplicationDataContainer *getContainer(IApplicationDataContainer *parent, const QString &group, bool create = false) const;
304 void clearContainerMaps();
305
306 HRESULT onDataChanged(IApplicationData*, IInspectable*);
307
308 ComPtr<IApplicationData> applicationData;
309 QVector<ComPtr<IApplicationDataContainer>> readContainers;
310 ComPtr<IApplicationDataContainer> writeContainer;
311 EventRegistrationToken dataChangedToken;
312 };
313
QWinRTSettingsPrivate(QSettings::Scope scope,const QString & organization,const QString & application)314 QWinRTSettingsPrivate::QWinRTSettingsPrivate(QSettings::Scope scope, const QString &organization,
315 const QString &application)
316 : QSettingsPrivate(QSettings::NativeFormat, scope, organization, application)
317 , writeContainer(0)
318 {
319 init(scope);
320 }
321
QWinRTSettingsPrivate(const QString & rPath)322 QWinRTSettingsPrivate::QWinRTSettingsPrivate(const QString &rPath)
323 : QSettingsPrivate(QSettings::NativeFormat, QSettings::UserScope, rPath, QString())
324 , writeContainer(0)
325 {
326 init(QSettings::UserScope);
327 }
328
~QWinRTSettingsPrivate()329 QWinRTSettingsPrivate::~QWinRTSettingsPrivate()
330 {
331 clearContainerMaps();
332 }
333
remove(const QString & uKey)334 void QWinRTSettingsPrivate::remove(const QString &uKey)
335 {
336 int lastIndex = uKey.lastIndexOf(QLatin1Char('/'));
337 QString groupName = (lastIndex > 0) ? uKey.left(lastIndex) : QString();
338 QString groupKey = uKey.mid(lastIndex + 1);
339
340 ComPtr<IApplicationDataContainer> container = getContainer(writeContainer.Get(), groupName, false);
341 if (!container)
342 return;
343
344 HRESULT hr;
345 ComPtr<IPropertySet> values;
346 hr = container->get_Values(&values);
347 if (FAILED(hr))
348 return;
349
350 ComPtr<IMap<HSTRING, IInspectable*>> settingsMap;
351
352 hr = values.As(&settingsMap);
353 if (FAILED(hr))
354 return;
355
356 HStringReference ref((const wchar_t*)groupKey.utf16(), groupKey.size());
357 hr = settingsMap->Remove(ref.Get());
358
359 // groupKey can be a container as well
360 hr = container->DeleteContainer(ref.Get());
361 init(scope);
362 }
363
set(const QString & uKey,const QVariant & value)364 void QWinRTSettingsPrivate::set(const QString &uKey, const QVariant &value)
365 {
366 int lastIndex = uKey.lastIndexOf(QLatin1Char('/'));
367 QString groupName = (lastIndex > 0) ? uKey.left(lastIndex) : QString();
368 QString groupKey = uKey.mid(lastIndex + 1);
369
370 ComPtr<IApplicationDataContainer> container = getContainer(writeContainer.Get(), groupName, true);
371
372 ComPtr<IPropertySet> values;
373 HRESULT hr = container->get_Values(&values);
374 if (FAILED(hr)) {
375 qErrnoWarning(hr, "Could not access Windows container values");
376 setStatus(QSettings::AccessError);
377 return;
378 }
379
380 ComPtr<IMap<HSTRING, IInspectable*>> settingsMap;
381 hr = values.As(&settingsMap);
382 if (FAILED(hr)) {
383 setStatus(QSettings::AccessError);
384 return;
385 }
386
387 ComPtr<IPropertyValueStatics> valueStatics;
388 hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Foundation_PropertyValue).Get(), &valueStatics);
389 if (FAILED(hr)) {
390 setStatus(QSettings::AccessError);
391 return;
392 }
393
394 ComPtr<IInspectable> val;
395
396 switch (value.type()) {
397 case QVariant::List:
398 case QVariant::StringList: {
399 QStringList l = variantListToStringList(value.toList());
400 QStringList::const_iterator it = l.constBegin();
401 bool containsNull = false;
402 for (; it != l.constEnd(); ++it) {
403 if ((*it).length() == 0 || it->contains(QChar::Null)) {
404 // We can only store as binary
405 containsNull = true;
406 break;
407 }
408 }
409
410 if (containsNull) {
411 // Store binary
412 const QString s = variantToString(value);
413 hr = valueStatics->CreateUInt8Array(s.length() * 2, (BYTE*) s.utf16(), &val);
414 } else {
415 // Store as native string list
416 int size = l.size();
417 HSTRING *nativeHandleList = new HSTRING[size+1];
418 for (int i = 0; i < size; ++i)
419 hr = WindowsCreateString((const wchar_t*)l[i].utf16(), l[i].size(), &nativeHandleList[i]);
420 // Add end marker
421 hr = WindowsCreateString((const wchar_t*)L"\0\0@", 3, &nativeHandleList[size]);
422 hr = valueStatics->CreateStringArray(size + 1 , nativeHandleList, &val);
423 for (int i = 0; i < size; ++i)
424 hr = WindowsDeleteString(nativeHandleList[i]);
425 delete [] nativeHandleList;
426 }
427 break;
428 }
429 case QVariant::Bool:
430 hr = valueStatics->CreateBoolean(boolean(value.toBool()), &val);
431 break;
432 case QVariant::Int:
433 hr = valueStatics->CreateInt32(INT32(value.toInt()), &val);
434 break;
435 case QVariant::UInt:
436 hr = valueStatics->CreateUInt32(UINT32(value.toUInt()), &val);
437 break;
438 case QVariant::LongLong:
439 hr = valueStatics->CreateInt64(INT64(value.toLongLong()), &val);
440 break;
441 case QVariant::ULongLong:
442 hr = valueStatics->CreateUInt64(UINT64(value.toULongLong()), &val);
443 break;
444 default: {
445 const QString s = variantToString(value);
446 if (s.contains(QChar::Null)) {
447 hr = valueStatics->CreateUInt8Array(s.length() * 2, (BYTE*) s.utf16(), &val);
448 } else {
449 HStringReference ref((const wchar_t*)s.utf16(), s.size());
450 hr = valueStatics->CreateString(ref.Get(), &val);
451 }
452
453 break;
454 }
455 }
456
457 RETURN_VOID_IF_FAILED("QSettings: Could not save QVariant value into IInspectable");
458
459 HStringReference key((const wchar_t*)groupKey.utf16(), groupKey.size());
460 boolean rep;
461
462 hr = settingsMap->Insert(key.Get(), val.Get(), &rep);
463 RETURN_VOID_IF_FAILED("QSettings: Could not store value");
464 }
465
get(const QString & uKey,QVariant * value) const466 bool QWinRTSettingsPrivate::get(const QString &uKey, QVariant *value) const
467 {
468 int lastIndex = uKey.lastIndexOf(QLatin1Char('/'));
469 QString groupName = (lastIndex > 0) ? uKey.left(lastIndex) : QString();
470 QString groupKey = uKey.mid(lastIndex + 1);
471
472 HRESULT hr;
473
474 for (int i = 0; i < readContainers.size(); ++i) {
475 ComPtr<IApplicationDataContainer> container = const_cast<QWinRTSettingsPrivate*>(this)->getContainer(readContainers.at(i).Get(), groupName);
476
477 if (!container)
478 continue;
479
480 ComPtr<IPropertySet> values;
481 hr = container->get_Values(&values);
482 if (FAILED(hr))
483 continue;
484
485 ComPtr<IMap<HSTRING, IInspectable*>> settingsMap;
486 hr = values.As(&settingsMap);
487 if (FAILED(hr))
488 continue;
489
490 HStringReference key((const wchar_t*)groupKey.utf16(), groupKey.size());
491 boolean exists;
492
493 hr = settingsMap.Get()->HasKey(key.Get(), &exists);
494 if (FAILED(hr))
495 continue;
496
497 if (!exists) {
498 if (!fallbacks)
499 break;
500 else
501 continue;
502 }
503
504 if (value) {
505 ComPtr<IInspectable> val;
506 hr = settingsMap->Lookup(key.Get(), &val);
507 if (FAILED(hr))
508 return false;
509
510 ComPtr<IPropertyValue> pVal;
511 hr = val.As(&pVal);
512 if (FAILED(hr))
513 return false;
514
515 *value = propertyValueToQVariant(pVal.Get());
516 }
517 return true;
518 }
519 setStatus(QSettings::AccessError);
520 return false;
521 }
522
children(const QString & uKey,ChildSpec spec) const523 QStringList QWinRTSettingsPrivate::children(const QString &uKey, ChildSpec spec) const
524 {
525 QStringList result;
526 for (int i = 0; i < readContainers.size(); ++i) {
527 ComPtr<IApplicationDataContainer> container = getContainer(readContainers.at(i).Get(), uKey, false);
528 if (!container.Get())
529 continue;
530
531 // Get Keys in this container
532 if (spec == AllKeys || spec == ChildKeys)
533 result += keyNames(container.Get());
534
535 // Get Subcontainer(s)
536 if (spec == AllKeys || spec == ChildGroups) {
537 const QStringList subContainerList = subContainerNames(container.Get(), spec == AllKeys);
538
539 if (spec == AllKeys) {
540 for (const QString &item : subContainerList) {
541 const QString subChildren = uKey.isEmpty() ? item : (uKey + QLatin1Char('/') + item);
542 const QStringList subResult = children(subChildren, ChildKeys);
543 for (const QString &subItem : subResult)
544 result += item + QLatin1Char('/') + subItem;
545 }
546 }
547
548 if (spec == ChildGroups)
549 result += subContainerList;
550 }
551
552 }
553 result.removeDuplicates();
554 return result;
555 }
556
clear()557 void QWinRTSettingsPrivate::clear()
558 {
559 ComPtr<IApplicationDataContainer> container;
560 HRESULT hr;
561 if (scope == QSettings::UserScope)
562 hr = applicationData->get_LocalSettings(&container);
563 else
564 hr = applicationData->get_RoamingSettings(&container);
565
566 RETURN_VOID_IF_FAILED("Could not access settings container");
567
568 QString containerName = applicationName.isEmpty() ? organizationName : applicationName;
569 HStringReference containerNativeName((const wchar_t*)containerName.utf16(), containerName.size());
570
571 hr = container->DeleteContainer(containerNativeName.Get());
572 RETURN_VOID_IF_FAILED("Could not delete Container");
573
574 init(scope);
575 }
576
sync()577 void QWinRTSettingsPrivate::sync()
578 {
579 // No native sync available
580 }
581
flush()582 void QWinRTSettingsPrivate::flush()
583 {
584 // No native flush available
585 }
586
fileName() const587 QString QWinRTSettingsPrivate::fileName() const
588 {
589 Q_UNIMPLEMENTED();
590 return QString();
591 }
592
onDataChanged(IApplicationData *,IInspectable *)593 HRESULT QWinRTSettingsPrivate::onDataChanged(IApplicationData *, IInspectable *)
594 {
595 // This only happens, if roaming data is changed by the OS.
596 // To ensure sanity we clean up the map and start from scratch
597 init(scope);
598 return S_OK;
599 }
600
init(QSettings::Scope scope)601 void QWinRTSettingsPrivate::init(QSettings::Scope scope)
602 {
603 clearContainerMaps();
604
605 ComPtr<IApplicationDataStatics> applicationDataStatics;
606 HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_ApplicationData).Get(), &applicationDataStatics);
607 if (FAILED(hr)) {
608 qErrnoWarning(hr, "Could not access Storage Factory");
609 setStatus(QSettings::AccessError);
610 return;
611 }
612
613 hr = applicationDataStatics->get_Current(&applicationData);
614 if (FAILED(hr)) {
615 qErrnoWarning(hr, "Could not access application data statics");
616 setStatus(QSettings::AccessError);
617 return;
618 }
619
620 const QString organizationString = organizationName.isEmpty() ? QLatin1String("OrganizationDefaults") : organizationName;
621 ComPtr<IApplicationDataContainer> localContainer;
622 if (scope == QSettings::UserScope && SUCCEEDED(applicationData->get_LocalSettings(&localContainer))) {
623 if (!applicationName.isEmpty())
624 readContainers.append(createSubContainer(localContainer.Get(), applicationName));
625 readContainers.append(createSubContainer(localContainer.Get(), organizationString));
626 }
627
628 ComPtr<IApplicationDataContainer> roamingContainer;
629 if (SUCCEEDED(applicationData->get_RoamingSettings(&roamingContainer))) {
630 if (!applicationName.isEmpty())
631 readContainers.append(createSubContainer(roamingContainer.Get(), applicationName));
632 readContainers.append(createSubContainer(roamingContainer.Get(), organizationString));
633 }
634
635 ComPtr<IApplicationDataContainer> writeRootContainer = (scope == QSettings::UserScope) ? localContainer : roamingContainer;
636 if (!applicationName.isEmpty())
637 writeContainer = createSubContainer(writeRootContainer.Get(), applicationName);
638 else
639 writeContainer = createSubContainer(writeRootContainer.Get(), organizationString);
640
641 hr = applicationData->add_DataChanged(Callback<DataHandler>(this, &QWinRTSettingsPrivate::onDataChanged).Get(), &dataChangedToken);
642 }
643
getContainer(IApplicationDataContainer * parent,const QString & group,bool create) const644 IApplicationDataContainer *QWinRTSettingsPrivate::getContainer(IApplicationDataContainer *parent, const QString &group, bool create) const
645 {
646 IApplicationDataContainer *current = parent;
647 if (group.isEmpty())
648 return current;
649 const QStringList groupPath = group.split(QLatin1Char('/'), Qt::SkipEmptyParts);
650
651 for (const QString &subGroup : groupPath) {
652 ComPtr<IApplicationDataContainer> sub = subContainer(current, subGroup);
653 if (!sub && create)
654 sub = createSubContainer(current, subGroup);
655 if (!sub)
656 return 0; // Something seriously went wrong
657 current = sub.Detach();
658 }
659 return current;
660 }
661
clearContainerMaps()662 void QWinRTSettingsPrivate::clearContainerMaps()
663 {
664 readContainers.clear();
665 writeContainer.Reset();
666 }
667
isWritable() const668 bool QWinRTSettingsPrivate::isWritable() const
669 {
670 return true;
671 }
672
create(QSettings::Format format,QSettings::Scope scope,const QString & organization,const QString & application)673 QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, QSettings::Scope scope,
674 const QString &organization, const QString &application)
675 {
676 if (format == QSettings::NativeFormat)
677 return new QWinRTSettingsPrivate(scope, organization, application);
678 else
679 return new QConfFileSettingsPrivate(format, scope, organization, application);
680 }
681
create(const QString & fileName,QSettings::Format format)682 QSettingsPrivate *QSettingsPrivate::create(const QString &fileName, QSettings::Format format)
683 {
684 if (format == QSettings::NativeFormat)
685 return new QWinRTSettingsPrivate(fileName);
686 else
687 return new QConfFileSettingsPrivate(fileName, format);
688 }
689
690 QT_END_NAMESPACE
691