Gui: Add interface for managing preference packs
This commit is contained in:
@@ -320,6 +320,14 @@ void App::Metadata::addGenericMetadata(const std::string& tag, const Meta::Gener
|
|||||||
_genericMetadata.insert(std::make_pair(tag, genericMetadata));
|
_genericMetadata.insert(std::make_pair(tag, genericMetadata));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void App::Metadata::removeContentItem(const std::string& tag, const std::string& itemName)
|
||||||
|
{
|
||||||
|
auto tagRange = _content.equal_range(tag);
|
||||||
|
auto foundItem = std::find_if(tagRange.first, tagRange.second, [itemName](auto check) -> bool { return itemName == check.second.name(); });
|
||||||
|
if (foundItem != tagRange.second)
|
||||||
|
_content.erase(foundItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
DOMElement* appendSimpleXMLNode(DOMElement* baseNode, const std::string& nodeName, const std::string& nodeContents)
|
DOMElement* appendSimpleXMLNode(DOMElement* baseNode, const std::string& nodeName, const std::string& nodeContents)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -255,6 +255,9 @@ namespace App {
|
|||||||
void setFreeCADMax(const Meta::Version& version);
|
void setFreeCADMax(const Meta::Version& version);
|
||||||
void addGenericMetadata(const std::string& tag, const Meta::GenericMetadata& genericMetadata);
|
void addGenericMetadata(const std::string& tag, const Meta::GenericMetadata& genericMetadata);
|
||||||
|
|
||||||
|
// Deleters (work in progress...)
|
||||||
|
void removeContentItem(const std::string& tag, const std::string& itemName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write the metadata to an XML file
|
* Write the metadata to an XML file
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -322,6 +322,7 @@ SET(Gui_UIC_SRCS
|
|||||||
DlgOnlineHelp.ui
|
DlgOnlineHelp.ui
|
||||||
DlgParameter.ui
|
DlgParameter.ui
|
||||||
DlgParameterFind.ui
|
DlgParameterFind.ui
|
||||||
|
DlgPreferencePackManagement.ui
|
||||||
DlgPreferences.ui
|
DlgPreferences.ui
|
||||||
DlgProjectInformation.ui
|
DlgProjectInformation.ui
|
||||||
DlgProjectUtility.ui
|
DlgProjectUtility.ui
|
||||||
@@ -418,6 +419,7 @@ SET(Dialog_CPP_SRCS
|
|||||||
DlgMaterialPropertiesImp.cpp
|
DlgMaterialPropertiesImp.cpp
|
||||||
DlgParameterImp.cpp
|
DlgParameterImp.cpp
|
||||||
DlgParameterFind.cpp
|
DlgParameterFind.cpp
|
||||||
|
DlgPreferencePackManagementImp.cpp
|
||||||
DlgProjectInformationImp.cpp
|
DlgProjectInformationImp.cpp
|
||||||
DlgProjectUtility.cpp
|
DlgProjectUtility.cpp
|
||||||
DlgPropertyLink.cpp
|
DlgPropertyLink.cpp
|
||||||
@@ -456,6 +458,7 @@ SET(Dialog_HPP_SRCS
|
|||||||
DlgMaterialPropertiesImp.h
|
DlgMaterialPropertiesImp.h
|
||||||
DlgParameterImp.h
|
DlgParameterImp.h
|
||||||
DlgParameterFind.h
|
DlgParameterFind.h
|
||||||
|
DlgPreferencePackManagementImp.h
|
||||||
DlgProjectInformationImp.h
|
DlgProjectInformationImp.h
|
||||||
DlgProjectUtility.h
|
DlgProjectUtility.h
|
||||||
DlgPropertyLink.h
|
DlgPropertyLink.h
|
||||||
@@ -499,6 +502,7 @@ SET(Dialog_SRCS
|
|||||||
DlgMaterialProperties.ui
|
DlgMaterialProperties.ui
|
||||||
DlgParameter.ui
|
DlgParameter.ui
|
||||||
DlgParameterFind.ui
|
DlgParameterFind.ui
|
||||||
|
DlgPreferencePackManagement.ui
|
||||||
DlgProjectInformation.ui
|
DlgProjectInformation.ui
|
||||||
DlgProjectUtility.ui
|
DlgProjectUtility.ui
|
||||||
DlgPropertyLink.ui
|
DlgPropertyLink.ui
|
||||||
|
|||||||
@@ -44,10 +44,7 @@
|
|||||||
#include "DlgPreferencesImp.h"
|
#include "DlgPreferencesImp.h"
|
||||||
|
|
||||||
#include "DlgCreateNewPreferencePackImp.h"
|
#include "DlgCreateNewPreferencePackImp.h"
|
||||||
|
#include "DlgPreferencePackManagementImp.h"
|
||||||
// Only needed until PreferencePacks can be managed from the AddonManager:
|
|
||||||
#include <boost/filesystem.hpp>
|
|
||||||
namespace fs = boost::filesystem;
|
|
||||||
|
|
||||||
|
|
||||||
using namespace Gui::Dialog;
|
using namespace Gui::Dialog;
|
||||||
@@ -97,19 +94,8 @@ DlgGeneralImp::DlgGeneralImp( QWidget* parent )
|
|||||||
recreatePreferencePackMenu();
|
recreatePreferencePackMenu();
|
||||||
connect(ui->SaveNewPreferencePack, &QPushButton::clicked, this, &DlgGeneralImp::saveAsNewPreferencePack);
|
connect(ui->SaveNewPreferencePack, &QPushButton::clicked, this, &DlgGeneralImp::saveAsNewPreferencePack);
|
||||||
|
|
||||||
// Future work: the Add-On Manager will be modified to include a section for Preference Packs, at which point this
|
ui->ManagePreferencePacks->setToolTip(tr("Manage preference packs"));
|
||||||
// button will be modified to open the Add-On Manager to that tab.
|
connect(ui->ManagePreferencePacks, &QPushButton::clicked, this, &DlgGeneralImp::onManagePreferencePacksClicked);
|
||||||
auto savedPreferencePacksDirectory = fs::path(App::Application::getUserAppDataDir()) / "SavedPreferencePacks";
|
|
||||||
|
|
||||||
// If that directory hasn't been created yet, just send the user to the preferences directory
|
|
||||||
if (!(fs::exists(savedPreferencePacksDirectory) && fs::is_directory(savedPreferencePacksDirectory))) {
|
|
||||||
savedPreferencePacksDirectory = fs::path(App::Application::getUserAppDataDir());
|
|
||||||
ui->ManagePreferencePacks->hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString pathToSavedPacks(QString::fromStdString(savedPreferencePacksDirectory.string()));
|
|
||||||
ui->ManagePreferencePacks->setToolTip(tr("Open the directory of saved user preference packs"));
|
|
||||||
connect(ui->ManagePreferencePacks, &QPushButton::clicked, this, [pathToSavedPacks]() { QDesktopServices::openUrl(QUrl::fromLocalFile(pathToSavedPacks)); });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -353,6 +339,7 @@ void DlgGeneralImp::recreatePreferencePackMenu()
|
|||||||
ui->PreferencePacks->setHorizontalHeaderLabels(columnHeaders);
|
ui->PreferencePacks->setHorizontalHeaderLabels(columnHeaders);
|
||||||
|
|
||||||
// Populate the Preference Packs list
|
// Populate the Preference Packs list
|
||||||
|
Application::Instance->prefPackManager()->rescan();
|
||||||
auto packs = Application::Instance->prefPackManager()->preferencePacks();
|
auto packs = Application::Instance->prefPackManager()->preferencePacks();
|
||||||
|
|
||||||
ui->PreferencePacks->setRowCount(packs.size());
|
ui->PreferencePacks->setRowCount(packs.size());
|
||||||
@@ -405,10 +392,19 @@ void DlgGeneralImp::newPreferencePackDialogAccepted()
|
|||||||
});
|
});
|
||||||
auto preferencePackName = newPreferencePackDialog->preferencePackName();
|
auto preferencePackName = newPreferencePackDialog->preferencePackName();
|
||||||
Application::Instance->prefPackManager()->save(preferencePackName, selectedTemplates);
|
Application::Instance->prefPackManager()->save(preferencePackName, selectedTemplates);
|
||||||
Application::Instance->prefPackManager()->rescan();
|
|
||||||
recreatePreferencePackMenu();
|
recreatePreferencePackMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DlgGeneralImp::onManagePreferencePacksClicked()
|
||||||
|
{
|
||||||
|
if (!this->preferencePackManagementDialog) {
|
||||||
|
this->preferencePackManagementDialog = std::make_unique<DlgPreferencePackManagementImp>(this);
|
||||||
|
connect(this->preferencePackManagementDialog.get(), &DlgPreferencePackManagementImp::packVisibilityChanged,
|
||||||
|
this, &DlgGeneralImp::recreatePreferencePackMenu);
|
||||||
|
}
|
||||||
|
this->preferencePackManagementDialog->show();
|
||||||
|
}
|
||||||
|
|
||||||
void DlgGeneralImp::onLoadPreferencePackClicked(const std::string& packName)
|
void DlgGeneralImp::onLoadPreferencePackClicked(const std::string& packName)
|
||||||
{
|
{
|
||||||
if (Application::Instance->prefPackManager()->apply(packName)) {
|
if (Application::Instance->prefPackManager()->apply(packName)) {
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ namespace Gui {
|
|||||||
namespace Dialog {
|
namespace Dialog {
|
||||||
class Ui_DlgGeneral;
|
class Ui_DlgGeneral;
|
||||||
class DlgCreateNewPreferencePackImp;
|
class DlgCreateNewPreferencePackImp;
|
||||||
|
class DlgPreferencePackManagementImp;
|
||||||
|
|
||||||
/** This class implements the settings for the application.
|
/** This class implements the settings for the application.
|
||||||
* You can change window style, size of pixmaps, size of recent file list and so on
|
* You can change window style, size of pixmaps, size of recent file list and so on
|
||||||
@@ -56,6 +57,7 @@ protected Q_SLOTS:
|
|||||||
void onLoadPreferencePackClicked(const std::string &packName);
|
void onLoadPreferencePackClicked(const std::string &packName);
|
||||||
void recreatePreferencePackMenu();
|
void recreatePreferencePackMenu();
|
||||||
void newPreferencePackDialogAccepted();
|
void newPreferencePackDialogAccepted();
|
||||||
|
void onManagePreferencePacksClicked();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setRecentFileSize();
|
void setRecentFileSize();
|
||||||
@@ -64,6 +66,7 @@ private:
|
|||||||
private:
|
private:
|
||||||
std::unique_ptr<Ui_DlgGeneral> ui;
|
std::unique_ptr<Ui_DlgGeneral> ui;
|
||||||
std::unique_ptr<DlgCreateNewPreferencePackImp> newPreferencePackDialog;
|
std::unique_ptr<DlgCreateNewPreferencePackImp> newPreferencePackDialog;
|
||||||
|
std::unique_ptr<DlgPreferencePackManagementImp> preferencePackManagementDialog;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Dialog
|
} // namespace Dialog
|
||||||
|
|||||||
105
src/Gui/DlgPreferencePackManagement.ui
Normal file
105
src/Gui/DlgPreferencePackManagement.ui
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Gui::Dialog::DlgPreferencePackManagement</class>
|
||||||
|
<widget class="QDialog" name="Gui::Dialog::DlgPreferencePackManagement">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>392</width>
|
||||||
|
<height>255</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Manage Preference Packs</string>
|
||||||
|
</property>
|
||||||
|
<property name="sizeGripEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="modal">
|
||||||
|
<bool>false</bool>
|
||||||
|
</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">
|
||||||
|
<widget class="QTreeWidget" name="treeWidget">
|
||||||
|
<property name="editTriggers">
|
||||||
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
|
</property>
|
||||||
|
<property name="showDropIndicator" stdset="0">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="alternatingRowColors">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::NoSelection</enum>
|
||||||
|
</property>
|
||||||
|
<property name="uniformRowHeights">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="headerHidden">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="columnCount">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<attribute name="headerStretchLastSection">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">1</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">2</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pushButtonOpenAddonManager">
|
||||||
|
<property name="text">
|
||||||
|
<string>Open Addon Manager...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
225
src/Gui/DlgPreferencePackManagementImp.cpp
Normal file
225
src/Gui/DlgPreferencePackManagementImp.cpp
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (c) 2022 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_
|
||||||
|
# include <QMessageBox>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "DlgPreferencePackManagementImp.h"
|
||||||
|
#include "ui_DlgPreferencePackManagement.h"
|
||||||
|
|
||||||
|
#include <PreferencePackManager.h>
|
||||||
|
#include <App/Application.h>
|
||||||
|
#include "Application.h"
|
||||||
|
#include "Command.h"
|
||||||
|
|
||||||
|
using namespace Gui::Dialog;
|
||||||
|
namespace fs = boost::filesystem;
|
||||||
|
|
||||||
|
const auto TemplateRole = Qt::UserRole;
|
||||||
|
|
||||||
|
/* TRANSLATOR Gui::Dialog::DlgPreferencePackManagementImp */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a Gui::Dialog::DlgPreferencePackManagementImp as a child of 'parent'
|
||||||
|
*/
|
||||||
|
DlgPreferencePackManagementImp::DlgPreferencePackManagementImp(QWidget* parent)
|
||||||
|
: QDialog(parent)
|
||||||
|
, ui(new Ui_DlgPreferencePackManagement)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
connect(ui->pushButtonOpenAddonManager, &QPushButton::clicked, this, &DlgPreferencePackManagementImp::showAddonManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DlgPreferencePackManagementImp::showEvent(QShowEvent* event)
|
||||||
|
{
|
||||||
|
// Separate out user-saved packs from installed packs: we can remove individual user-saved packs,
|
||||||
|
// but can only disable individual installed packs (though we can completely uninstall the pack's
|
||||||
|
// containing Addon by redirecting to the Addon Manager).
|
||||||
|
auto savedPreferencePacksDirectory = fs::path(App::Application::getUserAppDataDir()) / "SavedPreferencePacks";
|
||||||
|
auto modDirectory = fs::path(App::Application::getUserAppDataDir()) / "Mod";
|
||||||
|
auto resourcePath = fs::path(App::Application::getResourceDir()) / "Gui" / "PreferencePacks";
|
||||||
|
|
||||||
|
// The displayed tree has two levels: at the toplevel is either "User-Saved Packs" or the name
|
||||||
|
// of the addon containing the pack. Beneath those are the individual packs themselves. The tree view shows
|
||||||
|
// "Hide"/"Show" for packs installed as a Mod, and "Delete" for packs in the user-saved pack
|
||||||
|
// section.
|
||||||
|
auto userPacks = getPacksFromDirectory(savedPreferencePacksDirectory);
|
||||||
|
|
||||||
|
auto builtinPacks = getPacksFromDirectory(resourcePath);
|
||||||
|
|
||||||
|
std::map<std::string, std::vector<std::string>> installedPacks;
|
||||||
|
if (fs::exists(modDirectory) && fs::is_directory(modDirectory)) {
|
||||||
|
for (const auto& mod : fs::directory_iterator(modDirectory)) {
|
||||||
|
auto packs = getPacksFromDirectory(mod);
|
||||||
|
if (!packs.empty()) {
|
||||||
|
auto modName = mod.path().leaf().string();
|
||||||
|
installedPacks.emplace(modName, packs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->treeWidget->clear(); // Begin by clearing whatever is there
|
||||||
|
ui->treeWidget->header()->setDefaultAlignment(Qt::AlignLeft);
|
||||||
|
ui->treeWidget->setColumnCount(2);
|
||||||
|
ui->treeWidget->setSelectionMode(QAbstractItemView::SelectionMode::NoSelection);
|
||||||
|
ui->treeWidget->header()->setStretchLastSection(false);
|
||||||
|
ui->treeWidget->header()->setSectionResizeMode(0, QHeaderView::ResizeMode::Stretch);
|
||||||
|
ui->treeWidget->header()->setSectionResizeMode(1, QHeaderView::ResizeMode::ResizeToContents);
|
||||||
|
|
||||||
|
if (!userPacks.empty()) {
|
||||||
|
addTreeNode(tr("User-Saved Preference Packs").toStdString(), userPacks, TreeWidgetType::USER);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!builtinPacks.empty()) {
|
||||||
|
addTreeNode(tr("Built-In Preference Packs").toStdString(), builtinPacks, TreeWidgetType::BUILTIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& installedPack : installedPacks) {
|
||||||
|
addTreeNode(installedPack.first, installedPack.second, TreeWidgetType::ADDON);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event)
|
||||||
|
QDialog::showEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DlgPreferencePackManagementImp::addTreeNode(const std::string &name, const std::vector<std::string> &contents, TreeWidgetType twt)
|
||||||
|
{
|
||||||
|
static const auto iconIsVisible = QIcon(QLatin1String(":/icons/dagViewVisible.svg"));
|
||||||
|
static const auto iconIsInvisible = QIcon(QLatin1String(":/icons/Invisible.svg"));
|
||||||
|
auto packRoot = new QTreeWidgetItem();
|
||||||
|
packRoot->setText(0, QString::fromStdString(name));
|
||||||
|
std::vector<QTreeWidgetItem*> items;
|
||||||
|
for (const auto& packName : contents) {
|
||||||
|
auto pack = new QTreeWidgetItem(packRoot);
|
||||||
|
pack->setText(0, QString::fromStdString(packName));
|
||||||
|
items.push_back(pack);
|
||||||
|
}
|
||||||
|
ui->treeWidget->addTopLevelItem(packRoot);
|
||||||
|
packRoot->setExpanded(true);
|
||||||
|
for (const auto item : items) {
|
||||||
|
auto button = new QPushButton();
|
||||||
|
button->setFlat(true);
|
||||||
|
switch (twt) {
|
||||||
|
break; case TreeWidgetType::BUILTIN:
|
||||||
|
// The button is a "hide" button
|
||||||
|
if (Application::Instance->prefPackManager()->isVisible("##BUILT_IN##", item->text(0).toStdString()))
|
||||||
|
button->setIcon(iconIsVisible);
|
||||||
|
else
|
||||||
|
button->setIcon(iconIsInvisible);
|
||||||
|
button->setToolTip(tr("Toggle visibility of built-in preference pack '%1'").arg(item->text(0)));
|
||||||
|
connect(button, &QPushButton::clicked, [this, name, item]() {
|
||||||
|
this->hideBuiltInPack(item->text(0).toStdString());
|
||||||
|
});
|
||||||
|
break; case TreeWidgetType::USER:
|
||||||
|
// The button is a "delete" button
|
||||||
|
button->setIcon(QIcon(QLatin1String(":/icons/delete.svg")));
|
||||||
|
button->setToolTip(tr("Delete user-saved preference pack '%1'").arg(item->text(0)));
|
||||||
|
connect(button, &QPushButton::clicked, [this, item]() {
|
||||||
|
this->deleteUserPack(item->text(0).toStdString());
|
||||||
|
});
|
||||||
|
break; case TreeWidgetType::ADDON:
|
||||||
|
// The button is a "hide" button
|
||||||
|
if (Application::Instance->prefPackManager()->isVisible(name, item->text(0).toStdString()))
|
||||||
|
button->setIcon(iconIsVisible);
|
||||||
|
else
|
||||||
|
button->setIcon(iconIsInvisible);
|
||||||
|
button->setToolTip(tr("Toggle visibility of Addon preference pack '%1' (use Addon Manager to permanently remove)").arg(item->text(0)));
|
||||||
|
connect(button, &QPushButton::clicked, [this, name, item]() {
|
||||||
|
this->hideInstalledPack(name, item->text(0).toStdString());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ui->treeWidget->setItemWidget(item, 1, button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> DlgPreferencePackManagementImp::getPacksFromDirectory(const fs::path& path) const
|
||||||
|
{
|
||||||
|
std::vector<std::string> results;
|
||||||
|
auto packageMetadataFile = path / "package.xml";
|
||||||
|
if (fs::exists(packageMetadataFile) && fs::is_regular_file(packageMetadataFile)) {
|
||||||
|
try {
|
||||||
|
App::Metadata metadata(packageMetadataFile);
|
||||||
|
auto content = metadata.content();
|
||||||
|
for (const auto& item : content) {
|
||||||
|
if (item.first == "preferencepack") {
|
||||||
|
results.push_back(item.second.name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
// Failed to read the metadata, or to create the preferencePack based on it...
|
||||||
|
Base::Console().Error(("Failed to read " + packageMetadataFile.string()).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DlgPreferencePackManagementImp::deleteUserPack(const std::string& name)
|
||||||
|
{
|
||||||
|
// Do the deletion here...
|
||||||
|
auto result = QMessageBox::warning(this, tr("Delete saved preference pack?"),
|
||||||
|
tr("Are you sure you want to delete the preference pack named '%1'? This cannot be undone.").arg(QString::fromStdString(name)),
|
||||||
|
QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel);
|
||||||
|
if (result == QMessageBox::Yes) {
|
||||||
|
Application::Instance->prefPackManager()->deleteUserPack(name);
|
||||||
|
showEvent(nullptr);
|
||||||
|
packVisibilityChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DlgPreferencePackManagementImp::hideBuiltInPack(const std::string& prefPackName)
|
||||||
|
{
|
||||||
|
Application::Instance->prefPackManager()->toggleVisibility("##BUILT_IN##", prefPackName);
|
||||||
|
showEvent(nullptr);
|
||||||
|
packVisibilityChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DlgPreferencePackManagementImp::hideInstalledPack(const std::string& addonName, const std::string& prefPackName)
|
||||||
|
{
|
||||||
|
Application::Instance->prefPackManager()->toggleVisibility(addonName, prefPackName);
|
||||||
|
showEvent(nullptr);
|
||||||
|
packVisibilityChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DlgPreferencePackManagementImp::showAddonManager()
|
||||||
|
{
|
||||||
|
// Configure the view to show all preference packs (installed and uninstalled)
|
||||||
|
auto pref = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Addons");
|
||||||
|
pref->SetInt("PackageTypeSelection", 3);
|
||||||
|
pref->SetInt("StatusSelection", 0);
|
||||||
|
|
||||||
|
CommandManager& rMgr = Application::Instance->commandManager();
|
||||||
|
rMgr.runCommandByName("Std_AddonMgr");
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
DlgPreferencePackManagementImp::~DlgPreferencePackManagementImp()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "moc_DlgPreferencePackManagementImp.cpp"
|
||||||
86
src/Gui/DlgPreferencePackManagementImp.h
Normal file
86
src/Gui/DlgPreferencePackManagementImp.h
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (c) 2022 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 *
|
||||||
|
* *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef GUI_DIALOG_DLGPREFERENCEPACKMANAGEMENTIMP_H
|
||||||
|
#define GUI_DIALOG_DLGPREFERENCEPACKMANAGEMENTIMP_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <QDialog>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
class QTreeWidgetItem;
|
||||||
|
|
||||||
|
namespace Gui {
|
||||||
|
|
||||||
|
namespace Dialog {
|
||||||
|
|
||||||
|
class Ui_DlgPreferencePackManagement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class DlgCreateNewPreferencePackImp
|
||||||
|
*
|
||||||
|
* A dialog to request a preferencePack name and a set of preferencePack templates.
|
||||||
|
*
|
||||||
|
* \author Chris Hennes
|
||||||
|
*/
|
||||||
|
class GuiExport DlgPreferencePackManagementImp : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
DlgPreferencePackManagementImp(QWidget* parent = nullptr);
|
||||||
|
~DlgPreferencePackManagementImp();
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void packVisibilityChanged();
|
||||||
|
|
||||||
|
protected Q_SLOTS:
|
||||||
|
|
||||||
|
void deleteUserPack(const std::string & prefPackName);
|
||||||
|
void hideBuiltInPack(const std::string& prefPackName);
|
||||||
|
void hideInstalledPack(const std::string& addonName, const std::string& prefPackName);
|
||||||
|
|
||||||
|
void showEvent(QShowEvent* event) override;
|
||||||
|
void showAddonManager();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
enum class TreeWidgetType {
|
||||||
|
BUILTIN,
|
||||||
|
USER,
|
||||||
|
ADDON
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<Ui_DlgPreferencePackManagement> ui;
|
||||||
|
|
||||||
|
std::vector<std::string> getPacksFromDirectory(const boost::filesystem::path& path) const;
|
||||||
|
void addTreeNode(const std::string& name, const std::vector<std::string>& contents, TreeWidgetType twt);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Dialog
|
||||||
|
} // namespace Gui
|
||||||
|
|
||||||
|
#endif // GUI_DIALOG_DLGPREFERENCEPACKMANAGEMENTIMP_H
|
||||||
@@ -149,6 +149,7 @@ PreferencePackManager::PreferencePackManager()
|
|||||||
void PreferencePackManager::rescan()
|
void PreferencePackManager::rescan()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(_mutex);
|
std::lock_guard<std::mutex> lock(_mutex);
|
||||||
|
_preferencePacks.clear();
|
||||||
for (const auto& path : _preferencePackPaths) {
|
for (const auto& path : _preferencePackPaths) {
|
||||||
if (fs::exists(path) && fs::is_directory(path)) {
|
if (fs::exists(path) && fs::is_directory(path)) {
|
||||||
FindPreferencePacksInPackage(path);
|
FindPreferencePacksInPackage(path);
|
||||||
@@ -164,14 +165,24 @@ void PreferencePackManager::rescan()
|
|||||||
void Gui::PreferencePackManager::FindPreferencePacksInPackage(const fs::path& mod)
|
void Gui::PreferencePackManager::FindPreferencePacksInPackage(const fs::path& mod)
|
||||||
{
|
{
|
||||||
auto packageMetadataFile = mod / "package.xml";
|
auto packageMetadataFile = mod / "package.xml";
|
||||||
|
static const auto modDirectory = fs::path(App::Application::getUserAppDataDir()) / "Mod" / "SavedPreferencePacks";
|
||||||
|
static const auto resourcePath = fs::path(App::Application::getResourceDir()) / "Gui" / "PreferencePacks";
|
||||||
|
|
||||||
if (fs::exists(packageMetadataFile) && fs::is_regular_file(packageMetadataFile)) {
|
if (fs::exists(packageMetadataFile) && fs::is_regular_file(packageMetadataFile)) {
|
||||||
try {
|
try {
|
||||||
App::Metadata metadata(packageMetadataFile);
|
App::Metadata metadata(packageMetadataFile);
|
||||||
auto content = metadata.content();
|
auto content = metadata.content();
|
||||||
|
auto basename = mod.leaf().string();
|
||||||
|
if (mod == modDirectory)
|
||||||
|
basename = "##USER_SAVED##";
|
||||||
|
else if (mod == resourcePath)
|
||||||
|
basename = "##BUILT_IN##";
|
||||||
for (const auto& item : content) {
|
for (const auto& item : content) {
|
||||||
if (item.first == "preferencepack") {
|
if (item.first == "preferencepack") {
|
||||||
PreferencePack newPreferencePack(mod / item.second.name(), item.second);
|
if (isVisible(basename, item.second.name())) {
|
||||||
_preferencePacks.insert(std::make_pair(newPreferencePack.name(), newPreferencePack));
|
PreferencePack newPreferencePack(mod / item.second.name(), item.second);
|
||||||
|
_preferencePacks.insert(std::make_pair(newPreferencePack.name(), newPreferencePack));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -220,6 +231,77 @@ bool PreferencePackManager::apply(const std::string& preferencePackName) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string findUnusedName(const std::string &basename, ParameterGrp::handle parent)
|
||||||
|
{
|
||||||
|
int i = 1;
|
||||||
|
while (true) {
|
||||||
|
std::ostringstream nameToTest;
|
||||||
|
nameToTest << basename << "_" << i;
|
||||||
|
if (!parent->HasGroup(nameToTest.str().c_str()))
|
||||||
|
return nameToTest.str();
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PreferencePackManager::isVisible(const std::string& addonName, const std::string& preferencePackName) const
|
||||||
|
{
|
||||||
|
if (addonName == "" || preferencePackName == "")
|
||||||
|
return true;
|
||||||
|
|
||||||
|
auto pref = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/General/HiddenPreferencePacks");
|
||||||
|
auto hiddenPacks = pref->GetGroups();
|
||||||
|
auto hiddenPack = std::find_if(hiddenPacks.begin(), hiddenPacks.end(), [addonName, preferencePackName](ParameterGrp::handle handle) {
|
||||||
|
return (handle->GetASCII("addonName", "") == addonName) && (handle->GetASCII("preferencePackName", "") == preferencePackName);
|
||||||
|
});
|
||||||
|
if (hiddenPack == hiddenPacks.end())
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PreferencePackManager::toggleVisibility(const std::string& addonName, const std::string& preferencePackName)
|
||||||
|
{
|
||||||
|
if (preferencePackName == "")
|
||||||
|
return;
|
||||||
|
auto pref = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/General/HiddenPreferencePacks");
|
||||||
|
auto hiddenPacks = pref->GetGroups();
|
||||||
|
auto hiddenPack = std::find_if(hiddenPacks.begin(), hiddenPacks.end(), [addonName,preferencePackName](ParameterGrp::handle handle) {
|
||||||
|
return (handle->GetASCII("addonName", "") == addonName) && (handle->GetASCII("preferencePackName", "") == preferencePackName);
|
||||||
|
});
|
||||||
|
if (hiddenPack == hiddenPacks.end()) {
|
||||||
|
auto name = findUnusedName("PreferencePack", pref);
|
||||||
|
auto group = pref->GetGroup(name.c_str());
|
||||||
|
group->SetASCII("addonName", addonName.c_str());
|
||||||
|
group->SetASCII("preferencePackName", preferencePackName.c_str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auto groupName = (*hiddenPack)->GetGroupName();
|
||||||
|
hiddenPacks.clear(); // To decrement the reference count of the group we are about the remove...
|
||||||
|
pref->RemoveGrp(groupName);
|
||||||
|
}
|
||||||
|
rescan();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::PreferencePackManager::deleteUserPack(const std::string& name)
|
||||||
|
{
|
||||||
|
if (name == "")
|
||||||
|
return;
|
||||||
|
auto savedPreferencePacksDirectory = fs::path(App::Application::getUserAppDataDir()) / "SavedPreferencePacks";
|
||||||
|
auto savedPath = savedPreferencePacksDirectory / name;
|
||||||
|
std::unique_ptr<App::Metadata> metadata;
|
||||||
|
if (fs::exists(savedPreferencePacksDirectory / "package.xml")) {
|
||||||
|
metadata = std::make_unique<App::Metadata>(savedPreferencePacksDirectory / "package.xml");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw std::runtime_error("Lost the user-saved preference packs metadata file!");
|
||||||
|
}
|
||||||
|
metadata->removeContentItem("preferencepack", name);
|
||||||
|
metadata->write(savedPreferencePacksDirectory / "package.xml");
|
||||||
|
if (fs::exists(savedPath))
|
||||||
|
fs::remove_all(savedPath);
|
||||||
|
rescan();
|
||||||
|
}
|
||||||
|
|
||||||
void copyTemplateParameters(Base::Reference<ParameterGrp> templateGroup, const std::string& path, Base::Reference<ParameterGrp> outputGroup)
|
void copyTemplateParameters(Base::Reference<ParameterGrp> templateGroup, const std::string& path, Base::Reference<ParameterGrp> outputGroup)
|
||||||
{
|
{
|
||||||
auto userParameterHandle = App::GetApplication().GetParameterGroupByPath(path.c_str());
|
auto userParameterHandle = App::GetApplication().GetParameterGroupByPath(path.c_str());
|
||||||
|
|||||||
@@ -94,12 +94,12 @@ namespace Gui {
|
|||||||
void rescan();
|
void rescan();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an alphabetical list of names of all installed PreferencePacks
|
* Get an alphabetical list of names of all visible PreferencePacks
|
||||||
*/
|
*/
|
||||||
std::vector<std::string> preferencePackNames() const;
|
std::vector<std::string> preferencePackNames() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a map of all installed PreferencePack names and their associated packs
|
* Get a map of all visible PreferencePack names and their associated packs
|
||||||
*/
|
*/
|
||||||
std::map<std::string, PreferencePack> preferencePacks() const;
|
std::map<std::string, PreferencePack> preferencePacks() const;
|
||||||
|
|
||||||
@@ -109,6 +109,25 @@ namespace Gui {
|
|||||||
*/
|
*/
|
||||||
bool apply(const std::string& preferencePackName) const;
|
bool apply(const std::string& preferencePackName) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the visibility of the specified pack
|
||||||
|
* \return True if the preferencePack is visible, or false if not. All packs are visible by default,
|
||||||
|
* but can be marked as "invisible" (i.e. not returned by the manager in lists of packs) by using the
|
||||||
|
* toggleVisibility function.
|
||||||
|
*/
|
||||||
|
bool isVisible(const std::string& addonName, const std::string& preferencePackName) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle the visibility of the named preference pack in a named addon
|
||||||
|
*/
|
||||||
|
void toggleVisibility(const std::string& addonName, const std::string& preferencePackName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the user-saved pack specified by name
|
||||||
|
*/
|
||||||
|
void deleteUserPack(const std::string& name);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \struct TemplateFile A file containing a set of preferences that can be saved into
|
* \struct TemplateFile A file containing a set of preferences that can be saved into
|
||||||
* a PreferencePack
|
* a PreferencePack
|
||||||
|
|||||||
Reference in New Issue
Block a user