Gui: Add importing CFG to PrefPack dialog

This commit is contained in:
Chris Hennes
2022-09-15 22:43:57 -05:00
parent b34d200c54
commit 532e509dc2
5 changed files with 138 additions and 60 deletions

View File

@@ -103,22 +103,22 @@
</widget>
</item>
<item row="1" column="2">
<widget class="Gui::PrefCheckBox" name="SubstituteDecimal">
<property name="toolTip">
<string>If enabled, numerical keypad decimal separator will be substituted with locale separator</string>
</property>
<property name="text">
<string>Substitute decimal separator (needs restart)</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>SubstituteDecimalSeparator</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>General</cstring>
</property>
</widget>
</item>
</layout>
<widget class="Gui::PrefCheckBox" name="SubstituteDecimal">
<property name="toolTip">
<string>If enabled, numerical keypad decimal separator will be substituted with locale separator</string>
</property>
<property name="text">
<string>Substitute decimal separator (needs restart)</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>SubstituteDecimalSeparator</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>General</cstring>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
@@ -170,24 +170,24 @@
<attribute name="horizontalHeaderCascadingSectionResizes">
<bool>true</bool>
</attribute>
<attribute name="horizontalHeaderDefaultSectionSize">
<number>100</number>
</attribute>
<attribute name="horizontalHeaderMinimumSectionSize">
<number>30</number>
</attribute>
<attribute name="horizontalHeaderDefaultSectionSize">
<number>100</number>
</attribute>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderDefaultSectionSize">
<number>24</number>
</attribute>
<attribute name="verticalHeaderMinimumSectionSize">
<number>16</number>
</attribute>
<attribute name="verticalHeaderDefaultSectionSize">
<number>24</number>
</attribute>
<column>
<property name="text">
<string>Name</string>
@@ -232,6 +232,13 @@
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="ImportConfig">
<property name="text">
<string>Import config...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="SaveNewPreferencePack">
<property name="text">
@@ -556,7 +563,7 @@ after FreeCAD launches</string>
</item>
</layout>
</item>
<item row="2" column="0">
<item row="2" column="0">
<widget class="Gui::PrefCheckBox" name="SplashScreen">
<property name="toolTip">
<string>A Splash screen is a small loading window that is shown
@@ -577,7 +584,7 @@ display the splash screen</string>
</property>
</widget>
</item>
</layout>
</layout>
</widget>
</item>
</layout>

View File

@@ -24,7 +24,11 @@
#include "PreCompiled.h"
#ifndef _PreComp_
# include <QApplication>
# include <QFileDialog>
# include <QLocale>
# include <QMessageBox>
# include <algorithm>
# include <boost/filesystem.hpp>
#endif
#include "DlgGeneralImp.h"
@@ -39,8 +43,8 @@
#include "PreferencePackManager.h"
#include "Language/Translator.h"
using namespace Gui::Dialog;
namespace fs = boost::filesystem;
/* TRANSLATOR Gui::Dialog::DlgGeneralImp */
@@ -86,6 +90,8 @@ DlgGeneralImp::DlgGeneralImp( QWidget* parent )
}
recreatePreferencePackMenu();
connect(ui->ImportConfig, &QPushButton::clicked, this, &DlgGeneralImp::onImportConfigClicked);
connect(ui->SaveNewPreferencePack, &QPushButton::clicked, this, &DlgGeneralImp::saveAsNewPreferencePack);
ui->ManagePreferencePacks->setToolTip(tr("Manage preference packs"));
@@ -448,6 +454,29 @@ void DlgGeneralImp::onManagePreferencePacksClicked()
this->preferencePackManagementDialog->show();
}
void DlgGeneralImp::onImportConfigClicked()
{
auto path = fs::path(QFileDialog::getOpenFileName(this,
tr("Choose a FreeCAD config file to import"),
QString(),
QString::fromUtf8("*.cfg")).toStdString());
if (!path.empty()) {
// Create a name from the filename:
auto packName = path.filename().stem().string();
std::replace(packName.begin(), packName.end(), '_', ' ');
auto existingPacks = Application::Instance->prefPackManager()->preferencePackNames();
if (std::find(existingPacks.begin(), existingPacks.end(), packName)
!= existingPacks.end()) {
auto result = QMessageBox::question(
this, tr("File exists"),
tr("A preference pack with that name already exists. Overwrite?"));
if (result == QMessageBox::No) return; // Maybe someday ask for a new name?
}
Application::Instance->prefPackManager()->importConfig(packName, path);
recreatePreferencePackMenu();
}
}
void DlgGeneralImp::onLoadPreferencePackClicked(const std::string& packName)
{
if (Application::Instance->prefPackManager()->apply(packName)) {

View File

@@ -59,6 +59,7 @@ protected Q_SLOTS:
void recreatePreferencePackMenu();
void newPreferencePackDialogAccepted();
void onManagePreferencePacksClicked();
void onImportConfigClicked();
private:
void setRecentFileSize();

View File

@@ -160,7 +160,72 @@ void PreferencePackManager::rescan()
}
}
void Gui::PreferencePackManager::FindPreferencePacksInPackage(const fs::path& mod)
void Gui::PreferencePackManager::AddPackToMetadata(const std::string &packName) const
{
std::lock_guard<std::mutex> lock(_mutex);
auto savedPreferencePacksDirectory =
fs::path(App::Application::getUserAppDataDir()) / "SavedPreferencePacks";
fs::path preferencePackDirectory(savedPreferencePacksDirectory / packName);
if (fs::exists(preferencePackDirectory) && !fs::is_directory(preferencePackDirectory))
throw std::runtime_error("Cannot create " + savedPreferencePacksDirectory.string()
+ ": file with that name exists already");
if (!fs::exists(preferencePackDirectory)) fs::create_directories(preferencePackDirectory);
// Create or update the saved user preferencePacks package.xml metadata file
std::unique_ptr<App::Metadata> metadata;
if (fs::exists(savedPreferencePacksDirectory / "package.xml")) {
metadata = std::make_unique<App::Metadata>(savedPreferencePacksDirectory / "package.xml");
}
else {
metadata = std::make_unique<App::Metadata>();
metadata->setName("User-Saved Preference Packs");
std::stringstream str;
str << "Generated automatically -- edits may be lost when saving new preference packs. To "
<< "distribute one or more of these packs:\n"
<< " 1) copy the entire SavedPreferencePacks directory to a convenient location,\n"
<< " 2) rename the directory (usually to the name of the preference pack you are "
<< "distributing),\n"
<< " 3) delete any subfolders containing packs you don't want to distribute,\n"
<< " 4) use git to initialize the directory as a git repository,\n"
<< " 5) push it to a remote git host,\n"
<< " 6) activate Developer Mode in the Addon Manager,\n"
<< " 7) use Developer Tools in the Addon Manager to update the metadata file,\n"
<< " 8) add, commit, and push the updated package.xml file,\n"
<< " 9) add your remote host to the custom repositories list in the Addon Manager"
<< " preferences,\n"
<< " 10) use the Addon Manager to install your preference pack locally for testing.";
metadata->setDescription(str.str());
metadata->addLicense(App::Meta::License("All Rights Reserved", fs::path()));
}
for (const auto &item : metadata->content()) {
if (item.first == "preferencepack") {
if (item.second.name() == packName) {
// A pack with this name exists already, bail out
return;
}
}
}
App::Metadata newPreferencePackMetadata;
newPreferencePackMetadata.setName(packName);
metadata->addContentItem("preferencepack", newPreferencePackMetadata);
metadata->write(savedPreferencePacksDirectory / "package.xml");
}
void Gui::PreferencePackManager::importConfig(const std::string& packName,
const boost::filesystem::path& path)
{
AddPackToMetadata(packName);
auto savedPreferencePacksDirectory =
fs::path(App::Application::getUserAppDataDir()) / "SavedPreferencePacks";
auto cfgFilename = savedPreferencePacksDirectory / packName / (packName + ".cfg");
fs::copy_file(path, cfgFilename, fs::copy_option::overwrite_if_exists);
rescan();
}
void Gui::PreferencePackManager::FindPreferencePacksInPackage(const fs::path &mod)
{
auto packageMetadataFile = mod / "package.xml";
static const auto modDirectory = fs::path(App::Application::getUserAppDataDir()) / "Mod" / "SavedPreferencePacks";
@@ -366,37 +431,7 @@ void PreferencePackManager::save(const std::string& name, const std::vector<Temp
if (templates.empty())
return;
std::lock_guard<std::mutex> lock(_mutex);
auto savedPreferencePacksDirectory = fs::path(App::Application::getUserAppDataDir()) / "SavedPreferencePacks";
fs::path preferencePackDirectory(savedPreferencePacksDirectory / name);
if (fs::exists(preferencePackDirectory) && !fs::is_directory(preferencePackDirectory))
throw std::runtime_error("Cannot create " + savedPreferencePacksDirectory.string() + ": file with that name exists already");
if (!fs::exists(preferencePackDirectory))
fs::create_directories(preferencePackDirectory);
// Create or update the saved user preferencePacks package.xml metadata file
std::unique_ptr<App::Metadata> metadata;
if (fs::exists(savedPreferencePacksDirectory / "package.xml")) {
metadata = std::make_unique<App::Metadata>(savedPreferencePacksDirectory / "package.xml");
}
else {
// Create and set all of the required metadata to make it easier for PreferencePack authors to copy this
// file into their preferencePack distributions.
metadata = std::make_unique<App::Metadata>();
metadata->setName("User-Saved PreferencePacks");
metadata->setDescription("Generated automatically -- edits may be lost when saving new preferencePacks");
metadata->setVersion(static_cast<App::Meta::Version>(1));
metadata->addMaintainer(App::Meta::Contact("No Maintainer", "email@freecadweb.org"));
metadata->addLicense(App::Meta::License("(Unspecified)", "(Unspecified)"));
metadata->addUrl(App::Meta::Url("https://github.com/FreeCAD/FreeCAD", App::Meta::UrlType::repository));
}
App::Metadata newPreferencePackMetadata;
newPreferencePackMetadata.setName(name);
newPreferencePackMetadata.setVersion(static_cast<App::Meta::Version>(1));
metadata->addContentItem("preferencepack", newPreferencePackMetadata);
metadata->write(savedPreferencePacksDirectory / "package.xml");
AddPackToMetadata(name);
// Create the config file
ParameterManager outputParameterManager;
@@ -406,6 +441,8 @@ void PreferencePackManager::save(const std::string& name, const std::vector<Temp
templateParameterManager.LoadDocument(t.path.string().c_str());
copyTemplateParameters(templateParameterManager, outputParameterManager);
}
auto savedPreferencePacksDirectory =
fs::path(App::Application::getUserAppDataDir()) / "SavedPreferencePacks";
auto cfgFilename = savedPreferencePacksDirectory / name / (name + ".cfg");
outputParameterManager.SaveDocument(cfgFilename.string().c_str());
}

View File

@@ -156,9 +156,6 @@ namespace Gui {
* color that is only used internally, and it should not include things like fonts, or
* behavior information.
*
* Template files are always located in a directory hierarchy that differentiates between
* templates that only affect appearance, and those that affect behavior.
*
* The base FreeCAD installation includes default templates in:
* $INSTALL_DIR/data/Gui/PreferencePackTemplates/
*
@@ -189,6 +186,11 @@ namespace Gui {
*/
std::vector<boost::filesystem::path> configBackups() const;
/**
* Import an existing config file as a preference pack with a given name.
*/
void importConfig(const std::string &packName, const boost::filesystem::path &path);
private:
void FindPreferencePacksInPackage(const boost::filesystem::path& mod);
@@ -197,6 +199,8 @@ namespace Gui {
void DeleteOldBackups() const;
void AddPackToMetadata(const std::string &packName) const;
std::vector<boost::filesystem::path> _preferencePackPaths;
std::vector<TemplateFile> _templateFiles;
std::map<std::string, PreferencePack> _preferencePacks;