Browse Source

implemented quick settings ui

list input still buggy, no list delegate
pull/2/head
Skycoder42 7 years ago
parent
commit
1fd68c9adf
  1. 28
      src/imports/mvvmquick/ListSection.qml
  2. 26
      src/imports/mvvmquick/OverviewListView.qml
  3. 12
      src/imports/mvvmquick/QtMvvmApp.qml
  4. 19
      src/imports/mvvmquick/SectionListView.qml
  5. 80
      src/imports/mvvmquick/SettingsView.qml
  6. 4
      src/imports/mvvmquick/icons/ic_arrow_back_white_24px.svg
  7. 53
      src/imports/mvvmquick/multifilterproxymodel.cpp
  8. 33
      src/imports/mvvmquick/multifilterproxymodel.h
  9. 12
      src/imports/mvvmquick/mvvmquick.pro
  10. 58
      src/imports/mvvmquick/plugins.qmltypes
  11. 10
      src/imports/mvvmquick/qqmlquickpresenter.cpp
  12. 1
      src/imports/mvvmquick/qqmlquickpresenter.h
  13. 3
      src/imports/mvvmquick/qtmvvmquick_plugin.cpp
  14. 1
      src/imports/mvvmquick/qtmvvmquick_plugin.qrc
  15. 116
      src/imports/mvvmquick/settingsentrymodel.cpp
  16. 58
      src/imports/mvvmquick/settingsentrymodel.h
  17. 112
      src/imports/mvvmquick/settingssectionmodel.cpp
  18. 55
      src/imports/mvvmquick/settingssectionmodel.h
  19. 125
      src/imports/mvvmquick/settingsuibuilder.cpp
  20. 71
      src/imports/mvvmquick/settingsuibuilder.h
  21. 6
      src/mvvmcore/settingssetup.h
  22. 2
      src/mvvmquick/ListEdit.qml
  23. 4
      src/mvvmquick/MsgDelegate.qml

28
src/imports/mvvmquick/ListSection.qml

@ -1,14 +1,10 @@
import QtQuick 2.8
import QtQuick.Controls 2.1
import de.skycoder42.quickextras 2.0
import QtQuick 2.10
import QtQuick.Controls 2.3
import de.skycoder42.QtMvvm.Quick 1.0
Label {
property string title
CommonStyle {
id: style
}
width: parent.width
font.bold: true
font.capitalization: Font.SmallCaps
@ -18,14 +14,28 @@ Label {
background: Rectangle {
anchors.fill: parent
color: style.sBackground
color: {
if(QuickPresenter.currentStyle === "Material")
return Material.background;
else if(QuickPresenter.currentStyle === "Universal")
return Universal.background;
else
return "white";
}
Rectangle {
anchors.left: parent.left
anchors.bottom: parent.bottom
anchors.right: parent.right
height: 2
color: style.accent
color: {
if(QuickPresenter.currentStyle === "Material")
return Material.accent;
else if(QuickPresenter.currentStyle === "Universal")
return Universal.accent;
else
return "black";
}
}
}
}

26
src/imports/mvvmquick/OverviewListView.qml

@ -1,12 +1,13 @@
import QtQuick 2.8
import QtQuick.Controls 2.1
import QtQuick 2.10
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.3
import de.skycoder42.quickextras 2.0
import de.skycoder42.QtMvvm.Quick 1.0
ListView {
id: listView
id: _sectionListView
property bool showSections: true
property SettingsUiBuilder builder
section.property: showSections ? "category" : ""
section.labelPositioning: ViewSection.InlineLabels
@ -18,18 +19,7 @@ ListView {
id: delegate
width: parent.width
onClicked: builder.loadSection(settingsSection)
Timer {
id: enforcer
interval: 50
repeat: false
running: true
onTriggered: {
delegate.implicitHeight = Qt.binding(function(){return grid.implicitHeight + 32});
}
}
onClicked: builder.loadSection(section)
contentItem: GridLayout {
id: grid
@ -39,8 +29,8 @@ ListView {
TintIcon {
id: tintIcon
source: icon
visible: icon != ""
source: iconUrl
visible: iconUrl != ""
Layout.row: 0
Layout.column: 0
Layout.rowSpan: 2

12
src/imports/mvvmquick/QtMvvmApp.qml

@ -67,11 +67,8 @@ ApplicationWindow {
console.warn("No drawer like view active. Cannot toggle drawer");
}
Component.onCompleted: QuickPresenter.qmlPresenter = _root
onClosing: {
function closeAction() {
var closed = false;
if(!closed && _drawerLoader.item)
closed = _drawerLoader.item.closeAction();
if(!closed)
@ -80,7 +77,10 @@ ApplicationWindow {
closed = _rootPopup.closeAction();
if(!closed)
closed = _rootStack.closeAction();
close.accepted = !closed;
return closed;
}
Component.onCompleted: QuickPresenter.qmlPresenter = _root
onClosing: close.accepted = !closeAction();
}

19
src/imports/mvvmquick/SectionListView.qml

@ -1,9 +1,12 @@
import QtQuick 2.8
import QtQuick.Controls 2.1
import QtQuick 2.10
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.3
import de.skycoder42.QtMvvm.Quick 1.0
ListView {
id: listView
id: _listView
property SettingsUiBuilder builder
section.property: "group"
section.labelPositioning: ViewSection.InlineLabels
@ -16,6 +19,14 @@ ListView {
width: parent.width
height: item ? item.implicitHeight : 0
Component.onCompleted: loaderDelegate.setSource(delegateUrl, editProperties);
onLoaded: {
if(loaderDelegate.item && typeof loaderDelegate.item.showInput !== "undefined") {
loaderDelegate.item.showInput.connect(function(key, title, type, props){
builder.showDialog(key, title, type, props);
});
}
}
Component.onCompleted: loaderDelegate.setSource(delegateUrl, properties);
}
}

80
src/imports/mvvmquick/SettingsView.qml

@ -21,28 +21,18 @@ Page {
anchors.fill: parent
spacing: 0
ActionButton {
id: _backButton
source: "image://svg/de/skycoder42/qtmvvm/quick/icons/ic_arrow_back"
toolTip: qsTr("Go back")
onClicked: {
//TODO close settings view
//TODO remove, not needed
}
}
Item {
id: _labelContainer
Layout.fillWidth: true
Layout.minimumHeight: 56
Layout.leftMargin: 10
Label {
id: _titleLabel
font.pointSize: 16
font.bold: true
elide: Label.ElideRight
leftPadding: 10
horizontalAlignment: Qt.AlignLeft
verticalAlignment: Qt.AlignVCenter
anchors.fill: parent
@ -64,17 +54,17 @@ Page {
ActionButton {
id: _searchButton
visible: true
visible: _builder.allowSearch
toolTip: qsTr("Search in settings")
onClicked: toggleSearchState()
}
ActionButton {
id: _restoreButton
visible: true
visible: _builder.allowRestore
source: "image://svg/de/skycoder42/qtmvvm/quick/icons/ic_settings_backup_restore"
toolTip: qsTr("Restore settings")
onClicked: builder.restoreDefaults()
onClicked: _builder.restoreDefaults()
}
}
}
@ -193,28 +183,42 @@ Page {
}
}
// SettingsUiBuilder {
// id: builder
// buildView: _settingsView
// control: _settingsView.control
// filterText: _searchField.text
// onInitActions: {
// searchButton.visible = allowSearch;
// restoreButton.visible = allowSearch;
// }
// onCreateView: {
// if(isOverview) {
// _settingsStack.push("qrc:/de/skycoder42/qtmvvm/settings/quick/OverviewListView.qml", {
// "model": model,
// "showSections": showSections
// });
// } else {
// _settingsStack.push("qrc:/de/skycoder42/qtmvvm/settings/quick/SectionListView.qml", {
// "model": model
// });
// }
// }
// }
Component {
id: _overviewComponent
OverviewListView {
id: __ovListView
builder: _builder
Component.onCompleted: _settingsStack.push(__ovListView)
}
}
Component {
id: _sectionViewComponent
SectionListView {
id: __secListView
builder: _builder
Component.onCompleted: _settingsStack.push(__secListView)
}
}
SettingsUiBuilder {
id: _builder
buildView: _settingsView
viewModel: _settingsView.viewModel
filterText: _searchField.text
onPresentOverview: _overviewComponent.incubateObject(_settingsStack, {
model: model,
showSections: hasSections
}, Qt.Asynchronous)
onPresentSection: _sectionViewComponent.incubateObject(_settingsStack, {
model: model
}, Qt.Asynchronous)
onCloseSettings: QuickPresenter.popView()
}
}

4
src/imports/mvvmquick/icons/ic_arrow_back_white_24px.svg

@ -1,4 +0,0 @@
<svg fill="#FFFFFF" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
<path d="M0 0h24v24H0z" fill="none"/>
<path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/>
</svg>

Before

Width:  |  Height:  |  Size: 224 B

53
src/imports/mvvmquick/multifilterproxymodel.cpp

@ -0,0 +1,53 @@
#include "multifilterproxymodel.h"
using namespace QtMvvm;
MultiFilterProxyModel::MultiFilterProxyModel(QObject *parent) :
QSortFilterProxyModel(parent),
_filterRoles()
{}
void MultiFilterProxyModel::addFilterRole(int role)
{
_filterRoles.insert(role);
invalidateFilter();
}
void MultiFilterProxyModel::addFilterRoles(const QList<int> &roles)
{
_filterRoles.unite(QSet<int>::fromList(roles));
invalidateFilter();
}
void MultiFilterProxyModel::clearFilterRoles()
{
_filterRoles.clear();
invalidateFilter();
}
void MultiFilterProxyModel::setFilter(const QRegularExpression &regex)
{
_filterRegex = regex;
invalidateFilter();
}
bool MultiFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
if(!_filterRegex.isValid() || _filterRoles.isEmpty())
return true;
for(auto role : _filterRoles) {
auto rData = sourceModel()->data(sourceModel()->index(source_row, 0, source_parent), role);
//try as stringlist
auto strList = rData.toStringList();
for(auto str : strList) {
if(_filterRegex.match(str).hasMatch())
return true;
}
//try as string
auto str = rData.toString();
if(!str.isNull() && _filterRegex.match(str).hasMatch())
return true;
}
return false;
}

33
src/imports/mvvmquick/multifilterproxymodel.h

@ -0,0 +1,33 @@
#ifndef QTMVVM_MULTIFILTERPROXYMODEL_H
#define QTMVVM_MULTIFILTERPROXYMODEL_H
#include <QtCore/QSortFilterProxyModel>
#include <QtCore/QRegularExpression>
#include <QtCore/QSet>
namespace QtMvvm {
class MultiFilterProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
explicit MultiFilterProxyModel(QObject *parent = nullptr);
void addFilterRole(int role);
void addFilterRoles(const QList<int> &roles);
void clearFilterRoles();
void setFilter(const QRegularExpression &regex);
protected:
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
private:
QSet<int> _filterRoles;
QRegularExpression _filterRegex;
};
}
#endif // QTMVVM_MULTIFILTERPROXYMODEL_H

12
src/imports/mvvmquick/mvvmquick.pro

@ -9,12 +9,20 @@ DEFINES += "VERSION_MINOR=$$MODULE_VERSION_MINOR"
HEADERS += \
qtmvvmquick_plugin.h \
qqmlquickpresenter.h \
svgimageprovider.h
svgimageprovider.h \
settingsuibuilder.h \
settingssectionmodel.h \
multifilterproxymodel.h \
settingsentrymodel.h
SOURCES += \
qtmvvmquick_plugin.cpp \
qqmlquickpresenter.cpp \
svgimageprovider.cpp
svgimageprovider.cpp \
settingsuibuilder.cpp \
settingssectionmodel.cpp \
multifilterproxymodel.cpp \
settingsentrymodel.cpp
QML_FILES += \
QtMvvmApp.qml \

58
src/imports/mvvmquick/plugins.qmltypes

@ -87,12 +87,70 @@ Module {
Parameter { name: "inputViewFactory"; type: "InputViewFactory"; isPointer: true }
}
Method { name: "toggleDrawer" }
Method { name: "popView" }
Method {
name: "mimeTypeFilters"
type: "QStringList"
Parameter { name: "mimeTypes"; type: "QStringList" }
}
}
Component {
name: "QtMvvm::SettingsUiBuilder"
prototype: "QObject"
exports: ["de.skycoder42.QtMvvm.Quick/SettingsUiBuilder 1.0"]
exportMetaObjectRevisions: [0]
Property { name: "buildView"; type: "QQuickItem"; isPointer: true }
Property { name: "viewModel"; type: "SettingsViewModel"; isPointer: true }
Property { name: "filterText"; type: "string" }
Property { name: "allowSearch"; type: "bool" }
Property { name: "allowRestore"; type: "bool" }
Signal {
name: "presentOverview"
Parameter { name: "model"; type: "QAbstractItemModel"; isPointer: true }
Parameter { name: "hasSections"; type: "bool" }
}
Signal {
name: "presentSection"
Parameter { name: "model"; type: "QAbstractItemModel"; isPointer: true }
}
Signal { name: "closeSettings" }
Signal {
name: "buildViewChanged"
Parameter { name: "buildView"; type: "QQuickItem"; isPointer: true }
}
Signal {
name: "viewModelChanged"
Parameter { name: "viewModel"; type: "SettingsViewModel"; isPointer: true }
}
Signal {
name: "filterTextChanged"
Parameter { name: "filterText"; type: "string" }
}
Signal {
name: "allowSearchChanged"
Parameter { name: "allowSearch"; type: "bool" }
}
Signal {
name: "allowRestoreChanged"
Parameter { name: "allowRestore"; type: "bool" }
}
Method {
name: "loadSection"
Parameter { name: "section"; type: "QtMvvm::SettingsElements::Section" }
}
Method {
name: "showDialog"
Parameter { name: "key"; type: "string" }
Parameter { name: "title"; type: "string" }
Parameter { name: "type"; type: "string" }
Parameter { name: "properties"; type: "QVariantMap" }
}
Method { name: "restoreDefaults" }
Method {
name: "setFilterText"
Parameter { name: "filterText"; type: "string" }
}
}
Component {
prototype: "QObject"
name: "de.skycoder42.QtMvvm.Quick/FileDialog 1.0"

10
src/imports/mvvmquick/qqmlquickpresenter.cpp

@ -64,6 +64,16 @@ void QQmlQuickPresenter::toggleDrawer()
QMetaObject::invokeMethod(_qmlPresenter, "toggleDrawer");
}
void QQmlQuickPresenter::popView()
{
if(!_qmlPresenter) {
qmlWarning(this).space() << "No QML-Presenter registered! Unable to toggle drawer";
return;
}
QMetaObject::invokeMethod(_qmlPresenter, "closeAction");
}
void QQmlQuickPresenter::present(ViewModel *viewModel, const QVariantHash &params, const QUrl &viewUrl, QPointer<ViewModel> parent)
{
auto component = _componentCache.object(viewUrl);

1
src/imports/mvvmquick/qqmlquickpresenter.h

@ -42,6 +42,7 @@ public:
public Q_SLOTS:
void toggleDrawer();
void popView();
Q_SIGNALS:
void qmlPresenterChanged(QObject* qmlPresenter);

3
src/imports/mvvmquick/qtmvvmquick_plugin.cpp

@ -6,6 +6,7 @@
#include "qqmlquickpresenter.h"
#include "svgimageprovider.h"
#include "settingsuibuilder.h"
#ifdef Q_OS_ANDROID
#include "androidfilechooser.h"
#endif
@ -39,6 +40,8 @@ void QtMvvmQuickDeclarativeModule::registerTypes(const char *uri)
qmlRegisterUncreatableType<QtMvvm::InputViewFactory>(uri, 1, 0, "InputViewFactory", QStringLiteral("InputViewFactories can only be created from C++ via the QuickPresenter"));
qmlRegisterSingletonType<QtMvvm::QQmlQuickPresenter>(uri, 1, 0, "QuickPresenter", createQuickPresenterQmlSingleton);
qmlRegisterType<QtMvvm::SettingsUiBuilder>(uri, 1, 0, "SettingsUiBuilder");
#ifdef Q_OS_ANDROID
qmlRegisterType<QtMvvm::AndroidFileChooser>(uri, 1, 0, "FileChooser");
qmlRegisterType(QUrl(QStringLiteral("qrc:/de/skycoder42/qtmvvm/quick/qml/AndroidFileDialog.qml")), uri, 1, 0, "FileDialog");

1
src/imports/mvvmquick/qtmvvmquick_plugin.qrc

@ -4,7 +4,6 @@
<file alias="ic_help.svg">icons/ic_help_white_24px.svg</file>
<file alias="ic_info.svg">icons/ic_info_white_24px.svg</file>
<file alias="ic_warning.svg">icons/ic_warning_white_24px.svg</file>
<file alias="ic_arrow_back.svg">icons/ic_arrow_back_white_24px.svg</file>
<file alias="ic_close.svg">icons/ic_close_white_24px.svg</file>
<file alias="ic_search.svg">icons/ic_search_white_24px.svg</file>
<file alias="ic_settings_backup_restore.svg">icons/ic_settings_backup_restore_white_24px.svg</file>

116
src/imports/mvvmquick/settingsentrymodel.cpp

@ -0,0 +1,116 @@
#include "settingsentrymodel.h"
#include <QtCore/QRegularExpression>
using namespace QtMvvm;
const QList<int> SettingsEntryModel::FilterRoles {
SettingsEntryModel::GroupRole,
SettingsEntryModel::TitleRole,
SettingsEntryModel::ToolTipRole,
SettingsEntryModel::SearchKeysRole
};
SettingsEntryModel::SettingsEntryModel(QObject *parent) :
QAbstractListModel(parent),
_entries()
{}
void SettingsEntryModel::setup(const SettingsElements::Section &section, SettingsViewModel *viewModel, InputViewFactory *factory)
{
beginResetModel();
_entries.clear();
_viewModel = viewModel;
auto rIndex = 0;
for(auto group : section.groups) {
for(auto entry : group.entries) {
auto url = factory->getDelegate(entry.type, entry.properties);
if(group.title.isEmpty()) // unnamed groups are presented first
_entries.insert(rIndex++, EntryInfo{entry, url});
else
_entries.append(EntryInfo{entry, url, group});
}
}
endResetModel();
}
int SettingsEntryModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid())
return 0;
else
return _entries.size();
}
QVariant SettingsEntryModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
switch (role) {
case Qt::DisplayRole:
case TitleRole:
return _entries.value(index.row()).title;
case KeyRole:
return _entries.value(index.row()).key;
case TypeRole:
return QString::fromUtf8(_entries.value(index.row()).type);
case ToolTipRole:
return _entries.value(index.row()).tooltip;
case DelegateUrlRole:
return _entries.value(index.row()).delegateUrl;
case SettingsValueRole:
return _viewModel->loadValue(_entries.value(index.row()).key);
case PropertiesRole:
return _entries.value(index.row()).properties;
case GroupRole:
return _entries.value(index.row()).group.title;
case SearchKeysRole:
return _entries.value(index.row()).searchKeys;
default:
return QVariant();
}
}
bool SettingsEntryModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid() || role != SettingsValueRole)
return false;
_viewModel->saveValue(_entries.value(index.row()).key, value);
emit dataChanged(index, index, {SettingsValueRole});
return true;
}
QHash<int, QByteArray> SettingsEntryModel::roleNames() const
{
return {
{GroupRole, "group"},
{KeyRole, "key"},
{TypeRole, "type"},
{TitleRole, "title"},
{ToolTipRole, "tooltip"},
{DelegateUrlRole, "delegateUrl"},
{SettingsValueRole, "settingsValue"},
{PropertiesRole, "properties"}
};
}
Qt::ItemFlags SettingsEntryModel::flags(const QModelIndex &index) const
{
return QAbstractListModel::flags(index) | Qt::ItemIsEditable;
}
SettingsEntryModel::EntryInfo::EntryInfo(SettingsElements::Entry entry, const QUrl &delegateUrl, SettingsElements::Group group) :
Entry(entry),
delegateUrl(delegateUrl),
group(group)
{
static const QRegularExpression nameRegex(QStringLiteral("&(?!&)"),
QRegularExpression::DontCaptureOption |
QRegularExpression::OptimizeOnFirstUsageOption);
title.remove(nameRegex);
group.entries.clear();
}

58
src/imports/mvvmquick/settingsentrymodel.h

@ -0,0 +1,58 @@
#ifndef QTMVVM_SETTINGSENTRYMODEL_H
#define QTMVVM_SETTINGSENTRYMODEL_H
#include <QtCore/QAbstractListModel>
#include <QtMvvmCore/SettingsViewModel>
#include <QtMvvmCore/SettingsElements>
#include <QtMvvmQuick/InputViewFactory>
namespace QtMvvm {
class SettingsEntryModel : public QAbstractListModel
{
Q_OBJECT
public:
enum Roles {
GroupRole = Qt::UserRole + 1,
KeyRole,
TypeRole,
TitleRole,
ToolTipRole,
DelegateUrlRole,
SettingsValueRole,
PropertiesRole,
SearchKeysRole
};
Q_ENUM(Roles)
static const QList<int> FilterRoles;
explicit SettingsEntryModel(QObject *parent = nullptr);
void setup(const SettingsElements::Section &setup, SettingsViewModel *viewModel, InputViewFactory *factory);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
QHash<int, QByteArray> roleNames() const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
private:
struct EntryInfo : public SettingsElements::Entry {
public:
EntryInfo(SettingsElements::Entry entry = {}, const QUrl &delegateUrl = {}, SettingsElements::Group group = {});
QUrl delegateUrl;
SettingsElements::Group group;
};
SettingsViewModel *_viewModel;
QList<EntryInfo> _entries;
};
}
#endif // QTMVVM_SETTINGSENTRYMODEL_H

112
src/imports/mvvmquick/settingssectionmodel.cpp

@ -0,0 +1,112 @@
#include "settingssectionmodel.h"
#include "settingsuibuilder.h"
using namespace QtMvvm;
const QList<int> SettingsSectionModel::FilterRoles {
SettingsSectionModel::CategoryRole,
SettingsSectionModel::TitleRole,
SettingsSectionModel::ToolTipRole,
SettingsSectionModel::ExtraSearchKeysRole
};
SettingsSectionModel::SettingsSectionModel(QObject *parent) :
QAbstractListModel{parent},
_sections{},
_hasSections{false}
{}
void SettingsSectionModel::setup(const SettingsElements::Setup &setup)
{
beginResetModel();
_sections.clear();
_hasSections = false;
auto rIndex = 0;
for(auto category : setup.categories) {
if(category.sections.size() == 1) { // single sects are always at the beginning
_hasSections = true;
_sections.insert(rIndex++, category);
} else {
for(auto section : category.sections)
_sections.append(SectionInfo{section, category});
}
}
endResetModel();
}
int SettingsSectionModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid())
return 0;
else
return _sections.size();
}
QVariant SettingsSectionModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
switch (role) {
case Qt::DisplayRole:
case TitleRole:
return _sections.value(index.row()).title;
case IconRole:
return _sections.value(index.row()).icon;
case ToolTipRole:
return _sections.value(index.row()).tooltip;
case CategoryRole:
return _sections.value(index.row()).category.title;
case SectionRole:
return QVariant::fromValue<SettingsElements::Section>(_sections.value(index.row()));
case ExtraSearchKeysRole:
{
const auto &section = _sections[index.row()];
if(section.searchKeys.isEmpty()) {
for(auto group : section.groups) {
section.searchKeys.append(group.title);
for(auto entry : group.entries) {
section.searchKeys.append(entry.title);
section.searchKeys.append(entry.tooltip);
section.searchKeys.append(entry.searchKeys);
}
}
}
return section.searchKeys;
}
default:
return QVariant();
}
}
QHash<int, QByteArray> SettingsSectionModel::roleNames() const
{
return {
{CategoryRole, "category"},
{TitleRole, "title"},
{IconRole, "iconUrl"},
{ToolTipRole, "tooltip"},
{SectionRole, "section"}
};
}
bool SettingsSectionModel::hasSections() const
{
return _hasSections;
}
SettingsSectionModel::SectionInfo::SectionInfo(SettingsElements::Section section, SettingsElements::Category category) :
Section{section},
category{category}
{
icon = SettingsUiBuilder::svgEscape(icon);
category.sections.clear();
}
SettingsSectionModel::SectionInfo::SectionInfo(SettingsElements::Category category) :
Section{category.title, category.icon, category.tooltip, category.sections.first().groups, {}, {}},
category{}
{
icon = SettingsUiBuilder::svgEscape(icon);
}

55
src/imports/mvvmquick/settingssectionmodel.h

@ -0,0 +1,55 @@
#ifndef QTMVVM_SETTINGSSECTIONMODEL_H
#define QTMVVM_SETTINGSSECTIONMODEL_H
#include <QtCore/QAbstractListModel>
#include <QtMvvmCore/SettingsElements>
namespace QtMvvm {
class SettingsSectionModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(bool hasSections READ hasSections CONSTANT)
public:
enum Roles {
CategoryRole = Qt::UserRole + 1,
TitleRole,
IconRole,
ToolTipRole,
SectionRole,
ExtraSearchKeysRole
};
Q_ENUM(Roles)
static const QList<int> FilterRoles;
explicit SettingsSectionModel(QObject *parent = nullptr);
void setup(const SettingsElements::Setup &setup);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QHash<int, QByteArray> roleNames() const override;
bool hasSections() const;
private:
struct SectionInfo : public SettingsElements::Section {
public:
SectionInfo(SettingsElements::Section section = {}, SettingsElements::Category category = {});
SectionInfo(SettingsElements::Category category);
SettingsElements::Category category;
mutable QStringList searchKeys;
};
QList<SectionInfo> _sections;
bool _hasSections;
};
}
#endif // QTMVVM_SETTINGSSECTIONMODEL_H

125
src/imports/mvvmquick/settingsuibuilder.cpp

@ -0,0 +1,125 @@
#include "settingsuibuilder.h"
#include <QtCore/QRegularExpression>
#include <QtCore/QCoreApplication>
#include <QtMvvmCore/CoreApp>
#include <QtMvvmCore/Messages>
#include <QtQml/QQmlInfo>
#include <QtMvvmQuick/private/quickpresenter_p.h>
using namespace QtMvvm;
SettingsUiBuilder::SettingsUiBuilder(QObject *parent) :
QObject(parent),
_buildView(nullptr),
_viewModel(nullptr),
_filterText(),
_allowSearch(true),
_allowRestore(true),
_sectionFilterModel(new MultiFilterProxyModel(this)),
_sectionModel(new SettingsSectionModel(this)),
_entryFilterModel(new MultiFilterProxyModel(this)),
_entryModel(new SettingsEntryModel(this))
{
_sectionFilterModel->setSourceModel(_sectionModel);
_sectionFilterModel->addFilterRoles(SettingsSectionModel::FilterRoles);
_entryFilterModel->setSourceModel(_entryModel);
_entryFilterModel->addFilterRoles(SettingsEntryModel::FilterRoles);
connect(this, &SettingsUiBuilder::buildViewChanged,
this, &SettingsUiBuilder::startBuildUi);
connect(this, &SettingsUiBuilder::viewModelChanged,
this, &SettingsUiBuilder::startBuildUi);
}
QString SettingsUiBuilder::filterText() const
{
return _filterText;
}
QUrl SettingsUiBuilder::svgEscape(QUrl url)
{
if(url.scheme() == QStringLiteral("qrc")) {
auto path = url.path();
if(path.endsWith(QStringLiteral(".svg"))) {
path.chop(4);
path.prepend(QStringLiteral("image://svg"));
return path;
}
}
return url;
}
void SettingsUiBuilder::loadSection(const SettingsElements::Section &section)
{
auto inputFactory = QuickPresenterPrivate::currentPresenter()->inputViewFactory();
_entryModel->setup(section, _viewModel, inputFactory);
emit presentSection(_entryFilterModel);
}
void SettingsUiBuilder::showDialog(const QString &key, const QString &title, const QString &type, const QVariantMap &properties)
{
if(type == QStringLiteral("action"))
_viewModel->callAction(key, properties.value(QStringLiteral("args")).toMap());
else {
getInput(title + tr(":"), QString(), qUtf8Printable(type), this, [this, key](QVariant value) {
if(value.isValid())
_viewModel->saveValue(key, value);
}, _viewModel->loadValue(key), properties);
}
}
void SettingsUiBuilder::restoreDefaults()
{
if(!_viewModel->canRestoreDefaults())
return;
auto result = CoreApp::showDialog(_viewModel->restoreConfig());
connect(result, &MessageResult::dialogDone, this, [this](MessageConfig::StandardButton btn) {
if(btn != MessageConfig::Yes)
return;
emit closeSettings();
}, Qt::QueuedConnection);
}
void SettingsUiBuilder::setFilterText(QString filterText)
{
if (_filterText == filterText)
return;
_filterText = filterText;
emit filterTextChanged(filterText);
QRegularExpression regex(filterText,
QRegularExpression::CaseInsensitiveOption |
QRegularExpression::UseUnicodePropertiesOption |
QRegularExpression::DontCaptureOption);
_sectionFilterModel->setFilter(regex);
_entryFilterModel->setFilter(regex);
}
void SettingsUiBuilder::startBuildUi()
{
if(!_buildView || !_viewModel)
return;
auto setup = _viewModel->loadSetup(QStringLiteral("quick"));
//search/restore properties
_allowSearch = setup.allowSearch;
emit allowSearchChanged(_allowSearch);
_allowRestore = setup.allowRestore;
emit allowRestoreChanged(_allowRestore);
if(setup.categories.size() == 1 &&
setup.categories.first().sections.size() == 1)
loadSection(setup.categories.first().sections.first());
else {
_sectionModel->setup(setup);
emit presentOverview(_sectionFilterModel, _sectionModel->hasSections());
}
}

71
src/imports/mvvmquick/settingsuibuilder.h

@ -0,0 +1,71 @@
#ifndef QTMVVM_SETTINGSUIBUILDER_H
#define QTMVVM_SETTINGSUIBUILDER_H
#include <QtCore/QObject>
#include <QtCore/QUrl>
#include <QtMvvmCore/SettingsViewModel>
#include <QtQuick/QQuickItem>
#include "multifilterproxymodel.h"
#include "settingssectionmodel.h"
#include "settingsentrymodel.h"
namespace QtMvvm {
class SettingsUiBuilder : public QObject
{
Q_OBJECT
Q_PROPERTY(QQuickItem* buildView MEMBER _buildView NOTIFY buildViewChanged)
Q_PROPERTY(SettingsViewModel* viewModel MEMBER _viewModel NOTIFY viewModelChanged)
Q_PROPERTY(QString filterText READ filterText WRITE setFilterText NOTIFY filterTextChanged)
Q_PROPERTY(bool allowSearch MEMBER _allowSearch NOTIFY allowSearchChanged)
Q_PROPERTY(bool allowRestore MEMBER _allowRestore NOTIFY allowRestoreChanged)
public:
explicit SettingsUiBuilder(QObject *parent = nullptr);
QString filterText() const;
static QUrl svgEscape(QUrl url);
public Q_SLOTS:
void loadSection(const QtMvvm::SettingsElements::Section &section);
void showDialog(const QString &key, const QString &title, const QString &type, const QVariantMap &properties);
void restoreDefaults();
void setFilterText(QString filterText);
Q_SIGNALS:
void presentOverview(QAbstractItemModel *model, bool hasSections);
void presentSection(QAbstractItemModel *model);
void closeSettings();
void buildViewChanged(QQuickItem* buildView);
void viewModelChanged(SettingsViewModel* viewModel);
void filterTextChanged(QString filterText);
void allowSearchChanged(bool allowSearch);
void allowRestoreChanged(bool allowRestore);
private Q_SLOTS:
void startBuildUi();
private:
QQuickItem* _buildView;
SettingsViewModel *_viewModel;
QString _filterText;
bool _allowSearch;
bool _allowRestore;
MultiFilterProxyModel *_sectionFilterModel;
SettingsSectionModel *_sectionModel;
MultiFilterProxyModel *_entryFilterModel;
SettingsEntryModel *_entryModel;
};
}
#endif // QTMVVM_SETTINGSUIBUILDER_H

6
src/mvvmcore/settingssetup.h

@ -86,6 +86,12 @@ public:
}
Q_DECLARE_METATYPE(QtMvvm::SettingsElements::Entry)
Q_DECLARE_METATYPE(QtMvvm::SettingsElements::Group)
Q_DECLARE_METATYPE(QtMvvm::SettingsElements::Section)
Q_DECLARE_METATYPE(QtMvvm::SettingsElements::Category)
Q_DECLARE_METATYPE(QtMvvm::SettingsElements::Setup)
#define QtMvvm_ISettingsSetupLoaderIid "de.skycoder42.qtmvvm.settings.core.ISettingsSetupLoader"
Q_DECLARE_INTERFACE(QtMvvm::ISettingsSetupLoader, QtMvvm_ISettingsSetupLoaderIid)
Q_DECLARE_METATYPE(QtMvvm::ISettingsSetupLoader*)

2
src/mvvmquick/ListEdit.qml

@ -5,7 +5,7 @@ ComboBox {
id: _edit
property alias inputValue: _edit.currentValue
property alias listElements: _edit.model
property alias currentValue: _valueHelper.value
property var currentValue: _valueHelper ? _valueHelper.value : null
textRole: "name"
property var _valueHelper: { return {}; }

4
src/mvvmquick/MsgDelegate.qml

@ -7,6 +7,8 @@ ItemDelegate {
text: title
signal showInput(string key, string title, string type, var properties);
contentItem: ColumnLayout {
Label {
id: _titleLabel
@ -25,5 +27,5 @@ ItemDelegate {
}
}
onClicked: showInputDialog = true
onClicked: showInput(key, title, type, properties)
}

Loading…
Cancel
Save