qt 6.5.1 original

This commit is contained in:
kleuter
2023-10-29 23:33:08 +01:00
parent 71d22ab6b0
commit 85d238dfda
21202 changed files with 5499099 additions and 0 deletions

View File

@ -0,0 +1,40 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(settingseditor LANGUAGES CXX)
if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples")
endif()
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/tools/settingseditor")
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
qt_standard_project_setup()
qt_add_executable(settingseditor
locationdialog.cpp locationdialog.h
main.cpp
mainwindow.cpp mainwindow.h
settingstree.cpp settingstree.h
variantdelegate.cpp variantdelegate.h
)
set_target_properties(settingseditor PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(settingseditor PRIVATE
Qt6::Core
Qt6::Gui
Qt6::Widgets
)
install(TARGETS settingseditor
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
)

View File

@ -0,0 +1,46 @@
[Field%201]
Bottom=89
Flags=MULTILINE|VSCROLL|READONLY
Left=4
Right=296
State=No license agreement file found. Please contact support.
Top=14
Type=Text
[Field%202]
Bottom=8
Left=4
Right=294
Text=Press Page Down to see the rest of the agreement.
Top=0
Type=Label
[Field%203]
Bottom=111
Left=4
Right=297
Text=If you accept the terms of the agreement, select the first option below. You must accept the agreement to install this software. Click Next to continue.
Top=92
Type=Label
[Field%204]
Bottom=129
Flags=GROUP|NOTIFY
Left=4
Right=299
Text=I &accept the terms in the License Agreement
Top=120
Type=RadioButton
[Field%205]
Bottom=140
Flags=NOTIFY
Left=4
Right=300
State=1
Text=I &do not accept the terms in the License Agreement
Top=129
Type=RadioButton
[Settings]
NumFields=5

View File

@ -0,0 +1,26 @@
[Field%201]
Bottom=65
Left=0
Right=299
Text=QSA Build Options
Top=9
Type=Groupbox
[Field%202]
Bottom=37
Left=20
Right=284
Text=Don't compile QSA Workbench into QSA.
Top=27
Type=Checkbox
[Field%203]
Bottom=56
Left=20
Right=247
Text=Don't compile QSA Workbench nor QSA Editor into QSA.
Top=45
Type=Checkbox
[Settings]
NumFields=3

View File

@ -0,0 +1,193 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "locationdialog.h"
#include <QBoxLayout>
#include <QComboBox>
#include <QDialogButtonBox>
#include <QDir>
#include <QPushButton>
#include <QGroupBox>
#include <QHeaderView>
#include <QLabel>
#include <QLineEdit>
#include <QTableWidget>
#include <QTableWidgetItem>
LocationDialog::LocationDialog(QWidget *parent)
: QDialog(parent)
{
formatComboBox = new QComboBox;
formatComboBox->addItem(tr("Native"));
formatComboBox->addItem(tr("INI"));
scopeComboBox = new QComboBox;
scopeComboBox->addItem(tr("User"));
scopeComboBox->addItem(tr("System"));
organizationComboBox = new QComboBox;
organizationComboBox->addItem(tr("QtProject"));
organizationComboBox->setEditable(true);
applicationComboBox = new QComboBox;
applicationComboBox->addItem(tr("Any"));
applicationComboBox->addItem(tr("Qt Creator"));
applicationComboBox->addItem(tr("Application Example"));
applicationComboBox->addItem(tr("Assistant"));
applicationComboBox->addItem(tr("Designer"));
applicationComboBox->addItem(tr("Linguist"));
applicationComboBox->setEditable(true);
applicationComboBox->setCurrentIndex(1);
formatLabel = new QLabel(tr("&Format:"));
formatLabel->setBuddy(formatComboBox);
scopeLabel = new QLabel(tr("&Scope:"));
scopeLabel->setBuddy(scopeComboBox);
organizationLabel = new QLabel(tr("&Organization:"));
organizationLabel->setBuddy(organizationComboBox);
applicationLabel = new QLabel(tr("&Application:"));
applicationLabel->setBuddy(applicationComboBox);
locationsGroupBox = new QGroupBox(tr("Setting Locations"));
const QStringList labels{tr("Location"), tr("Access")};
locationsTable = new QTableWidget;
locationsTable->setSelectionMode(QAbstractItemView::SingleSelection);
locationsTable->setSelectionBehavior(QAbstractItemView::SelectRows);
locationsTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
locationsTable->setColumnCount(2);
locationsTable->setHorizontalHeaderLabels(labels);
locationsTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
locationsTable->horizontalHeader()->resizeSection(1, 180);
connect(locationsTable, &QTableWidget::itemActivated, this, &LocationDialog::itemActivated);
buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(formatComboBox, &QComboBox::activated,
this, &LocationDialog::updateLocationsTable);
connect(scopeComboBox, &QComboBox::activated,
this, &LocationDialog::updateLocationsTable);
connect(organizationComboBox->lineEdit(),
&QLineEdit::editingFinished,
this, &LocationDialog::updateLocationsTable);
connect(applicationComboBox->lineEdit(),
&QLineEdit::editingFinished,
this, &LocationDialog::updateLocationsTable);
connect(applicationComboBox, &QComboBox::activated,
this, &LocationDialog::updateLocationsTable);
connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
QVBoxLayout *locationsLayout = new QVBoxLayout(locationsGroupBox);
locationsLayout->addWidget(locationsTable);
QGridLayout *mainLayout = new QGridLayout(this);
mainLayout->addWidget(formatLabel, 0, 0);
mainLayout->addWidget(formatComboBox, 0, 1);
mainLayout->addWidget(scopeLabel, 1, 0);
mainLayout->addWidget(scopeComboBox, 1, 1);
mainLayout->addWidget(organizationLabel, 2, 0);
mainLayout->addWidget(organizationComboBox, 2, 1);
mainLayout->addWidget(applicationLabel, 3, 0);
mainLayout->addWidget(applicationComboBox, 3, 1);
mainLayout->addWidget(locationsGroupBox, 4, 0, 1, 2);
mainLayout->addWidget(buttonBox, 5, 0, 1, 2);
updateLocationsTable();
setWindowTitle(tr("Open Application Settings"));
resize(650, 400);
}
QSettings::Format LocationDialog::format() const
{
if (formatComboBox->currentIndex() == 0)
return QSettings::NativeFormat;
else
return QSettings::IniFormat;
}
QSettings::Scope LocationDialog::scope() const
{
if (scopeComboBox->currentIndex() == 0)
return QSettings::UserScope;
else
return QSettings::SystemScope;
}
QString LocationDialog::organization() const
{
return organizationComboBox->currentText();
}
QString LocationDialog::application() const
{
if (applicationComboBox->currentText() == tr("Any"))
return QString();
else
return applicationComboBox->currentText();
}
void LocationDialog::itemActivated(QTableWidgetItem *)
{
buttonBox->button(QDialogButtonBox::Ok)->animateClick();
}
void LocationDialog::updateLocationsTable()
{
locationsTable->setUpdatesEnabled(false);
locationsTable->setRowCount(0);
for (int i = 0; i < 2; ++i) {
if (i == 0 && scope() == QSettings::SystemScope)
continue;
QSettings::Scope actualScope = (i == 0) ? QSettings::UserScope
: QSettings::SystemScope;
for (int j = 0; j < 2; ++j) {
if (j == 0 && application().isEmpty())
continue;
QString actualApplication;
if (j == 0)
actualApplication = application();
QSettings settings(format(), actualScope, organization(),
actualApplication);
int row = locationsTable->rowCount();
locationsTable->setRowCount(row + 1);
QTableWidgetItem *item0 = new QTableWidgetItem(QDir::toNativeSeparators(settings.fileName()));
QTableWidgetItem *item1 = new QTableWidgetItem;
bool disable = (settings.childKeys().isEmpty()
&& settings.childGroups().isEmpty());
if (row == 0) {
if (settings.isWritable()) {
item1->setText(tr("Read-write"));
disable = false;
} else {
item1->setText(tr("Read-only"));
}
buttonBox->button(QDialogButtonBox::Ok)->setDisabled(disable);
} else {
item1->setText(tr("Read-only fallback"));
}
if (disable) {
item0->setFlags(item0->flags() & ~Qt::ItemIsEnabled);
item1->setFlags(item1->flags() & ~Qt::ItemIsEnabled);
}
locationsTable->setItem(row, 0, item0);
locationsTable->setItem(row, 1, item1);
}
}
locationsTable->setUpdatesEnabled(true);
}

View File

@ -0,0 +1,49 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef LOCATIONDIALOG_H
#define LOCATIONDIALOG_H
#include <QDialog>
#include <QSettings>
QT_BEGIN_NAMESPACE
class QComboBox;
class QDialogButtonBox;
class QGroupBox;
class QLabel;
class QTableWidget;
class QTableWidgetItem;
QT_END_NAMESPACE
class LocationDialog : public QDialog
{
Q_OBJECT
public:
LocationDialog(QWidget *parent = nullptr);
QSettings::Format format() const;
QSettings::Scope scope() const;
QString organization() const;
QString application() const;
private slots:
void updateLocationsTable();
void itemActivated(QTableWidgetItem *);
private:
QLabel *formatLabel;
QLabel *scopeLabel;
QLabel *organizationLabel;
QLabel *applicationLabel;
QComboBox *formatComboBox;
QComboBox *scopeComboBox;
QComboBox *organizationComboBox;
QComboBox *applicationComboBox;
QGroupBox *locationsGroupBox;
QTableWidget *locationsTable;
QDialogButtonBox *buttonBox;
};
#endif

View File

@ -0,0 +1,17 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QCoreApplication::setApplicationName("Settings Editor");
QCoreApplication::setApplicationVersion(QT_VERSION_STR);
MainWindow mainWin;
mainWin.show();
return app.exec();
}

View File

@ -0,0 +1,175 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "locationdialog.h"
#include "mainwindow.h"
#include "settingstree.h"
#include <QAction>
#include <QApplication>
#include <QFileDialog>
#include <QInputDialog>
#include <QLineEdit>
#include <QMenuBar>
#include <QMessageBox>
#include <QScreen>
#include <QStandardPaths>
#include <QStatusBar>
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
, settingsTree(new SettingsTree)
{
setCentralWidget(settingsTree);
createActions();
autoRefreshAct->setChecked(true);
fallbacksAct->setChecked(true);
setWindowTitle(QCoreApplication::applicationName());
const QRect availableGeometry = screen()->availableGeometry();
adjustSize();
move((availableGeometry.width() - width()) / 2, (availableGeometry.height() - height()) / 2);
}
void MainWindow::openSettings()
{
if (!locationDialog)
locationDialog = new LocationDialog(this);
if (locationDialog->exec() != QDialog::Accepted)
return;
SettingsPtr settings(new QSettings(locationDialog->format(),
locationDialog->scope(),
locationDialog->organization(),
locationDialog->application()));
setSettingsObject(settings);
fallbacksAct->setEnabled(true);
}
void MainWindow::openIniFile()
{
const QString directory = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
const QString fileName =
QFileDialog::getOpenFileName(this, tr("Open INI File"),
directory, tr("INI Files (*.ini *.conf)"));
if (fileName.isEmpty())
return;
SettingsPtr settings(new QSettings(fileName, QSettings::IniFormat));
setSettingsObject(settings);
fallbacksAct->setEnabled(false);
}
void MainWindow::openPropertyList()
{
const QString directory = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
const QString fileName =
QFileDialog::getOpenFileName(this, tr("Open Property List"),
directory, tr("Property List Files (*.plist)"));
if (fileName.isEmpty())
return;
SettingsPtr settings(new QSettings(fileName, QSettings::NativeFormat));
setSettingsObject(settings);
fallbacksAct->setEnabled(false);
}
void MainWindow::openRegistryPath()
{
const QString path =
QInputDialog::getText(this, tr("Open Registry Path"),
tr("Enter the path in the Windows registry:"),
QLineEdit::Normal, "HKEY_CURRENT_USER\\");
if (path.isEmpty())
return;
SettingsPtr settings(new QSettings(path, QSettings::NativeFormat));
setSettingsObject(settings);
fallbacksAct->setEnabled(false);
}
void MainWindow::about()
{
QMessageBox::about(this, tr("About Settings Editor"),
tr("The <b>Settings Editor</b> example shows how to access "
"application settings using Qt."));
}
void MainWindow::createActions()
{
QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
QAction *openSettingsAct = fileMenu->addAction(tr("&Open Application Settings..."), this, &MainWindow::openSettings);
openSettingsAct->setShortcuts(QKeySequence::Open);
QAction *openIniFileAct = fileMenu->addAction(tr("Open I&NI File..."), this, &MainWindow::openIniFile);
openIniFileAct->setShortcut(tr("Ctrl+N"));
#ifdef Q_OS_MACOS
QAction *openPropertyListAct = fileMenu->addAction(tr("Open Apple &Property List..."), this, &MainWindow::openPropertyList);
openPropertyListAct->setShortcut(tr("Ctrl+P"));
#endif // Q_OS_MACOS
#ifdef Q_OS_WIN
QAction *openRegistryPathAct = fileMenu->addAction(tr("Open Windows &Registry Path..."), this, &MainWindow::openRegistryPath);
openRegistryPathAct->setShortcut(tr("Ctrl+G"));
#endif // Q_OS_WIN
fileMenu->addSeparator();
refreshAct = fileMenu->addAction(tr("&Refresh"), settingsTree, &SettingsTree::refresh);
refreshAct->setShortcut(tr("Ctrl+R"));
refreshAct->setEnabled(false);
fileMenu->addSeparator();
QAction *exitAct = fileMenu->addAction(tr("E&xit"), this, &QWidget::close);
exitAct->setShortcuts(QKeySequence::Quit);
QMenu *optionsMenu = menuBar()->addMenu(tr("&Options"));
autoRefreshAct = optionsMenu->addAction(tr("&Auto-Refresh"));
autoRefreshAct->setShortcut(tr("Ctrl+A"));
autoRefreshAct->setCheckable(true);
autoRefreshAct->setEnabled(false);
connect(autoRefreshAct, &QAction::triggered,
settingsTree, &SettingsTree::setAutoRefresh);
connect(autoRefreshAct, &QAction::triggered,
refreshAct, &QAction::setDisabled);
fallbacksAct = optionsMenu->addAction(tr("&Fallbacks"));
fallbacksAct->setShortcut(tr("Ctrl+F"));
fallbacksAct->setCheckable(true);
fallbacksAct->setEnabled(false);
connect(fallbacksAct, &QAction::triggered,
settingsTree, &SettingsTree::setFallbacksEnabled);
QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
helpMenu->addAction(tr("&About"), this, &MainWindow::about);
helpMenu->addAction(tr("About &Qt"), qApp, &QCoreApplication::quit);
}
void MainWindow::setSettingsObject(const SettingsPtr &settings)
{
settings->setFallbacksEnabled(fallbacksAct->isChecked());
settingsTree->setSettingsObject(settings);
refreshAct->setEnabled(true);
autoRefreshAct->setEnabled(true);
QString niceName = QDir::cleanPath(settings->fileName());
int pos = niceName.lastIndexOf(QLatin1Char('/'));
if (pos != -1)
niceName.remove(0, pos + 1);
if (!settings->isWritable())
niceName = tr("%1 (read only)").arg(niceName);
setWindowTitle(tr("%1 - %2").arg(niceName, QCoreApplication::applicationName()));
statusBar()->showMessage(tr("Opened \"%1\"").arg(QDir::toNativeSeparators(settings->fileName())));
}

View File

@ -0,0 +1,44 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QSharedPointer>
QT_BEGIN_NAMESPACE
class QAction;
class QSettings;
QT_END_NAMESPACE
class LocationDialog;
class SettingsTree;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
typedef QSharedPointer<QSettings> SettingsPtr;
MainWindow(QWidget *parent = nullptr);
private slots:
void openSettings();
void openIniFile();
void openPropertyList();
void openRegistryPath();
void about();
private:
void createActions();
void setSettingsObject(const SettingsPtr &settings);
SettingsTree *settingsTree = nullptr;
LocationDialog *locationDialog = nullptr;
QAction *refreshAct = nullptr;
QAction *autoRefreshAct = nullptr;
QAction *fallbacksAct = nullptr;
};
#endif

View File

@ -0,0 +1,18 @@
QT += widgets
requires(qtConfig(tablewidget))
HEADERS = locationdialog.h \
mainwindow.h \
settingstree.h \
variantdelegate.h
SOURCES = locationdialog.cpp \
main.cpp \
mainwindow.cpp \
settingstree.cpp \
variantdelegate.cpp
EXAMPLE_FILES = inifiles
# install
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/tools/settingseditor
INSTALLS += target

View File

@ -0,0 +1,231 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "settingstree.h"
#include "variantdelegate.h"
#include <QApplication>
#include <QHeaderView>
#include <QScreen>
#include <QSettings>
SettingsTree::SettingsTree(QWidget *parent)
: QTreeWidget(parent),
m_typeChecker(new TypeChecker)
{
setItemDelegate(new VariantDelegate(m_typeChecker, this));
setHeaderLabels({tr("Setting"), tr("Type"), tr("Value")});
header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
header()->setSectionResizeMode(2, QHeaderView::Stretch);
refreshTimer.setInterval(2000);
groupIcon.addPixmap(style()->standardPixmap(QStyle::SP_DirClosedIcon),
QIcon::Normal, QIcon::Off);
groupIcon.addPixmap(style()->standardPixmap(QStyle::SP_DirOpenIcon),
QIcon::Normal, QIcon::On);
keyIcon.addPixmap(style()->standardPixmap(QStyle::SP_FileIcon));
connect(&refreshTimer, &QTimer::timeout, this, &SettingsTree::maybeRefresh);
}
SettingsTree::~SettingsTree() = default;
void SettingsTree::setSettingsObject(const SettingsPtr &newSettings)
{
settings = newSettings;
clear();
if (settings.isNull()) {
refreshTimer.stop();
} else {
refresh();
if (autoRefresh)
refreshTimer.start();
}
}
QSize SettingsTree::sizeHint() const
{
const QRect availableGeometry = screen()->availableGeometry();
return QSize(availableGeometry.width() * 2 / 3, availableGeometry.height() * 2 / 3);
}
void SettingsTree::setAutoRefresh(bool autoRefresh)
{
this->autoRefresh = autoRefresh;
if (!settings.isNull()) {
if (autoRefresh) {
maybeRefresh();
refreshTimer.start();
} else {
refreshTimer.stop();
}
}
}
void SettingsTree::setFallbacksEnabled(bool enabled)
{
if (!settings.isNull()) {
settings->setFallbacksEnabled(enabled);
refresh();
}
}
void SettingsTree::maybeRefresh()
{
if (state() != EditingState)
refresh();
}
void SettingsTree::refresh()
{
if (settings.isNull())
return;
disconnect(this, &QTreeWidget::itemChanged,
this, &SettingsTree::updateSetting);
settings->sync();
updateChildItems(nullptr);
connect(this, &QTreeWidget::itemChanged,
this, &SettingsTree::updateSetting);
}
bool SettingsTree::event(QEvent *event)
{
if (event->type() == QEvent::WindowActivate) {
if (isActiveWindow() && autoRefresh)
maybeRefresh();
}
return QTreeWidget::event(event);
}
void SettingsTree::updateSetting(QTreeWidgetItem *item)
{
QString key = item->text(0);
QTreeWidgetItem *ancestor = item->parent();
while (ancestor) {
key.prepend(ancestor->text(0) + QLatin1Char('/'));
ancestor = ancestor->parent();
}
settings->setValue(key, item->data(2, Qt::UserRole));
if (autoRefresh)
refresh();
}
void SettingsTree::updateChildItems(QTreeWidgetItem *parent)
{
int dividerIndex = 0;
const QStringList childGroups = settings->childGroups();
for (const QString &group : childGroups) {
QTreeWidgetItem *child;
int childIndex = findChild(parent, group, dividerIndex);
if (childIndex != -1) {
child = childAt(parent, childIndex);
child->setText(1, QString());
child->setText(2, QString());
child->setData(2, Qt::UserRole, QVariant());
moveItemForward(parent, childIndex, dividerIndex);
} else {
child = createItem(group, parent, dividerIndex);
}
child->setIcon(0, groupIcon);
++dividerIndex;
settings->beginGroup(group);
updateChildItems(child);
settings->endGroup();
}
const QStringList childKeys = settings->childKeys();
for (const QString &key : childKeys) {
QTreeWidgetItem *child;
int childIndex = findChild(parent, key, 0);
if (childIndex == -1 || childIndex >= dividerIndex) {
if (childIndex != -1) {
child = childAt(parent, childIndex);
for (int i = 0; i < child->childCount(); ++i)
delete childAt(child, i);
moveItemForward(parent, childIndex, dividerIndex);
} else {
child = createItem(key, parent, dividerIndex);
}
child->setIcon(0, keyIcon);
++dividerIndex;
} else {
child = childAt(parent, childIndex);
}
QVariant value = settings->value(key);
if (value.userType() == QMetaType::UnknownType) {
child->setText(1, "Invalid");
} else {
if (value.typeId() == QMetaType::QString) {
const QString stringValue = value.toString();
if (m_typeChecker->boolExp.match(stringValue).hasMatch()) {
value.setValue(stringValue.compare("true", Qt::CaseInsensitive) == 0);
} else if (m_typeChecker->signedIntegerExp.match(stringValue).hasMatch())
value.setValue(stringValue.toInt());
}
child->setText(1, value.typeName());
}
child->setText(2, VariantDelegate::displayText(value));
child->setData(2, Qt::UserRole, value);
}
while (dividerIndex < childCount(parent))
delete childAt(parent, dividerIndex);
}
QTreeWidgetItem *SettingsTree::createItem(const QString &text,
QTreeWidgetItem *parent, int index)
{
QTreeWidgetItem *after = nullptr;
if (index != 0)
after = childAt(parent, index - 1);
QTreeWidgetItem *item;
if (parent)
item = new QTreeWidgetItem(parent, after);
else
item = new QTreeWidgetItem(this, after);
item->setText(0, text);
item->setFlags(item->flags() | Qt::ItemIsEditable);
return item;
}
QTreeWidgetItem *SettingsTree::childAt(QTreeWidgetItem *parent, int index) const
{
return (parent ? parent->child(index) : topLevelItem(index));
}
int SettingsTree::childCount(QTreeWidgetItem *parent) const
{
return (parent ? parent->childCount() : topLevelItemCount());
}
int SettingsTree::findChild(QTreeWidgetItem *parent, const QString &text,
int startIndex) const
{
for (int i = startIndex; i < childCount(parent); ++i) {
if (childAt(parent, i)->text(0) == text)
return i;
}
return -1;
}
void SettingsTree::moveItemForward(QTreeWidgetItem *parent, int oldIndex,
int newIndex)
{
for (int i = 0; i < oldIndex - newIndex; ++i)
delete childAt(parent, newIndex);
}

View File

@ -0,0 +1,61 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef SETTINGSTREE_H
#define SETTINGSTREE_H
#include <QIcon>
#include <QTimer>
#include <QTreeWidget>
#include <QSharedPointer>
QT_BEGIN_NAMESPACE
class QSettings;
QT_END_NAMESPACE
struct TypeChecker;
class SettingsTree : public QTreeWidget
{
Q_OBJECT
public:
using SettingsPtr = QSharedPointer<QSettings>;
using TypeCheckerPtr = QSharedPointer<TypeChecker>;
SettingsTree(QWidget *parent = nullptr);
~SettingsTree();
void setSettingsObject(const SettingsPtr &settings);
QSize sizeHint() const override;
public slots:
void setAutoRefresh(bool autoRefresh);
void setFallbacksEnabled(bool enabled);
void maybeRefresh();
void refresh();
protected:
bool event(QEvent *event) override;
private slots:
void updateSetting(QTreeWidgetItem *item);
private:
void updateChildItems(QTreeWidgetItem *parent);
QTreeWidgetItem *createItem(const QString &text, QTreeWidgetItem *parent,
int index);
QTreeWidgetItem *childAt(QTreeWidgetItem *parent, int index) const;
int childCount(QTreeWidgetItem *parent) const;
int findChild(QTreeWidgetItem *parent, const QString &text, int startIndex) const;
void moveItemForward(QTreeWidgetItem *parent, int oldIndex, int newIndex);
SettingsPtr settings;
TypeCheckerPtr m_typeChecker;
QTimer refreshTimer;
QIcon groupIcon;
QIcon keyIcon;
bool autoRefresh = false;
};
#endif

View File

@ -0,0 +1,377 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "variantdelegate.h"
#include <QCheckBox>
#include <QDateTime>
#include <QLineEdit>
#include <QSpinBox>
#include <QRegularExpressionValidator>
#include <QTextStream>
#include <algorithm>
static bool isPrintableChar(char c)
{
return uchar(c) >= 32 && uchar(c) < 128;
}
static bool isPrintable(const QByteArray &ba)
{
return std::all_of(ba.cbegin(), ba.cend(), isPrintableChar);
}
static QString byteArrayToString(const QByteArray &ba)
{
if (isPrintable(ba))
return QString::fromLatin1(ba);
QString result;
for (char c : ba) {
if (isPrintableChar(c)) {
if (c == '\\')
result += QLatin1Char(c);
result += QLatin1Char(c);
} else {
const uint uc = uchar(c);
result += "\\x";
if (uc < 16)
result += '0';
result += QString::number(uc, 16);
}
}
return result;
}
TypeChecker::TypeChecker()
{
boolExp.setPattern("^(true)|(false)$");
boolExp.setPatternOptions(QRegularExpression::CaseInsensitiveOption);
Q_ASSERT(boolExp.isValid());
byteArrayExp.setPattern(R"RX(^[\x00-\xff]*$)RX");
charExp.setPattern("^.$");
Q_ASSERT(charExp.isValid());
colorExp.setPattern(R"RX(^\(([0-9]*),([0-9]*),([0-9]*),([0-9]*)\)$)RX");
Q_ASSERT(colorExp.isValid());
doubleExp.setPattern("");
pointExp.setPattern(R"RX(^\((-?[0-9]*),(-?[0-9]*)\)$)RX");
Q_ASSERT(pointExp.isValid());
rectExp.setPattern(R"RX(^\((-?[0-9]*),(-?[0-9]*),(-?[0-9]*),(-?[0-9]*)\)$)RX");
Q_ASSERT(rectExp.isValid());
signedIntegerExp.setPattern("^-?[0-9]*$");
Q_ASSERT(signedIntegerExp.isValid());
sizeExp = pointExp;
unsignedIntegerExp.setPattern("^[0-9]+$");
Q_ASSERT(unsignedIntegerExp.isValid());
const QString datePattern = "([0-9]{,4})-([0-9]{,2})-([0-9]{,2})";
dateExp.setPattern('^' + datePattern + '$');
Q_ASSERT(dateExp.isValid());
const QString timePattern = "([0-9]{,2}):([0-9]{,2}):([0-9]{,2})";
timeExp.setPattern('^' + timePattern + '$');
Q_ASSERT(timeExp.isValid());
dateTimeExp.setPattern('^' + datePattern + 'T' + timePattern + '$');
Q_ASSERT(dateTimeExp.isValid());
}
VariantDelegate::VariantDelegate(const QSharedPointer<TypeChecker> &typeChecker,
QObject *parent)
: QStyledItemDelegate(parent),
m_typeChecker(typeChecker)
{
}
void VariantDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
if (index.column() == 2) {
QVariant value = index.model()->data(index, Qt::UserRole);
if (!isSupportedType(value.userType())) {
QStyleOptionViewItem myOption = option;
myOption.state &= ~QStyle::State_Enabled;
QStyledItemDelegate::paint(painter, myOption, index);
return;
}
}
QStyledItemDelegate::paint(painter, option, index);
}
QWidget *VariantDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem & /* option */,
const QModelIndex &index) const
{
if (index.column() != 2)
return nullptr;
QVariant originalValue = index.model()->data(index, Qt::UserRole);
if (!isSupportedType(originalValue.userType()))
return nullptr;
switch (originalValue.userType()) {
case QMetaType::Bool:
return new QCheckBox(parent);
break;
case QMetaType::Int:
case QMetaType::LongLong: {
auto spinBox = new QSpinBox(parent);
spinBox->setRange(-32767, 32767);
return spinBox;
}
case QMetaType::UInt:
case QMetaType::ULongLong: {
auto spinBox = new QSpinBox(parent);
spinBox->setRange(0, 63335);
return spinBox;
}
default:
break;
}
QLineEdit *lineEdit = new QLineEdit(parent);
lineEdit->setFrame(false);
QRegularExpression regExp;
switch (originalValue.userType()) {
case QMetaType::Bool:
regExp = m_typeChecker->boolExp;
break;
case QMetaType::QByteArray:
regExp = m_typeChecker->byteArrayExp;
break;
case QMetaType::QChar:
regExp = m_typeChecker->charExp;
break;
case QMetaType::QColor:
regExp = m_typeChecker->colorExp;
break;
case QMetaType::QDate:
regExp = m_typeChecker->dateExp;
break;
case QMetaType::QDateTime:
regExp = m_typeChecker->dateTimeExp;
break;
case QMetaType::Double:
regExp = m_typeChecker->doubleExp;
break;
case QMetaType::Int:
case QMetaType::LongLong:
regExp = m_typeChecker->signedIntegerExp;
break;
case QMetaType::QPoint:
regExp = m_typeChecker->pointExp;
break;
case QMetaType::QRect:
regExp = m_typeChecker->rectExp;
break;
case QMetaType::QSize:
regExp = m_typeChecker->sizeExp;
break;
case QMetaType::QTime:
regExp = m_typeChecker->timeExp;
break;
case QMetaType::UInt:
case QMetaType::ULongLong:
regExp = m_typeChecker->unsignedIntegerExp;
break;
default:
break;
}
if (regExp.isValid()) {
QValidator *validator = new QRegularExpressionValidator(regExp, lineEdit);
lineEdit->setValidator(validator);
}
return lineEdit;
}
void VariantDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const
{
QVariant value = index.model()->data(index, Qt::UserRole);
if (auto spinBox = qobject_cast<QSpinBox *>(editor)) {
const auto userType = value.userType();
if (userType == QMetaType::UInt || userType == QMetaType::ULongLong)
spinBox->setValue(value.toUInt());
else
spinBox->setValue(value.toInt());
} else if (auto checkBox = qobject_cast<QCheckBox *>(editor)) {
checkBox->setChecked(value.toBool());
} else if (QLineEdit *lineEdit = qobject_cast<QLineEdit *>(editor)) {
if (value.userType() == QMetaType::QByteArray
&& !isPrintable(value.toByteArray())) {
lineEdit->setReadOnly(true);
}
lineEdit->setText(displayText(value));
}
}
void VariantDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
const QVariant originalValue = index.model()->data(index, Qt::UserRole);
QVariant value;
if (auto spinBox = qobject_cast<QSpinBox *>(editor)) {
value.setValue(spinBox->value());
} else if (auto checkBox = qobject_cast<QCheckBox *>(editor)) {
value.setValue(checkBox->isChecked());
} else if (QLineEdit *lineEdit = qobject_cast<QLineEdit *>(editor)) {
if (!lineEdit->isModified())
return;
QString text = lineEdit->text();
const QValidator *validator = lineEdit->validator();
if (validator) {
int pos;
if (validator->validate(text, pos) != QValidator::Acceptable)
return;
}
QRegularExpressionMatch match;
switch (originalValue.userType()) {
case QMetaType::QChar:
value = text.at(0);
break;
case QMetaType::QColor:
match = m_typeChecker->colorExp.match(text);
value = QColor(qMin(match.captured(1).toInt(), 255),
qMin(match.captured(2).toInt(), 255),
qMin(match.captured(3).toInt(), 255),
qMin(match.captured(4).toInt(), 255));
break;
case QMetaType::QDate:
{
QDate date = QDate::fromString(text, Qt::ISODate);
if (!date.isValid())
return;
value = date;
}
break;
case QMetaType::QDateTime:
{
QDateTime dateTime = QDateTime::fromString(text, Qt::ISODate);
if (!dateTime.isValid())
return;
value = dateTime;
}
break;
case QMetaType::QPoint:
match = m_typeChecker->pointExp.match(text);
value = QPoint(match.captured(1).toInt(), match.captured(2).toInt());
break;
case QMetaType::QRect:
match = m_typeChecker->rectExp.match(text);
value = QRect(match.captured(1).toInt(), match.captured(2).toInt(),
match.captured(3).toInt(), match.captured(4).toInt());
break;
case QMetaType::QSize:
match = m_typeChecker->sizeExp.match(text);
value = QSize(match.captured(1).toInt(), match.captured(2).toInt());
break;
case QMetaType::QStringList:
value = text.split(',');
break;
case QMetaType::QTime:
{
QTime time = QTime::fromString(text, Qt::ISODate);
if (!time.isValid())
return;
value = time;
}
break;
default:
value = text;
value.convert(originalValue.metaType());
}
}
model->setData(index, displayText(value), Qt::DisplayRole);
model->setData(index, value, Qt::UserRole);
}
bool VariantDelegate::isSupportedType(int type)
{
switch (type) {
case QMetaType::Bool:
case QMetaType::QByteArray:
case QMetaType::QChar:
case QMetaType::QColor:
case QMetaType::QDate:
case QMetaType::QDateTime:
case QMetaType::Double:
case QMetaType::Int:
case QMetaType::LongLong:
case QMetaType::QPoint:
case QMetaType::QRect:
case QMetaType::QSize:
case QMetaType::QString:
case QMetaType::QStringList:
case QMetaType::QTime:
case QMetaType::UInt:
case QMetaType::ULongLong:
return true;
default:
return false;
}
}
QString VariantDelegate::displayText(const QVariant &value)
{
switch (value.userType()) {
case QMetaType::Bool:
return value.toBool() ? "" : "";
case QMetaType::QByteArray:
return byteArrayToString(value.toByteArray());
case QMetaType::QChar:
case QMetaType::Double:
case QMetaType::Int:
case QMetaType::LongLong:
case QMetaType::QString:
case QMetaType::UInt:
case QMetaType::ULongLong:
return value.toString();
case QMetaType::QColor:
{
QColor color = qvariant_cast<QColor>(value);
return QString("(%1,%2,%3,%4)")
.arg(color.red()).arg(color.green())
.arg(color.blue()).arg(color.alpha());
}
case QMetaType::QDate:
return value.toDate().toString(Qt::ISODate);
case QMetaType::QDateTime:
return value.toDateTime().toString(Qt::ISODate);
case QMetaType::UnknownType:
return "<Invalid>";
case QMetaType::QPoint:
{
QPoint point = value.toPoint();
return QString("(%1,%2)").arg(point.x()).arg(point.y());
}
case QMetaType::QRect:
{
QRect rect = value.toRect();
return QString("(%1,%2,%3,%4)")
.arg(rect.x()).arg(rect.y())
.arg(rect.width()).arg(rect.height());
}
case QMetaType::QSize:
{
QSize size = value.toSize();
return QString("(%1,%2)").arg(size.width()).arg(size.height());
}
case QMetaType::QStringList:
return value.toStringList().join(',');
case QMetaType::QTime:
return value.toTime().toString(Qt::ISODate);
default:
break;
}
return QString("<%1>").arg(value.typeName());
}

View File

@ -0,0 +1,53 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef VARIANTDELEGATE_H
#define VARIANTDELEGATE_H
#include <QStyledItemDelegate>
#include <QRegularExpression>
#include <QSharedPointer>
struct TypeChecker
{
TypeChecker();
QRegularExpression boolExp;
QRegularExpression byteArrayExp;
QRegularExpression charExp;
QRegularExpression colorExp;
QRegularExpression dateExp;
QRegularExpression dateTimeExp;
QRegularExpression doubleExp;
QRegularExpression pointExp;
QRegularExpression rectExp;
QRegularExpression signedIntegerExp;
QRegularExpression sizeExp;
QRegularExpression timeExp;
QRegularExpression unsignedIntegerExp;
};
class VariantDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
explicit VariantDelegate(const QSharedPointer<TypeChecker> &typeChecker,
QObject *parent = nullptr);
void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const override;
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const override;
void setEditorData(QWidget *editor, const QModelIndex &index) const override;
void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const override;
static bool isSupportedType(int type);
static QString displayText(const QVariant &value);
private:
QSharedPointer<TypeChecker> m_typeChecker;
};
#endif