[GUI] Add PreferencePack support

Preference Packs are collections of preferences that can be applied en
mass to the user's current setup. Any preference that can be stored in
user.cfg can be stored in a preference pack, and they are designed to be
easy to distribute.

Support is also added for saving a subset of current preferences into a
new preference pack in order to facilitate easy creation of new
"themes", etc.
This commit is contained in:
Chris Hennes
2021-04-19 12:19:50 -05:00
parent 30fd2ce5b8
commit 858e88afe1
29 changed files with 1858 additions and 32 deletions

View File

@@ -0,0 +1,153 @@
/***************************************************************************
* Copyright (c) 2021 Chris Hennes <chennes@pioneerlibrarysystem.org> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#endif
#include "DlgCreateNewPreferencePackImp.h"
#include "ui_DlgCreateNewPreferencePack.h"
#include <QPushButton>
using namespace Gui::Dialog;
const auto TemplateRole = Qt::UserRole;
/* TRANSLATOR Gui::Dialog::DlgCreateNewPreferencePackImp */
/**
* Constructs a Gui::Dialog::DlgCreateNewPreferencePackImp as a child of 'parent'
*/
DlgCreateNewPreferencePackImp::DlgCreateNewPreferencePackImp(QWidget* parent)
: QDialog(parent)
, ui(new Ui_DlgCreateNewPreferencePack)
{
ui->setupUi(this);
QRegExp validNames(QString::fromUtf8("[^/\\\\?%*:|\"<>]+"));
_nameValidator.setRegExp(validNames);
ui->lineEdit->setValidator(&_nameValidator);
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
connect(ui->treeWidget, &QTreeWidget::itemChanged, this, &DlgCreateNewPreferencePackImp::onItemChanged);
}
DlgCreateNewPreferencePackImp::~DlgCreateNewPreferencePackImp()
{
}
void DlgCreateNewPreferencePackImp::setPreferencePackTemplates(const std::vector<Gui::PreferencePackManager::TemplateFile>& availableTemplates)
{
ui->treeWidget->clear();
_groups.clear();
ui->treeWidget->header()->setDefaultSectionSize(250);
_templates = availableTemplates;
for (const auto &t : _templates) {
QTreeWidgetItem* group;
if (auto foundGroup = _groups.find(t.group); foundGroup != _groups.end()) {
group = foundGroup->second;
}
else {
group = new QTreeWidgetItem(ui->treeWidget, QStringList(QString::fromStdString(t.group)));
group->setCheckState(0, Qt::Checked);
group->setExpanded(true);
_groups.insert(std::make_pair(t.group, group));
}
QStringList itemColumns;
itemColumns.push_back(QString::fromStdString(t.name));
switch (t.type) {
case Gui::PreferencePack::Type::Appearance: itemColumns.push_back(tr("Appearance")); break;
case Gui::PreferencePack::Type::Behavior: itemColumns.push_back(tr("Behavior")); break;
case Gui::PreferencePack::Type::Combination: itemColumns.push_back(tr("Combination")); break;
}
auto newItem = new QTreeWidgetItem(group, itemColumns);
newItem->setCheckState(0, Qt::Checked);
if (group->checkState(0) != newItem->checkState(0))
group->setCheckState(0, Qt::PartiallyChecked);
newItem->setData(0, TemplateRole, QVariant::fromValue(t));
group->addChild(newItem);
}
}
std::vector<Gui::PreferencePackManager::TemplateFile> DlgCreateNewPreferencePackImp::selectedTemplates() const
{
std::vector<Gui::PreferencePackManager::TemplateFile> results;
for (const auto& group : _groups)
for (int childIndex = 0; childIndex < group.second->childCount(); ++childIndex)
if (auto child = group.second->child(childIndex); child->checkState(0) == Qt::Checked)
if (child->data(0, TemplateRole).canConvert<Gui::PreferencePackManager::TemplateFile>())
results.push_back(child->data(0, TemplateRole).value<Gui::PreferencePackManager::TemplateFile>());
return results;
}
std::string DlgCreateNewPreferencePackImp::preferencePackName() const
{
return ui->lineEdit->text().toStdString();
}
void DlgCreateNewPreferencePackImp::onItemChanged(QTreeWidgetItem* item, int column)
{
Q_UNUSED(column);
const QSignalBlocker blocker(ui->treeWidget);
if (auto group = item->parent(); group) {
// Child clicked
bool firstItemChecked = false;
for (int childIndex = 0; childIndex < group->childCount(); ++childIndex) {
auto child = group->child(childIndex);
if (childIndex == 0) {
firstItemChecked = child->checkState(0) == Qt::Checked;
}
else {
bool thisItemChecked = child->checkState(0) == Qt::Checked;
if (firstItemChecked != thisItemChecked) {
group->setCheckState(0, Qt::PartiallyChecked);
return;
}
}
}
group->setCheckState(0, firstItemChecked ? Qt::Checked : Qt::Unchecked);
}
else {
// Group clicked:
auto groupCheckState = item->checkState(0);
for (int childIndex = 0; childIndex < item->childCount(); ++childIndex) {
auto child = item->child(childIndex);
child->setCheckState(0, groupCheckState);
}
}
}
void DlgCreateNewPreferencePackImp::on_lineEdit_textEdited(const QString& text)
{
ui->buttonBox->button(QDialogButtonBox::Ok)->setDisabled(text.isEmpty());
}
#include "moc_DlgCreateNewPreferencePackImp.cpp"