Warning: That file was not part of the compilation database. It may have many parsing errors.
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
322 | QWinRTSettingsPrivate::QWinRTSettingsPrivate(const QString &rPath) |
323 | : QSettingsPrivate(QSettings::NativeFormat, QSettings::UserScope, rPath, QString()) |
324 | , writeContainer(0) |
325 | { |
326 | init(QSettings::UserScope); |
327 | } |
328 | |
329 | QWinRTSettingsPrivate::~QWinRTSettingsPrivate() |
330 | { |
331 | clearContainerMaps(); |
332 | } |
333 | |
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 | |
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 | |
466 | 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 | |
523 | 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 | |
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 | |
577 | void QWinRTSettingsPrivate::sync() |
578 | { |
579 | // No native sync available |
580 | } |
581 | |
582 | void QWinRTSettingsPrivate::flush() |
583 | { |
584 | // No native flush available |
585 | } |
586 | |
587 | QString QWinRTSettingsPrivate::fileName() const |
588 | { |
589 | Q_UNIMPLEMENTED(); |
590 | return QString(); |
591 | } |
592 | |
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 | |
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 | |
644 | 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('/'), QString::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 | |
662 | void QWinRTSettingsPrivate::clearContainerMaps() |
663 | { |
664 | readContainers.clear(); |
665 | writeContainer.Reset(); |
666 | } |
667 | |
668 | bool QWinRTSettingsPrivate::isWritable() const |
669 | { |
670 | return true; |
671 | } |
672 | |
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 | |
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 |
Warning: That file was not part of the compilation database. It may have many parsing errors.