diff --git a/src/Gui/DlgPreferences.ui b/src/Gui/DlgPreferences.ui
index aa54ee4c1f..092907905d 100644
--- a/src/Gui/DlgPreferences.ui
+++ b/src/Gui/DlgPreferences.ui
@@ -6,8 +6,8 @@
0
0
- 570
- 454
+ 800
+ 600
@@ -20,80 +20,233 @@
true
-
- 9
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
6
- -
-
+
-
+
- 6
-
-
0
-
-
+
-
+
0
0
- 120
+ 180
0
- 128
+ 240
16777215
+
+ false
+
+
+ QFrame { background-color: rgba(0, 0, 0, 25); }
+QFrame::item { padding: 6px 8px };
+
- QFrame::StyledPanel
+ QFrame::NoFrame
- QFrame::Sunken
+ QFrame::Raised
-
- Qt::ScrollBarAlwaysOff
-
-
-
- 96
- 96
-
-
-
- 12
-
-
- QListView::IconMode
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 12
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ Qt::NoContextMenu
+
+
+ false
+
+
+ background-color: transparent;
+
+
+ QFrame::NoFrame
+
+
+ 0
+
+
+ false
+
+
+
+ 24
+ 24
+
+
+
+ false
+
+
+
+ -
+
+
+ 8
+
+
+ 16
+
+
+ 16
+
+
+ 16
+
+
+ 16
+
+
-
+
+
+
+ 1
+ 0
+
+
+
+ Reset
+
+
+
+
+
+
-
-
+
+
+
+ 12
+
+
+ 16
+
+
+ 16
+
+
+ 16
+
+
+ 16
+
+
-
+
+
+ QLayout::SetDefaultConstraint
+
+
-
+
+
+
+ 18
+
+
+
+ Header
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
+
+ 1
+ 1
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ false
+
+
+ QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok
+
+
+ false
+
+
+
+
+
- -
-
-
- QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok|QDialogButtonBox::Reset
-
-
-
- listBox
+ groupsTreeView
diff --git a/src/Gui/DlgPreferencesImp.cpp b/src/Gui/DlgPreferencesImp.cpp
index 87c48f5879..baa741cbb2 100644
--- a/src/Gui/DlgPreferencesImp.cpp
+++ b/src/Gui/DlgPreferencesImp.cpp
@@ -56,7 +56,24 @@
using namespace Gui::Dialog;
-const int DlgPreferencesImp::GroupNameRole = Qt::UserRole;
+QWidget* PreferencesPageItem::getWidget() const {
+ return _widget;
+}
+
+void PreferencesPageItem::setWidget(QWidget* widget)
+{
+ if (_widget) {
+ _widget->setProperty(PropertyName, QVariant::fromValue(nullptr));
+ }
+
+ _widget = widget;
+ _widget->setProperty(PropertyName, QVariant::fromValue(this));
+}
+
+Q_DECLARE_METATYPE(PreferencesPageItem*);
+
+const int DlgPreferencesImp::GroupNameRole = Qt::UserRole + 1;
+const int DlgPreferencesImp::PageNameRole = Qt::UserRole + 2;
/* TRANSLATOR Gui::Dialog::DlgPreferencesImp */
@@ -78,16 +95,28 @@ DlgPreferencesImp::DlgPreferencesImp(QWidget* parent, Qt::WindowFlags fl)
{
ui->setupUi(this);
- QFontMetrics fm(font());
- int length = QtTools::horizontalAdvance(fm, longestGroupName());
- ui->listBox->setFixedWidth(Base::clamp(length + 20, 108, 120));
- ui->listBox->setGridSize(QSize(Base::clamp(length + 20, 108, 120), 75));
-
// remove unused help button
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
- setupConnections();
+ connect(ui->buttonBox,
+ &QDialogButtonBox::clicked,
+ this,
+ &DlgPreferencesImp::onButtonBoxClicked);
+ connect(ui->buttonBox,
+ &QDialogButtonBox::helpRequested,
+ getMainWindow(),
+ &MainWindow::whatsThis);
+ connect(ui->groupsTreeView,
+ &QTreeView::clicked,
+ this,
+ &DlgPreferencesImp::onPageSelected);
+ connect(ui->buttonReset,
+ &QPushButton::clicked,
+ this,
+ &DlgPreferencesImp::showResetOptions);
+ ui->groupsTreeView->setModel(&_model);
+
setupPages();
// Maintain a static pointer to the current active dialog (if there is one) so that
@@ -106,110 +135,127 @@ DlgPreferencesImp::~DlgPreferencesImp()
}
}
-void DlgPreferencesImp::setupConnections()
-{
- connect(ui->buttonBox, &QDialogButtonBox::clicked,
- this, &DlgPreferencesImp::onButtonBoxClicked);
- connect(ui->buttonBox, &QDialogButtonBox::helpRequested,
- getMainWindow(), &MainWindow::whatsThis);
- connect(ui->listBox, &QListWidget::currentItemChanged,
- this, &DlgPreferencesImp::changeGroup);
- if (auto reset = ui->buttonBox->button(QDialogButtonBox::Reset)) {
- QString text = reset->text();
- text.append(QLatin1String("..."));
- reset->setText(text);
- }
-}
-
void DlgPreferencesImp::setupPages()
{
// make sure that pages are ready to create
GetWidgetFactorySupplier();
- for (const auto &group : _pages) {
- QTabWidget* groupTab = createTabForGroup(group.first);
- for (const auto &page : group.second) {
- createPageInGroup(groupTab, page);
+
+ for (const auto &[name, pages] : _pages) {
+ auto* group = createGroup(name);
+
+ for (const auto &page : pages) {
+ createPageInGroup(group, page);
}
}
- // show the first group
- ui->listBox->setCurrentRow(0);
+ updatePageDependentLabels();
}
-QString DlgPreferencesImp::longestGroupName() const
+QPixmap DlgPreferencesImp::loadIconForGroup(const std::string &name) const
{
- std::string name;
- for (const auto &group : _pages) {
- if (group.first.size() > name.size())
- name = group.first;
+ std::string fileName = name;
+
+ // normalize file name
+ for (auto& ch : fileName) {
+ ch = ch == ' ' ? '_' : tolower(ch);
}
- return QString::fromStdString(name);
-}
-
-/**
- * Create the necessary widgets for a new group named \a groupName. Returns a
- * pointer to the group's QTabWidget: that widget's lifetime is managed by the
- * tabWidgetStack, do not manually deallocate.
- */
-QTabWidget* DlgPreferencesImp::createTabForGroup(const std::string &groupName)
-{
- QString groupNameQString = QString::fromStdString(groupName);
-
- std::string fileName = groupName;
- QString tooltip;
- getGroupData(groupName, fileName, tooltip);
-
- auto tabWidget = new QTabWidget;
- ui->tabWidgetStack->addWidget(tabWidget);
- tabWidget->setProperty("GroupName", QVariant(groupNameQString));
-
- auto item = new QListWidgetItem(ui->listBox);
- item->setData(GroupNameRole, QVariant(groupNameQString));
- item->setText(QObject::tr(groupNameQString.toLatin1()));
- item->setToolTip(tooltip);
-
- for (auto &ch : fileName) {
- if (ch == ' ')
- ch = '_';
- else
- ch = tolower(ch);
- }
fileName = std::string("preferences-") + fileName;
- QPixmap icon = Gui::BitmapFactory().pixmapFromSvg(fileName.c_str(), QSize(48, 48));
+ QPixmap icon = Gui::BitmapFactory().pixmapFromSvg(fileName.c_str(), QSize(24, 24));
+
if (icon.isNull()) {
icon = Gui::BitmapFactory().pixmap(fileName.c_str());
if (icon.isNull()) {
qWarning() << "No group icon found for " << fileName.c_str();
}
- else if (icon.size() != QSize(48, 48)) {
- icon = icon.scaled(48, 48, Qt::KeepAspectRatio, Qt::SmoothTransformation);
- qWarning() << "Group icon for " << fileName.c_str() << " is not of size 48x48, so it was scaled";
+ else if (icon.size() != QSize(24, 24)) {
+ icon = icon.scaled(24, 24, Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
}
- item->setIcon(icon);
- item->setTextAlignment(Qt::AlignHCenter);
- item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
- return tabWidget;
+ return icon;
}
/**
- * Create a new preference page called \a pageName on the group tab \a tabWidget.
+ * Create the necessary widgets for a new group named \a groupName. Returns a
+ * pointer to the group's SettingsPageItem: that widget's lifetime is managed by the
+ * QStandardItemModel, do not manually deallocate.
*/
-void DlgPreferencesImp::createPageInGroup(QTabWidget *tabWidget, const std::string &pageName)
+PreferencesPageItem* DlgPreferencesImp::createGroup(const std::string &groupName)
+{
+ QString groupNameQString = QString::fromStdString(groupName);
+
+ std::string iconName;
+
+ QString tooltip;
+ getGroupData(groupName, iconName, tooltip);
+
+ auto groupPages = new QStackedWidget;
+ groupPages->setProperty(GroupNameProperty, QVariant(groupNameQString));
+
+ ui->groupWidgetStack->addWidget(groupPages);
+
+ auto item = new PreferencesPageItem;
+
+ item->setData(QVariant(groupNameQString), GroupNameRole);
+ item->setText(QObject::tr(groupNameQString.toLatin1()));
+ item->setToolTip(tooltip);
+ item->setIcon(loadIconForGroup(iconName));
+ item->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ item->setWidget(groupPages);
+
+ _model.invisibleRootItem()->appendRow(item);
+
+ return item;
+}
+
+
+PreferencePage* DlgPreferencesImp::createPreferencePage(const std::string& pageName, const std::string& groupName)
+{
+ PreferencePage* page = WidgetFactory().createPreferencePage(pageName.c_str());
+
+ if (!page) {
+ return nullptr;
+ }
+
+ // settings layout already takes care for margins, we need to reset everything to 0
+ page->setContentsMargins(0, 0, 0, 0);
+ page->layout()->setContentsMargins(0, 0, 0, 0);
+ page->setProperty(GroupNameProperty, QString::fromStdString(groupName));
+ page->setProperty(PageNameProperty, QString::fromStdString(pageName));
+
+ return page;
+}
+
+/**
+ * Create a new preference page called \a pageName in the group \a groupItem.
+ */
+void DlgPreferencesImp::createPageInGroup(PreferencesPageItem *groupItem, const std::string &pageName)
{
try {
- PreferencePage* page = WidgetFactory().createPreferencePage(pageName.c_str());
- if (page) {
- tabWidget->addTab(page, page->windowTitle());
- page->loadSettings();
- page->setProperty("GroupName", tabWidget->property("GroupName"));
- page->setProperty("PageName", QVariant(QString::fromStdString(pageName)));
- }
- else {
+ PreferencePage* page = createPreferencePage(pageName, groupItem->data(GroupNameRole).toString().toStdString());
+
+ if (!page) {
Base::Console().Warning("%s is not a preference page\n", pageName.c_str());
+
+ return;
}
+
+ auto pageItem = new PreferencesPageItem;
+
+ pageItem->setText(page->windowTitle());
+ pageItem->setEditable(false);
+ pageItem->setData(groupItem->data(GroupNameRole), GroupNameRole);
+ pageItem->setData(QString::fromStdString(pageName), PageNameRole);
+ pageItem->setWidget(page);
+
+ groupItem->appendRow(pageItem);
+
+ page->loadSettings();
+
+ auto pages = qobject_cast(groupItem->getWidget());
+ pages->addWidget(page);
}
catch (const Base::Exception& e) {
Base::Console().Error("Base exception thrown for '%s'\n", pageName.c_str());
@@ -220,11 +266,11 @@ void DlgPreferencesImp::createPageInGroup(QTabWidget *tabWidget, const std::stri
}
}
-void DlgPreferencesImp::changeGroup(QListWidgetItem *current, QListWidgetItem *previous)
+void DlgPreferencesImp::updatePageDependentLabels()
{
- if (!current)
- current = previous;
- ui->tabWidgetStack->setCurrentIndex(ui->listBox->row(current));
+ auto currentPageItem = getCurrentPage();
+
+ ui->headerLabel->setText(currentPageItem->text());
}
/**
@@ -236,7 +282,7 @@ void DlgPreferencesImp::changeGroup(QListWidgetItem *current, QListWidgetItem *p
*/
void DlgPreferencesImp::addPage(const std::string& className, const std::string& group)
{
- std::list::iterator groupToAddTo = _pages.end();
+ auto groupToAddTo = _pages.end();
for (auto it = _pages.begin(); it != _pages.end(); ++it) {
if (it->first == group) {
groupToAddTo = it;
@@ -263,7 +309,7 @@ void DlgPreferencesImp::addPage(const std::string& className, const std::string&
void DlgPreferencesImp::removePage(const std::string& className, const std::string& group)
{
- for (std::list::iterator it = _pages.begin(); it != _pages.end(); ++it) {
+ for (auto it = _pages.begin(); it != _pages.end(); ++it) {
if (it->first == group) {
if (className.empty()) {
_pages.erase(it);
@@ -274,8 +320,9 @@ void DlgPreferencesImp::removePage(const std::string& className, const std::stri
for (auto jt = p.begin(); jt != p.end(); ++jt) {
if (*jt == className) {
p.erase(jt);
- if (p.empty())
+ if (p.empty()) {
_pages.erase(it);
+ }
return;
}
}
@@ -302,16 +349,19 @@ void DlgPreferencesImp::setGroupData(const std::string& name, const std::string&
void DlgPreferencesImp::getGroupData(const std::string& group, std::string& icon, QString& tip)
{
auto it = _groupMap.find(group);
+
if (it != _groupMap.end()) {
icon = it->second.iconName;
tip = it->second.tooltip;
}
- if (icon.empty())
+ if (icon.empty()) {
icon = group;
+ }
- if (tip.isEmpty())
+ if (tip.isEmpty()) {
tip = QObject::tr(group.c_str());
+ }
}
/**
@@ -319,16 +369,20 @@ void DlgPreferencesImp::getGroupData(const std::string& group, std::string& icon
*/
void DlgPreferencesImp::activateGroupPage(const QString& group, int index)
{
- int ct = ui->listBox->count();
- for (int i=0; ilistBox->item(i);
- if (item->data(GroupNameRole).toString() == group) {
- ui->listBox->setCurrentItem(item);
- auto tabWidget = dynamic_cast(ui->tabWidgetStack->widget(i));
- if (tabWidget) {
- tabWidget->setCurrentIndex(index);
- break;
- }
+ for (int i = 0; i < ui->groupWidgetStack->count(); i++) {
+ auto* pageStackWidget = qobject_cast(ui->groupWidgetStack->widget(i));
+
+ if (!pageStackWidget) {
+ continue;
+ }
+
+ if (pageStackWidget->property(GroupNameProperty).toString() == group) {
+ ui->groupWidgetStack->setCurrentWidget(pageStackWidget);
+ pageStackWidget->setCurrentIndex(index);
+
+ updatePageDependentLabels();
+
+ return;
}
}
}
@@ -338,20 +392,20 @@ void DlgPreferencesImp::activateGroupPage(const QString& group, int index)
*/
void DlgPreferencesImp::activeGroupPage(QString& group, int& index) const
{
- int row = ui->listBox->currentRow();
- auto item = ui->listBox->item(row);
- auto tabWidget = dynamic_cast(ui->tabWidgetStack->widget(row));
+ auto groupWidget = qobject_cast(ui->groupWidgetStack->currentWidget());
- if (item && tabWidget) {
- group = item->data(GroupNameRole).toString();
- index = tabWidget->currentIndex();
+ if (groupWidget) {
+ group = groupWidget->property(GroupNameProperty).toString();
+ index = groupWidget->currentIndex();
}
}
void DlgPreferencesImp::accept()
{
this->invalidParameter = false;
+
applyChanges();
+
if (!this->invalidParameter) {
QDialog::accept();
restartIfRequired();
@@ -364,48 +418,48 @@ void DlgPreferencesImp::reject()
restartIfRequired();
}
-void DlgPreferencesImp::onButtonBoxClicked(QAbstractButton* btn)
+void DlgPreferencesImp::onButtonBoxClicked(QAbstractButton* btn)
{
if (ui->buttonBox->standardButton(btn) == QDialogButtonBox::Apply) {
applyChanges();
}
- else if (ui->buttonBox->standardButton(btn) == QDialogButtonBox::Reset) {
- showResetOptions();
- }
}
void DlgPreferencesImp::showResetOptions()
{
- // clang-format off
QMenu menu(this);
- // Reset per tab
- auto tabWidget = static_cast(ui->tabWidgetStack->currentWidget());
- int tabIndex = tabWidget->currentIndex();
- QString tabText = tabWidget->tabText(tabIndex);
- QAction* tabAction = menu.addAction(tr("Reset tab '%1'...").arg(tabText), this,
- &DlgPreferencesImp::onButtonResetTabClicked);
- tabAction->setToolTip(tr("Resets the user settings for the tab '%1'").arg(tabText));
+ auto currentPageItem = getCurrentPage();
+ auto currentGroupItem = static_cast(currentPageItem->parent());
+
+ auto pageText = currentPageItem->text();
+ auto groupText = currentGroupItem->text();
+
+ // Reset per page
+ QAction* pageAction = menu.addAction(tr("Reset page '%1'...").arg(pageText),
+ this,
+ [&] { restorePageDefaults(currentPageItem); });
+ pageAction->setToolTip(tr("Resets the user settings for the page '%1'").arg(pageText));
// Reset per group
- int groupIndex = ui->listBox->currentRow();
- QString group = ui->listBox->item(groupIndex)->text();
- QAction* grpAction = menu.addAction(tr("Reset group '%1'...").arg(group), this,
- &DlgPreferencesImp::onButtonResetGroupClicked);
- grpAction->setToolTip(tr("Resets the user settings for the group '%1'").arg(group));
+ QAction* groupAction = menu.addAction(tr("Reset group '%1'...").arg(groupText),
+ this,
+ [&] { restorePageDefaults(static_cast(currentPageItem->parent())); });
+ groupAction->setToolTip(tr("Resets the user settings for the group '%1'").arg(groupText));
// Reset all
- QAction* allAction = menu.addAction(tr("Reset all..."), this,
+ QAction* allAction = menu.addAction(tr("Reset all..."),
+ this,
&DlgPreferencesImp::restoreDefaults);
allAction->setToolTip(tr("Resets the user settings entirely"));
- connect(&menu, &QMenu::hovered, [&menu](QAction* hover){
+ connect(&menu, &QMenu::hovered, [&menu](QAction* hover) {
QPoint pos = menu.pos();
pos.rx() += menu.width() + 10;
QToolTip::showText(pos, hover->toolTip());
});
+
menu.exec(QCursor::pos());
- // clang-format on
}
void DlgPreferencesImp::restoreDefaults()
@@ -432,89 +486,6 @@ void DlgPreferencesImp::restoreDefaults()
reject();
}
}
-
-void DlgPreferencesImp::onButtonResetTabClicked()
-{
- auto tabWidget = static_cast(ui->tabWidgetStack->widget(ui->listBox->currentRow()));
-
- QMessageBox box(this);
- box.setIcon(QMessageBox::Question);
- box.setWindowTitle(tr("Reset Tab Settings"));
- box.setText(tr("All the settings for the tab '%1' will be deleted.").arg(tabWidget->tabText(tabWidget->currentIndex())));
- box.setInformativeText(tr("Do you want to continue?"));
- box.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
- box.setDefaultButton(QMessageBox::No);
-
- if (box.exec() == QMessageBox::Yes) {
- int pageIndex = tabWidget->currentIndex();
- QString pageText = tabWidget->tabText(pageIndex);
- PreferencePage* page = qobject_cast(tabWidget->widget(pageIndex));
-
- restorePageDefaults(&page);
- page->setProperty("GroupName", tabWidget->property("GroupName"));
-
- tabWidget->removeTab(pageIndex);
- tabWidget->insertTab(pageIndex, page, pageText);
- tabWidget->setCurrentIndex(pageIndex);
-
- applyChanges();
- }
-}
-
-void DlgPreferencesImp::onButtonResetGroupClicked()
-{
- QMessageBox box(this);
- box.setIcon(QMessageBox::Question);
- box.setWindowTitle(tr("Reset Group Settings"));
- box.setText(tr("All the settings for the group '%1' will be deleted.").arg(ui->listBox->currentItem()->text()));
- box.setInformativeText(tr("Do you want to continue?"));
- box.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
- box.setDefaultButton(QMessageBox::No);
-
- if (box.exec() == QMessageBox::Yes) {
- auto tabWidget = static_cast(ui->tabWidgetStack->widget(ui->listBox->currentRow()));
- int pageIndex = tabWidget->currentIndex();
-
- for (int i = 0; i < tabWidget->count(); i++) {
- QString pageText = tabWidget->tabText(i);
- PreferencePage* page = qobject_cast(tabWidget->widget(i));
-
- restorePageDefaults(&page);
- page->setProperty("GroupName", tabWidget->property("GroupName"));
-
- tabWidget->removeTab(i);
- tabWidget->insertTab(i, page, pageText);
- }
-
- tabWidget->setCurrentIndex(pageIndex);
-
- applyChanges();
- }
-}
-
-void DlgPreferencesImp::restorePageDefaults(PreferencePage** page)
-{
- QList prefs = (*page)->findChildren();
-
- for (const auto & pref : prefs) {
- if (!pref->property("prefPath").isNull() && !pref->property("prefEntry").isNull()) {
- std::string path = pref->property("prefPath").toString().toStdString();
- std::string entry = pref->property("prefEntry").toString().toStdString();
-
- ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(std::string("User parameter:BaseApp/Preferences/" + path).c_str());
-
- for (const auto & pn : hGrp->GetParameterNames(entry.c_str())){
- hGrp->RemoveAttribute(pn.first, pn.second.c_str());
- }
- }
- }
-
- std::string pageName = (*page)->property("PageName").toString().toStdString();
- (*page) = WidgetFactory().createPreferencePage(pageName.c_str());
- (*page)->loadSettings();
- (*page)->setProperty("PageName", QVariant(QString::fromStdString(pageName)));
-}
-
/**
* If the dialog is currently showing and the static variable _pages changed, this function
* will rescan that list of pages and add any that are new to the current dialog. It will not
@@ -526,33 +497,39 @@ void DlgPreferencesImp::reloadPages()
// Make sure that pages are ready to create
GetWidgetFactorySupplier();
- for (const auto &group : _pages) {
- QString groupName = QString::fromStdString(group.first);
+ for (const auto &[ group, pages ] : _pages) {
+ QString groupName = QString::fromStdString(group);
// First, does this group already exist?
- QTabWidget* tabWidget = nullptr;
- for (int tabNumber = 0; tabNumber < ui->tabWidgetStack->count(); ++tabNumber) {
- auto thisTabWidget = qobject_cast(ui->tabWidgetStack->widget(tabNumber));
- if (thisTabWidget->property("GroupName").toString() == groupName) {
- tabWidget = thisTabWidget;
+ PreferencesPageItem* groupItem = nullptr;
+
+ auto root = _model.invisibleRootItem();
+ for (int i = 0; i < root->rowCount(); i++) {
+ auto currentGroupItem = static_cast(root->child(i));
+ auto currentGroupName = currentGroupItem->data(GroupNameRole).toString();
+
+ if (currentGroupName == groupName) {
+ groupItem = currentGroupItem;
break;
}
}
- // This is a new tab that wasn't there when we started this instance of the dialog:
- if (!tabWidget) {
- tabWidget = createTabForGroup(group.first);
+ // This is a new group that wasn't there when we started this instance of the dialog:
+ if (!groupItem) {
+ groupItem = createGroup(group);
}
// Move on to the pages in the group to see if we need to add any
- for (const auto& page : group.second) {
-
+ for (const auto& page : pages) {
// Does this page already exist?
QString pageName = QString::fromStdString(page);
+
bool pageExists = false;
- for (int pageNumber = 0; pageNumber < tabWidget->count(); ++pageNumber) {
- auto prefPage = qobject_cast(tabWidget->widget(pageNumber));
- if (prefPage && prefPage->property("PageName").toString() == pageName) {
+
+ for (int i = 0; i < groupItem->rowCount(); i++) {
+ auto currentPageItem = static_cast(groupItem->child(i));
+
+ if (currentPageItem->data(PageNameRole).toString() == pageName) {
pageExists = true;
break;
}
@@ -560,7 +537,7 @@ void DlgPreferencesImp::reloadPages()
// This is a new page that wasn't there when we started this instance of the dialog:
if (!pageExists) {
- createPageInGroup(tabWidget, page);
+ createPageInGroup(groupItem, page);
}
}
}
@@ -573,36 +550,44 @@ void DlgPreferencesImp::applyChanges()
// call it to validate if user input is correct. If something fails (i.e.,
// not correct), shows a messageBox and set this->invalidParameter = true to
// cancel further operation in other methods (like in accept()).
- try {
- for (int i=0; itabWidgetStack->count(); i++) {
- auto tabWidget = static_cast(ui->tabWidgetStack->widget(i));
- for (int j=0; jcount(); j++) {
- QWidget* page = tabWidget->widget(j);
- int index = page->metaObject()->indexOfMethod("checkSettings()");
+
+ for (int i = 0; i < ui->groupWidgetStack->count(); i++) {
+ auto pagesStackWidget = qobject_cast(ui->groupWidgetStack->widget(i));
+
+ for (int j = 0; j < pagesStackWidget->count(); j++) {
+ QWidget* page = pagesStackWidget->widget(j);
+
+ int index = page->metaObject()->indexOfMethod("checkSettings()");
+
+ if (index >= 0) {
try {
- if (index >= 0) {
- page->qt_metacall(QMetaObject::InvokeMetaMethod, index, nullptr);
- }
+ page->qt_metacall(QMetaObject::InvokeMetaMethod, index, nullptr);
}
catch (const Base::Exception& e) {
- ui->listBox->setCurrentRow(i);
- tabWidget->setCurrentIndex(j);
- QMessageBox::warning(this, tr("Wrong parameter"), QString::fromLatin1(e.what()));
- throw;
+ ui->groupWidgetStack->setCurrentIndex(i);
+ pagesStackWidget->setCurrentIndex(j);
+
+ QMessageBox::warning(this,
+ tr("Wrong parameter"),
+ QString::fromLatin1(e.what()));
+
+ this->invalidParameter = true;
+
+ // exit early due to found errors
+ return;
}
}
}
- } catch (const Base::Exception&) {
- this->invalidParameter = true;
- return;
}
// If everything is ok (i.e., no validation problem), call method
// saveSettings() in every subpage (DlgSetting*) object.
- for (int i=0; itabWidgetStack->count(); i++) {
- auto tabWidget = static_cast(ui->tabWidgetStack->widget(i));
- for (int j=0; jcount(); j++) {
- auto page = qobject_cast(tabWidget->widget(j));
+ for (int i = 0; i < ui->groupWidgetStack->count(); i++) {
+ auto pageStackWidget = qobject_cast(ui->groupWidgetStack->widget(i));
+
+ for (int j = 0; j < pageStackWidget->count(); j++) {
+ auto page = qobject_cast(pageStackWidget->widget(j));
+
if (page) {
page->saveSettings();
restartRequired = restartRequired || page->isRestartRequired();
@@ -610,8 +595,10 @@ void DlgPreferencesImp::applyChanges()
}
}
- bool saveParameter = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/General")->
- GetBool("SaveUserParameter", true);
+ bool saveParameter = App::GetApplication()
+ .GetParameterGroupByPath("User parameter:BaseApp/Preferences/General")
+ ->GetBool("SaveUserParameter", true);
+
if (saveParameter) {
ParameterManager* parmgr = App::GetApplication().GetParameterSet("User parameter");
parmgr->SaveDocument(App::Application::Config()["UserParameter"].c_str());
@@ -621,18 +608,19 @@ void DlgPreferencesImp::applyChanges()
void DlgPreferencesImp::restartIfRequired()
{
if (restartRequired) {
- QMessageBox* restartBox = new QMessageBox();
- restartBox->setIcon(QMessageBox::Warning);
- restartBox->setWindowTitle(tr("Restart required"));
- restartBox->setText(tr("You must restart FreeCAD for changes to take effect."));
- restartBox->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
- restartBox->setDefaultButton(QMessageBox::Cancel);
- auto okBtn = restartBox->button(QMessageBox::Ok);
- auto cancelBtn = restartBox->button(QMessageBox::Cancel);
+ QMessageBox restartBox;
+
+ restartBox.setIcon(QMessageBox::Warning);
+ restartBox.setWindowTitle(tr("Restart required"));
+ restartBox.setText(tr("You must restart FreeCAD for changes to take effect."));
+ restartBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
+ restartBox.setDefaultButton(QMessageBox::Cancel);
+ auto okBtn = restartBox.button(QMessageBox::Ok);
+ auto cancelBtn = restartBox.button(QMessageBox::Cancel);
okBtn->setText(tr("Restart now"));
cancelBtn->setText(tr("Restart later"));
- int exec = restartBox->exec();
+ int exec = restartBox.exec();
if (exec == QMessageBox::Ok) {
//restart FreeCAD after a delay to give time to this dialog to close
@@ -653,71 +641,54 @@ void DlgPreferencesImp::showEvent(QShowEvent* ev)
QDialog::showEvent(ev);
}
-void DlgPreferencesImp::resizeEvent(QResizeEvent* ev)
+QModelIndex findRootIndex(const QModelIndex& index)
{
- if (canEmbedScrollArea) {
- // embed the widget stack into a scroll area if the size is
- // bigger than the available desktop
- QRect rect = QApplication::primaryScreen()->availableGeometry();
- int maxHeight = rect.height() - 60;
- int maxWidth = rect.width();
- if (height() > maxHeight || width() > maxWidth) {
- canEmbedScrollArea = false;
- ui->hboxLayout->removeWidget(ui->tabWidgetStack);
- auto scrollArea = new QScrollArea(this);
- scrollArea->setFrameShape(QFrame::NoFrame);
- scrollArea->setWidgetResizable(true);
- scrollArea->setWidget(ui->tabWidgetStack);
- ui->hboxLayout->addWidget(scrollArea);
+ auto root = index;
- // if possible the minimum width should so that it doesn't show
- // a horizontal scroll bar.
- auto bar = scrollArea->verticalScrollBar();
- if (bar) {
- int newWidth = width() + bar->width();
- newWidth = std::min(newWidth, maxWidth);
- int newHeight = std::min(height(), maxHeight);
- QMetaObject::invokeMethod(this, "resizeWindow",
- Qt::QueuedConnection,
- Q_ARG(int, newWidth),
- Q_ARG(int, newHeight));
- }
- QPoint center = rect.center();
- move(center.x() - width() * 0.5, 10);
- }
+ while (root.parent().isValid()) {
+ root = root.parent();
}
- QDialog::resizeEvent(ev);
+
+ return root;
}
-void DlgPreferencesImp::resizeWindow(int w, int h)
+void DlgPreferencesImp::onPageSelected(const QModelIndex& index)
{
- resize(w, h);
+ auto root = findRootIndex(index);
+
+ auto* groupItem = static_cast(_model.itemFromIndex(root));
+ auto* pagesStackWidget = static_cast(groupItem->getWidget());
+
+ ui->groupWidgetStack->setCurrentWidget(groupItem->getWidget());
+
+ if (index != root) {
+ pagesStackWidget->setCurrentIndex(index.row());
+ }
+
+ updatePageDependentLabels();
}
void DlgPreferencesImp::changeEvent(QEvent *e)
{
if (e->type() == QEvent::LanguageChange) {
ui->retranslateUi(this);
- // update the widgets' tabs
- for (int i=0; itabWidgetStack->count(); i++) {
- auto tabWidget = static_cast(ui->tabWidgetStack->widget(i));
- for (int j=0; jcount(); j++) {
- QWidget* page = tabWidget->widget(j);
- tabWidget->setTabText(j, page->windowTitle());
+
+ auto root = _model.invisibleRootItem();
+ for (int i = 0; i < root->rowCount(); i++) {
+ auto groupItem = static_cast(root->child(i));
+ auto groupName = groupItem->data(GroupNameRole).toString();
+
+ groupItem->setText(QObject::tr(groupName.toLatin1()));
+
+ for (int j = 0; j < groupItem->rowCount(); j++) {
+ auto pageModelItem = static_cast(groupItem->child(j));
+ auto pageModelWidget = static_cast(pageModelItem->getWidget());
+
+ pageModelItem->setText(pageModelWidget->windowTitle());
}
}
- // update the items' text
- for (int i=0; ilistBox->count(); i++) {
- QListWidgetItem *item = ui->listBox->item(i);
- QByteArray group = item->data(GroupNameRole).toByteArray();
- item->setText(QObject::tr(group.constData()));
- }
- //resizes items list and buttons
- QFontMetrics fm(font());
- int length = QtTools::horizontalAdvance(fm, longestGroupName());
- ui->listBox->setFixedWidth(Base::clamp(length + 20, 108, 120));
- ui->listBox->setGridSize(QSize(Base::clamp(length + 20, 108, 120), 75));
+ updatePageDependentLabels();
} else {
QWidget::changeEvent(e);
}
@@ -725,15 +696,74 @@ void DlgPreferencesImp::changeEvent(QEvent *e)
void DlgPreferencesImp::reload()
{
- for (int i = 0; i < ui->tabWidgetStack->count(); i++) {
- auto tabWidget = static_cast(ui->tabWidgetStack->widget(i));
- for (int j = 0; j < tabWidget->count(); j++) {
- auto page = qobject_cast(tabWidget->widget(j));
- if (page)
+ for (int i = 0; i < ui->groupWidgetStack->count(); i++) {
+ auto pageStackWidget = static_cast(ui->groupWidgetStack->widget(i));
+
+ for (int j = 0; j < pageStackWidget->count(); j++) {
+ auto page = qobject_cast(pageStackWidget->widget(j));
+
+ if (page) {
page->loadSettings();
+ }
}
}
+
applyChanges();
}
+void DlgPreferencesImp::restorePageDefaults(PreferencesPageItem* item)
+{
+ if (item->hasChildren()) {
+ // If page has children iterate over them and restore each
+ for (int i = 0; i < item->rowCount(); i++) {
+ auto child = static_cast(item->child(i));
+
+ restorePageDefaults(child);
+ }
+ }
+ else {
+ auto* page = qobject_cast(item->getWidget());
+ auto prefs = page->findChildren();
+
+ page->resetSettingsToDefaults();
+
+ std::string pageName = page->property(PageNameProperty).toString().toStdString();
+ std::string groupName = page->property(GroupNameProperty).toString().toStdString();
+
+ auto newPage = createPreferencePage(pageName, groupName);
+
+ newPage->loadSettings();
+
+ auto groupPageStack = qobject_cast(page->parentWidget());
+ auto replacedWidgetIndex = groupPageStack->indexOf(page);
+ auto currentWidgetIndex = groupPageStack->currentIndex();
+
+ groupPageStack->removeWidget(page);
+ groupPageStack->insertWidget(replacedWidgetIndex, newPage);
+
+ item->setWidget(newPage);
+
+ if (replacedWidgetIndex == currentWidgetIndex) {
+ groupPageStack->setCurrentIndex(currentWidgetIndex);
+ }
+ }
+}
+
+PreferencesPageItem* DlgPreferencesImp::getCurrentPage() const
+{
+ auto groupPagesStack = qobject_cast(ui->groupWidgetStack->currentWidget());
+
+ if (!groupPagesStack) {
+ return nullptr;
+ }
+
+ auto pageWidget = qobject_cast(groupPagesStack->currentWidget());
+
+ if (!pageWidget) {
+ return nullptr;
+ }
+
+ return pageWidget->property(PreferencesPageItem::PropertyName).value();
+}
+
#include "moc_DlgPreferencesImp.cpp"
diff --git a/src/Gui/DlgPreferencesImp.h b/src/Gui/DlgPreferencesImp.h
index 18631e3869..013aa1ced7 100644
--- a/src/Gui/DlgPreferencesImp.h
+++ b/src/Gui/DlgPreferencesImp.h
@@ -27,6 +27,7 @@
#define GUI_DIALOG_DLGPREFERENCESIMP_H
#include
+#include
#include
#include
@@ -34,11 +35,22 @@ class QAbstractButton;
class QListWidgetItem;
class QTabWidget;
-namespace Gui {
-namespace Dialog {
+namespace Gui::Dialog {
class PreferencePage;
class Ui_DlgPreferences;
+class PreferencesPageItem : public QStandardItem
+{
+public:
+ QWidget* getWidget() const;
+ void setWidget(QWidget* widget);
+
+ static constexpr char const* PropertyName = "SettingsPageItem";
+
+private:
+ QWidget *_widget = nullptr;
+};
+
/**
* This class implements a dialog containing several preference pages.
*
@@ -120,6 +132,8 @@ public:
static void getGroupData(const std::string& group, std::string& icon, QString& tip);
static void reloadSettings();
+ static PreferencePage* createPreferencePage(const std::string& pageName, const std::string& groupName);
+
explicit DlgPreferencesImp(QWidget* parent = nullptr, Qt::WindowFlags fl = Qt::WindowFlags());
~DlgPreferencesImp() override;
@@ -130,53 +144,63 @@ public:
void activeGroupPage(QString& group, int& index) const;
protected:
- void setupConnections();
void changeEvent(QEvent *e) override;
void showEvent(QShowEvent*) override;
- void resizeEvent(QResizeEvent*) override;
- void onButtonResetTabClicked();
- void onButtonResetGroupClicked();
-
protected Q_SLOTS:
- void changeGroup(QListWidgetItem *current, QListWidgetItem *previous);
void onButtonBoxClicked(QAbstractButton*);
- void resizeWindow(int w, int h);
+ void onPageSelected(const QModelIndex &index);
private:
/** @name for internal use only */
//@{
void setupPages();
void reloadPages();
- QTabWidget* createTabForGroup(const std::string& groupName);
- void createPageInGroup(QTabWidget* tabWidget, const std::string& pageName);
+
+ PreferencesPageItem* getCurrentPage() const;
+
+ PreferencesPageItem* createGroup(const std::string& groupName);
+ void createPageInGroup(PreferencesPageItem* item, const std::string& pageName);
+
void applyChanges();
void showResetOptions();
void restoreDefaults();
- void restorePageDefaults(PreferencePage**);
- QString longestGroupName() const;
+ void restorePageDefaults(PreferencesPageItem* item);
void restartIfRequired();
+
+ void updatePageDependentLabels();
+
+ QPixmap loadIconForGroup(const std::string& name) const;
//@}
private:
using TGroupPages = std::pair>;
+
static std::list _pages; /**< Name of all registered preference pages */
+
+ QStandardItemModel _model;
+
struct Group {
std::string iconName;
QString tooltip;
};
static std::map _groupMap;
std::unique_ptr ui;
+
bool invalidParameter;
bool canEmbedScrollArea;
bool restartRequired;
- static const int GroupNameRole; /**< A name for our Qt::UserRole, used when storing user data in a list item */
+ /**< A name for our Qt::UserRole, used when storing user data in a list item */
+ static const int GroupNameRole;
+ static const int PageNameRole;
+
+ static constexpr char const* GroupNameProperty = "GroupName";
+ static constexpr char const* PageNameProperty = "PageName";
static DlgPreferencesImp* _activeDialog; /**< Defaults to the nullptr, points to the current instance if there is one */
};
-} // namespace Dialog
} // namespace Gui
#endif // GUI_DIALOG_DLGPREFERENCESIMP_H
diff --git a/src/Gui/PrefWidgets.cpp b/src/Gui/PrefWidgets.cpp
index 314380b311..445392c041 100644
--- a/src/Gui/PrefWidgets.cpp
+++ b/src/Gui/PrefWidgets.cpp
@@ -815,7 +815,7 @@ void PrefFontBox::savePreferences()
QFont currFont = currentFont();
QString currName = currFont.family();
- getWindowParameter()->SetASCII( entryName() , currName.toUtf8() );
+ getWindowParameter()->SetASCII(entryName(), currName.toUtf8());
}
#include "moc_PrefWidgets.cpp"
diff --git a/src/Gui/PropertyPage.cpp b/src/Gui/PropertyPage.cpp
index 26123473f2..2526ad8967 100644
--- a/src/Gui/PropertyPage.cpp
+++ b/src/Gui/PropertyPage.cpp
@@ -28,6 +28,7 @@
#endif
#include
+#include
#include "PropertyPage.h"
#include "PrefWidgets.h"
@@ -209,6 +210,24 @@ void PreferenceUiForm::saveSettings()
savePrefWidgets();
}
+void PreferencePage::resetSettingsToDefaults()
+{
+ auto prefs = this->findChildren();
+
+ for (const auto& pref : prefs) {
+ if (!pref->property("prefPath").isNull() && !pref->property("prefEntry").isNull()) {
+ std::string path = pref->property("prefPath").toString().toStdString();
+ std::string entry = pref->property("prefEntry").toString().toStdString();
+
+ ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
+ std::string("User parameter:BaseApp/Preferences/" + path).c_str());
+
+ for (const auto& pn : hGrp->GetParameterNames(entry.c_str())) {
+ hGrp->RemoveAttribute(pn.first, pn.second.c_str());
+ }
+ }
+ }
+}
// ----------------------------------------------------------------
/** Construction */
diff --git a/src/Gui/PropertyPage.h b/src/Gui/PropertyPage.h
index 5d17f3bf8f..9fbf03e0b5 100644
--- a/src/Gui/PropertyPage.h
+++ b/src/Gui/PropertyPage.h
@@ -79,6 +79,7 @@ public:
public Q_SLOTS:
virtual void loadSettings()=0;
virtual void saveSettings()=0;
+ virtual void resetSettingsToDefaults();
protected:
void changeEvent(QEvent* event) override = 0;