Browse Source

Implemented settings GUI code

pull/2/head
Skycoder42 7 years ago
parent
commit
ec40fa3a6c
  1. 32
      examples/mvvmcore/SampleCore/settings.xml
  2. 2
      examples/mvvmwidgets/SampleWidgets/SampleWidgets.pro
  3. 2
      examples/mvvmwidgets/SampleWidgets/main.cpp
  4. 2
      examples/mvvmwidgets/SampleWidgets/sampleview.cpp
  5. 6
      examples/mvvmwidgets/SampleWidgets/sampleview.ui
  6. 2
      src/mvvmquick/ListEdit.qml
  7. 8
      src/mvvmsettingscore/mvvmsettingscore.pro
  8. 21
      src/mvvmsettingscore/settingssetup.h
  9. 77
      src/mvvmsettingscore/settingssetuploader.cpp
  10. 52
      src/mvvmsettingscore/settingssetuploader_p.h
  11. 7
      src/mvvmsettingscore/settingsviewmodel.cpp
  12. 4
      src/mvvmsettingscore/settingsviewmodel.h
  13. 2
      src/mvvmsettingscore/settingsviewmodel_p.h
  14. 0
      src/mvvmsettingscore/translations/qtmvvmsettingscore_de.ts
  15. 0
      src/mvvmsettingscore/translations/qtmvvmsettingscore_template.ts
  16. 39
      src/mvvmsettingswidgets/mvvmsettingswidgets.pro
  17. 14
      src/mvvmsettingswidgets/qpmx.json
  18. 12
      src/mvvmsettingswidgets/qtmvvmsettingswidgets_global.h
  19. 477
      src/mvvmsettingswidgets/settingsdialog.cpp
  20. 34
      src/mvvmsettingswidgets/settingsdialog.h
  21. 232
      src/mvvmsettingswidgets/settingsdialog.ui
  22. 89
      src/mvvmsettingswidgets/settingsdialog_p.h
  23. 4
      src/mvvmwidgets/widgetspresenter.cpp
  24. 3
      src/src.pro
  25. 3
      sync.profile

32
examples/mvvmcore/SampleCore/settings.xml

@ -8,21 +8,24 @@
type="bool"
title="&Check me"
tooltip="I am a checkbox!"
default="false">
default="true">
<SearchKey>property</SearchKey>
<SearchKey>bool</SearchKey>
<Property key="text" type="string">Please do check me</Property>
</Entry>
<Entry key="prop2"
type="string"
title="Enter a &amp;name"/>
title="Enter a &amp;name">
<Property key="placeholderText" type="string">Enter a nice name</Property>
</Entry>
</Group>
<Group title="Sub-Group" tooltip="This is a tooltip">
<Entry key="prop3"
type="action"
title="Open &amp;system settings">
<Property key="name" type="string">baum</Property>
<Property key="value" type="double">4.2</Property>
<Property key="text" type="string">Trigger Action</Property>
<Property key="args" type="object">
<Property key="hint" type="string">You can use this to trigger whatever kind of action you need</Property>
</Property>
</Entry>
<Entry key="prop4"
type="selection"
@ -47,35 +50,35 @@
<Entry key="prop6"
type="selection"
title="Select a &amp;mode"
default="10">
default="3">
<Property key="listElements" type="list">
<Element type="object">
<Property key="name" type="string">Value A</Property>
<Property key="value" type="int">1</property>
<Property key="value" type="int">1</Property>
</Element>
<Element type="object">
<Property key="name" type="string">Value B</Property>
<Property key="value" type="int">2</property>
<Property key="value" type="int">2</Property>
</Element>
<Element type="object">
<Property key="name" type="string">Value C</Property>
<Property key="value" type="int">4</property>
<Property key="value" type="int">4</Property>
</Element>
<Element type="object">
<Property key="name" type="string">Value A+B</Property>
<Property key="value" type="int">3</property>
<Property key="value" type="int">3</Property>
</Element>
<Element type="object">
<Property key="name" type="string">Value A+C</Property>
<Property key="value" type="int">5</property>
<Property key="value" type="int">5</Property>
</Element>
<Element type="object">
<Property key="name" type="string">Value B+C</Property>
<Property key="value" type="int">6</property>
<Property key="value" type="int">6</Property>
</Element>
<Element type="object">
<Property key="name" type="string">Value A+B+C</Property>
<Property key="value" type="int">7</property>
<Property key="value" type="int">7</Property>
</Element>
</Property>
</Entry>
@ -84,6 +87,7 @@
<Category title="Another main category">
<Entry key="prop7"
type="int"
title="Enter a &amp;number"/>
title="Enter a &amp;number"
default="42" />
</Category>
</SettingsConfig>

2
examples/mvvmwidgets/SampleWidgets/SampleWidgets.pro

@ -1,6 +1,6 @@
TEMPLATE = app
QT += core gui widgets mvvmwidgets mvvmsettingscore
QT += core gui widgets mvvmwidgets mvvmsettingswidgets
TARGET = SampleWidgets

2
examples/mvvmwidgets/SampleWidgets/main.cpp

@ -1,6 +1,7 @@
#include <QApplication>
#include <QtMvvmCore/ServiceRegistry>
#include <QtMvvmWidgets/WidgetsPresenter>
#include <QtMvvmSettingsWidgets/SettingsDialog>
#include <samplecoreapp.h>
#include "widgetseventservice.h"
@ -25,6 +26,7 @@ int main(int argc, char *argv[])
QtMvvm::WidgetsPresenter::registerView<ResultDialog>();
QtMvvm::WidgetsPresenter::registerView<TabView>();
QtMvvm::WidgetsPresenter::registerView<TabItemView>();
QtMvvm::WidgetsPresenter::registerView<QtMvvm::SettingsDialog>();
if(TEST_CURRENT == TEST_DIRECT)
QtMvvm::ServiceRegistry::instance()->registerObject<EchoService>();

2
examples/mvvmwidgets/SampleWidgets/sampleview.cpp

@ -30,6 +30,8 @@ SampleView::SampleView(QtMvvm::ViewModel *viewModel, QWidget *parent) :
_viewModel, &SampleViewModel::getFiles);
connect(ui->actionShow_Tabs, &QAction::triggered,
_viewModel, &SampleViewModel::showTabs);
connect(ui->actionShow_Settings, &QAction::triggered,
_viewModel, &SampleViewModel::showSettings);
}
SampleView::~SampleView()

6
examples/mvvmwidgets/SampleWidgets/sampleview.ui

@ -107,6 +107,7 @@
<string>&amp;Actions</string>
</property>
<addaction name="actionShow_Tabs"/>
<addaction name="actionShow_Settings"/>
<addaction name="separator"/>
<addaction name="actionUseless_Input"/>
<addaction name="actionAdd_Files"/>
@ -135,6 +136,11 @@
<string>Show &amp;Tabs</string>
</property>
</action>
<action name="actionShow_Settings">
<property name="text">
<string>Show &amp;Settings</string>
</property>
</action>
</widget>
<resources/>
<connections/>

2
src/mvvmquick/ListEdit.qml

@ -23,7 +23,7 @@ ComboBox {
return _edit.displayText;
},
set: function (value) {
var index = find(value);
var index = find(value); //TODO find VALUE, not text... somehow via the model?
if(index !== -1)
currentIndex = index;
else if(editable)

8
src/mvvmsettingscore/mvvmsettingscore.pro

@ -14,8 +14,8 @@ SOURCES += \
qtmvvmsettingscore_global.cpp
TRANSLATIONS += \
translations/qtmvvsettingsmcore_de.ts \
translations/qtmvvsettingsmcore_template.ts
translations/qtmvvmsettingscore_de.ts \
translations/qtmvvmsettingscore_template.ts
DISTFILES += $$TRANSLATIONS
@ -35,6 +35,6 @@ win32 {
!ReleaseBuild:!DebugBuild:!system(qpmx -d $$shell_quote($$_PRO_FILE_PWD_) --qmake-run init $$QPMX_EXTRA_OPTIONS $$shell_quote($$QMAKE_QMAKE) $$shell_quote($$OUT_PWD)): error(qpmx initialization failed. Check the compilation log for details.)
else: include($$OUT_PWD/qpmx_generated.pri)
qpmx_ts_target.files -= $$OUT_PWD/$$QPMX_WORKINGDIR/qtmvvsettingsmcore_template.qm
qpmx_ts_target.files += translations/qtmvvsettingsmcore_template.ts
qpmx_ts_target.files -= $$OUT_PWD/$$QPMX_WORKINGDIR/qtmvvmsettingscore_template.qm
qpmx_ts_target.files += translations/qtmvvmsettingscore_template.ts

21
src/mvvmsettingscore/settingssetup.h

@ -14,7 +14,7 @@ namespace QtMvvm {
namespace SettingsElements {
struct SettingsEntry
struct Entry
{
QString key;
QByteArray type;
@ -28,47 +28,47 @@ struct SettingsEntry
QString selectors;
};
struct SettingsGroup
struct Group
{
QString title;
QString tooltip;
QList<SettingsEntry> entries;
QList<Entry> entries;
QString frontends;
QString selectors;
};
struct SettingsSection
struct Section
{
QString title;
QUrl icon;
QString tooltip;
QList<SettingsGroup> groups;
QList<Group> groups;
QString frontends;
QString selectors;
};
struct SettingsCategory
struct Category
{
QString title;
QUrl icon;
QString tooltip;
QList<SettingsSection> sections;
QList<Section> sections;
QString frontends;
QString selectors;
};
struct SettingsSetup
struct Setup
{
bool allowSearch = true;
bool allowRestore = true;
QList<SettingsCategory> categories;
QList<Category> categories;
};
}
@ -80,7 +80,8 @@ class ISettingsSetupLoader
public:
virtual inline ~ISettingsSetupLoader() = default;
virtual SettingsElements::SettingsSetup loadSetup(const QString &filePath, const QString &frontend, const QFileSelector *selector) const = 0;
virtual void changeDefaultIcon(const QUrl &defaultIcon) = 0;
virtual SettingsElements::Setup loadSetup(const QString &filePath, const QString &frontend, const QFileSelector *selector) const = 0;
};
}

77
src/mvvmsettingscore/settingssetuploader.cpp

@ -19,16 +19,20 @@ using namespace QtMvvm::SettingsElements;
#define trctx(x) QCoreApplication::translate("qtmvvm_settings_xml", qUtf8Printable(x))
QUrl SettingsSetupLoader::defaultIcon(QStringLiteral("qrc:/qtmvvm/icons/settings.svg"));
SettingsSetupLoader::SettingsSetupLoader(QObject *parent) :
QObject(parent),
_defaultIcon(QStringLiteral("qrc:/qtmvvm/icons/settings.svg")),
_cache()
{}
SettingsSetup SettingsSetupLoader::loadSetup(const QString &filePath, const QString &frontend, const QFileSelector *selector) const
void SettingsSetupLoader::changeDefaultIcon(const QUrl &defaultIcon)
{
_defaultIcon = defaultIcon;
}
Setup SettingsSetupLoader::loadSetup(const QString &filePath, const QString &frontend, const QFileSelector *selector) const
{
SettingsSetup setup;
Setup setup;
if(!_cache.contains(filePath)) {
QFile file(QDir::cleanPath(filePath));
if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
@ -50,7 +54,7 @@ SettingsSetup SettingsSetupLoader::loadSetup(const QString &filePath, const QStr
reader.name() == QStringLiteral("Include")) {
do {
if(reader.name() == QStringLiteral("Include")) {
SettingsCategory category;
Category category;
if(readCategoryInclude(reader, category))
setup.categories.append(category);
} else
@ -62,7 +66,7 @@ SettingsSetup SettingsSetupLoader::loadSetup(const QString &filePath, const QStr
testXmlValid(reader);
file.close();
_cache.insert(filePath, new SettingsSetup(setup));
_cache.insert(filePath, new Setup(setup));
} else
setup = *(_cache.object(filePath));
@ -85,7 +89,7 @@ bool SettingsSetupLoader::event(QEvent *event)
return QObject::event(event);
}
SettingsCategory SettingsSetupLoader::readCategory(QXmlStreamReader &reader) const
Category SettingsSetupLoader::readCategory(QXmlStreamReader &reader) const
{
testXmlValid(reader);
if(reader.name() != QStringLiteral("Category"))
@ -109,7 +113,7 @@ SettingsCategory SettingsSetupLoader::readCategory(QXmlStreamReader &reader) con
return category;
}
SettingsCategory SettingsSetupLoader::readDefaultCategory(QXmlStreamReader &reader) const
Category SettingsSetupLoader::readDefaultCategory(QXmlStreamReader &reader) const
{
testXmlValid(reader);
auto category = createDefaultCategory();
@ -118,13 +122,13 @@ SettingsCategory SettingsSetupLoader::readDefaultCategory(QXmlStreamReader &read
return category;
}
void SettingsSetupLoader::readCategoryChildren(QXmlStreamReader &reader, SettingsCategory &category) const
void SettingsSetupLoader::readCategoryChildren(QXmlStreamReader &reader, Category &category) const
{
if(reader.name() == QStringLiteral("Section") ||
reader.name() == QStringLiteral("Include")) {
do {
if(reader.name() == QStringLiteral("Include")) {
SettingsSection section;
Section section;
if(readSectionInclude(reader, section))
category.sections.append(section);
} else
@ -134,7 +138,7 @@ void SettingsSetupLoader::readCategoryChildren(QXmlStreamReader &reader, Setting
category.sections.append(readDefaultSection(reader));
}
SettingsSection SettingsSetupLoader::readSection(QXmlStreamReader &reader) const
Section SettingsSetupLoader::readSection(QXmlStreamReader &reader) const
{
testXmlValid(reader);
if(reader.name() != QStringLiteral("Section"))
@ -158,7 +162,7 @@ SettingsSection SettingsSetupLoader::readSection(QXmlStreamReader &reader) const
return section;
}
SettingsSection SettingsSetupLoader::readDefaultSection(QXmlStreamReader &reader) const
Section SettingsSetupLoader::readDefaultSection(QXmlStreamReader &reader) const
{
testXmlValid(reader);
auto section = createDefaultSection();
@ -167,13 +171,13 @@ SettingsSection SettingsSetupLoader::readDefaultSection(QXmlStreamReader &reader
return section;
}
void SettingsSetupLoader::readSectionChildren(QXmlStreamReader &reader, SettingsSection &section) const
void SettingsSetupLoader::readSectionChildren(QXmlStreamReader &reader, Section &section) const
{
if(reader.name() == QStringLiteral("Group") ||
reader.name() == QStringLiteral("Include")) {
do {
if(reader.name() == QStringLiteral("Include")) {
SettingsGroup group;
Group group;
if(readGroupInclude(reader, group))
section.groups.append(group);
} else
@ -183,13 +187,13 @@ void SettingsSetupLoader::readSectionChildren(QXmlStreamReader &reader, Settings
section.groups.append(readDefaultGroup(reader));
}
SettingsGroup SettingsSetupLoader::readGroup(QXmlStreamReader &reader) const
Group SettingsSetupLoader::readGroup(QXmlStreamReader &reader) const
{
testXmlValid(reader);
if(reader.name() != QStringLiteral("Group"))
throwElement(reader, "Group");
SettingsGroup group;
Group group;
if(reader.hasValue("title"))
group.title = trctx(reader.stringValue("title"));
if(reader.hasValue("tooltip"))
@ -204,22 +208,22 @@ SettingsGroup SettingsSetupLoader::readGroup(QXmlStreamReader &reader) const
return group;
}
SettingsGroup SettingsSetupLoader::readDefaultGroup(QXmlStreamReader &reader) const
Group SettingsSetupLoader::readDefaultGroup(QXmlStreamReader &reader) const
{
testXmlValid(reader);
SettingsGroup group;
Group group;
readGroupChildren(reader, group);
testXmlValid(reader);
return group;
}
void SettingsSetupLoader::readGroupChildren(QXmlStreamReader &reader, SettingsGroup &group) const
void SettingsSetupLoader::readGroupChildren(QXmlStreamReader &reader, Group &group) const
{
if(reader.name() == QStringLiteral("Entry") ||
reader.name() == QStringLiteral("Include")) {
do {
if(reader.name() == QStringLiteral("Include")) {
SettingsEntry entry;
Entry entry;
if(readEntryInclude(reader, entry))
group.entries.append(entry);
} else
@ -229,13 +233,13 @@ void SettingsSetupLoader::readGroupChildren(QXmlStreamReader &reader, SettingsGr
throwXmlError(reader, QStringLiteral("Unexpected element type <%1>").arg(reader.name()).toUtf8());
}
SettingsEntry SettingsSetupLoader::readEntry(QXmlStreamReader &reader) const
Entry SettingsSetupLoader::readEntry(QXmlStreamReader &reader) const
{
testXmlValid(reader);
if(reader.name() != QStringLiteral("Entry"))
throwElement(reader, "Entry");
SettingsEntry entry;
Entry entry;
if(!reader.hasValue("key"))
throwAttrib(reader, "key");
@ -265,17 +269,17 @@ SettingsEntry SettingsSetupLoader::readEntry(QXmlStreamReader &reader) const
return entry;
}
SettingsCategory SettingsSetupLoader::createDefaultCategory() const
Category SettingsSetupLoader::createDefaultCategory() const
{
SettingsCategory category;
Category category;
category.title = tr("General Settings");
category.icon = defaultIcon;
category.icon = _defaultIcon;
return category;
}
SettingsSection SettingsSetupLoader::createDefaultSection() const
Section SettingsSetupLoader::createDefaultSection() const
{
SettingsSection section;
Section section;
section.title = tr("General");
return section;
}
@ -284,7 +288,8 @@ std::tuple<QString, QVariant> SettingsSetupLoader::readProperty(QXmlStreamReader
{
if(!reader.hasValue("key"))
throwAttrib(reader, "key");
return std::make_tuple(reader.stringValue("key"), readElement(reader));
auto key = reader.stringValue("key");
return std::make_tuple(key, readElement(reader));
}
QVariant SettingsSetupLoader::readElement(QXmlStreamReader &reader) const
@ -337,28 +342,28 @@ QVariant SettingsSetupLoader::readElement(QXmlStreamReader &reader) const
return mVariant;
}
bool SettingsSetupLoader::readCategoryInclude(QXmlStreamReader &reader, SettingsCategory &category) const
bool SettingsSetupLoader::readCategoryInclude(QXmlStreamReader &reader, Category &category) const
{
return readInclude(reader, [this, &category](QXmlStreamReader &reader){
category = readCategory(reader);
}, QStringLiteral("Category"));
}
bool SettingsSetupLoader::readSectionInclude(QXmlStreamReader &reader, SettingsSection &section) const
bool SettingsSetupLoader::readSectionInclude(QXmlStreamReader &reader, Section &section) const
{
return readInclude(reader, [this, &section](QXmlStreamReader &reader){
section = readSection(reader);
}, QStringLiteral("Section"));
}
bool SettingsSetupLoader::readGroupInclude(QXmlStreamReader &reader, SettingsGroup &group) const
bool SettingsSetupLoader::readGroupInclude(QXmlStreamReader &reader, Group &group) const
{
return readInclude(reader, [this, &group](QXmlStreamReader &reader){
group = readGroup(reader);
}, QStringLiteral("Group"));
}
bool SettingsSetupLoader::readEntryInclude(QXmlStreamReader &reader, SettingsEntry &entry) const
bool SettingsSetupLoader::readEntryInclude(QXmlStreamReader &reader, Entry &entry) const
{
return readInclude(reader, [this, &entry](QXmlStreamReader &reader){
entry = readEntry(reader);
@ -404,7 +409,7 @@ bool SettingsSetupLoader::readInclude(QXmlStreamReader &reader, const std::funct
}
}
void SettingsSetupLoader::clearSetup(SettingsSetup &setup, const QString &frontend, const QStringList &selectors) const
void SettingsSetupLoader::clearSetup(Setup &setup, const QString &frontend, const QStringList &selectors) const
{
for(auto it = setup.categories.begin(); it != setup.categories.end();) {
if(isUsable(*it, frontend, selectors)) {
@ -415,7 +420,7 @@ void SettingsSetupLoader::clearSetup(SettingsSetup &setup, const QString &fronte
}
}
void SettingsSetupLoader::clearCategory(SettingsCategory &category, const QString &frontend, const QStringList &selectors) const
void SettingsSetupLoader::clearCategory(Category &category, const QString &frontend, const QStringList &selectors) const
{
for(auto it = category.sections.begin(); it != category.sections.end();) {
if(isUsable(*it, frontend, selectors)) {
@ -426,7 +431,7 @@ void SettingsSetupLoader::clearCategory(SettingsCategory &category, const QStrin
}
}
void SettingsSetupLoader::clearSection(SettingsSection &section, const QString &frontend, const QStringList &selectors) const
void SettingsSetupLoader::clearSection(Section &section, const QString &frontend, const QStringList &selectors) const
{
for(auto it = section.groups.begin(); it != section.groups.end();) {
if(isUsable(*it, frontend, selectors)) {
@ -437,7 +442,7 @@ void SettingsSetupLoader::clearSection(SettingsSection &section, const QString &
}
}
void SettingsSetupLoader::clearGroup(SettingsGroup &group, const QString &frontend, const QStringList &selectors) const
void SettingsSetupLoader::clearGroup(Group &group, const QString &frontend, const QStringList &selectors) const
{
for(auto it = group.entries.begin(); it != group.entries.end();) {
if(isUsable(*it, frontend, selectors))

52
src/mvvmsettingscore/settingssetuploader_p.h

@ -14,7 +14,7 @@
namespace QtMvvm {
class SettingsSetupLoader : public QObject, public ISettingsSetupLoader
class Q_MVVMSETTINGSCORE_EXPORT SettingsSetupLoader : public QObject, public ISettingsSetupLoader
{
Q_OBJECT
Q_INTERFACES(QtMvvm::ISettingsSetupLoader)
@ -22,53 +22,53 @@ class SettingsSetupLoader : public QObject, public ISettingsSetupLoader
public:
Q_INVOKABLE SettingsSetupLoader(QObject *parent = nullptr);
SettingsElements::SettingsSetup loadSetup(const QString &filePath, const QString &frontend, const QFileSelector *selector) const final;
void changeDefaultIcon(const QUrl &defaultIcon) override;
SettingsElements::Setup loadSetup(const QString &filePath, const QString &frontend, const QFileSelector *selector) const final;
bool event(QEvent *event) override;
private:
static QUrl defaultIcon;
mutable QCache<QString, SettingsElements::SettingsSetup> _cache;
QUrl _defaultIcon;
mutable QCache<QString, SettingsElements::Setup> _cache;
//Functions to read the settings XML
SettingsElements::SettingsCategory readCategory(QXmlStreamReader &reader) const;
SettingsElements::SettingsCategory readDefaultCategory(QXmlStreamReader &reader) const;
void readCategoryChildren(QXmlStreamReader &reader, SettingsElements::SettingsCategory &category) const;
SettingsElements::Category readCategory(QXmlStreamReader &reader) const;
SettingsElements::Category readDefaultCategory(QXmlStreamReader &reader) const;
void readCategoryChildren(QXmlStreamReader &reader, SettingsElements::Category &category) const;
SettingsElements::SettingsSection readSection(QXmlStreamReader &reader) const;
SettingsElements::SettingsSection readDefaultSection(QXmlStreamReader &reader) const;
void readSectionChildren(QXmlStreamReader &reader, SettingsElements::SettingsSection &section) const;
SettingsElements::Section readSection(QXmlStreamReader &reader) const;
SettingsElements::Section readDefaultSection(QXmlStreamReader &reader) const;
void readSectionChildren(QXmlStreamReader &reader, SettingsElements::Section &section) const;
SettingsElements::SettingsGroup readGroup(QXmlStreamReader &reader) const;
SettingsElements::SettingsGroup readDefaultGroup(QXmlStreamReader &reader) const;
void readGroupChildren(QXmlStreamReader &reader, SettingsElements::SettingsGroup &group) const;
SettingsElements::Group readGroup(QXmlStreamReader &reader) const;
SettingsElements::Group readDefaultGroup(QXmlStreamReader &reader) const;
void readGroupChildren(QXmlStreamReader &reader, SettingsElements::Group &group) const;
SettingsElements::SettingsEntry readEntry(QXmlStreamReader &reader) const;
SettingsElements::Entry readEntry(QXmlStreamReader &reader) const;
SettingsElements::SettingsCategory createDefaultCategory() const;
SettingsElements::SettingsSection createDefaultSection() const;
SettingsElements::Category createDefaultCategory() const;
SettingsElements::Section createDefaultSection() const;
std::tuple<QString, QVariant> readProperty(QXmlStreamReader &reader) const;
QVariant readElement(QXmlStreamReader &reader) const;
//Functions to read included files
bool readCategoryInclude(QXmlStreamReader &reader, SettingsElements::SettingsCategory &category) const;
bool readSectionInclude(QXmlStreamReader &reader, SettingsElements::SettingsSection &section) const;
bool readGroupInclude(QXmlStreamReader &reader, SettingsElements::SettingsGroup &group) const;
bool readEntryInclude(QXmlStreamReader &reader, SettingsElements::SettingsEntry &entry) const;
bool readCategoryInclude(QXmlStreamReader &reader, SettingsElements::Category &category) const;
bool readSectionInclude(QXmlStreamReader &reader, SettingsElements::Section &section) const;
bool readGroupInclude(QXmlStreamReader &reader, SettingsElements::Group &group) const;
bool readEntryInclude(QXmlStreamReader &reader, SettingsElements::Entry &entry) const;
bool readInclude(QXmlStreamReader &reader, const std::function<void(QXmlStreamReader&)> &readFn, const QString &typeName) const;
//Functions to filter the elements
void clearSetup(SettingsElements::SettingsSetup &setup, const QString &frontend, const QStringList &selectors) const;
void clearCategory(SettingsElements::SettingsCategory &category, const QString &frontend, const QStringList &selectors) const;
void clearSection(SettingsElements::SettingsSection &section, const QString &frontend, const QStringList &selectors) const;
void clearGroup(SettingsElements::SettingsGroup &group, const QString &frontend, const QStringList &selectors) const;
void clearSetup(SettingsElements::Setup &setup, const QString &frontend, const QStringList &selectors) const;
void clearCategory(SettingsElements::Category &category, const QString &frontend, const QStringList &selectors) const;
void clearSection(SettingsElements::Section &section, const QString &frontend, const QStringList &selectors) const;
void clearGroup(SettingsElements::Group &group, const QString &frontend, const QStringList &selectors) const;
template <typename T>
bool isUsable(const T &configElement, const QString &frontend, const QStringList &selectors) const;
};
class SettingsXmlException : public SettingsLoaderException
class Q_MVVMSETTINGSCORE_EXPORT SettingsXmlException : public SettingsLoaderException
{
public:
SettingsXmlException(const QXmlStreamReader &reader);

7
src/mvvmsettingscore/settingsviewmodel.cpp

@ -46,7 +46,7 @@ ISettingsSetupLoader *SettingsViewModel::settingsSetupLoader() const
return d->setupLoader;
}
SettingsElements::SettingsSetup SettingsViewModel::loadSetup(const QString &frontend) const
SettingsElements::Setup SettingsViewModel::loadSetup(const QString &frontend) const
{
try {
QFileSelector selector;
@ -80,7 +80,8 @@ void SettingsViewModel::resetValue(const QString &key)
void SettingsViewModel::callAction(const QString &entryId, const QVariantMap &parameters)
{
Q_UNUSED(parameters)
logWarning() << "Unknown action requested with entry id:" << entryId;
logWarning() << "Unknown action requested with entry id" << entryId
<< "and parameters" << parameters;
}
void SettingsViewModel::setSettingsSetupLoader(ISettingsSetupLoader *settingsSetupLoader)
@ -102,4 +103,6 @@ void SettingsViewModel::onInit(const QVariantHash &params)
d->setupFile = params.value(paramSetupFile).toString();
if(d->setupFile.isEmpty())
d->setupFile = QStringLiteral(":/etc/settings.xml");
emit beginLoadSetup();
}

4
src/mvvmsettingscore/settingsviewmodel.h

@ -36,7 +36,7 @@ public:
virtual QtMvvm::MessageConfig restoreConfig() const;
ISettingsSetupLoader* settingsSetupLoader() const;
SettingsElements::SettingsSetup loadSetup(const QString &frontend) const;
SettingsElements::Setup loadSetup(const QString &frontend) const;
QSettings *settings() const;
@ -52,6 +52,8 @@ public Q_SLOTS:
Q_SIGNALS:
void settingsSetupLoaderChanged(QtMvvm::ISettingsSetupLoader* settingsSetupLoader);
void beginLoadSetup();
protected:
void onInit(const QVariantHash &params) override;

2
src/mvvmsettingscore/settingsviewmodel_p.h

@ -14,7 +14,7 @@ public:
QSettings *settings = nullptr;
QString setupFile;
SettingsElements::SettingsSetup currentSetup;
SettingsElements::Setup currentSetup;
};
}

0
src/mvvmsettingscore/translations/qtmvvsettingsmcore_de.ts → src/mvvmsettingscore/translations/qtmvvmsettingscore_de.ts

0
src/mvvmsettingscore/translations/qtmvvsettingsmcore_template.ts → src/mvvmsettingscore/translations/qtmvvmsettingscore_template.ts

39
src/mvvmsettingswidgets/mvvmsettingswidgets.pro

@ -0,0 +1,39 @@
TARGET = QtMvvmSettingsWidgets
QT = core gui mvvmsettingscore mvvmwidgets mvvmcore-private
HEADERS += qtmvvmsettingswidgets_global.h \
settingsdialog.h \
settingsdialog_p.h
SOURCES += \
settingsdialog.cpp
TRANSLATIONS += \
translations/qtmvvmsettingswidgets_de.ts \
translations/qtmvvmsettingswidgets_template.ts
DISTFILES += $$TRANSLATIONS
qpmx_ts_target.path = $$[QT_INSTALL_TRANSLATIONS]
qpmx_ts_target.depends += lrelease
load(qt_module)
win32 {
QMAKE_TARGET_PRODUCT = "$$TARGET"
QMAKE_TARGET_COMPANY = "Skycoder42"
QMAKE_TARGET_COPYRIGHT = "Felix Barz"
} else:mac {
QMAKE_TARGET_BUNDLE_PREFIX = "com.skycoder42."
}
!ReleaseBuild:!DebugBuild:!system(qpmx -d $$shell_quote($$_PRO_FILE_PWD_) --qmake-run init $$QPMX_EXTRA_OPTIONS $$shell_quote($$QMAKE_QMAKE) $$shell_quote($$OUT_PWD)): error(qpmx initialization failed. Check the compilation log for details.)
else: include($$OUT_PWD/qpmx_generated.pri)
qpmx_ts_target.files -= $$OUT_PWD/$$QPMX_WORKINGDIR/qtmvvmsettingswidgets_template.qm
qpmx_ts_target.files += translations/qtmvvmsettingswidgets_template.ts
FORMS += \
settingsdialog.ui

14
src/mvvmsettingswidgets/qpmx.json

@ -0,0 +1,14 @@
{
"dependencies": [],
"license": {
"file": "",
"name": ""
},
"prcFile": "",
"priFile": "",
"priIncludes": [
],
"publishers": {
},
"source": false
}

12
src/mvvmsettingswidgets/qtmvvmsettingswidgets_global.h

@ -0,0 +1,12 @@
#ifndef QTMVVMSETTINGSWIDGETS_GLOBAL_H
#define QTMVVMSETTINGSWIDGETS_GLOBAL_H
#include <QtCore/qglobal.h>
#if defined(QT_BUILD_MVVMSETTINGSWIDGETS_LIB)
# define Q_MVVMSETTINGSWIDGETS_EXPORT Q_DECL_EXPORT
#else
# define Q_MVVMSETTINGSWIDGETS_EXPORT Q_DECL_IMPORT
#endif
#endif // QTMVVMSETTINGSWIDGETS_GLOBAL_H

477
src/mvvmsettingswidgets/settingsdialog.cpp

@ -0,0 +1,477 @@
#include "settingsdialog.h"
#include "settingsdialog_p.h"
#include "ui_settingsdialog.h"
#include <QtCore/QMetaProperty>
#include <QtCore/QRegularExpression>
#include <QtMvvmCore/CoreApp>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QScrollArea>
#include <QtMvvmWidgets/WidgetsPresenter>
#include <QtMvvmWidgets/InputWidgetFactory>
#include <QtMvvmCore/private/qtmvvm_logging_p.h>
using namespace QtMvvm;
SettingsDialog::SettingsDialog(ViewModel *viewModel, QWidget *parent) :
QDialog(parent),
d(new SettingsDialogPrivate(this, viewModel))
{
d->ui->setupUi(this);
//TODO ???
// d->ui->buttonBox->button(QDialogButtonBox::Ok)->setAutoDefault(false);
// d->ui->buttonBox->button(QDialogButtonBox::Cancel)->setAutoDefault(false);
// d->ui->buttonBox->button(QDialogButtonBox::Apply)->setAutoDefault(false);
// d->ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)->setAutoDefault(false);
// d->ui->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
connect(d->ui->buttonBox, &QDialogButtonBox::clicked,
d, &SettingsDialogPrivate::buttonBoxClicked);
connect(d->ui->filterLineEdit, &QLineEdit::textChanged,
d, &SettingsDialogPrivate::filterTextChanged);
if(parentWidget()) {
setWindowModality(Qt::WindowModal);
setWindowFlags(Qt::Sheet | Qt::WindowCloseButtonHint | Qt::WindowContextHelpButtonHint);
} else {
setWindowModality(Qt::ApplicationModal);
setWindowFlags(Qt::Dialog | Qt::WindowCloseButtonHint | Qt::WindowContextHelpButtonHint);
}
#ifdef Q_OS_OSX
auto font = d->ui->titleLabel->font();
font.setPointSize(16);
d->ui->titleLabel->setFont(font);
#endif
int listSpacing = d->calcSpacing(Qt::Vertical);
d->delegate = new CategoryItemDelegate(std::bind(&SettingsDialogPrivate::updateWidth, d, std::placeholders::_1),
d->ui->categoryListWidget->iconSize(),
qMax(qRound(listSpacing * (2./3.)), 1),
this);
d->ui->categoryListWidget->setItemDelegate(d->delegate);
d->ui->categoryListWidget->setSpacing(qMax(qRound(listSpacing / 3.), 1) - 1);
int spacing = d->calcSpacing(Qt::Horizontal);
d->ui->contentLayout->setSpacing(spacing);
d->ui->categoryLineSpacer->changeSize(spacing,
0,
QSizePolicy::Fixed,
QSizePolicy::Fixed);
connect(d->viewModel, &SettingsViewModel::beginLoadSetup,
d, &SettingsDialogPrivate::createUi);
}
SettingsDialog::~SettingsDialog() {}
QString SettingsDialog::labelFilterStyleSheet() const
{
return QStringLiteral("QLabel {"
" background-color: rgba(19,232,51,0.4);"
" border: 1px solid rgba(19,196,45,0.8);"
" border-radius: 4px;"
"}");
}
QUrl SettingsDialog::iconOverwrite() const
{
return QStringLiteral("qrc:/qtmvvm/icons/settings.ico");
}
// ------------- Private Implementation -------------
const QString SettingsDialogPrivate::TabContentId(QStringLiteral("__qtmvvm_settings_widgets_tab_content"));
SettingsDialogPrivate::SettingsDialogPrivate(SettingsDialog *q_ptr, ViewModel *viewModel) :
QObject(q_ptr),
q(q_ptr),
viewModel(static_cast<SettingsViewModel*>(viewModel)),
ui(new Ui::SettingsDialog()),
delegate(nullptr),
maxWidthBase(0),
entryMap(),
changedEntries()
{}
SettingsDialogPrivate::~SettingsDialogPrivate() {}
void SettingsDialogPrivate::createUi()
{
auto icoUrl = q->iconOverwrite();
if(icoUrl.isValid())
viewModel->settingsSetupLoader()->changeDefaultIcon(icoUrl);
auto setup = viewModel->loadSetup(QStringLiteral("widgets"));
ui->filterLineEdit->setVisible(setup.allowSearch);
ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)->setVisible(setup.allowRestore && viewModel->canRestoreDefaults());
for(auto category : setup.categories)
createCategory(category);
resetListSize();
ui->categoryListWidget->setCurrentRow(0);
}
void SettingsDialogPrivate::createCategory(const SettingsElements::Category &category)
{
auto item = new QListWidgetItem();
item->setText(category.title);
item->setIcon(loadIcon(category.icon));
item->setToolTip(category.tooltip.isNull() ? category.title : category.tooltip);
item->setWhatsThis(item->toolTip());
auto tab = new QTabWidget(ui->contentStackWidget);
tab->setTabBarAutoHide(true);
ui->contentStackWidget->addWidget(tab);
ui->categoryListWidget->addItem(item);
for(auto section : category.sections)
createSection(section, tab);
}
void SettingsDialogPrivate::createSection(const SettingsElements::Section &section, QTabWidget *tabWidget)
{
auto scrollArea = new QScrollArea(tabWidget);
scrollArea->setWidgetResizable(true);
scrollArea->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
scrollArea->setAutoFillBackground(true);
auto pal = scrollArea->palette();
pal.setColor(QPalette::Window, tabWidget->palette().color(QPalette::Base));
scrollArea->setPalette(pal);
scrollArea->setFrameShape(QFrame::NoFrame);
auto scrollContent = new QWidget(scrollArea);
scrollContent->setObjectName(TabContentId);
auto layout = new QFormLayout(scrollContent);
scrollContent->setLayout(layout);
scrollArea->setWidget(scrollContent);
auto index = tabWidget->addTab(scrollArea, loadIcon(section.icon), section.title);
auto tooltip = section.tooltip.isNull() ? section.title : section.tooltip;
tabWidget->tabBar()->setTabToolTip(index, tooltip);
tabWidget->tabBar()->setTabWhatsThis(index, tooltip);
for(auto group : section.groups)
createGroup(group, scrollContent, layout);
}
void SettingsDialogPrivate::createGroup(const SettingsElements::Group &group, QWidget *contentWidget, QFormLayout *layout)
{
QWidget *sectionWidget = nullptr;
QFormLayout *sectionLayout = nullptr;
if(group.title.isNull()) {
sectionWidget = contentWidget;
sectionLayout = layout;
} else {
auto groupBox = new QGroupBox(group.title, contentWidget);
groupBox->setToolTip(group.tooltip.isNull() ? group.title : group.tooltip);
layout->addRow(groupBox);
sectionWidget = groupBox;
sectionLayout = new QFormLayout(groupBox);
groupBox->setLayout(sectionLayout);
}
for(auto entry : group.entries)
createEntry(entry, sectionWidget, sectionLayout);
}
void SettingsDialogPrivate::createEntry(const SettingsElements::Entry &entry, QWidget *sectionWidget, QFormLayout *layout)
{
QWidget *content = nullptr;
if(entry.type == "action") {
auto btn = new QPushButton(sectionWidget);
for(auto it = entry.properties.constBegin(); it != entry.properties.constEnd(); it++)
btn->setProperty(qUtf8Printable(it.key()), it.value());
auto key = entry.key;
auto args = entry.properties.value(QStringLiteral("args")).toMap();
connect(btn, &QPushButton::clicked, this, [this, key, args](){
viewModel->callAction(key, args);
});
content = btn;
} else {
auto presenter = dynamic_cast<WidgetsPresenter*>(CoreApp::instance()->presenter());
if(!presenter) {
logWarning() << "Unable to convert QtMvvm::CoreApp::presenter to a QtMvvm::WidgetsPresenter - cannot create settings entry";
return;
}
auto widgetFactory = presenter->inputWidgetFactory();
content = widgetFactory->createInput(entry.type, sectionWidget, entry.properties);
if(!content) {
logWarning() << "Failed to create settings widget for type" << entry.type;
return;
}
auto property = content->metaObject()->userProperty();
property.write(content, viewModel->loadValue(entry.key, entry.defaultValue));
if(property.hasNotifySignal()) {
auto changedSlot = metaObject()->method(metaObject()->indexOfSlot("propertyChanged()"));
connect(content, property.notifySignal(),
this, changedSlot);
} else
changedEntries.insert(content);
entryMap.insert(content, {entry, property});
}
auto label = new QLabel(entry.title + tr(":"), sectionWidget);
label->setBuddy(content);
label->setToolTip(entry.tooltip.isNull() ? entry.title : entry.tooltip);
label->setWhatsThis(label->toolTip());
if(content->toolTip().isNull())
content->setToolTip(label->toolTip());
if(content->whatsThis().isNull())
content->setWhatsThis(label->toolTip());
layout->addRow(label, content);
}
void SettingsDialogPrivate::saveValues()
{
for(auto it = changedEntries.begin(); it != changedEntries.end();) {
auto widget = *it;
auto info = entryMap.value(widget);
viewModel->saveValue(info.first.key, info.second.read(widget));
if(info.second.hasNotifySignal())
it = changedEntries.erase(it);
else
it++;
}
}
void SettingsDialogPrivate::restoreValues()
{
for(auto info : entryMap)
viewModel->resetValue(info.first.key);
}
int SettingsDialogPrivate::calcSpacing(Qt::Orientation orientation)
{
auto baseSize = q->style()->pixelMetric(orientation == Qt::Horizontal ?
QStyle::PM_LayoutHorizontalSpacing :
QStyle::PM_LayoutVerticalSpacing);
if(baseSize < 0)
baseSize = q->style()->layoutSpacing(QSizePolicy::DefaultType, QSizePolicy::DefaultType, orientation);
if(baseSize < 0) {
#ifdef Q_OS_OSX
baseSize = 10;
#else
baseSize = 6;
#endif
}
return baseSize;
}
void SettingsDialogPrivate::updateWidth(int width)
{
if(width > maxWidthBase) {
maxWidthBase = width;
QStyle *style = ui->categoryListWidget->style();
width += style->pixelMetric(QStyle::PM_ScrollBarExtent);
width += style->pixelMetric(QStyle::PM_LayoutHorizontalSpacing);
ui->categoryListWidget->setFixedWidth(width);
}
}
void SettingsDialogPrivate::resetListSize()
{
int max = ui->categoryListWidget->count();
if(max <= 1) {
ui->categoryContentWidget->hide();
q->resize(q->width() - ui->categoryContentWidget->sizeHint().width(), q->height());
} else {
auto width = ui->categoryListWidget->sizeHint().width();
ui->categoryListWidget->setFixedWidth(width);
maxWidthBase = width;
}
}
QIcon SettingsDialogPrivate::loadIcon(const QUrl &icon)
{
if(icon.scheme() == QStringLiteral("qrc"))
return QIcon(QLatin1Char(':') + icon.path());
else
return QIcon(icon.toLocalFile());
}
void SettingsDialogPrivate::searchInDialog(const QRegularExpression &regex)
{
for(int i = 0, max = ui->categoryListWidget->count(); i < max; ++i) {
auto item = ui->categoryListWidget->item(i);
auto tab = qobject_cast<QTabWidget*>(ui->contentStackWidget->widget(i));
if(!tab)
continue;
if(searchInCategory(regex, tab) ||
regex.match(item->text()).hasMatch()) {
item->setHidden(false);
if(ui->categoryListWidget->currentRow() == -1)
ui->categoryListWidget->setCurrentRow(i);
} else {
item->setHidden(true);
if(ui->categoryListWidget->currentRow() == i) {
auto found = false;
for(int j = 0; j < max; j++) {
if(!ui->categoryListWidget->item(j)->isHidden()){
ui->categoryListWidget->setCurrentRow(j);
found = true;
break;
}
}
if(!found) {
ui->categoryListWidget->setCurrentRow(-1);
ui->contentStackWidget->setCurrentIndex(max);
}
}
}
}
}
bool SettingsDialogPrivate::searchInCategory(const QRegularExpression &regex, QTabWidget *tab)
{
auto someFound = false;
for(int i = 0, max = tab->count(); i < max; ++i) {
if(searchInSection(regex, tab->widget(i)->findChild<QWidget*>(TabContentId)) ||
regex.match(tab->tabText(i)).hasMatch()){
tab->setTabEnabled(i, true);
someFound = true;
} else
tab->setTabEnabled(i, false);
}
return someFound;
}
bool SettingsDialogPrivate::searchInSection(const QRegularExpression &regex, QWidget *contentWidget)
{
auto layout = qobject_cast<QFormLayout*>(contentWidget->layout());
if(!layout)
return false;
auto someFound = false;
for(int i = 0, max = layout->rowCount(); i < max; ++i) {
auto spanItem = layout->itemAt(i, QFormLayout::SpanningRole);
if(spanItem) {
auto group = qobject_cast<QGroupBox*>(spanItem->widget());
if(!group)
continue;
someFound |= searchInGroup(regex, group) ||
regex.match(group->title()).hasMatch();
} else {
auto label = qobject_cast<QLabel*>(layout->itemAt(i, QFormLayout::LabelRole)->widget());
if(!label)
continue;
auto content = layout->itemAt(i, QFormLayout::FieldRole)->widget();
someFound |= searchInEntry(regex, label, content);
}
}
return someFound;
}
bool SettingsDialogPrivate::searchInGroup(const QRegularExpression &regex, QGroupBox *groupWidget)
{
auto layout = qobject_cast<QFormLayout*>(groupWidget->layout());
if(!layout)
return false;
auto someFound = false;
for(int i = 0, max = layout->rowCount(); i < max; ++i) {
auto label = qobject_cast<QLabel*>(layout->itemAt(i, QFormLayout::LabelRole)->widget());
if(!label)
continue;
auto content = layout->itemAt(i, QFormLayout::FieldRole)->widget();
someFound |= searchInEntry(regex, label, content);
}
return someFound;
}
bool SettingsDialogPrivate::searchInEntry(const QRegularExpression &regex, QLabel *label, QWidget *content)
{
if(regex.pattern().isEmpty()) {
label->setStyleSheet(QString());
return false;
}
auto keys = entryMap.value(content).first.searchKeys;
keys.append(label->text());
for(auto key : keys) {
if(regex.match(key).hasMatch()) {
label->setStyleSheet(q->labelFilterStyleSheet());
return true;
}
}
label->setStyleSheet(QString());
return false;
}
void SettingsDialogPrivate::propertyChanged()
{
auto widget = qobject_cast<QWidget*>(sender());
if(widget)
changedEntries.insert(widget);
}
void SettingsDialogPrivate::buttonBoxClicked(QAbstractButton *button)
{
switch(ui->buttonBox->standardButton(button)) {
case QDialogButtonBox::Ok:
saveValues();
q->accept();
break;
case QDialogButtonBox::Cancel:
q->reject();
break;
case QDialogButtonBox::Apply:
saveValues();
break;
case QDialogButtonBox::RestoreDefaults:
if(viewModel->canRestoreDefaults()) {
auto result = CoreApp::showDialog(viewModel->restoreConfig());
connect(result, &MessageResult::dialogDone, this, [this](MessageConfig::StandardButton result) {
if(result == MessageConfig::Yes) {
restoreValues();
q->accept();
}
});
}
break;
default:
Q_UNREACHABLE();
}
}
void SettingsDialogPrivate::filterTextChanged(const QString &searchText)
{
searchInDialog(QRegularExpression {
searchText,
QRegularExpression::CaseInsensitiveOption |
QRegularExpression::DontCaptureOption |
QRegularExpression::UseUnicodePropertiesOption
});
}
CategoryItemDelegate::CategoryItemDelegate(std::function<void (int)> updateFunc, const QSize &iconSize, int layoutSpacing, QObject *parent) :
QStyledItemDelegate(parent),
_iconSize(),
_updateFunc(updateFunc)
{
this->_iconSize = iconSize + QSize(0, layoutSpacing);
}
QSize CategoryItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QSize size = QStyledItemDelegate::sizeHint(option, index);
_updateFunc(size.width());
return size.expandedTo(_iconSize);
}

34
src/mvvmsettingswidgets/settingsdialog.h

@ -0,0 +1,34 @@
#ifndef QTMVVM_SETTINGSDIALOG_H
#define QTMVVM_SETTINGSDIALOG_H
#include <QtCore/qscopedpointer.h>
#include <QtMvvmSettingsCore/settingsviewmodel.h>
#include <QtWidgets/qdialog.h>
#include "QtMvvmSettingsWidgets/qtmvvmsettingswidgets_global.h"
namespace QtMvvm {
class SettingsDialogPrivate;
class Q_MVVMSETTINGSWIDGETS_EXPORT SettingsDialog : public QDialog
{
Q_OBJECT
public:
Q_INVOKABLE explicit SettingsDialog(QtMvvm::ViewModel *viewModel, QWidget *parent = nullptr);
~SettingsDialog();
protected:
virtual QString labelFilterStyleSheet() const;
virtual QUrl iconOverwrite() const;
private:
friend class QtMvvm::SettingsDialogPrivate;
SettingsDialogPrivate *d;
};
}
#endif // QTMVVM_SETTINGSDIALOG_H

232
src/mvvmsettingswidgets/settingsdialog.ui

@ -0,0 +1,232 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SettingsDialog</class>
<widget class="QDialog" name="SettingsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>850</width>
<height>500</height>
</rect>
</property>
<property name="windowTitle">
<string>Settings</string>
</property>
<property name="sizeGripEnabled">
<bool>true</bool>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QHBoxLayout" name="settingsRootLayout" stretch="0,1">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="QWidget" name="categoryContentWidget" native="true">
<layout class="QHBoxLayout" name="categoryLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QListWidget" name="categoryListWidget">
<property name="palette">
<palette>
<active>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="0">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="0">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>240</red>
<green>240</green>
<blue>240</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAsNeeded</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
<property name="resizeMode">
<enum>QListView::Adjust</enum>
</property>
<property name="spacing">
<number>1</number>
</property>
</widget>
</item>
<item>
<widget class="Line" name="listSeperatorLine">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<spacer name="categoryLineSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>6</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="contentLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="rightMargin">
<number>2</number>
</property>
<item>
<widget class="QLabel" name="titleLabel">
<property name="font">
<font>
<pointsize>10</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="indent">
<number>4</number>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="filterLineEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
<property name="placeholderText">
<string>Search in settings…</string>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QStackedWidget" name="contentStackWidget"/>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::RestoreDefaults</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>categoryListWidget</sender>
<signal>currentRowChanged(int)</signal>
<receiver>contentStackWidget</receiver>
<slot>setCurrentIndex(int)</slot>
<hints>
<hint type="sourcelabel">
<x>123</x>
<y>172</y>
</hint>
<hint type="destinationlabel">
<x>488</x>
<y>189</y>
</hint>
</hints>
</connection>
<connection>
<sender>categoryListWidget</sender>
<signal>currentTextChanged(QString)</signal>
<receiver>titleLabel</receiver>
<slot>setText(QString)</slot>
<hints>
<hint type="sourcelabel">
<x>156</x>
<y>42</y>
</hint>
<hint type="destinationlabel">
<x>466</x>
<y>16</y>
</hint>
</hints>
</connection>
</connections>
</ui>

89
src/mvvmsettingswidgets/settingsdialog_p.h

@ -0,0 +1,89 @@
#ifndef QTMVVM_SETTINGSDIALOG_P_H
#define QTMVVM_SETTINGSDIALOG_P_H
#include <functional>
#include <QtCore/QSet>
#include <QtWidgets/QStyledItemDelegate>
#include <QtWidgets/QFormLayout>
#include <QtWidgets/QGroupBox>
#include <QtWidgets/QLabel>
#include <QtWidgets/QTabWidget>
#include <QtWidgets/QAbstractButton>
#include "qtmvvmsettingswidgets_global.h"
#include "settingsdialog.h"
namespace Ui {
class SettingsDialog;
}
namespace QtMvvm {
class CategoryItemDelegate : public QStyledItemDelegate
{
public:
CategoryItemDelegate(std::function<void(int)> _updateFunc,
const QSize &_iconSize,
int layoutSpacing,
QObject *parent = nullptr);
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
private:
QSize _iconSize;
std::function<void(int)> _updateFunc;
};
class SettingsDialogPrivate : public QObject
{
Q_OBJECT
public:
SettingsDialogPrivate(SettingsDialog *q_ptr, ViewModel *viewModel);
~SettingsDialogPrivate();
static const QString TabContentId;
SettingsDialog *q;
SettingsViewModel *viewModel;
QScopedPointer<Ui::SettingsDialog> ui;
CategoryItemDelegate *delegate;
int maxWidthBase;
typedef QPair<SettingsElements::Entry, QMetaProperty> EntryInfo;
QHash<QWidget*, EntryInfo> entryMap;
QSet<QWidget*> changedEntries;
void createCategory(const SettingsElements::Category &category);
void createSection(const SettingsElements::Section &section, QTabWidget *tabWidget);
void createGroup(const SettingsElements::Group &group, QWidget *contentWidget, QFormLayout *layout);
void createEntry(const SettingsElements::Entry &entry, QWidget *sectionWidget, QFormLayout *layout);
void saveValues();
void restoreValues();
int calcSpacing(Qt::Orientation orientation);
void updateWidth(int width);
void resetListSize();
QIcon loadIcon(const QUrl &icon);
void searchInDialog(const QRegularExpression &regex);
bool searchInCategory(const QRegularExpression &regex, QTabWidget *tab);
bool searchInSection(const QRegularExpression &regex, QWidget *contentWidget);
bool searchInGroup(const QRegularExpression &regex, QGroupBox *groupWidget);
bool searchInEntry(const QRegularExpression &regex, QLabel *label, QWidget *content);
public Q_SLOTS:
void createUi();
void propertyChanged();
void buttonBoxClicked(QAbstractButton *button);
void filterTextChanged(const QString &searchText);
};
}
#endif // QTMVVM_SETTINGSDIALOG_P_H

4
src/mvvmwidgets/widgetspresenter.cpp

@ -58,9 +58,9 @@ void WidgetsPresenter::present(ViewModel *viewModel, const QVariantHash &params,
auto view = qobject_cast<QWidget*>(viewMetaObject->newInstance(Q_ARG(QtMvvm::ViewModel*, viewModel),
Q_ARG(QWidget*, parentView)));
if(!view) {
throw PresenterException(QByteArrayLiteral("Failed to create view of type") +
throw PresenterException(QByteArrayLiteral("Failed to create view of type \"") +
viewMetaObject->className() +
QByteArrayLiteral("(did you mark the constructor as Q_INVOKABLE? "
QByteArrayLiteral("\" (did you mark the constructor as Q_INVOKABLE? "
"Required signature: \"Q_INVOKABLE Contructor(QtMvvm::ViewModel *, QWidget*);\")"));
}

3
src/src.pro

@ -5,7 +5,8 @@ SUBDIRS += mvvmcore \
mvvmwidgets \
mvvmquick \
imports \
mvvmsettingscore
mvvmsettingscore \
mvvmsettingswidgets
prepareRecursiveTarget(lrelease)
QMAKE_EXTRA_TARGETS += lrelease

3
sync.profile

@ -2,7 +2,8 @@
"QtMvvmCore" => "$basedir/src/mvvmcore",
"QtMvvmWidgets" => "$basedir/src/mvvmwidgets",
"QtMvvmQuick" => "$basedir/src/mvvmquick",
"QtMvvmSettingsCore" => "$basedir/src/mvvmsettingscore"
"QtMvvmSettingsCore" => "$basedir/src/mvvmsettingscore",
"QtMvvmSettingsWidgets" => "$basedir/src/mvvmsettingswidgets"
);
# Force generation of camel case headers for classes inside QtDataSync namespaces

Loading…
Cancel
Save