25 changed files with 1024 additions and 100 deletions
@ -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 |
|||
|
@ -0,0 +1,14 @@ |
|||
{ |
|||
"dependencies": [], |
|||
"license": { |
|||
"file": "", |
|||
"name": "" |
|||
}, |
|||
"prcFile": "", |
|||
"priFile": "", |
|||
"priIncludes": [ |
|||
], |
|||
"publishers": { |
|||
}, |
|||
"source": false |
|||
} |
@ -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
|
@ -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 §ion, 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 ®ex) |
|||
{ |
|||
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 ®ex, 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 ®ex, 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 ®ex, 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 ®ex, 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); |
|||
} |
@ -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
|
@ -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> |
@ -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 §ion, 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 ®ex); |
|||
bool searchInCategory(const QRegularExpression ®ex, QTabWidget *tab); |
|||
bool searchInSection(const QRegularExpression ®ex, QWidget *contentWidget); |
|||
bool searchInGroup(const QRegularExpression ®ex, QGroupBox *groupWidget); |
|||
bool searchInEntry(const QRegularExpression ®ex, 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
|
Loading…
Reference in new issue