Browse Source

WIP new settings setup loader

CI test is needed...
pull/2/head
Skycoder42 7 years ago
parent
commit
48cddc5074
No known key found for this signature in database GPG Key ID: 8E01AD9EF0578D2B
  1. 42
      src/mvvmcore/settingsconfigloader.cpp
  2. 6
      src/mvvmcore/settingsconfigloader_p.h
  3. 2
      src/mvvmcore/settingssetup.h
  4. 26
      src/settingsconfig/settingsconfig.xsd
  5. 69
      src/settingsconfig/settingsconfigimpl.cpp
  6. 12
      src/settingsconfig/settingsconfigimpl.h
  7. 4
      tools/settingsgenerator/settingstranslator.cpp

42
src/mvvmcore/settingsconfigloader.cpp

@ -14,41 +14,46 @@ void SettingsConfigLoader::changeDefaultIcon(const QUrl &defaultIcon)
Setup SettingsConfigLoader::loadSetup(const QString &filePath, const QString &frontend, const QFileSelector *selector) const
{
auto keyTuple = std::make_tuple(filePath, frontend, selector->allSelectors());
Setup setup;
if(!_cache.contains(filePath)) {
if(!_cache.contains(keyTuple)) {
try {
const_cast<SettingsConfigLoader*>(this)->setFilters(frontend, selector);
auto config = const_cast<SettingsConfigLoader*>(this)->readDocument(filePath);
const_cast<SettingsConfigLoader*>(this)->resetFilters();
if(!nonstd::holds_alternative<SettingsConfigType>(config))
throw SettingsConfigException{"Root Element of \"" + filePath.toUtf8() + "\" must be a SettingsConfig"};
_cache.insert(filePath, convertSettings(nonstd::get<SettingsConfigType>(config)));
setup = convertSettings(nonstd::get<SettingsConfigType>(config));
_cache.insert(keyTuple, new Setup{setup});
} catch (Exception &e) {
throw SettingsConfigException{e};
}
} else
setup = *(_cache.object(filePath));
setup = *(_cache.object(keyTuple));
//TODO clearSetup(setup, frontend, selector->allSelectors());
return setup;
}
Setup *SettingsConfigLoader::convertSettings(const SettingsConfigType &settings) const
Setup SettingsConfigLoader::convertSettings(const SettingsConfigType &settings) const
{
QScopedPointer<Setup> setup{new Setup{}};
Setup setup;
setup->allowSearch = settings.allowSearch;
setup->allowRestore = settings.allowRestore;
setup.allowSearch = settings.allowSearch;
setup.allowRestore = settings.allowRestore;
for(const auto &element : settings.content) {
if(nonstd::holds_alternative<CategoryType>(element)) {//holds categories -> read them
const auto &category = nonstd::get<CategoryType>(element);
setup->categories.append(convertCategory(category, category.content));
setup.categories.append(convertCategory(category, category.content));
} else { //hold anything else -> create default from all child and thus break
setup->categories.append(convertCategory({}, settings.content));
setup.categories.append(convertCategory({}, settings.content));
break;
}
}
return setup.take();
return setup;
}
template<typename... TContent>
@ -58,8 +63,6 @@ Category SettingsConfigLoader::convertCategory(const CategoryType &category, con
cat.title = category.title.value_or(tr("General Settings"));
cat.icon = category.icon ? QUrl{category.icon.value()} : _defaultIcon;
cat.tooltip = category.tooltip.value_or(QString{});
cat.selectors = category.selectors.value_or(QString{});
cat.frontends = category.frontends.value_or(QString{});
for(const auto &element : content) {
if(nonstd::holds_alternative<SectionType>(element)) {//holds sections -> read them
const auto &section = nonstd::get<SectionType>(element);
@ -79,8 +82,6 @@ Section SettingsConfigLoader::convertSection(const SectionType &section, const Q
sec.title = section.title.value_or(tr("General"));
sec.icon = section.icon ? QUrl{section.icon.value()} : QUrl{};
sec.tooltip = section.tooltip.value_or(QString{});
sec.selectors = section.selectors.value_or(QString{});
sec.frontends = section.frontends.value_or(QString{});
for(const auto &element : content) {
if(nonstd::holds_alternative<GroupType>(element)) {//holds sections -> read them
const auto &group = nonstd::get<GroupType>(element);
@ -99,8 +100,6 @@ Group SettingsConfigLoader::convertGroup(const GroupType &group, const QList<var
Group grp;
grp.title = group.title.value_or(QString{});
grp.tooltip = group.tooltip.value_or(QString{});
grp.selectors = group.selectors.value_or(QString{});
grp.frontends = group.frontends.value_or(QString{});
for(const auto &element : content) {
if(nonstd::holds_alternative<EntryType>(element)) {//holds sections -> read them
const auto &entry = nonstd::get<EntryType>(element);
@ -135,3 +134,12 @@ QException *SettingsConfigException::clone() const
{
return new SettingsConfigException{_what};
}
uint qHash(const std::tuple<QString, QString, QStringList> &key, uint seed)
{
return qHash(std::get<0>(key), seed) ^
qHash(std::get<1>(key), seed) ^
qHash(std::get<2>(key), seed);
}

6
src/mvvmcore/settingsconfigloader_p.h

@ -23,9 +23,9 @@ public:
private:
QUrl _defaultIcon;
mutable QCache<QString, SettingsElements::Setup> _cache;
mutable QCache<std::tuple<QString, QString, QStringList>, SettingsElements::Setup> _cache;
SettingsElements::Setup *convertSettings(const SettingsConfigType &settings) const;
SettingsElements::Setup convertSettings(const SettingsConfigType &settings) const;
template <typename... TContent>
SettingsElements::Category convertCategory(const CategoryType &category, const QList<variant<TContent...>> &content) const;
@ -52,4 +52,6 @@ private:
}
uint qHash(const std::tuple<QString, QString, QStringList> &key, uint seed);
#endif // SETTINGSCONFIGLOADER_P_H

2
src/mvvmcore/settingssetup.h

@ -34,7 +34,7 @@ struct Entry
QVariantMap properties;
//! *[Internal]* A logical string describing the allowed frontends
QString frontends;
QString frontends; //MAJOR remove all
//! *[Internal]* A logical string describing the allowed selectors
QString selectors;
};

26
src/settingsconfig/settingsconfig.xsd

@ -13,15 +13,8 @@
<qxg:method name="finish_category_content" type="CategoryContentGroup" asGroup="true"/>
<qxg:method name="finish_settings_config_content" type="SettingsConfigContentGroup" asGroup="true"/>
<!-- Basic property-like elements definitions -->
<xs:complexType name="IncludeType">
<xs:simpleContent>
<xs:extension base="xs:string" qxg:member="includePath">
<xs:attribute type="xs:boolean" name="optional" default="false" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<!-- Basic property-like elements definitions -->
<xs:complexType name="ElementType" mixed="true" qxg:declare="true" qxg:member="content">
<xs:sequence>
<xs:element maxOccurs="unbounded" minOccurs="0" type="PropertyType" name="Property" qxg:member="properties"/>
@ -43,11 +36,15 @@
<!-- Group Definitions to build the elements from -->
<xs:attributeGroup name="SelectableContrainerInfo">
<xs:attribute type="xs:string" name="frontends" use="optional"/>
<xs:attribute type="xs:string" name="selectors" use="optional"/>
</xs:attributeGroup>
<xs:attributeGroup name="BasicContainerInfo">
<xs:attributeGroup ref="SelectableContrainerInfo" qxg:inherit="true"/>
<xs:attribute type="xs:string" name="title" use="optional"/>
<xs:attribute type="xs:string" name="tooltip" use="optional"/>
<xs:attribute type="xs:string" name="frontends" use="optional"/>
<xs:attribute type="xs:string" name="selectors" use="optional"/>
</xs:attributeGroup>
<xs:attributeGroup name="ExtendedContainerInfo">
@ -100,6 +97,15 @@
<!-- Element definitions -->
<xs:complexType name="IncludeType" qxg:declare="true">
<xs:simpleContent>
<xs:extension base="xs:string" qxg:member="includePath">
<xs:attributeGroup ref="SelectableContrainerInfo" qxg:inherit="true"/>
<xs:attribute type="xs:boolean" name="optional" default="false" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="EntryType" qxg:declare="true">
<xs:sequence>
<xs:choice maxOccurs="unbounded" minOccurs="0" qxg:unordered="true">

69
src/settingsconfig/settingsconfigimpl.cpp

@ -3,6 +3,7 @@
#include <QtCore/QFileInfo>
#include <QtCore/QDir>
#include <QtCore/QDebug>
#include <QtCore/QFileSelector>
namespace {
@ -37,6 +38,23 @@ struct VariantInfo<QList<SettingsConfigBase::variant<SettingsConfigBase::Include
}
void SettingsConfigImpl::setFilters(QString frontend, const QFileSelector *selector)
{
_frontend = std::move(frontend);
_selector = selector;
}
void SettingsConfigImpl::resetFilters()
{
_frontend.clear();
_selector = nullptr;
}
void SettingsConfigImpl::setIncludesOptional(bool alwaysOptional)
{
_alwaysOptional = alwaysOptional;
}
bool SettingsConfigImpl::finish_group_content(QXmlStreamReader &reader, GroupContentGroup &data, bool hasNext)
{
hasNext = read_GroupContentGroup(reader, data, hasNext);
@ -72,16 +90,31 @@ void SettingsConfigImpl::finishContents(QXmlStreamReader &reader, TGroup &group)
for(auto it = group.begin(); it != group.end();) {
// convert includes to the actual data
if(nonstd::holds_alternative<IncludeType>(*it)) {
if(!isUsable(nonstd::get<IncludeType>(*it))) {
it = group.erase(it);
continue;
}
if(!readGeneralInclude(reader, nonstd::get<IncludeType>(*it), it, group))
continue;
}
// verify that the contents are all of the same type
if(index) {
if(index.value() != it->index())
throw XmlException{reader, QStringLiteral("Detected mixture of different child elements. Only includes and a single other type are allowed")};
} else
index = it->index();
++it;
//erase if not usable due to selectors
bool visited = false;
nonstd::visit([&](auto &&element){ //TODO use trick if neccessary: https://en.cppreference.com/w/cpp/utility/variant/visit
visited = true;
if(isUsable(element))
++it;
else
it = group.erase(it);
}, *it);
Q_ASSERT(visited);
}
}
@ -89,6 +122,9 @@ template<typename TIter, typename TList>
bool SettingsConfigImpl::readGeneralInclude(QXmlStreamReader &reader, IncludeType include, TIter &it, TList &list)
{
try {
if(_selector)
include.includePath = _selector->select(include.includePath);
//make the path relative if possbile
if(dynamic_cast<QFileDevice*>(reader.device())) {
QFileInfo docInfo{static_cast<QFileDevice*>(reader.device())->fileName()};
@ -98,7 +134,7 @@ bool SettingsConfigImpl::readGeneralInclude(QXmlStreamReader &reader, IncludeTyp
VariantInfo<TList>::convert(reader, *it, readDocument(include.includePath));
return true;
} catch(FileException &e) {
if(include.optional) {
if(include.optional || _alwaysOptional) {
qWarning() << e.what();
it = list.erase(it);
return false;
@ -107,3 +143,32 @@ bool SettingsConfigImpl::readGeneralInclude(QXmlStreamReader &reader, IncludeTyp
}
}
bool SettingsConfigImpl::isUsable(const SelectableContrainerInfo &element) const
{
if(!_frontend.isNull() && element.frontends) {
auto fronts = element.frontends.value().split(QLatin1Char('|'), QString::SkipEmptyParts);
if(!fronts.contains(_frontend))
return false;
}
if(_selector && element.selectors) {
auto selectors = _selector->allSelectors();
auto selects = element.selectors.value().split(QLatin1Char('|'), QString::SkipEmptyParts);
for(const auto &select : selects) {
auto sels = select.split(QLatin1Char('&'), QString::SkipEmptyParts);
auto allSelected = true;
for(const auto &sel : sels) {
if(!selectors.contains(sel)) {
allSelected = false;
break;
}
}
if(allSelected)
return true;
}
return false;
}
return true;
}

12
src/settingsconfig/settingsconfigimpl.h

@ -3,9 +3,15 @@
#include "settingsconfig.h"
class QFileSelector;
class SettingsConfigImpl : public SettingsConfigBase
{
protected:
void setFilters(QString frontend, const QFileSelector *selector);
void resetFilters();
void setIncludesOptional(bool alwaysOptional);
bool finish_group_content(QXmlStreamReader &reader, GroupContentGroup &data, bool hasNext) override;
bool finish_section_content(QXmlStreamReader &reader, SectionContentGroup &data, bool hasNext) override;
bool finish_category_content(QXmlStreamReader &reader, CategoryContentGroup &data, bool hasNext) override;
@ -16,6 +22,12 @@ private:
void finishContents(QXmlStreamReader &reader, TGroup &group);
template <typename TIter, typename TList>
bool readGeneralInclude(QXmlStreamReader &reader, IncludeType include, TIter &it, TList &list);
bool isUsable(const SelectableContrainerInfo &element) const;
QString _frontend;
const QFileSelector *_selector = nullptr;
bool _alwaysOptional = false;
};
#endif // SETTINGSCONFIGIMPL_H

4
tools/settingsgenerator/settingstranslator.cpp

@ -4,7 +4,9 @@
SettingsTranslator::SettingsTranslator(const QString &srcPath) :
_srcFile{srcPath},
_src{&_srcFile}
{}
{
setIncludesOptional(true);
}
void SettingsTranslator::process(const QString &inPath)
{

Loading…
Cancel
Save