Gui: Prevent UiLoader from loading 3rd-party Qt plugins.
Due to a flaw in the QUiLoader, UiLoader were loading all designer plugins it can find in QApplication::libraryPaths(). This in general a bad practice and leads to bugs due to some plugins may perform some unexpected actions upon load which may interfere with FreeCAD's functionality. To avoid such problems reset the libraryPaths before creation of a UiLoader object. Also move setLanguageChangeEnabled(true) into constructor due to it's called every time it's being instanced anyway. See: https://github.com/FreeCAD/FreeCAD/issues/8708
This commit is contained in:
committed by
wwmayer
parent
64eb85b1ea
commit
992dec2c6b
@@ -119,12 +119,11 @@ void PreferencePage::changeEvent(QEvent *e)
|
||||
PreferenceUiForm::PreferenceUiForm(const QString& fn, QWidget* parent)
|
||||
: PreferencePage(parent), form(nullptr)
|
||||
{
|
||||
UiLoader loader;
|
||||
loader.setLanguageChangeEnabled(true);
|
||||
loader.setWorkingDirectory(QFileInfo(fn).absolutePath());
|
||||
auto loader = UiLoader::newInstance();
|
||||
loader->setWorkingDirectory(QFileInfo(fn).absolutePath());
|
||||
QFile file(fn);
|
||||
if (file.open(QFile::ReadOnly))
|
||||
form = loader.load(&file, this);
|
||||
form = loader->load(&file, this);
|
||||
file.close();
|
||||
if (form) {
|
||||
this->setWindowTitle(form->windowTitle());
|
||||
|
||||
@@ -544,8 +544,7 @@ TaskDialogPython::~TaskDialogPython()
|
||||
bool TaskDialogPython::tryLoadUiFile()
|
||||
{
|
||||
if (dlg.hasAttr(std::string("ui"))) {
|
||||
UiLoader loader;
|
||||
loader.setLanguageChangeEnabled(true);
|
||||
auto loader = UiLoader::newInstance();
|
||||
QString fn, icon;
|
||||
Py::String ui(dlg.getAttr(std::string("ui")));
|
||||
std::string path = static_cast<std::string>(ui);
|
||||
@@ -554,7 +553,7 @@ bool TaskDialogPython::tryLoadUiFile()
|
||||
QFile file(fn);
|
||||
QWidget* form = nullptr;
|
||||
if (file.open(QFile::ReadOnly))
|
||||
form = loader.load(&file, nullptr);
|
||||
form = loader->load(&file, nullptr);
|
||||
file.close();
|
||||
if (form) {
|
||||
appendForm(form, QPixmap(icon));
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#ifndef _PreComp_
|
||||
# include <QAction>
|
||||
# include <QActionGroup>
|
||||
# include <QCoreApplication>
|
||||
# include <QDir>
|
||||
# include <QFile>
|
||||
# include <QLayout>
|
||||
@@ -488,10 +489,20 @@ QString QUiLoader::errorString() const
|
||||
UiLoader::UiLoader(QObject* parent)
|
||||
: QUiLoader(parent)
|
||||
{
|
||||
// do not use the plugins for additional widgets as we don't need them and
|
||||
// the application may crash under Linux (tested on Ubuntu 7.04 & 7.10).
|
||||
clearPluginPaths();
|
||||
this->cw = availableWidgets();
|
||||
setLanguageChangeEnabled(true);
|
||||
}
|
||||
|
||||
std::unique_ptr<UiLoader> UiLoader::newInstance(QObject *parent)
|
||||
{
|
||||
QCoreApplication *app=QCoreApplication::instance();
|
||||
QStringList libPaths= app->libraryPaths();
|
||||
|
||||
app->setLibraryPaths(QStringList{}); //< backup library paths, so QUiLoader won't load plugins by default
|
||||
std::unique_ptr<UiLoader> rv{new UiLoader{parent}};
|
||||
app->setLibraryPaths(libPaths);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
UiLoader::~UiLoader()
|
||||
@@ -544,8 +555,8 @@ void UiLoaderPy::init_type()
|
||||
}
|
||||
|
||||
UiLoaderPy::UiLoaderPy()
|
||||
: loader{UiLoader::newInstance()}
|
||||
{
|
||||
loader.setLanguageChangeEnabled(true);
|
||||
}
|
||||
|
||||
UiLoaderPy::~UiLoaderPy()
|
||||
@@ -592,7 +603,7 @@ Py::Object UiLoaderPy::load(const Py::Tuple& args)
|
||||
}
|
||||
|
||||
if (device) {
|
||||
QWidget* widget = loader.load(device, parent);
|
||||
QWidget* widget = loader->load(device, parent);
|
||||
if (widget) {
|
||||
wrap.loadGuiModule();
|
||||
wrap.loadWidgetsModule();
|
||||
@@ -613,7 +624,7 @@ Py::Object UiLoaderPy::load(const Py::Tuple& args)
|
||||
|
||||
Py::Object UiLoaderPy::createWidget(const Py::Tuple& args)
|
||||
{
|
||||
return wrapFromWidgetFactory(args, std::bind(&UiLoader::createWidget, &loader,
|
||||
return wrapFromWidgetFactory(args, std::bind(&UiLoader::createWidget, loader.get(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2,
|
||||
std::placeholders::_3));
|
||||
@@ -625,7 +636,7 @@ Py::Object UiLoaderPy::addPluginPath(const Py::Tuple& args)
|
||||
if (wrap.loadCoreModule()) {
|
||||
std::string fn;
|
||||
if (wrap.toCString(args[0], fn)) {
|
||||
loader.addPluginPath(QString::fromStdString(fn));
|
||||
loader->addPluginPath(QString::fromStdString(fn));
|
||||
}
|
||||
}
|
||||
return Py::None();
|
||||
@@ -633,13 +644,13 @@ Py::Object UiLoaderPy::addPluginPath(const Py::Tuple& args)
|
||||
|
||||
Py::Object UiLoaderPy::clearPluginPaths(const Py::Tuple& /*args*/)
|
||||
{
|
||||
loader.clearPluginPaths();
|
||||
loader->clearPluginPaths();
|
||||
return Py::None();
|
||||
}
|
||||
|
||||
Py::Object UiLoaderPy::pluginPaths(const Py::Tuple& /*args*/)
|
||||
{
|
||||
auto list = loader.pluginPaths();
|
||||
auto list = loader->pluginPaths();
|
||||
Py::List py;
|
||||
for (const auto& it : list) {
|
||||
py.append(Py::String(it.toStdString()));
|
||||
@@ -649,7 +660,7 @@ Py::Object UiLoaderPy::pluginPaths(const Py::Tuple& /*args*/)
|
||||
|
||||
Py::Object UiLoaderPy::availableWidgets(const Py::Tuple& /*args*/)
|
||||
{
|
||||
auto list = loader.availableWidgets();
|
||||
auto list = loader->availableWidgets();
|
||||
Py::List py;
|
||||
for (const auto& it : list) {
|
||||
py.append(Py::String(it.toStdString()));
|
||||
@@ -665,17 +676,17 @@ Py::Object UiLoaderPy::availableWidgets(const Py::Tuple& /*args*/)
|
||||
|
||||
Py::Object UiLoaderPy::errorString(const Py::Tuple& /*args*/)
|
||||
{
|
||||
return Py::String(loader.errorString().toStdString());
|
||||
return Py::String(loader->errorString().toStdString());
|
||||
}
|
||||
|
||||
Py::Object UiLoaderPy::isLanguageChangeEnabled(const Py::Tuple& /*args*/)
|
||||
{
|
||||
return Py::Boolean(loader.isLanguageChangeEnabled());
|
||||
return Py::Boolean(loader->isLanguageChangeEnabled());
|
||||
}
|
||||
|
||||
Py::Object UiLoaderPy::setLanguageChangeEnabled(const Py::Tuple& args)
|
||||
{
|
||||
loader.setLanguageChangeEnabled(Py::Boolean(args[0]));
|
||||
loader->setLanguageChangeEnabled(Py::Boolean(args[0]));
|
||||
return Py::None();
|
||||
}
|
||||
|
||||
@@ -685,7 +696,7 @@ Py::Object UiLoaderPy::setWorkingDirectory(const Py::Tuple& args)
|
||||
if (wrap.loadCoreModule()) {
|
||||
std::string fn;
|
||||
if (wrap.toCString(args[0], fn)) {
|
||||
loader.setWorkingDirectory(QString::fromStdString(fn));
|
||||
loader->setWorkingDirectory(QString::fromStdString(fn));
|
||||
}
|
||||
}
|
||||
return Py::None();
|
||||
@@ -693,7 +704,7 @@ Py::Object UiLoaderPy::setWorkingDirectory(const Py::Tuple& args)
|
||||
|
||||
Py::Object UiLoaderPy::workingDirectory(const Py::Tuple& /*args*/)
|
||||
{
|
||||
QDir dir = loader.workingDirectory();
|
||||
QDir dir = loader->workingDirectory();
|
||||
QString path = dir.absolutePath();
|
||||
return Py::String(path.toStdString());
|
||||
}
|
||||
|
||||
@@ -106,8 +106,29 @@ private:
|
||||
*/
|
||||
class UiLoader : public QUiLoader
|
||||
{
|
||||
public:
|
||||
protected:
|
||||
/**
|
||||
* A protected construct for UiLoader.
|
||||
* To create an instance of UiLoader @see UiLoader::newInstance()
|
||||
*/
|
||||
explicit UiLoader(QObject* parent=nullptr);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates a new instance of a UiLoader.
|
||||
*
|
||||
* Due to its flaw the QUiLoader upon creation loads every available Qt
|
||||
* designer plugin it can find in QApplication::libraryPaths(). Some of
|
||||
* those plugins may perform some unexpected actions upon load which may
|
||||
* interfere with FreeCAD's functionality. Only way to avoid such behaviour
|
||||
* is to reset QApplication::libraryPaths, create a QUiLoader and then
|
||||
* restore the libs paths. Hence need for this function to wrap
|
||||
* construction.
|
||||
*
|
||||
* @see https://github.com/FreeCAD/FreeCAD/issues/8708
|
||||
*/
|
||||
static std::unique_ptr<UiLoader> newInstance(QObject *parent=0);
|
||||
|
||||
~UiLoader() override;
|
||||
|
||||
/**
|
||||
@@ -149,7 +170,7 @@ private:
|
||||
static PyObject *PyMake(struct _typeobject *, PyObject *, PyObject *);
|
||||
|
||||
private:
|
||||
UiLoader loader;
|
||||
std::unique_ptr<UiLoader> loader;
|
||||
};
|
||||
|
||||
} // namespace Gui
|
||||
|
||||
@@ -461,11 +461,10 @@ void PyResource::load(const char* name)
|
||||
|
||||
QWidget* w=nullptr;
|
||||
try {
|
||||
UiLoader loader;
|
||||
loader.setLanguageChangeEnabled(true);
|
||||
auto loader = UiLoader::newInstance();
|
||||
QFile file(fn);
|
||||
if (file.open(QFile::ReadOnly))
|
||||
w = loader.load(&file, QApplication::activeWindow());
|
||||
w = loader->load(&file, QApplication::activeWindow());
|
||||
file.close();
|
||||
}
|
||||
catch (...) {
|
||||
|
||||
Reference in New Issue
Block a user