├── README.md ├── setting_tools.ico ├── de_skycoder42_qtmvvm_settings_widgets.qrc ├── de_skycoder42_qtmvvm_settings_widgets.pri ├── .gitignore ├── qtmvvm_settings_widgets_de.ts ├── qtmvvm_settings_widgets_template.ts ├── qpm.json ├── qpmx.json ├── LICENSE ├── settingsdialog.h ├── settingsdialog.ui └── settingsdialog.cpp /README.md: -------------------------------------------------------------------------------- 1 | # QtMvvmSettingsWidgets 2 | 3 | Has been replaced by https://github.com/Skycoder42/QtMvvm 4 | -------------------------------------------------------------------------------- /setting_tools.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/QtMvvmSettingsWidgets/master/setting_tools.ico -------------------------------------------------------------------------------- /de_skycoder42_qtmvvm_settings_widgets.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | setting_tools.ico 4 | 5 | 6 | -------------------------------------------------------------------------------- /de_skycoder42_qtmvvm_settings_widgets.pri: -------------------------------------------------------------------------------- 1 | HEADERS += $$PWD/settingsdialog.h 2 | 3 | SOURCES += $$PWD/settingsdialog.cpp 4 | 5 | FORMS += $$PWD/settingsdialog.ui 6 | 7 | RESOURCES += $$PWD/de_skycoder42_qtmvvm_settings_widgets.qrc 8 | 9 | TRANSLATIONS += $$PWD/qtmvvm_settings_widgets_de.ts \ 10 | $$PWD/qtmvvm_settings_widgets_template.ts 11 | 12 | INCLUDEPATH += $$PWD 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # C++ objects and libs 2 | 3 | *.slo 4 | *.lo 5 | *.o 6 | *.a 7 | *.la 8 | *.lai 9 | *.so 10 | *.dll 11 | *.dylib 12 | 13 | # Qt-es 14 | 15 | /.qmake.cache 16 | /.qmake.stash 17 | *.pro.user 18 | *.pro.user.* 19 | *.qbs.user 20 | *.qbs.user.* 21 | *.moc 22 | moc_*.cpp 23 | qrc_*.cpp 24 | ui_*.h 25 | Makefile* 26 | *build-* 27 | 28 | # QtCreator 29 | 30 | *.autosave 31 | 32 | # QtCtreator Qml 33 | *.qmlproject.user 34 | *.qmlproject.user.* 35 | 36 | # QtCtreator CMake 37 | CMakeLists.txt.user 38 | 39 | #qpm 40 | vendor -------------------------------------------------------------------------------- /qtmvvm_settings_widgets_de.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SettingsDialog 6 | 7 | 8 | Settings 9 | Einstellungen 10 | 11 | 12 | 13 | Search in settings… 14 | In Einstellungen suchen… 15 | 16 | 17 | 18 | : 19 | : 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /qtmvvm_settings_widgets_template.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SettingsDialog 6 | 7 | 8 | Settings 9 | 10 | 11 | 12 | 13 | Search in settings… 14 | 15 | 16 | 17 | 18 | : 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /qpm.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": { 3 | "email": "skycoder42.de@gmx.de", 4 | "name": "Skycoder" 5 | }, 6 | "dependencies": [ 7 | "de.skycoder42.qtmvvm.settings.core@1.1.2", 8 | "de.skycoder42.qtmvvm.widgets@1.1.2" 9 | ], 10 | "description": "The widgets frontend of QtMvvm settings module", 11 | "license": "BSD_3_CLAUSE", 12 | "name": "de.skycoder42.qtmvvm.settings.widgets", 13 | "pri_filename": "de_skycoder42_qtmvvm_settings_widgets.pri", 14 | "repository": { 15 | "type": "GITHUB", 16 | "url": "https://github.com/Skycoder42/QtMvvmSettingsWidgets.git" 17 | }, 18 | "version": { 19 | "fingerprint": "", 20 | "label": "1.1.3", 21 | "revision": "" 22 | }, 23 | "webpage": "https://github.com/Skycoder42/QtMvvm" 24 | } 25 | -------------------------------------------------------------------------------- /qpmx.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": [ 3 | { 4 | "package": "de.skycoder42.qtmvvm.settings.core", 5 | "provider": "qpm", 6 | "version": "1.1.2" 7 | }, 8 | { 9 | "package": "de.skycoder42.qtmvvm.widgets", 10 | "provider": "qpm", 11 | "version": "1.1.2" 12 | } 13 | ], 14 | "license": { 15 | "file": "LICENSE", 16 | "name": "BSD_3_CLAUSE" 17 | }, 18 | "prcFile": "", 19 | "priFile": "de_skycoder42_qtmvvm_settings_widgets.pri", 20 | "priIncludes": [ 21 | ], 22 | "publishers": { 23 | "qpm": { 24 | "author": { 25 | "email": "skycoder42.de@gmx.de", 26 | "name": "Skycoder" 27 | }, 28 | "description": "The widgets frontend of QtMvvm settings module", 29 | "name": "de.skycoder42.qtmvvm.settings.widgets", 30 | "repository": { 31 | "type": "GITHUB", 32 | "url": "https://github.com/Skycoder42/QtMvvmSettingsWidgets.git" 33 | }, 34 | "webpage": "https://github.com/Skycoder42/QtMvvm" 35 | } 36 | }, 37 | "source": false 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2017, Felix Barz 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /settingsdialog.h: -------------------------------------------------------------------------------- 1 | #ifndef SETTINGSDIALOG_H 2 | #define SETTINGSDIALOG_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace Ui { 18 | class SettingsDialog; 19 | } 20 | 21 | class CategoryItemDelegate : public QStyledItemDelegate 22 | { 23 | public: 24 | CategoryItemDelegate(std::function _updateFunc, 25 | const QSize &_iconSize, 26 | int layoutSpacing, 27 | QObject *parent = nullptr); 28 | 29 | QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; 30 | 31 | private: 32 | QSize _iconSize; 33 | std::function _updateFunc; 34 | }; 35 | 36 | class SettingsDialog : public QDialog 37 | { 38 | Q_OBJECT 39 | 40 | public: 41 | Q_INVOKABLE SettingsDialog(Control *mControl, QWidget *parent = nullptr); 42 | ~SettingsDialog(); 43 | 44 | private slots: 45 | void resetListSize(); 46 | void updateWidth(int width); 47 | 48 | void propertyChanged(); 49 | void saveValues(); 50 | void restoreValues(); 51 | 52 | void on_buttonBox_clicked(QAbstractButton *button); 53 | void on_filterLineEdit_textChanged(const QString &searchText); 54 | 55 | private: 56 | SettingsControl *_control; 57 | Ui::SettingsDialog *_ui; 58 | CategoryItemDelegate *_delegate; 59 | int _maxWidthBase; 60 | 61 | typedef QPair EntryInfo; 62 | QHash _entryMap; 63 | QSet _changedEntries; 64 | 65 | int calcSpacing(Qt::Orientation orientation); 66 | 67 | void createUi(const SettingsSetup &setup); 68 | void createCategory(const SettingsCategory &category); 69 | void createSection(const SettingsSection §ion, QTabWidget *tabWidget); 70 | void createGroup(const SettingsGroup &group, QWidget *contentWidget, QFormLayout *layout); 71 | void createEntry(const SettingsEntry &entry, QWidget *sectionWidget, QFormLayout *layout); 72 | 73 | void searchInDialog(const QRegularExpression ®ex); 74 | bool searchInCategory(const QRegularExpression ®ex, QTabWidget *tab); 75 | bool searchInSection(const QRegularExpression ®ex, QWidget *contentWidget); 76 | bool searchInGroup(const QRegularExpression ®ex, QGroupBox *groupWidget); 77 | bool searchInEntry(const QRegularExpression ®ex, QLabel *label, QWidget *content); 78 | 79 | QIcon loadIcon(const QUrl &icon); 80 | }; 81 | 82 | #endif // SETTINGSDIALOG_H 83 | -------------------------------------------------------------------------------- /settingsdialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | SettingsDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 850 10 | 500 11 | 12 | 13 | 14 | Settings 15 | 16 | 17 | true 18 | 19 | 20 | true 21 | 22 | 23 | 24 | 0 25 | 26 | 27 | 28 | 29 | 30 | 0 31 | 32 | 33 | 0 34 | 35 | 36 | 0 37 | 38 | 39 | 0 40 | 41 | 42 | 0 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 255 53 | 255 54 | 255 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 255 64 | 255 65 | 255 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 240 75 | 240 76 | 240 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | QFrame::NoFrame 85 | 86 | 87 | Qt::ScrollBarAsNeeded 88 | 89 | 90 | Qt::ScrollBarAlwaysOff 91 | 92 | 93 | QAbstractItemView::NoEditTriggers 94 | 95 | 96 | 97 | 32 98 | 32 99 | 100 | 101 | 102 | QListView::Adjust 103 | 104 | 105 | 1 106 | 107 | 108 | 109 | 110 | 111 | 112 | Qt::Vertical 113 | 114 | 115 | 116 | 117 | 118 | 119 | Qt::Horizontal 120 | 121 | 122 | 123 | 6 124 | 0 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 2 138 | 139 | 140 | 141 | 142 | 143 | 10 144 | 75 145 | true 146 | 147 | 148 | 149 | Qt::PlainText 150 | 151 | 152 | 4 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 0 161 | 0 162 | 163 | 164 | 165 | 166 | 200 167 | 0 168 | 169 | 170 | 171 | Search in settings… 172 | 173 | 174 | true 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | Qt::Horizontal 187 | 188 | 189 | QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::RestoreDefaults 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | categoryListWidget 201 | currentRowChanged(int) 202 | contentStackWidget 203 | setCurrentIndex(int) 204 | 205 | 206 | 123 207 | 172 208 | 209 | 210 | 488 211 | 189 212 | 213 | 214 | 215 | 216 | categoryListWidget 217 | currentTextChanged(QString) 218 | titleLabel 219 | setText(QString) 220 | 221 | 222 | 156 223 | 42 224 | 225 | 226 | 466 227 | 16 228 | 229 | 230 | 231 | 232 | 233 | -------------------------------------------------------------------------------- /settingsdialog.cpp: -------------------------------------------------------------------------------- 1 | #include "settingsdialog.h" 2 | #include "ui_settingsdialog.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | static void settingsInit(); 13 | Q_COREAPP_STARTUP_FUNCTION(settingsInit) 14 | 15 | #define TAB_CONTENT_NAME QStringLiteral("tabContent_371342666") 16 | 17 | SettingsDialog::SettingsDialog(Control *mControl, QWidget *parent) : 18 | QDialog(parent), 19 | _control(static_cast(mControl)), 20 | _ui(new Ui::SettingsDialog), 21 | _delegate(nullptr), 22 | _maxWidthBase(0), 23 | _entryMap(), 24 | _changedEntries() 25 | { 26 | _ui->setupUi(this); 27 | _ui->buttonBox->button(QDialogButtonBox::Ok)->setAutoDefault(false); 28 | _ui->buttonBox->button(QDialogButtonBox::Cancel)->setAutoDefault(false); 29 | _ui->buttonBox->button(QDialogButtonBox::Apply)->setAutoDefault(false); 30 | _ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)->setAutoDefault(false); 31 | _ui->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true); 32 | 33 | if(parentWidget()) { 34 | setWindowModality(Qt::WindowModal); 35 | setWindowFlags(Qt::Sheet | Qt::WindowCloseButtonHint | Qt::WindowContextHelpButtonHint); 36 | } else { 37 | setWindowModality(Qt::ApplicationModal); 38 | setWindowFlags(Qt::Dialog | Qt::WindowCloseButtonHint | Qt::WindowContextHelpButtonHint); 39 | } 40 | 41 | #ifdef Q_OS_OSX 42 | auto font = _ui->titleLabel->font(); 43 | font.setPointSize(16); 44 | _ui->titleLabel->setFont(font); 45 | #endif 46 | 47 | int listSpacing = calcSpacing(Qt::Vertical); 48 | _delegate = new CategoryItemDelegate(std::bind(&SettingsDialog::updateWidth, this, std::placeholders::_1), 49 | _ui->categoryListWidget->iconSize(), 50 | qMax(qRound(listSpacing * (2./3.)), 1), 51 | this); 52 | _ui->categoryListWidget->setItemDelegate(_delegate); 53 | _ui->categoryListWidget->setSpacing(qMax(qRound(listSpacing / 3.), 1) - 1); 54 | 55 | int spacing = calcSpacing(Qt::Horizontal); 56 | _ui->contentLayout->setSpacing(spacing); 57 | _ui->categoryLineSpacer->changeSize(spacing, 58 | 0, 59 | QSizePolicy::Fixed, 60 | QSizePolicy::Fixed); 61 | 62 | createUi(_control->loadSetup("widgets")); 63 | } 64 | 65 | SettingsDialog::~SettingsDialog() 66 | { 67 | delete _ui; 68 | } 69 | 70 | void SettingsDialog::resetListSize() 71 | { 72 | int max = _ui->categoryListWidget->count(); 73 | if(max <= 1) { 74 | _ui->categoryContentWidget->hide(); 75 | resize(width() - _ui->categoryContentWidget->sizeHint().width(), height()); 76 | } else { 77 | auto width = _ui->categoryListWidget->sizeHint().width(); 78 | _ui->categoryListWidget->setFixedWidth(width); 79 | _maxWidthBase = width; 80 | } 81 | } 82 | 83 | void SettingsDialog::updateWidth(int width) 84 | { 85 | if(width > _maxWidthBase) { 86 | _maxWidthBase = width; 87 | QStyle *style = _ui->categoryListWidget->style(); 88 | width += style->pixelMetric(QStyle::PM_ScrollBarExtent); 89 | width += style->pixelMetric(QStyle::PM_LayoutHorizontalSpacing); 90 | _ui->categoryListWidget->setFixedWidth(width); 91 | } 92 | } 93 | 94 | void SettingsDialog::propertyChanged() 95 | { 96 | auto widget = qobject_cast(sender()); 97 | if(widget) 98 | _changedEntries.insert(widget); 99 | } 100 | 101 | void SettingsDialog::saveValues() 102 | { 103 | for(auto it = _changedEntries.begin(); it != _changedEntries.end();) { 104 | auto widget = *it; 105 | auto info = _entryMap.value(widget); 106 | _control->saveValue(info.first.key, info.second.read(widget)); 107 | if(info.second.hasNotifySignal()) 108 | it = _changedEntries.erase(it); 109 | else 110 | it++; 111 | } 112 | } 113 | 114 | void SettingsDialog::restoreValues() 115 | { 116 | foreach(auto info, _entryMap) 117 | _control->resetValue(info.first.key); 118 | } 119 | 120 | void SettingsDialog::on_buttonBox_clicked(QAbstractButton *button) 121 | { 122 | switch(_ui->buttonBox->standardButton(button)) { 123 | case QDialogButtonBox::Ok: 124 | saveValues(); 125 | accept(); 126 | break; 127 | case QDialogButtonBox::Cancel: 128 | reject(); 129 | break; 130 | case QDialogButtonBox::Apply: 131 | saveValues(); 132 | break; 133 | case QDialogButtonBox::RestoreDefaults: 134 | if(_control->canRestoreDefaults()) { 135 | auto result = CoreMessage::message(_control->restoreConfig()); 136 | connect(result, &MessageResult::positiveAction, this, [=](){ 137 | restoreValues(); 138 | accept(); 139 | }); 140 | } 141 | break; 142 | default: 143 | Q_UNREACHABLE(); 144 | } 145 | } 146 | 147 | void SettingsDialog::on_filterLineEdit_textChanged(const QString &searchText) 148 | { 149 | auto regex = QRegularExpression::escape(searchText); 150 | regex.replace(QStringLiteral("\\*"), QStringLiteral(".*")); 151 | regex.replace(QStringLiteral("\\?"), QStringLiteral(".")); 152 | searchInDialog(QRegularExpression(regex, QRegularExpression::CaseInsensitiveOption)); 153 | } 154 | 155 | int SettingsDialog::calcSpacing(Qt::Orientation orientation) 156 | { 157 | auto baseSize = style()->pixelMetric(orientation == Qt::Horizontal ? 158 | QStyle::PM_LayoutHorizontalSpacing : 159 | QStyle::PM_LayoutVerticalSpacing); 160 | if(baseSize < 0) 161 | baseSize = style()->layoutSpacing(QSizePolicy::DefaultType, QSizePolicy::DefaultType, orientation); 162 | if(baseSize < 0) 163 | baseSize = style()->layoutSpacing(QSizePolicy::LineEdit, QSizePolicy::LineEdit, orientation); 164 | if(baseSize < 0) { 165 | #ifdef Q_OS_OSX 166 | baseSize = 10; 167 | #else 168 | baseSize = 6; 169 | #endif 170 | } 171 | 172 | return baseSize; 173 | } 174 | 175 | void SettingsDialog::createUi(const SettingsSetup &setup) 176 | { 177 | _ui->filterLineEdit->setVisible(setup.allowSearch); 178 | _ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)->setVisible(setup.allowRestore && _control->canRestoreDefaults()); 179 | 180 | foreach(auto category, setup.categories) 181 | createCategory(category); 182 | 183 | resetListSize(); 184 | _ui->categoryListWidget->setCurrentRow(0); 185 | } 186 | 187 | void SettingsDialog::createCategory(const SettingsCategory &category) 188 | { 189 | auto item = new QListWidgetItem(); 190 | item->setText(category.title); 191 | item->setIcon(loadIcon(category.icon)); 192 | item->setToolTip(category.tooltip.isNull() ? category.title : category.tooltip); 193 | item->setWhatsThis(item->toolTip()); 194 | auto tab = new QTabWidget(); 195 | tab->setTabBarAutoHide(true); 196 | 197 | _ui->contentStackWidget->addWidget(tab); 198 | _ui->categoryListWidget->addItem(item); 199 | 200 | foreach(auto section, category.sections) 201 | createSection(section, tab); 202 | } 203 | 204 | void SettingsDialog::createSection(const SettingsSection §ion, QTabWidget *tabWidget) 205 | { 206 | auto scrollArea = new QScrollArea(); 207 | scrollArea->setWidgetResizable(true); 208 | scrollArea->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); 209 | scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 210 | scrollArea->setAutoFillBackground(true); 211 | auto pal = scrollArea->palette(); 212 | pal.setColor(QPalette::Window, tabWidget->palette().color(QPalette::Base)); 213 | scrollArea->setPalette(pal); 214 | scrollArea->setFrameShape(QFrame::NoFrame); 215 | 216 | auto scrollContent = new QWidget(scrollArea); 217 | scrollContent->setObjectName(TAB_CONTENT_NAME); 218 | auto layout = new QFormLayout(scrollContent); 219 | scrollContent->setLayout(layout); 220 | scrollArea->setWidget(scrollContent); 221 | 222 | auto index = tabWidget->addTab(scrollArea, loadIcon(section.icon), section.title); 223 | auto tooltip = section.tooltip.isNull() ? section.title : section.tooltip; 224 | tabWidget->tabBar()->setTabToolTip(index, tooltip); 225 | tabWidget->tabBar()->setTabWhatsThis(index, tooltip); 226 | 227 | foreach(auto group, section.groups) 228 | createGroup(group, scrollContent, layout); 229 | } 230 | 231 | void SettingsDialog::createGroup(const SettingsGroup &group, QWidget *contentWidget, QFormLayout *layout) 232 | { 233 | QWidget *sectionWidget = nullptr; 234 | QFormLayout *sectionLayout = nullptr; 235 | if(group.title.isNull()) { 236 | sectionWidget = contentWidget; 237 | sectionLayout = layout; 238 | } else { 239 | auto groupBox = new QGroupBox(group.title, contentWidget); 240 | layout->addRow(groupBox); 241 | sectionWidget = groupBox; 242 | sectionLayout = new QFormLayout(groupBox); 243 | groupBox->setLayout(sectionLayout); 244 | } 245 | 246 | foreach(auto entry, group.entries) 247 | createEntry(entry, sectionWidget, sectionLayout); 248 | } 249 | 250 | void SettingsDialog::createEntry(const SettingsEntry &entry, QWidget *sectionWidget, QFormLayout *layout) 251 | { 252 | auto widgetFactory = WidgetPresenter::inputWidgetFactory(); 253 | QWidget *content = widgetFactory->createWidget(entry.type, sectionWidget, entry.properties); 254 | if(!content) { 255 | qWarning() << "Failed to create settings widget for type" << entry.type; 256 | return; 257 | } 258 | auto property = widgetFactory->userProperty(content); 259 | if(!property.isValid()) { 260 | qWarning() << "Failed to get user property for type" << entry.type; 261 | return; 262 | } 263 | 264 | property.write(content, _control->loadValue(entry.key, entry.defaultValue)); 265 | if(property.hasNotifySignal()) { 266 | auto changedSlot = metaObject()->method(metaObject()->indexOfSlot("propertyChanged()")); 267 | connect(content, property.notifySignal(), 268 | this, changedSlot); 269 | } else 270 | _changedEntries.insert(content); 271 | 272 | auto label = new QLabel(entry.title + tr(":"), sectionWidget); 273 | label->setBuddy(content); 274 | label->setToolTip(entry.tooltip.isNull() ? entry.title : entry.tooltip); 275 | label->setWhatsThis(label->toolTip()); 276 | if(content->toolTip().isNull()) 277 | content->setToolTip(label->toolTip()); 278 | if(content->whatsThis().isNull()) 279 | content->setWhatsThis(label->toolTip()); 280 | 281 | layout->addRow(label, content); 282 | _entryMap.insert(content, {entry, property}); 283 | } 284 | 285 | void SettingsDialog::searchInDialog(const QRegularExpression ®ex) 286 | { 287 | for(int i = 0, max = _ui->categoryListWidget->count(); i < max; ++i) { 288 | auto item = _ui->categoryListWidget->item(i); 289 | auto tab = static_cast(_ui->contentStackWidget->widget(i)); 290 | 291 | if(searchInCategory(regex, tab) || 292 | regex.match(item->text()).hasMatch()) { 293 | item->setHidden(false); 294 | 295 | if(_ui->categoryListWidget->currentRow() == -1) 296 | _ui->categoryListWidget->setCurrentRow(i); 297 | } else { 298 | item->setHidden(true); 299 | 300 | if(_ui->categoryListWidget->currentRow() == i) { 301 | auto found = false; 302 | for(int j = 0; j < max; j++) { 303 | if(!_ui->categoryListWidget->item(j)->isHidden()){ 304 | _ui->categoryListWidget->setCurrentRow(j); 305 | found = true; 306 | break; 307 | } 308 | } 309 | if(!found) { 310 | _ui->categoryListWidget->setCurrentRow(-1); 311 | _ui->contentStackWidget->setCurrentIndex(max); 312 | } 313 | } 314 | } 315 | } 316 | } 317 | 318 | bool SettingsDialog::searchInCategory(const QRegularExpression ®ex, QTabWidget *tab) 319 | { 320 | auto someFound = false; 321 | 322 | for(int i = 0, max = tab->count(); i < max; ++i) { 323 | if(searchInSection(regex, tab->widget(i)->findChild(TAB_CONTENT_NAME)) || 324 | regex.match(tab->tabText(i)).hasMatch()){ 325 | tab->setTabEnabled(i, true); 326 | someFound = true; 327 | } else 328 | tab->setTabEnabled(i, false); 329 | } 330 | 331 | return someFound; 332 | } 333 | 334 | bool SettingsDialog::searchInSection(const QRegularExpression ®ex, QWidget *contentWidget) 335 | { 336 | auto someFound = false; 337 | 338 | auto layout = static_cast(contentWidget->layout()); 339 | for(int i = 0, max = layout->rowCount(); i < max; ++i) { 340 | auto spanItem = layout->itemAt(i, QFormLayout::SpanningRole); 341 | if(spanItem) { 342 | auto group = static_cast(spanItem->widget()); 343 | someFound |= searchInGroup(regex, group) || 344 | regex.match(group->title()).hasMatch(); 345 | } else { 346 | auto label = static_cast(layout->itemAt(i, QFormLayout::LabelRole)->widget()); 347 | auto content = layout->itemAt(i, QFormLayout::FieldRole)->widget(); 348 | someFound |= searchInEntry(regex, label, content); 349 | } 350 | } 351 | 352 | return someFound; 353 | } 354 | 355 | bool SettingsDialog::searchInGroup(const QRegularExpression ®ex, QGroupBox *groupWidget) 356 | { 357 | auto someFound = false; 358 | 359 | auto layout = static_cast(groupWidget->layout()); 360 | for(int i = 0, max = layout->rowCount(); i < max; ++i) { 361 | auto label = static_cast(layout->itemAt(i, QFormLayout::LabelRole)->widget()); 362 | auto content = layout->itemAt(i, QFormLayout::FieldRole)->widget(); 363 | someFound |= searchInEntry(regex, label, content); 364 | } 365 | 366 | return someFound; 367 | } 368 | 369 | bool SettingsDialog::searchInEntry(const QRegularExpression ®ex, QLabel *label, QWidget *content) 370 | { 371 | if(regex.pattern().isEmpty()) { 372 | label->setStyleSheet(QString()); 373 | return false; 374 | } 375 | auto keys = _entryMap.value(content).first.searchKeys; 376 | keys.append(label->text()); 377 | foreach(auto key, keys) { 378 | if(regex.match(key).hasMatch()) { 379 | label->setStyleSheet(QStringLiteral("QLabel {" 380 | " background-color: rgba(19,232,51,0.4);" 381 | " border: 1px solid rgba(19,196,45,0.8);" 382 | " border-radius: 4px;" 383 | "}")); 384 | return true; 385 | } 386 | } 387 | label->setStyleSheet(QString()); 388 | return false; 389 | } 390 | 391 | QIcon SettingsDialog::loadIcon(const QUrl &icon) 392 | { 393 | if(icon.scheme() == QStringLiteral("qrc")) 394 | return QIcon(QLatin1Char(':') + icon.path()); 395 | else 396 | return QIcon(icon.toLocalFile()); 397 | } 398 | 399 | 400 | 401 | CategoryItemDelegate::CategoryItemDelegate(std::function updateFunc, const QSize &iconSize, int layoutSpacing, QObject *parent) : 402 | QStyledItemDelegate(parent), 403 | _iconSize(), 404 | _updateFunc(updateFunc) 405 | { 406 | this->_iconSize = iconSize + QSize(0, layoutSpacing); 407 | } 408 | 409 | QSize CategoryItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const 410 | { 411 | QSize size = QStyledItemDelegate::sizeHint(option, index); 412 | _updateFunc(size.width()); 413 | return size.expandedTo(_iconSize); 414 | } 415 | 416 | static void settingsInit() 417 | { 418 | XmlSettingsSetupLoader::overwriteDefaultIcon(QStringLiteral("qrc:/qtmvvm/icons/settings.ico")); 419 | } 420 | --------------------------------------------------------------------------------