| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the QtCore module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU Lesser General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Lesser |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
| ** packaging of this file. Please review the following information to |
| ** ensure the GNU Lesser General Public License version 3 requirements |
| ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 2.0 or (at your option) the GNU General |
| ** Public license version 3 or any later version approved by the KDE Free |
| ** Qt Foundation. The licenses are as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
| ** https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "qsettings.h" |
| |
| #include "qsettings_p.h" |
| #include "qvector.h" |
| #include "qmap.h" |
| #include "qdebug.h" |
| #include "qfunctions_winrt.h" |
| |
| #include <wrl.h> |
| #include <wrl/event.h> |
| #include <Windows.ApplicationModel.h> |
| #include <windows.storage.h> |
| |
| using namespace ABI::Windows::ApplicationModel; |
| using namespace ABI::Windows::Storage; |
| using namespace ABI::Windows::Foundation; |
| using namespace ABI::Windows::Foundation::Collections; |
| using namespace Microsoft::WRL; |
| using namespace Microsoft::WRL::Wrappers; |
| |
| typedef ITypedEventHandler<ApplicationData*, IInspectable*> DataHandler; |
| typedef Collections::IKeyValuePair<HSTRING, ApplicationDataContainer*> ContainerItem; |
| typedef Collections::IIterable<ContainerItem*> ContainerIterable; |
| typedef Collections::IIterator<ContainerItem*> ContainerIterator; |
| |
| typedef Collections::IKeyValuePair<HSTRING, IInspectable*> ValueItem; |
| typedef Collections::IIterable<ValueItem*> ValueIterable; |
| typedef Collections::IIterator<ValueItem*> ValueIterator; |
| |
| QT_BEGIN_NAMESPACE |
| |
| static IApplicationDataContainer *subContainer(IApplicationDataContainer *parent, const QString &name) |
| { |
| ComPtr<IMapView<HSTRING, ApplicationDataContainer*>> childrenContainer; |
| HRESULT hr = parent->get_Containers(&childrenContainer); |
| if (FAILED(hr)) |
| return 0; |
| |
| ComPtr< ContainerIterable > iterable; |
| ComPtr< ContainerIterator > iterator; |
| |
| hr = childrenContainer.As(&iterable); |
| if (FAILED(hr)) |
| return 0; |
| |
| hr = iterable->First(&iterator); |
| if (FAILED(hr)) |
| return 0; |
| boolean current; |
| hr = iterator->get_HasCurrent(¤t); |
| if (FAILED(hr)) |
| return 0; |
| |
| while (SUCCEEDED(hr) && current) { |
| ComPtr<ContainerItem> item; |
| hr = iterator->get_Current(&item); |
| if (FAILED(hr)) |
| return 0; |
| |
| HString key; |
| hr = item->get_Key(key.GetAddressOf()); |
| if (FAILED(hr)) |
| continue; |
| QString subName = QString::fromWCharArray(key.GetRawBuffer(nullptr)); |
| if (name == subName) { |
| IApplicationDataContainer *container; |
| hr = item->get_Value(&container); |
| return SUCCEEDED(hr) ? container : 0; |
| } |
| hr = iterator->MoveNext(¤t); |
| } |
| |
| return 0; |
| } |
| |
| static QStringList subContainerNames(IApplicationDataContainer *container, bool recursive = false) |
| { |
| QStringList result; |
| ComPtr<IMapView<HSTRING, ApplicationDataContainer*>> childrenContainer; |
| HRESULT hr = container->get_Containers(&childrenContainer); |
| if (FAILED(hr)) |
| return result; |
| |
| ComPtr< ContainerIterable > iterable; |
| ComPtr< ContainerIterator > iterator; |
| |
| hr = childrenContainer.As(&iterable); |
| if (FAILED(hr)) |
| return result; |
| |
| hr = iterable->First(&iterator); |
| if (FAILED(hr)) |
| return result; |
| boolean current; |
| hr = iterator->get_HasCurrent(¤t); |
| if (FAILED(hr)) |
| return result; |
| |
| while (SUCCEEDED(hr) && current) { |
| ComPtr<ContainerItem> item; |
| hr = iterator->get_Current(&item); |
| if (FAILED(hr)) |
| return result; |
| |
| HString key; |
| hr = item->get_Key(key.GetAddressOf()); |
| if (SUCCEEDED(hr)) { |
| QString subName = QString::fromWCharArray(key.GetRawBuffer(nullptr)); |
| result.append(subName); |
| if (recursive) { |
| ComPtr<IApplicationDataContainer> sub = subContainer(container, subName); |
| QStringList subSubNames = subContainerNames(sub.Get(), recursive); |
| for (int i = 0; i < subSubNames.size(); ++i) |
| subSubNames[i] = subName + QLatin1Char('/') + subSubNames[i]; |
| result.append(subSubNames); |
| } |
| hr = iterator->MoveNext(¤t); |
| } |
| } |
| return result; |
| } |
| |
| static QStringList keyNames(IApplicationDataContainer *container) { |
| HRESULT hr; |
| QStringList result; |
| ComPtr<IPropertySet> values; |
| hr = container->get_Values(&values); |
| if (FAILED(hr)) |
| return result; |
| |
| ComPtr<IMap<HSTRING, IInspectable*>> settingsMap; |
| |
| hr = values.As(&settingsMap); |
| if (FAILED(hr)) |
| return result; |
| |
| ComPtr<IMapView<HSTRING, IInspectable*>> mapView; |
| hr = settingsMap->GetView(&mapView); |
| if (FAILED(hr)) |
| return result; |
| |
| ComPtr< ValueIterable > iterable; |
| ComPtr< ValueIterator > iterator; |
| |
| hr = mapView.As(&iterable); |
| if (FAILED(hr)) |
| return result; |
| |
| boolean current = false; |
| hr = iterable->First(&iterator); |
| if (FAILED(hr)) |
| return result; |
| hr = iterator->get_HasCurrent(¤t); |
| if (FAILED(hr)) |
| return result; |
| |
| while (SUCCEEDED(hr) && current){ |
| ComPtr<ValueItem> item; |
| hr = iterator->get_Current(&item); |
| if (FAILED(hr)) |
| return result; |
| |
| HString key; |
| hr = item->get_Key(key.GetAddressOf()); |
| if (SUCCEEDED(hr)) { |
| result += QString::fromWCharArray(key.GetRawBuffer(nullptr)); |
| hr = iterator->MoveNext(¤t); |
| } |
| } |
| return result; |
| } |
| |
| static IApplicationDataContainer *createSubContainer(IApplicationDataContainer *parent, const QString &name) |
| { |
| HStringReference childGroupNativeName((const wchar_t*)name.utf16(), name.size()); |
| |
| IApplicationDataContainer *result = subContainer(parent, name); |
| if (!result) |
| parent->CreateContainer(childGroupNativeName.Get(), ApplicationDataCreateDisposition_Always, &result); |
| return result; |
| } |
| |
| #define PROP_CASE_TO_VARIANT(TYPE, VARTYPE, QTYPE) \ |
| case PropertyType_##TYPE: { \ |
| VARTYPE v; \ |
| value->Get##TYPE(&v); \ |
| result.setValue( QTYPE(v) ); \ |
| break; \ |
| } |
| |
| static QVariant propertyValueToQVariant(IPropertyValue *value) |
| { |
| QVariant result; |
| PropertyType type; |
| value->get_Type(&type); |
| switch (type) { |
| PROP_CASE_TO_VARIANT(Boolean, boolean, bool) |
| PROP_CASE_TO_VARIANT(UInt8, UINT8, quint8) |
| PROP_CASE_TO_VARIANT(Int16, INT16, qint16) |
| PROP_CASE_TO_VARIANT(UInt16, UINT16, quint16) |
| PROP_CASE_TO_VARIANT(Int32, INT32, qint32) |
| PROP_CASE_TO_VARIANT(UInt32, UINT32, quint32) |
| PROP_CASE_TO_VARIANT(Int64, INT64, qint64) |
| PROP_CASE_TO_VARIANT(UInt64, UINT64, quint64) |
| PROP_CASE_TO_VARIANT(Single, FLOAT, float) |
| PROP_CASE_TO_VARIANT(Double, DOUBLE, double) |
| case PropertyType_StringArray: { |
| UINT32 size; |
| HSTRING *content; |
| value->GetStringArray(&size, &content); |
| QStringList list; |
| // The last item is assumed to be added by us |
| for (UINT32 i = 0; i < size - 1; ++i) { |
| QString s = QString::fromWCharArray(WindowsGetStringRawBuffer(content[i], nullptr)); |
| list.append(s); |
| } |
| result = QSettingsPrivate::stringListToVariantList(list); |
| break; |
| } |
| case PropertyType_String: { |
| HString v; |
| value->GetString(v.GetAddressOf()); |
| result = QSettingsPrivate::stringToVariant(QString::fromWCharArray(v.GetRawBuffer(nullptr))); |
| break; |
| } |
| default: { |
| UINT32 size; |
| BYTE *arr; |
| value->GetUInt8Array(&size, &arr); |
| QByteArray data = QByteArray::fromRawData((const char*)arr, size); |
| QString s; |
| if (size) { |
| // We assume this is our qt stored data like on other platforms |
| // as well. QList and others are converted to byte arrays |
| s = QString::fromWCharArray((const wchar_t *)data.constData(), data.size() / 2); |
| result = QSettingsPrivate::stringToVariant(s); |
| } |
| break; |
| } |
| } |
| return result; |
| } |
| |
| class QWinRTSettingsPrivate : public QSettingsPrivate |
| { |
| public: |
| QWinRTSettingsPrivate(QSettings::Scope scope, const QString &organization, |
| const QString &application); |
| QWinRTSettingsPrivate(const QString &rKey); |
| ~QWinRTSettingsPrivate(); |
| |
| void remove(const QString &uKey) override; |
| void set(const QString &uKey, const QVariant &value) override; |
| bool get(const QString &uKey, QVariant *value) const override; |
| QStringList children(const QString &uKey, ChildSpec spec) const override; |
| void clear() override; |
| void sync() override; |
| void flush() override; |
| bool isWritable() const override; |
| QString fileName() const override; |
| |
| private: |
| void init(QSettings::Scope scope); |
| IApplicationDataContainer *getContainer(IApplicationDataContainer *parent, const QString &group, bool create = false) const; |
| void clearContainerMaps(); |
| |
| HRESULT onDataChanged(IApplicationData*, IInspectable*); |
| |
| ComPtr<IApplicationData> applicationData; |
| QVector<ComPtr<IApplicationDataContainer>> readContainers; |
| ComPtr<IApplicationDataContainer> writeContainer; |
| EventRegistrationToken dataChangedToken; |
| }; |
| |
| QWinRTSettingsPrivate::QWinRTSettingsPrivate(QSettings::Scope scope, const QString &organization, |
| const QString &application) |
| : QSettingsPrivate(QSettings::NativeFormat, scope, organization, application) |
| , writeContainer(0) |
| { |
| init(scope); |
| } |
| |
| QWinRTSettingsPrivate::QWinRTSettingsPrivate(const QString &rPath) |
| : QSettingsPrivate(QSettings::NativeFormat, QSettings::UserScope, rPath, QString()) |
| , writeContainer(0) |
| { |
| init(QSettings::UserScope); |
| } |
| |
| QWinRTSettingsPrivate::~QWinRTSettingsPrivate() |
| { |
| clearContainerMaps(); |
| } |
| |
| void QWinRTSettingsPrivate::remove(const QString &uKey) |
| { |
| int lastIndex = uKey.lastIndexOf(QLatin1Char('/')); |
| QString groupName = (lastIndex > 0) ? uKey.left(lastIndex) : QString(); |
| QString groupKey = uKey.mid(lastIndex + 1); |
| |
| ComPtr<IApplicationDataContainer> container = getContainer(writeContainer.Get(), groupName, false); |
| if (!container) |
| return; |
| |
| HRESULT hr; |
| ComPtr<IPropertySet> values; |
| hr = container->get_Values(&values); |
| if (FAILED(hr)) |
| return; |
| |
| ComPtr<IMap<HSTRING, IInspectable*>> settingsMap; |
| |
| hr = values.As(&settingsMap); |
| if (FAILED(hr)) |
| return; |
| |
| HStringReference ref((const wchar_t*)groupKey.utf16(), groupKey.size()); |
| hr = settingsMap->Remove(ref.Get()); |
| |
| // groupKey can be a container as well |
| hr = container->DeleteContainer(ref.Get()); |
| init(scope); |
| } |
| |
| void QWinRTSettingsPrivate::set(const QString &uKey, const QVariant &value) |
| { |
| int lastIndex = uKey.lastIndexOf(QLatin1Char('/')); |
| QString groupName = (lastIndex > 0) ? uKey.left(lastIndex) : QString(); |
| QString groupKey = uKey.mid(lastIndex + 1); |
| |
| ComPtr<IApplicationDataContainer> container = getContainer(writeContainer.Get(), groupName, true); |
| |
| ComPtr<IPropertySet> values; |
| HRESULT hr = container->get_Values(&values); |
| if (FAILED(hr)) { |
| qErrnoWarning(hr, "Could not access Windows container values"); |
| setStatus(QSettings::AccessError); |
| return; |
| } |
| |
| ComPtr<IMap<HSTRING, IInspectable*>> settingsMap; |
| hr = values.As(&settingsMap); |
| if (FAILED(hr)) { |
| setStatus(QSettings::AccessError); |
| return; |
| } |
| |
| ComPtr<IPropertyValueStatics> valueStatics; |
| hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Foundation_PropertyValue).Get(), &valueStatics); |
| if (FAILED(hr)) { |
| setStatus(QSettings::AccessError); |
| return; |
| } |
| |
| ComPtr<IInspectable> val; |
| |
| switch (value.type()) { |
| case QVariant::List: |
| case QVariant::StringList: { |
| QStringList l = variantListToStringList(value.toList()); |
| QStringList::const_iterator it = l.constBegin(); |
| bool containsNull = false; |
| for (; it != l.constEnd(); ++it) { |
| if ((*it).length() == 0 || it->contains(QChar::Null)) { |
| // We can only store as binary |
| containsNull = true; |
| break; |
| } |
| } |
| |
| if (containsNull) { |
| // Store binary |
| const QString s = variantToString(value); |
| hr = valueStatics->CreateUInt8Array(s.length() * 2, (BYTE*) s.utf16(), &val); |
| } else { |
| // Store as native string list |
| int size = l.size(); |
| HSTRING *nativeHandleList = new HSTRING[size+1]; |
| for (int i = 0; i < size; ++i) |
| hr = WindowsCreateString((const wchar_t*)l[i].utf16(), l[i].size(), &nativeHandleList[i]); |
| // Add end marker |
| hr = WindowsCreateString((const wchar_t*)L"\0\0@", 3, &nativeHandleList[size]); |
| hr = valueStatics->CreateStringArray(size + 1 , nativeHandleList, &val); |
| for (int i = 0; i < size; ++i) |
| hr = WindowsDeleteString(nativeHandleList[i]); |
| delete [] nativeHandleList; |
| } |
| break; |
| } |
| case QVariant::Bool: |
| hr = valueStatics->CreateBoolean(boolean(value.toBool()), &val); |
| break; |
| case QVariant::Int: |
| hr = valueStatics->CreateInt32(INT32(value.toInt()), &val); |
| break; |
| case QVariant::UInt: |
| hr = valueStatics->CreateUInt32(UINT32(value.toUInt()), &val); |
| break; |
| case QVariant::LongLong: |
| hr = valueStatics->CreateInt64(INT64(value.toLongLong()), &val); |
| break; |
| case QVariant::ULongLong: |
| hr = valueStatics->CreateUInt64(UINT64(value.toULongLong()), &val); |
| break; |
| default: { |
| const QString s = variantToString(value); |
| if (s.contains(QChar::Null)) { |
| hr = valueStatics->CreateUInt8Array(s.length() * 2, (BYTE*) s.utf16(), &val); |
| } else { |
| HStringReference ref((const wchar_t*)s.utf16(), s.size()); |
| hr = valueStatics->CreateString(ref.Get(), &val); |
| } |
| |
| break; |
| } |
| } |
| |
| RETURN_VOID_IF_FAILED("QSettings: Could not save QVariant value into IInspectable"); |
| |
| HStringReference key((const wchar_t*)groupKey.utf16(), groupKey.size()); |
| boolean rep; |
| |
| hr = settingsMap->Insert(key.Get(), val.Get(), &rep); |
| RETURN_VOID_IF_FAILED("QSettings: Could not store value"); |
| } |
| |
| bool QWinRTSettingsPrivate::get(const QString &uKey, QVariant *value) const |
| { |
| int lastIndex = uKey.lastIndexOf(QLatin1Char('/')); |
| QString groupName = (lastIndex > 0) ? uKey.left(lastIndex) : QString(); |
| QString groupKey = uKey.mid(lastIndex + 1); |
| |
| HRESULT hr; |
| |
| for (int i = 0; i < readContainers.size(); ++i) { |
| ComPtr<IApplicationDataContainer> container = const_cast<QWinRTSettingsPrivate*>(this)->getContainer(readContainers.at(i).Get(), groupName); |
| |
| if (!container) |
| continue; |
| |
| ComPtr<IPropertySet> values; |
| hr = container->get_Values(&values); |
| if (FAILED(hr)) |
| continue; |
| |
| ComPtr<IMap<HSTRING, IInspectable*>> settingsMap; |
| hr = values.As(&settingsMap); |
| if (FAILED(hr)) |
| continue; |
| |
| HStringReference key((const wchar_t*)groupKey.utf16(), groupKey.size()); |
| boolean exists; |
| |
| hr = settingsMap.Get()->HasKey(key.Get(), &exists); |
| if (FAILED(hr)) |
| continue; |
| |
| if (!exists) { |
| if (!fallbacks) |
| break; |
| else |
| continue; |
| } |
| |
| if (value) { |
| ComPtr<IInspectable> val; |
| hr = settingsMap->Lookup(key.Get(), &val); |
| if (FAILED(hr)) |
| return false; |
| |
| ComPtr<IPropertyValue> pVal; |
| hr = val.As(&pVal); |
| if (FAILED(hr)) |
| return false; |
| |
| *value = propertyValueToQVariant(pVal.Get()); |
| } |
| return true; |
| } |
| setStatus(QSettings::AccessError); |
| return false; |
| } |
| |
| QStringList QWinRTSettingsPrivate::children(const QString &uKey, ChildSpec spec) const |
| { |
| QStringList result; |
| for (int i = 0; i < readContainers.size(); ++i) { |
| ComPtr<IApplicationDataContainer> container = getContainer(readContainers.at(i).Get(), uKey, false); |
| if (!container.Get()) |
| continue; |
| |
| // Get Keys in this container |
| if (spec == AllKeys || spec == ChildKeys) |
| result += keyNames(container.Get()); |
| |
| // Get Subcontainer(s) |
| if (spec == AllKeys || spec == ChildGroups) { |
| const QStringList subContainerList = subContainerNames(container.Get(), spec == AllKeys); |
| |
| if (spec == AllKeys) { |
| for (const QString &item : subContainerList) { |
| const QString subChildren = uKey.isEmpty() ? item : (uKey + QLatin1Char('/') + item); |
| const QStringList subResult = children(subChildren, ChildKeys); |
| for (const QString &subItem : subResult) |
| result += item + QLatin1Char('/') + subItem; |
| } |
| } |
| |
| if (spec == ChildGroups) |
| result += subContainerList; |
| } |
| |
| } |
| result.removeDuplicates(); |
| return result; |
| } |
| |
| void QWinRTSettingsPrivate::clear() |
| { |
| ComPtr<IApplicationDataContainer> container; |
| HRESULT hr; |
| if (scope == QSettings::UserScope) |
| hr = applicationData->get_LocalSettings(&container); |
| else |
| hr = applicationData->get_RoamingSettings(&container); |
| |
| RETURN_VOID_IF_FAILED("Could not access settings container"); |
| |
| QString containerName = applicationName.isEmpty() ? organizationName : applicationName; |
| HStringReference containerNativeName((const wchar_t*)containerName.utf16(), containerName.size()); |
| |
| hr = container->DeleteContainer(containerNativeName.Get()); |
| RETURN_VOID_IF_FAILED("Could not delete Container"); |
| |
| init(scope); |
| } |
| |
| void QWinRTSettingsPrivate::sync() |
| { |
| // No native sync available |
| } |
| |
| void QWinRTSettingsPrivate::flush() |
| { |
| // No native flush available |
| } |
| |
| QString QWinRTSettingsPrivate::fileName() const |
| { |
| Q_UNIMPLEMENTED(); |
| return QString(); |
| } |
| |
| HRESULT QWinRTSettingsPrivate::onDataChanged(IApplicationData *, IInspectable *) |
| { |
| // This only happens, if roaming data is changed by the OS. |
| // To ensure sanity we clean up the map and start from scratch |
| init(scope); |
| return S_OK; |
| } |
| |
| void QWinRTSettingsPrivate::init(QSettings::Scope scope) |
| { |
| clearContainerMaps(); |
| |
| ComPtr<IApplicationDataStatics> applicationDataStatics; |
| HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_ApplicationData).Get(), &applicationDataStatics); |
| if (FAILED(hr)) { |
| qErrnoWarning(hr, "Could not access Storage Factory"); |
| setStatus(QSettings::AccessError); |
| return; |
| } |
| |
| hr = applicationDataStatics->get_Current(&applicationData); |
| if (FAILED(hr)) { |
| qErrnoWarning(hr, "Could not access application data statics"); |
| setStatus(QSettings::AccessError); |
| return; |
| } |
| |
| const QString organizationString = organizationName.isEmpty() ? QLatin1String("OrganizationDefaults") : organizationName; |
| ComPtr<IApplicationDataContainer> localContainer; |
| if (scope == QSettings::UserScope && SUCCEEDED(applicationData->get_LocalSettings(&localContainer))) { |
| if (!applicationName.isEmpty()) |
| readContainers.append(createSubContainer(localContainer.Get(), applicationName)); |
| readContainers.append(createSubContainer(localContainer.Get(), organizationString)); |
| } |
| |
| ComPtr<IApplicationDataContainer> roamingContainer; |
| if (SUCCEEDED(applicationData->get_RoamingSettings(&roamingContainer))) { |
| if (!applicationName.isEmpty()) |
| readContainers.append(createSubContainer(roamingContainer.Get(), applicationName)); |
| readContainers.append(createSubContainer(roamingContainer.Get(), organizationString)); |
| } |
| |
| ComPtr<IApplicationDataContainer> writeRootContainer = (scope == QSettings::UserScope) ? localContainer : roamingContainer; |
| if (!applicationName.isEmpty()) |
| writeContainer = createSubContainer(writeRootContainer.Get(), applicationName); |
| else |
| writeContainer = createSubContainer(writeRootContainer.Get(), organizationString); |
| |
| hr = applicationData->add_DataChanged(Callback<DataHandler>(this, &QWinRTSettingsPrivate::onDataChanged).Get(), &dataChangedToken); |
| } |
| |
| IApplicationDataContainer *QWinRTSettingsPrivate::getContainer(IApplicationDataContainer *parent, const QString &group, bool create) const |
| { |
| IApplicationDataContainer *current = parent; |
| if (group.isEmpty()) |
| return current; |
| const QStringList groupPath = group.split(QLatin1Char('/'), QString::SkipEmptyParts); |
| |
| for (const QString &subGroup : groupPath) { |
| ComPtr<IApplicationDataContainer> sub = subContainer(current, subGroup); |
| if (!sub && create) |
| sub = createSubContainer(current, subGroup); |
| if (!sub) |
| return 0; // Something seriously went wrong |
| current = sub.Detach(); |
| } |
| return current; |
| } |
| |
| void QWinRTSettingsPrivate::clearContainerMaps() |
| { |
| readContainers.clear(); |
| writeContainer.Reset(); |
| } |
| |
| bool QWinRTSettingsPrivate::isWritable() const |
| { |
| return true; |
| } |
| |
| QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, QSettings::Scope scope, |
| const QString &organization, const QString &application) |
| { |
| if (format == QSettings::NativeFormat) |
| return new QWinRTSettingsPrivate(scope, organization, application); |
| else |
| return new QConfFileSettingsPrivate(format, scope, organization, application); |
| } |
| |
| QSettingsPrivate *QSettingsPrivate::create(const QString &fileName, QSettings::Format format) |
| { |
| if (format == QSettings::NativeFormat) |
| return new QWinRTSettingsPrivate(fileName); |
| else |
| return new QConfFileSettingsPrivate(fileName, format); |
| } |
| |
| QT_END_NAMESPACE |