improved settings dialog API

This commit is contained in:
Martchus 2016-04-04 14:49:40 +02:00
parent 4cca128180
commit 87fd94a2e0
15 changed files with 1880 additions and 14 deletions

View File

@ -18,12 +18,15 @@ set(HEADER_FILES
settingsdialog/optioncategorymodel.h
settingsdialog/optionpage.h
settingsdialog/settingsdialog.h
settingsdialog/qtsettings.h
widgets/buttonoverlay.h
widgets/clearcombobox.h
widgets/clearlineedit.h
widgets/clearplaintextedit.h
widgets/clearspinbox.h
widgets/iconbutton.h
paletteeditor/paletteeditor.h
paletteeditor/colorbutton.h
)
set(SRC_FILES
aboutdialog/aboutdialog.cpp
@ -38,18 +41,24 @@ set(SRC_FILES
settingsdialog/optioncategorymodel.cpp
settingsdialog/optionpage.cpp
settingsdialog/settingsdialog.cpp
settingsdialog/qtsettings.cpp
widgets/buttonoverlay.cpp
widgets/clearcombobox.cpp
widgets/clearlineedit.cpp
widgets/clearplaintextedit.cpp
widgets/clearspinbox.cpp
widgets/iconbutton.cpp
paletteeditor/paletteeditor.cpp
paletteeditor/colorbutton.cpp
resources/qtutilsicons.qrc
)
set(WIDGETS_UI_FILES
aboutdialog/aboutdialog.ui
enterpassworddialog/enterpassworddialog.ui
settingsdialog/settingsdialog.ui
settingsdialog/qtappearanceoptionpage.ui
settingsdialog/qtlanguageoptionpage.ui
paletteeditor/paletteeditor.ui
)
# meta data

View File

@ -0,0 +1,233 @@
#include "./colorbutton.h"
#include <QColorDialog>
#include <QPainter>
#include <QMimeData>
#include <QDragEnterEvent>
#include <QDrag>
#include <QApplication>
namespace Widgets {
class ColorButtonPrivate
{
ColorButton *q_ptr;
Q_DECLARE_PUBLIC(ColorButton)
public:
QColor m_color;
#ifndef QT_NO_DRAGANDDROP
QColor m_dragColor;
QPoint m_dragStart;
bool m_dragging;
#endif
bool m_backgroundCheckered;
void slotEditColor();
QColor shownColor() const;
QPixmap generatePixmap() const;
};
void ColorButtonPrivate::slotEditColor()
{
const QColor newColor = QColorDialog::getColor(m_color, q_ptr, QString(), QColorDialog::ShowAlphaChannel);
if (!newColor.isValid() || newColor == q_ptr->color())
return;
q_ptr->setColor(newColor);
emit q_ptr->colorChanged(m_color);
}
QColor ColorButtonPrivate::shownColor() const
{
#ifndef QT_NO_DRAGANDDROP
if (m_dragging)
return m_dragColor;
#endif
return m_color;
}
QPixmap ColorButtonPrivate::generatePixmap() const
{
QPixmap pix(24, 24);
int pixSize = 20;
QBrush br(shownColor());
QPixmap pm(2 * pixSize, 2 * pixSize);
QPainter pmp(&pm);
pmp.fillRect(0, 0, pixSize, pixSize, Qt::lightGray);
pmp.fillRect(pixSize, pixSize, pixSize, pixSize, Qt::lightGray);
pmp.fillRect(0, pixSize, pixSize, pixSize, Qt::darkGray);
pmp.fillRect(pixSize, 0, pixSize, pixSize, Qt::darkGray);
pmp.fillRect(0, 0, 2 * pixSize, 2 * pixSize, shownColor());
br = QBrush(pm);
QPainter p(&pix);
int corr = 1;
QRect r = pix.rect().adjusted(corr, corr, -corr, -corr);
p.setBrushOrigin((r.width() % pixSize + pixSize) / 2 + corr, (r.height() % pixSize + pixSize) / 2 + corr);
p.fillRect(r, br);
p.fillRect(r.width() / 4 + corr, r.height() / 4 + corr,
r.width() / 2, r.height() / 2,
QColor(shownColor().rgb()));
p.drawRect(pix.rect().adjusted(0, 0, -1, -1));
return pix;
}
///////////////
ColorButton::ColorButton(QWidget *parent)
: QToolButton(parent), d_ptr(new ColorButtonPrivate)
{
d_ptr->q_ptr = this;
d_ptr->m_dragging = false;
d_ptr->m_backgroundCheckered = true;
setAcceptDrops(true);
connect(this, SIGNAL(clicked()), this, SLOT(slotEditColor()));
setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred));
}
ColorButton::~ColorButton()
{
}
void ColorButton::setColor(const QColor &color)
{
if (d_ptr->m_color == color)
return;
d_ptr->m_color = color;
update();
}
QColor ColorButton::color() const
{
return d_ptr->m_color;
}
void ColorButton::setBackgroundCheckered(bool checkered)
{
if (d_ptr->m_backgroundCheckered == checkered)
return;
d_ptr->m_backgroundCheckered = checkered;
update();
}
bool ColorButton::isBackgroundCheckered() const
{
return d_ptr->m_backgroundCheckered;
}
void ColorButton::paintEvent(QPaintEvent *event)
{
QToolButton::paintEvent(event);
if (!isEnabled())
return;
const int pixSize = 10;
QBrush br(d_ptr->shownColor());
if (d_ptr->m_backgroundCheckered) {
QPixmap pm(2 * pixSize, 2 * pixSize);
QPainter pmp(&pm);
pmp.fillRect(0, 0, pixSize, pixSize, Qt::white);
pmp.fillRect(pixSize, pixSize, pixSize, pixSize, Qt::white);
pmp.fillRect(0, pixSize, pixSize, pixSize, Qt::black);
pmp.fillRect(pixSize, 0, pixSize, pixSize, Qt::black);
pmp.fillRect(0, 0, 2 * pixSize, 2 * pixSize, d_ptr->shownColor());
br = QBrush(pm);
}
QPainter p(this);
const int corr = 4;
QRect r = rect().adjusted(corr, corr, -corr, -corr);
p.setBrushOrigin((r.width() % pixSize + pixSize) / 2 + corr, (r.height() % pixSize + pixSize) / 2 + corr);
p.fillRect(r, br);
//const int adjX = qRound(r.width() / 4.0);
//const int adjY = qRound(r.height() / 4.0);
//p.fillRect(r.adjusted(adjX, adjY, -adjX, -adjY),
// QColor(d_ptr->shownColor().rgb()));
/*
p.fillRect(r.adjusted(0, r.height() * 3 / 4, 0, 0),
QColor(d_ptr->shownColor().rgb()));
p.fillRect(r.adjusted(0, 0, 0, -r.height() * 3 / 4),
QColor(d_ptr->shownColor().rgb()));
*/
/*
const QColor frameColor0(0, 0, 0, qRound(0.2 * (0xFF - d_ptr->shownColor().alpha())));
p.setPen(frameColor0);
p.drawRect(r.adjusted(adjX, adjY, -adjX - 1, -adjY - 1));
*/
const QColor frameColor1(0, 0, 0, 26);
p.setPen(frameColor1);
p.drawRect(r.adjusted(1, 1, -2, -2));
const QColor frameColor2(0, 0, 0, 51);
p.setPen(frameColor2);
p.drawRect(r.adjusted(0, 0, -1, -1));
}
void ColorButton::mousePressEvent(QMouseEvent *event)
{
#ifndef QT_NO_DRAGANDDROP
if (event->button() == Qt::LeftButton)
d_ptr->m_dragStart = event->pos();
#endif
QToolButton::mousePressEvent(event);
}
void ColorButton::mouseMoveEvent(QMouseEvent *event)
{
#ifndef QT_NO_DRAGANDDROP
if (event->buttons() & Qt::LeftButton &&
(d_ptr->m_dragStart - event->pos()).manhattanLength() > QApplication::startDragDistance()) {
QMimeData *mime = new QMimeData;
mime->setColorData(color());
QDrag *drg = new QDrag(this);
drg->setMimeData(mime);
drg->setPixmap(d_ptr->generatePixmap());
setDown(false);
event->accept();
drg->start();
return;
}
#endif
QToolButton::mouseMoveEvent(event);
}
#ifndef QT_NO_DRAGANDDROP
void ColorButton::dragEnterEvent(QDragEnterEvent *event)
{
const QMimeData *mime = event->mimeData();
if (!mime->hasColor())
return;
event->accept();
d_ptr->m_dragColor = qvariant_cast<QColor>(mime->colorData());
d_ptr->m_dragging = true;
update();
}
void ColorButton::dragLeaveEvent(QDragLeaveEvent *event)
{
event->accept();
d_ptr->m_dragging = false;
update();
}
void ColorButton::dropEvent(QDropEvent *event)
{
event->accept();
d_ptr->m_dragging = false;
if (d_ptr->m_dragColor == color())
return;
setColor(d_ptr->m_dragColor);
emit colorChanged(color());
}
#endif
}
#include "moc_colorbutton.cpp"

View File

@ -0,0 +1,53 @@
#ifndef COLORBUTTON_H
#define COLORBUTTON_H
#include <c++utilities/application/global.h>
#include <QToolButton>
namespace Widgets {
/*!
* \brief The ColorButton class is used by PaletteEditor.
*
* This is taken from qttools/src/shared/qtgradienteditor/qtcolorbutton.h.
*/
class LIB_EXPORT ColorButton : public QToolButton
{
Q_OBJECT
Q_PROPERTY(bool backgroundCheckered READ isBackgroundCheckered WRITE setBackgroundCheckered)
public:
ColorButton(QWidget *parent = nullptr);
~ColorButton();
bool isBackgroundCheckered() const;
void setBackgroundCheckered(bool checkered);
QColor color() const;
public slots:
void setColor(const QColor &color);
signals:
void colorChanged(const QColor &color);
protected:
void paintEvent(QPaintEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
#ifndef QT_NO_DRAGANDDROP
void dragEnterEvent(QDragEnterEvent *event);
void dragLeaveEvent(QDragLeaveEvent *event);
void dropEvent(QDropEvent *event);
#endif
private:
QScopedPointer<class ColorButtonPrivate> d_ptr;
Q_DECLARE_PRIVATE(ColorButton)
Q_DISABLE_COPY(ColorButton)
Q_PRIVATE_SLOT(d_func(), void slotEditColor())
};
}
#endif

View File

@ -0,0 +1,561 @@
#include "./paletteeditor.h"
#include "./colorbutton.h"
#include <QMetaProperty>
#include <QPainter>
#include <QToolButton>
#include <QLabel>
#include <QHeaderView>
using namespace Widgets;
namespace Dialogs {
enum { BrushRole = 33 };
PaletteEditor::PaletteEditor(QWidget *parent) :
QDialog(parent),
m_currentColorGroup(QPalette::Active),
m_paletteModel(new PaletteModel(this)),
m_modelUpdated(false),
m_paletteUpdated(false),
m_compute(true)
{
m_ui.setupUi(this);
m_ui.paletteView->setModel(m_paletteModel);
updatePreviewPalette();
updateStyledButton();
m_ui.paletteView->setModel(m_paletteModel);
ColorDelegate *delegate = new ColorDelegate(this);
m_ui.paletteView->setItemDelegate(delegate);
m_ui.paletteView->setEditTriggers(QAbstractItemView::AllEditTriggers);
connect(m_paletteModel, &PaletteModel::paletteChanged,
this, &PaletteEditor::paletteChanged);
m_ui.paletteView->setSelectionBehavior(QAbstractItemView::SelectRows);
m_ui.paletteView->setDragEnabled(true);
m_ui.paletteView->setDropIndicatorShown(true);
m_ui.paletteView->setRootIsDecorated(false);
m_ui.paletteView->setColumnHidden(2, true);
m_ui.paletteView->setColumnHidden(3, true);
}
PaletteEditor::~PaletteEditor()
{
}
QPalette PaletteEditor::palette() const
{
return m_editPalette;
}
void PaletteEditor::setPalette(const QPalette &palette)
{
m_editPalette = palette;
const uint mask = palette.resolve();
for (int i = 0; i < (int)QPalette::NColorRoles; i++) {
if (!(mask & (1 << i))) {
m_editPalette.setBrush(QPalette::Active, static_cast<QPalette::ColorRole>(i),
m_parentPalette.brush(QPalette::Active, static_cast<QPalette::ColorRole>(i)));
m_editPalette.setBrush(QPalette::Inactive, static_cast<QPalette::ColorRole>(i),
m_parentPalette.brush(QPalette::Inactive, static_cast<QPalette::ColorRole>(i)));
m_editPalette.setBrush(QPalette::Disabled, static_cast<QPalette::ColorRole>(i),
m_parentPalette.brush(QPalette::Disabled, static_cast<QPalette::ColorRole>(i)));
}
}
m_editPalette.resolve(mask);
updatePreviewPalette();
updateStyledButton();
m_paletteUpdated = true;
if (!m_modelUpdated)
m_paletteModel->setPalette(m_editPalette, m_parentPalette);
m_paletteUpdated = false;
}
void PaletteEditor::setPalette(const QPalette &palette, const QPalette &parentPalette)
{
m_parentPalette = parentPalette;
setPalette(palette);
}
void PaletteEditor::on_buildButton_colorChanged(const QColor &)
{
buildPalette();
}
void PaletteEditor::on_activeRadio_clicked()
{
m_currentColorGroup = QPalette::Active;
updatePreviewPalette();
}
void PaletteEditor::on_inactiveRadio_clicked()
{
m_currentColorGroup = QPalette::Inactive;
updatePreviewPalette();
}
void PaletteEditor::on_disabledRadio_clicked()
{
m_currentColorGroup = QPalette::Disabled;
updatePreviewPalette();
}
void PaletteEditor::on_computeRadio_clicked()
{
if (m_compute)
return;
m_ui.paletteView->setColumnHidden(2, true);
m_ui.paletteView->setColumnHidden(3, true);
m_compute = true;
m_paletteModel->setCompute(true);
}
void PaletteEditor::on_detailsRadio_clicked()
{
if (!m_compute)
return;
const int w = m_ui.paletteView->columnWidth(1);
m_ui.paletteView->setColumnHidden(2, false);
m_ui.paletteView->setColumnHidden(3, false);
QHeaderView *header = m_ui.paletteView->header();
header->resizeSection(1, w / 3);
header->resizeSection(2, w / 3);
header->resizeSection(3, w / 3);
m_compute = false;
m_paletteModel->setCompute(false);
}
void PaletteEditor::paletteChanged(const QPalette &palette)
{
m_modelUpdated = true;
if (!m_paletteUpdated)
setPalette(palette);
m_modelUpdated = false;
}
void PaletteEditor::buildPalette()
{
const QColor btn = m_ui.buildButton->color();
const QPalette temp = QPalette(btn);
setPalette(temp);
}
void PaletteEditor::updatePreviewPalette()
{
const QPalette::ColorGroup g = currentColorGroup();
// build the preview palette
const QPalette currentPalette = palette();
QPalette previewPalette;
for(int i = QPalette::WindowText; i < QPalette::NColorRoles; ++i) {
const QPalette::ColorRole r = static_cast<QPalette::ColorRole>(i);
const QBrush br = currentPalette.brush(g, r);
previewPalette.setBrush(QPalette::Active, r, br);
previewPalette.setBrush(QPalette::Inactive, r, br);
previewPalette.setBrush(QPalette::Disabled, r, br);
}
}
void PaletteEditor::updateStyledButton()
{
m_ui.buildButton->setColor(palette().color(QPalette::Active, QPalette::Button));
}
QPalette PaletteEditor::getPalette(QWidget *parent, const QPalette &init,
const QPalette &parentPal, int *ok)
{
PaletteEditor dlg(parent);
QPalette parentPalette(parentPal);
uint mask = init.resolve();
for (int i = 0; i < (int)QPalette::NColorRoles; ++i) {
if (!(mask & (1 << i))) {
parentPalette.setBrush(QPalette::Active, static_cast<QPalette::ColorRole>(i),
init.brush(QPalette::Active, static_cast<QPalette::ColorRole>(i)));
parentPalette.setBrush(QPalette::Inactive, static_cast<QPalette::ColorRole>(i),
init.brush(QPalette::Inactive, static_cast<QPalette::ColorRole>(i)));
parentPalette.setBrush(QPalette::Disabled, static_cast<QPalette::ColorRole>(i),
init.brush(QPalette::Disabled, static_cast<QPalette::ColorRole>(i)));
}
}
dlg.setPalette(init, parentPalette);
const int result = dlg.exec();
if (ok) *ok = result;
return result == QDialog::Accepted ? dlg.palette() : init;
}
//////////////////////
PaletteModel::PaletteModel(QObject *parent) :
QAbstractTableModel(parent),
m_compute(true)
{
const QMetaObject *meta = metaObject();
const int index = meta->indexOfProperty("colorRole");
const QMetaProperty p = meta->property(index);
const QMetaEnum e = p.enumerator();
for (int r = QPalette::WindowText; r < QPalette::NColorRoles; r++) {
m_roleNames[static_cast<QPalette::ColorRole>(r)] = QLatin1String(e.key(r));
}
}
int PaletteModel::rowCount(const QModelIndex &) const
{
return m_roleNames.count();
}
int PaletteModel::columnCount(const QModelIndex &) const
{
return 4;
}
QVariant PaletteModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (index.row() < 0 || index.row() >= QPalette::NColorRoles)
return QVariant();
if (index.column() < 0 || index.column() >= 4)
return QVariant();
if (index.column() == 0) {
if (role == Qt::DisplayRole)
return m_roleNames[static_cast<QPalette::ColorRole>(index.row())];
if (role == Qt::EditRole) {
const uint mask = m_palette.resolve();
if (mask & (1 << index.row()))
return true;
return false;
}
return QVariant();
}
if (role == BrushRole)
return m_palette.brush(columnToGroup(index.column()),
static_cast<QPalette::ColorRole>(index.row()));
return QVariant();
}
bool PaletteModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid())
return false;
if (index.column() != 0 && role == BrushRole) {
const QBrush br = qvariant_cast<QBrush>(value);
const QPalette::ColorRole r = static_cast<QPalette::ColorRole>(index.row());
const QPalette::ColorGroup g = columnToGroup(index.column());
m_palette.setBrush(g, r, br);
QModelIndex idxBegin = PaletteModel::index(r, 0);
QModelIndex idxEnd = PaletteModel::index(r, 3);
if (m_compute) {
m_palette.setBrush(QPalette::Inactive, r, br);
switch (r) {
case QPalette::WindowText:
case QPalette::Text:
case QPalette::ButtonText:
case QPalette::Base:
break;
case QPalette::Dark:
m_palette.setBrush(QPalette::Disabled, QPalette::WindowText, br);
m_palette.setBrush(QPalette::Disabled, QPalette::Dark, br);
m_palette.setBrush(QPalette::Disabled, QPalette::Text, br);
m_palette.setBrush(QPalette::Disabled, QPalette::ButtonText, br);
idxBegin = PaletteModel::index(0, 0);
idxEnd = PaletteModel::index(m_roleNames.count() - 1, 3);
break;
case QPalette::Window:
m_palette.setBrush(QPalette::Disabled, QPalette::Base, br);
m_palette.setBrush(QPalette::Disabled, QPalette::Window, br);
idxBegin = PaletteModel::index(QPalette::Base, 0);
break;
case QPalette::Highlight:
//m_palette.setBrush(QPalette::Disabled, QPalette::Highlight, c.dark(120));
break;
default:
m_palette.setBrush(QPalette::Disabled, r, br);
break;
}
}
emit paletteChanged(m_palette);
emit dataChanged(idxBegin, idxEnd);
return true;
}
if (index.column() == 0 && role == Qt::EditRole) {
uint mask = m_palette.resolve();
const bool isMask = qvariant_cast<bool>(value);
const int r = index.row();
if (isMask)
mask |= (1 << r);
else {
m_palette.setBrush(QPalette::Active, static_cast<QPalette::ColorRole>(r),
m_parentPalette.brush(QPalette::Active, static_cast<QPalette::ColorRole>(r)));
m_palette.setBrush(QPalette::Inactive, static_cast<QPalette::ColorRole>(r),
m_parentPalette.brush(QPalette::Inactive, static_cast<QPalette::ColorRole>(r)));
m_palette.setBrush(QPalette::Disabled, static_cast<QPalette::ColorRole>(r),
m_parentPalette.brush(QPalette::Disabled, static_cast<QPalette::ColorRole>(r)));
mask &= ~(1 << index.row());
}
m_palette.resolve(mask);
emit paletteChanged(m_palette);
const QModelIndex idxEnd = PaletteModel::index(r, 3);
emit dataChanged(index, idxEnd);
return true;
}
return false;
}
Qt::ItemFlags PaletteModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return Qt::ItemIsEnabled;
return Qt::ItemIsEditable | Qt::ItemIsEnabled;
}
QVariant PaletteModel::headerData(int section, Qt::Orientation orientation,
int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
if (section == 0)
return tr("Color Role");
if (section == groupToColumn(QPalette::Active))
return tr("Active");
if (section == groupToColumn(QPalette::Inactive))
return tr("Inactive");
if (section == groupToColumn(QPalette::Disabled))
return tr("Disabled");
}
return QVariant();
}
QPalette PaletteModel::getPalette() const
{
return m_palette;
}
void PaletteModel::setPalette(const QPalette &palette, const QPalette &parentPalette)
{
m_parentPalette = parentPalette;
m_palette = palette;
const QModelIndex idxBegin = index(0, 0);
const QModelIndex idxEnd = index(m_roleNames.count() - 1, 3);
emit dataChanged(idxBegin, idxEnd);
}
QPalette::ColorGroup PaletteModel::columnToGroup(int index) const
{
if (index == 1)
return QPalette::Active;
if (index == 2)
return QPalette::Inactive;
return QPalette::Disabled;
}
int PaletteModel::groupToColumn(QPalette::ColorGroup group) const
{
if (group == QPalette::Active)
return 1;
if (group == QPalette::Inactive)
return 2;
return 3;
}
//////////////////////////
BrushEditor::BrushEditor(QWidget *parent) :
QWidget(parent),
m_button(new ColorButton(this)),
m_changed(false)
{
QLayout *layout = new QHBoxLayout(this);
layout->setMargin(0);
layout->addWidget(m_button);
connect(m_button, &ColorButton::colorChanged, this, &BrushEditor::brushChanged);
setFocusProxy(m_button);
}
void BrushEditor::setBrush(const QBrush &brush)
{
m_button->setColor(brush.color());
m_changed = false;
}
QBrush BrushEditor::brush() const
{
return QBrush(m_button->color());
}
void BrushEditor::brushChanged()
{
m_changed = true;
emit changed(this);
}
bool BrushEditor::changed() const
{
return m_changed;
}
//////////////////////////
RoleEditor::RoleEditor(QWidget *parent) :
QWidget(parent),
m_label(new QLabel(this)),
m_edited(false)
{
QHBoxLayout *layout = new QHBoxLayout(this);
layout->setMargin(0);
layout->setSpacing(0);
layout->addWidget(m_label);
m_label->setAutoFillBackground(true);
m_label->setIndent(3); // ### hardcode it should have the same value of textMargin in QItemDelegate
setFocusProxy(m_label);
QToolButton *button = new QToolButton(this);
button->setToolButtonStyle(Qt::ToolButtonIconOnly);
button->setIcon(QIcon(QStringLiteral(":/qtutilities/icons/hicolor/16x16/actions/edit-clear.png")));
button->setIconSize(QSize(8,8));
button->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::MinimumExpanding));
layout->addWidget(button);
connect(button, &QAbstractButton::clicked, this, &RoleEditor::emitResetProperty);
}
void RoleEditor::setLabel(const QString &label)
{
m_label->setText(label);
}
void RoleEditor::setEdited(bool on)
{
QFont font;
if (on == true) {
font.setBold(on);
}
m_label->setFont(font);
m_edited = on;
}
bool RoleEditor::edited() const
{
return m_edited;
}
void RoleEditor::emitResetProperty()
{
setEdited(false);
emit changed(this);
}
//////////////////////////
ColorDelegate::ColorDelegate(QObject *parent) :
QItemDelegate(parent)
{
}
QWidget *ColorDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &index) const
{
QWidget *ed = nullptr;
if (index.column() == 0) {
RoleEditor *editor = new RoleEditor(parent);
connect(editor, &RoleEditor::changed, this, &ColorDelegate::commitData);
//editor->setFocusPolicy(Qt::NoFocus);
//editor->installEventFilter(const_cast<ColorDelegate *>(this));
ed = editor;
} else {
typedef void (BrushEditor::*BrushEditorWidgetSignal)(QWidget *);
BrushEditor *editor = new BrushEditor(parent);
connect(editor, static_cast<BrushEditorWidgetSignal>(&BrushEditor::changed),
this, &ColorDelegate::commitData);
editor->setFocusPolicy(Qt::NoFocus);
editor->installEventFilter(const_cast<ColorDelegate *>(this));
ed = editor;
}
return ed;
}
void ColorDelegate::setEditorData(QWidget *ed, const QModelIndex &index) const
{
if (index.column() == 0) {
const bool mask = qvariant_cast<bool>(index.model()->data(index, Qt::EditRole));
RoleEditor *editor = static_cast<RoleEditor *>(ed);
editor->setEdited(mask);
const QString colorName = qvariant_cast<QString>(index.model()->data(index, Qt::DisplayRole));
editor->setLabel(colorName);
} else {
const QBrush br = qvariant_cast<QBrush>(index.model()->data(index, BrushRole));
BrushEditor *editor = static_cast<BrushEditor *>(ed);
editor->setBrush(br);
}
}
void ColorDelegate::setModelData(QWidget *ed, QAbstractItemModel *model,
const QModelIndex &index) const
{
if (index.column() == 0) {
RoleEditor *editor = static_cast<RoleEditor *>(ed);
const bool mask = editor->edited();
model->setData(index, mask, Qt::EditRole);
} else {
BrushEditor *editor = static_cast<BrushEditor *>(ed);
if (editor->changed()) {
QBrush br = editor->brush();
model->setData(index, br, BrushRole);
}
}
}
void ColorDelegate::updateEditorGeometry(QWidget *ed,
const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QItemDelegate::updateEditorGeometry(ed, option, index);
ed->setGeometry(ed->geometry().adjusted(0, 0, -1, -1));
}
void ColorDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opt, const QModelIndex &index) const
{
QStyleOptionViewItem option = opt;
const bool mask = qvariant_cast<bool>(index.model()->data(index, Qt::EditRole));
if (index.column() == 0 && mask) {
option.font.setBold(true);
}
QBrush br = qvariant_cast<QBrush>(index.model()->data(index, BrushRole));
if (br.style() == Qt::LinearGradientPattern ||
br.style() == Qt::RadialGradientPattern ||
br.style() == Qt::ConicalGradientPattern) {
painter->save();
painter->translate(option.rect.x(), option.rect.y());
painter->scale(option.rect.width(), option.rect.height());
QGradient gr = *(br.gradient());
gr.setCoordinateMode(QGradient::LogicalMode);
br = QBrush(gr);
painter->fillRect(0, 0, 1, 1, br);
painter->restore();
} else {
painter->save();
painter->setBrushOrigin(option.rect.x(), option.rect.y());
painter->fillRect(option.rect, br);
painter->restore();
}
QItemDelegate::paint(painter, option, index);
const QColor color = static_cast<QRgb>(QApplication::style()->styleHint(QStyle::SH_Table_GridLineColor, &option));
const QPen oldPen = painter->pen();
painter->setPen(QPen(color));
painter->drawLine(option.rect.right(), option.rect.y(),
option.rect.right(), option.rect.bottom());
painter->drawLine(option.rect.x(), option.rect.bottom(),
option.rect.right(), option.rect.bottom());
painter->setPen(oldPen);
}
QSize ColorDelegate::sizeHint(const QStyleOptionViewItem &opt, const QModelIndex &index) const
{
return QItemDelegate::sizeHint(opt, index) + QSize(4, 4);
}
}

View File

@ -0,0 +1,178 @@
#ifndef PALETTEEDITOR_H
#define PALETTEEDITOR_H
#include "ui_paletteeditor.h"
#include <c++utilities/application/global.h>
#include <QItemDelegate>
QT_FORWARD_DECLARE_CLASS(QListView)
QT_FORWARD_DECLARE_CLASS(QLabel)
namespace Widgets {
class ColorButton;
}
namespace Dialogs {
/*!
* \brief The PaletteEditor class provides a dialog to customize a QPalette.
*
* This is taken from qttools/src/designer/src/components/propertyeditor/paletteeditor.cpp.
* In contrast to the original version this version doesn't provide a preview.
*/
class LIB_EXPORT PaletteEditor : public QDialog
{
Q_OBJECT
public:
PaletteEditor(QWidget *parent);
~PaletteEditor();
static QPalette getPalette(QWidget *parent, const QPalette &init = QPalette(),
const QPalette &parentPal = QPalette(), int *result = nullptr);
QPalette palette() const;
void setPalette(const QPalette &palette);
void setPalette(const QPalette &palette, const QPalette &parentPalette);
private slots:
void on_buildButton_colorChanged(const QColor &);
void on_activeRadio_clicked();
void on_inactiveRadio_clicked();
void on_disabledRadio_clicked();
void on_computeRadio_clicked();
void on_detailsRadio_clicked();
void paletteChanged(const QPalette &palette);
private:
void buildPalette();
void updatePreviewPalette();
void updateStyledButton();
QPalette::ColorGroup currentColorGroup() const
{
return m_currentColorGroup;
}
Ui::PaletteEditor m_ui;
QPalette m_editPalette;
QPalette m_parentPalette;
QPalette::ColorGroup m_currentColorGroup;
class PaletteModel *m_paletteModel;
bool m_modelUpdated;
bool m_paletteUpdated;
bool m_compute;
};
/*!
* \brief The PaletteModel class is used by PaletteEditor.
*/
class LIB_EXPORT PaletteModel : public QAbstractTableModel
{
Q_OBJECT
Q_PROPERTY(QPalette::ColorRole colorRole READ colorRole)
public:
explicit PaletteModel(QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role) const;
bool setData(const QModelIndex &index, const QVariant &value, int role);
Qt::ItemFlags flags(const QModelIndex &index) const;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const;
QPalette getPalette() const;
void setPalette(const QPalette &palette, const QPalette &parentPalette);
QPalette::ColorRole colorRole() const { return QPalette::NoRole; }
void setCompute(bool on) { m_compute = on; }
signals:
void paletteChanged(const QPalette &palette);
private:
QPalette::ColorGroup columnToGroup(int index) const;
int groupToColumn(QPalette::ColorGroup group) const;
QPalette m_palette;
QPalette m_parentPalette;
QMap<QPalette::ColorRole, QString> m_roleNames;
bool m_compute;
};
/*!
* \brief The BrushEditor class is used by PaletteEditor.
*/
class LIB_EXPORT BrushEditor : public QWidget
{
Q_OBJECT
public:
explicit BrushEditor(QWidget *parent = nullptr);
void setBrush(const QBrush &brush);
QBrush brush() const;
bool changed() const;
signals:
void changed(QWidget *widget);
private slots:
void brushChanged();
private:
Widgets::ColorButton *m_button;
bool m_changed;
};
/*!
* \brief The RoleEditor class is used by PaletteEditor.
*/
class LIB_EXPORT RoleEditor : public QWidget
{
Q_OBJECT
public:
explicit RoleEditor(QWidget *parent = nullptr);
void setLabel(const QString &label);
void setEdited(bool on);
bool edited() const;
signals:
void changed(QWidget *widget);
private slots:
void emitResetProperty();
private:
QLabel *m_label;
bool m_edited;
};
/*!
* \brief The ColorDelegate class is used by PaletteEditor.
*/
class LIB_EXPORT ColorDelegate : public QItemDelegate
{
Q_OBJECT
public:
explicit ColorDelegate(QObject *parent = nullptr);
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const;
void setEditorData(QWidget *ed, const QModelIndex &index) const;
void setModelData(QWidget *ed, QAbstractItemModel *model,
const QModelIndex &index) const;
void updateEditorGeometry(QWidget *ed,
const QStyleOptionViewItem &option, const QModelIndex &index) const;
virtual void paint(QPainter *painter, const QStyleOptionViewItem &opt,
const QModelIndex &index) const;
QSize sizeHint(const QStyleOptionViewItem &opt, const QModelIndex &index) const Q_DECL_OVERRIDE;
};
}
#endif // PALETTEEDITOR_H

View File

@ -0,0 +1,175 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialogs::PaletteEditor</class>
<widget class="QDialog" name="Dialogs::PaletteEditor">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>365</width>
<height>409</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Edit Palette</string>
</property>
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>9</number>
</property>
<property name="topMargin">
<number>9</number>
</property>
<property name="rightMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<item>
<widget class="QGroupBox" name="advancedBox">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="title">
<string>Tune Palette</string>
</property>
<layout class="QGridLayout">
<property name="leftMargin">
<number>9</number>
</property>
<property name="topMargin">
<number>9</number>
</property>
<property name="rightMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<property name="spacing">
<number>6</number>
</property>
<item row="1" column="0" colspan="4">
<widget class="QTreeView" name="paletteView">
<property name="minimumSize">
<size>
<width>0</width>
<height>200</height>
</size>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QRadioButton" name="detailsRadio">
<property name="text">
<string>Show Detai&amp;ls</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QRadioButton" name="computeRadio">
<property name="text">
<string>&amp;Compute Details</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Quick</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="Widgets::ColorButton" name="buildButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Ignored">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Widgets::ColorButton</class>
<extends>QToolButton</extends>
<header>paletteeditor/colorbutton.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>Dialogs::PaletteEditor</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>180</x>
<y>331</y>
</hint>
<hint type="destinationlabel">
<x>134</x>
<y>341</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>Dialogs::PaletteEditor</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>287</x>
<y>329</y>
</hint>
<hint type="destinationlabel">
<x>302</x>
<y>342</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -60,13 +60,11 @@ bool OptionPage::matches(const QString &searchKeyWord)
if(searchKeyWord.isEmpty()) {
return true;
}
if(displayName().contains(searchKeyWord, Qt::CaseInsensitive)) {
return true;
}
if(!m_keywordsInitialized) {
if(!m_widget) {
m_widget.reset(setupWidget()); // ensure widget has been created
}
m_keywords << m_widget->windowTitle();
// find common subwidgets
for(const QLabel *label : m_widget->findChildren<QLabel *>())
m_keywords << label->text();
@ -81,7 +79,7 @@ bool OptionPage::matches(const QString &searchKeyWord)
m_keywordsInitialized = true;
}
for(const QString &keyword : m_keywords)
if (keyword.contains(searchKeyWord, Qt::CaseInsensitive))
if(keyword.contains(searchKeyWord, Qt::CaseInsensitive))
return true;
return false;
}

View File

@ -17,15 +17,16 @@ public:
virtual ~OptionPage();
QWidget *parentWindow() const;
virtual QString displayName() const = 0;
QWidget *widget();
bool hasBeenShown() const;
virtual bool apply() = 0;
virtual void reset() = 0;
bool matches(const QString &searchKeyWord);
const QStringList &errors() const;
protected:
virtual QWidget *setupWidget() = 0;
QStringList &errors();
private:
std::unique_ptr<QWidget> m_widget;
@ -33,6 +34,7 @@ private:
bool m_shown;
bool m_keywordsInitialized;
QStringList m_keywords;
QStringList m_errors;
};
/*!
@ -51,6 +53,25 @@ inline bool OptionPage::hasBeenShown() const
return m_widget != nullptr && m_shown;
}
/*!
* \brief Returns the errors which haven been occurred when applying the changes.
*/
inline const QStringList &OptionPage::errors() const
{
return m_errors;
}
/*!
* \brief Returns the errors which haven been occurred when applying the changes.
*
* Error messages should be added when implementing apply() and something goes wrong.
* In this case, apply() should return false.
*/
inline QStringList &OptionPage::errors()
{
return m_errors;
}
/*!
* \class Dialogs::UiFileBasedOptionPage
* \brief The UiFileBasedOptionPage class is the base class for SettingsDialog pages using UI files
@ -65,7 +86,6 @@ public:
explicit UiFileBasedOptionPage(QWidget *parentWindow = nullptr);
virtual ~UiFileBasedOptionPage();
virtual QString displayName() const = 0;
virtual bool apply() = 0;
virtual void reset() = 0;
@ -114,4 +134,45 @@ inline UiClass *UiFileBasedOptionPage<UiClass>::ui()
}
#define BEGIN_DECLARE_OPTION_PAGE(SomeClass) \
class SomeClass : public ::Dialogs::OptionPage \
{ \
public: \
explicit SomeClass(QWidget *parentWidget = nullptr); \
~SomeClass(); \
bool apply(); \
void reset(); \
private:
#define BEGIN_DECLARE_UI_FILE_BASED_OPTION_PAGE(SomeClass) \
namespace Ui { \
class SomeClass; \
} \
typedef ::Dialogs::UiFileBasedOptionPage<Ui::SomeClass> SomeClass ## Base; \
class SomeClass : public ::Dialogs::UiFileBasedOptionPage<Ui::SomeClass> \
{ \
public: \
explicit SomeClass(QWidget *parentWidget = nullptr); \
~SomeClass(); \
bool apply(); \
void reset(); \
private:
#define END_DECLARE_OPTION_PAGE \
};
#define DECLARE_SETUP_WIDGETS \
protected: \
QWidget *setupWidget(); \
private:
#define DECLARE_UI_FILE_BASED_OPTION_PAGE(SomeClass) \
BEGIN_DECLARE_UI_FILE_BASED_OPTION_PAGE(SomeClass) \
END_DECLARE_OPTION_PAGE
#define DECLARE_UI_FILE_BASED_OPTION_PAGE_CUSTOM_SETUP(SomeClass) \
BEGIN_DECLARE_UI_FILE_BASED_OPTION_PAGE(SomeClass) \
DECLARE_SETUP_WIDGETS \
END_DECLARE_OPTION_PAGE
#endif // OPTIONSPAGE_H

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NS::Class</class>
<widget class="QWidget" name="NS::Class">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>345</width>
<height>146</height>
</rect>
</property>
<property name="windowTitle">
<string>Window title</string>
</property>
<property name="styleSheet">
<string notr="true">QGroupBox { font-weight: bold };</string>
</property>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,277 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialogs::QtAppearanceOptionPage</class>
<widget class="QWidget" name="Dialogs::QtAppearanceOptionPage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>514</width>
<height>158</height>
</rect>
</property>
<property name="windowTitle">
<string>Appearance</string>
</property>
<property name="styleSheet">
<string notr="true">QGroupBox { font-weight: bold };</string>
</property>
<layout class="QGridLayout" name="mainGridLayout">
<item row="3" column="0">
<widget class="QLabel" name="styleSheetLabel">
<property name="text">
<string>Style sheet</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="2" alignment="Qt::AlignHCenter">
<widget class="QCheckBox" name="fontCheckBox">
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="widgetStyleComboBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QToolButton" name="paletteToolButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>select ...</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="widgetStyleLabel">
<property name="text">
<string>Widget style</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="fontHorizontalLayout">
<property name="spacing">
<number>4</number>
</property>
<item>
<widget class="QFontComboBox" name="fontComboBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="fontPushButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>More options ...</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="4" column="0">
<widget class="QLabel" name="paletteLabel">
<property name="text">
<string>Palette</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="1">
<layout class="QHBoxLayout" name="styleSheetHorizontalLayout">
<property name="spacing">
<number>4</number>
</property>
<item>
<widget class="Widgets::ClearLineEdit" name="styleSheetLineEdit">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="styleSheetPushButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Select file ...</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="fontLabel">
<property name="text">
<string>Font</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="useDefaultLabel">
<property name="text">
<string>Use system default</string>
</property>
</widget>
</item>
<item row="2" column="2" alignment="Qt::AlignHCenter">
<widget class="QCheckBox" name="widgetStyleCheckBox">
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="2" alignment="Qt::AlignHCenter">
<widget class="QCheckBox" name="styleSheetCheckBox">
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="2" alignment="Qt::AlignHCenter">
<widget class="QCheckBox" name="paletteCheckBox">
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Widgets::ClearLineEdit</class>
<extends>QLineEdit</extends>
<header location="global">qtutilities/widgets/clearlineedit.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>fontCheckBox</sender>
<signal>toggled(bool)</signal>
<receiver>fontComboBox</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>462</x>
<y>38</y>
</hint>
<hint type="destinationlabel">
<x>193</x>
<y>39</y>
</hint>
</hints>
</connection>
<connection>
<sender>fontCheckBox</sender>
<signal>toggled(bool)</signal>
<receiver>fontPushButton</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>462</x>
<y>38</y>
</hint>
<hint type="destinationlabel">
<x>365</x>
<y>39</y>
</hint>
</hints>
</connection>
<connection>
<sender>widgetStyleCheckBox</sender>
<signal>toggled(bool)</signal>
<receiver>widgetStyleComboBox</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>462</x>
<y>71</y>
</hint>
<hint type="destinationlabel">
<x>240</x>
<y>72</y>
</hint>
</hints>
</connection>
<connection>
<sender>styleSheetCheckBox</sender>
<signal>toggled(bool)</signal>
<receiver>styleSheetLineEdit</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>462</x>
<y>104</y>
</hint>
<hint type="destinationlabel">
<x>196</x>
<y>105</y>
</hint>
</hints>
</connection>
<connection>
<sender>styleSheetCheckBox</sender>
<signal>toggled(bool)</signal>
<receiver>styleSheetPushButton</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>462</x>
<y>104</y>
</hint>
<hint type="destinationlabel">
<x>368</x>
<y>105</y>
</hint>
</hints>
</connection>
<connection>
<sender>paletteCheckBox</sender>
<signal>toggled(bool)</signal>
<receiver>paletteToolButton</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>462</x>
<y>137</y>
</hint>
<hint type="destinationlabel">
<x>99</x>
<y>138</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialogs::QtLanguageOptionPage</class>
<widget class="QWidget" name="Dialogs::QtLanguageOptionPage">
<property name="windowTitle">
<string>Localization</string>
</property>
<property name="styleSheet">
<string notr="true">QGroupBox { font-weight: bold };</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QLabel" name="localeLabel">
<property name="text">
<string>Locale</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="localeComboBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="2" alignment="Qt::AlignHCenter">
<widget class="QCheckBox" name="localeCheckBox">
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="defaultLabel">
<property name="text">
<string>Use system default</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>localeCheckBox</sender>
<signal>toggled(bool)</signal>
<receiver>localeComboBox</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>159</x>
<y>39</y>
</hint>
<hint type="destinationlabel">
<x>75</x>
<y>39</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,145 @@
#include "./qtsettings.h"
#include "./optioncategorymodel.h"
#include "./optioncategoryfiltermodel.h"
#include "./optioncategory.h"
#include "./optionpage.h"
#include "../paletteeditor/paletteeditor.h"
#include "ui_qtappearanceoptionpage.h"
#include "ui_qtlanguageoptionpage.h"
#include <QStyleFactory>
#include <QFontDialog>
#include <QFileDialog>
#include <QTimer>
#include <iostream>
using namespace std;
namespace Dialogs {
/*!
* \brief Returns a new OptionCatecory containing all Qt related
* option pages.
*/
OptionCategory *qtOptionCategory(QObject *parent)
{
auto *category = new OptionCategory(parent);
category->setDisplayName(QCoreApplication::translate("QtGui::QtOptionCategory", "Qt"));
category->setIcon(QIcon::fromTheme(QStringLiteral("qtcreator")));
category->assignPages(QList<OptionPage *>()
<< new QtAppearanceOptionPage
<< new QtLanguageOptionPage);
return category;
}
QtAppearanceOptionPage::QtAppearanceOptionPage(QWidget *parentWidget) :
QtAppearanceOptionPageBase(parentWidget),
m_fontDialog(nullptr)
{}
QtAppearanceOptionPage::~QtAppearanceOptionPage()
{}
bool QtAppearanceOptionPage::apply()
{
if(hasBeenShown()) {
// read style sheet
QString styleSheet;
if(!ui()->styleSheetLineEdit->text().isEmpty()) {
QFile file(ui()->styleSheetLineEdit->text());
if(!file.open(QFile::ReadOnly)) {
return false;
}
styleSheet.append(file.readAll());
if(file.error() != QFile::NoError) {
return false;
}
}
// apply config
const QFont font = ui()->fontComboBox->font();
const QPalette palette = ui()->paletteToolButton->palette();
QGuiApplication::setFont(font);
QGuiApplication::setPalette(palette);
if(auto *qapp = qobject_cast<QApplication *>(QApplication::instance())) {
qapp->setStyleSheet(styleSheet);
} else {
return false;
}
QApplication::setStyle(ui()->widgetStyleComboBox->currentText());
}
return true;
}
void QtAppearanceOptionPage::reset()
{
if(hasBeenShown()) {
ui()->widgetStyleComboBox->setCurrentText(QApplication::style() ? QApplication::style()->objectName() : QString());
ui()->styleSheetLineEdit->setText(QString() /* TODO */);
ui()->fontComboBox->setCurrentFont(QGuiApplication::font());
ui()->fontPushButton->setPalette(QGuiApplication::palette());
}
}
QWidget *QtAppearanceOptionPage::setupWidget()
{
// call base implementation first, so ui() is available
auto *widget = QtAppearanceOptionPageBase::setupWidget();
// setup widget style selection
ui()->widgetStyleComboBox->addItems(QStyleFactory::keys());
// setup style sheet selection
QObject::connect(ui()->styleSheetPushButton, &QPushButton::clicked, [this] {
QString styleSheetPath = QFileDialog::getOpenFileName(this->widget());
if(!styleSheetPath.isEmpty()) {
ui()->styleSheetLineEdit->setText(styleSheetPath);
}
});
// setup font selection
QObject::connect(ui()->fontPushButton, &QPushButton::clicked, [this] {
if(!m_fontDialog) {
m_fontDialog = new QFontDialog(this->widget());
m_fontDialog->setCurrentFont(ui()->fontComboBox->font());
QObject::connect(m_fontDialog, &QFontDialog::fontSelected, ui()->fontComboBox, &QFontComboBox::setCurrentFont);
QObject::connect(ui()->fontComboBox, &QFontComboBox::currentFontChanged, m_fontDialog, &QFontDialog::setCurrentFont);
}
m_fontDialog->show();
});
// setup palette selection
QObject::connect(ui()->paletteToolButton, &QToolButton::clicked, [this] {
ui()->paletteToolButton->setPalette(PaletteEditor::getPalette(this->widget(), ui()->paletteToolButton->palette()));
});
return widget;
}
QtLanguageOptionPage::QtLanguageOptionPage(QWidget *parentWidget) :
QtLanguageOptionPageBase(parentWidget)
{}
QtLanguageOptionPage::~QtLanguageOptionPage()
{}
bool QtLanguageOptionPage::apply()
{
if(hasBeenShown()) {
QLocale::setDefault(ui()->localeComboBox->currentText());
}
return true;
}
void QtLanguageOptionPage::reset()
{
if(hasBeenShown()) {
ui()->localeComboBox->setCurrentText(QLocale().name());
}
}
}

View File

@ -0,0 +1,28 @@
// The functions and classes declared in this header are experimental.
// API/ABI might change in minor release!
#ifndef QT_UTILITIES_QTSETTINGS_H
#define QT_UTILITIES_QTSETTINGS_H
#include "./optionpage.h"
#include <memory>
QT_FORWARD_DECLARE_CLASS(QFontDialog)
namespace Dialogs {
class OptionCategory;
OptionCategory LIB_EXPORT *qtOptionCategory(QObject *parent = nullptr);
BEGIN_DECLARE_UI_FILE_BASED_OPTION_PAGE(QtAppearanceOptionPage)
DECLARE_SETUP_WIDGETS
QFontDialog *m_fontDialog;
END_DECLARE_OPTION_PAGE
DECLARE_UI_FILE_BASED_OPTION_PAGE(QtLanguageOptionPage)
}
#endif // QT_UTILITIES_QTSETTINGS_H

View File

@ -12,6 +12,8 @@
#include <QItemSelectionModel>
#include <QShowEvent>
#include <QScrollArea>
#include <QStringBuilder>
#include <QMessageBox>
namespace Dialogs {
@ -30,7 +32,8 @@ SettingsDialog::SettingsDialog(QWidget *parent) :
m_categoryModel(new OptionCategoryModel(this)),
m_categoryFilterModel(new OptionCategoryFilterModel(this)),
m_currentCategory(nullptr),
m_tabBarAlwaysVisible(true)
m_tabBarAlwaysVisible(true),
m_categoriesAlwaysVisible(true)
{
m_ui->setupUi(this);
makeHeading(m_ui->headingLabel);
@ -61,7 +64,6 @@ SettingsDialog::~SettingsDialog()
/*!
* \brief Sets whether the tab bar is always visible.
*
* \sa SettingsDialog::isTabBarAlwaysVisible()
*/
void SettingsDialog::setTabBarAlwaysVisible(bool value)
@ -72,6 +74,21 @@ void SettingsDialog::setTabBarAlwaysVisible(bool value)
}
}
/*!
* \brief Sets whether the category selection is always visible.
* \sa SettingsDialog::areCategoriesAlwaysVisible()
*/
void SettingsDialog::setCategoriesAlwaysVisible(bool value)
{
m_categoriesAlwaysVisible = value;
bool visible = value || m_categoryModel->rowCount();
m_ui->filterLineEdit->setVisible(visible);
m_ui->categoriesListView->setVisible(visible);
if(!visible) {
m_ui->filterLineEdit->clear();
}
}
/*!
* \brief Returns the category for the specified \a categoryIndex.
*
@ -155,14 +172,14 @@ void SettingsDialog::updateTabWidget()
if(index < m_ui->pagesTabWidget->count()) {
scrollArea = qobject_cast<QScrollArea *>(m_ui->pagesTabWidget->widget(index));
scrollArea->takeWidget();
m_ui->pagesTabWidget->setTabText(index, page->displayName());
m_ui->pagesTabWidget->setTabText(index, page->widget()->windowTitle());
} else {
scrollArea = new QScrollArea(m_ui->pagesTabWidget);
scrollArea->setFrameStyle(QFrame::NoFrame);
scrollArea->setBackgroundRole(QPalette::Base);
scrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
scrollArea->setWidgetResizable(true);
m_ui->pagesTabWidget->addTab(scrollArea, page->displayName());
m_ui->pagesTabWidget->addTab(scrollArea, page->widget()->windowTitle());
}
if(page->widget()->layout()) {
page->widget()->layout()->setAlignment(Qt::AlignTop | Qt::AlignLeft);
@ -189,15 +206,41 @@ void SettingsDialog::updateTabWidget()
*/
bool SettingsDialog::apply()
{
QString errorMessage;
for(OptionCategory *category : m_categoryModel->categories()) {
for(OptionPage *page : category->pages()) {
if(!page->apply()) {
return false;
if(errorMessage.isEmpty()) {
errorMessage = tr("<p><b>Errors occured when applying changes.</b></p><ul>");
}
if(const_cast<const OptionPage *>(page)->errors().isEmpty()) {
errorMessage.append(QStringLiteral("<li><i>")
% category->displayName()
% QLatin1Char('/')
% page->widget()->windowTitle()
% QStringLiteral("</i>: ")
% tr("unknonw error")
% QStringLiteral("</li>"));
} else {
for(const QString &error : const_cast<const OptionPage *>(page)->errors()) {
errorMessage.append(QStringLiteral("<li><i>")
% category->displayName()
% QLatin1Char('/')
% page->widget()->windowTitle()
% QStringLiteral("</i>: ")
% error
% QStringLiteral("</li>"));
}
}
}
}
}
if(!errorMessage.isEmpty()) {
errorMessage.append(QStringLiteral("</ul>"));
QMessageBox::warning(this, windowTitle(), errorMessage);
}
emit applied();
return true;
return errorMessage.isEmpty();
}
/*!

View File

@ -21,13 +21,16 @@ class SettingsDialog;
class LIB_EXPORT SettingsDialog : public QDialog
{
Q_OBJECT
Q_PROPERTY(bool isTabBarAlwaysVisible READ isTabBarAlwaysVisible WRITE setTabBarAlwaysVisible)
Q_PROPERTY(bool tabBarAlwaysVisible READ isTabBarAlwaysVisible WRITE setTabBarAlwaysVisible)
Q_PROPERTY(bool categoriesAlwaysVisible READ areCategoriesAlwaysVisible WRITE setCategoriesAlwaysVisible)
public:
explicit SettingsDialog(QWidget *parent = nullptr);
virtual ~SettingsDialog();
~SettingsDialog();
bool isTabBarAlwaysVisible() const;
void setTabBarAlwaysVisible(bool value);
bool areCategoriesAlwaysVisible() const;
void setCategoriesAlwaysVisible(bool value);
OptionCategoryModel *categoryModel();
OptionCategory *category(int categoryIndex) const;
OptionPage *page(int categoryIndex, int pageIndex) const;
@ -54,6 +57,7 @@ private:
OptionCategoryFilterModel *m_categoryFilterModel;
OptionCategory *m_currentCategory;
bool m_tabBarAlwaysVisible;
bool m_categoriesAlwaysVisible;
};
/*!
@ -68,6 +72,18 @@ inline bool SettingsDialog::isTabBarAlwaysVisible() const
return m_tabBarAlwaysVisible;
}
/*!
* \brief Returns whether the category selection is always visible.
*
* The category selection is always visible by default.
*
* \sa SettingsDialog::setCategoriesAlwaysVisible()
*/
inline bool SettingsDialog::areCategoriesAlwaysVisible() const
{
return m_categoriesAlwaysVisible;
}
/*!
* \brief Returns the category model used by the settings dialog to manage the categories.
*/