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
756 lines
22 KiB
C++
756 lines
22 KiB
C++
/***************************************************************************
|
|
* Copyright (c) 2004 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
|
* *
|
|
* 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 <QApplication>
|
|
# include <QVBoxLayout>
|
|
#endif
|
|
|
|
#ifdef FC_OS_WIN32
|
|
#undef max
|
|
#undef min
|
|
#ifdef _MSC_VER
|
|
#pragma warning( disable : 4099 )
|
|
#pragma warning( disable : 4522 )
|
|
#endif
|
|
#endif
|
|
|
|
#include <App/Application.h>
|
|
#include <Base/Console.h>
|
|
#include <Base/Exception.h>
|
|
#include <Base/Interpreter.h>
|
|
|
|
#include "WidgetFactory.h"
|
|
#include "PrefWidgets.h"
|
|
#include "PythonWrapper.h"
|
|
#include "UiLoader.h"
|
|
|
|
|
|
using namespace Gui;
|
|
|
|
Gui::WidgetFactoryInst* Gui::WidgetFactoryInst::_pcSingleton = nullptr;
|
|
|
|
WidgetFactoryInst& WidgetFactoryInst::instance()
|
|
{
|
|
if (!_pcSingleton)
|
|
_pcSingleton = new WidgetFactoryInst;
|
|
return *_pcSingleton;
|
|
}
|
|
|
|
void WidgetFactoryInst::destruct ()
|
|
{
|
|
if (_pcSingleton)
|
|
delete _pcSingleton;
|
|
_pcSingleton = nullptr;
|
|
}
|
|
|
|
/**
|
|
* Creates a widget with the name \a sName which is a child of \a parent.
|
|
* To create an instance of this widget once it must has been registered.
|
|
* If there is no appropriate widget registered nullptr is returned.
|
|
*/
|
|
QWidget* WidgetFactoryInst::createWidget (const char* sName, QWidget* parent) const
|
|
{
|
|
auto w = static_cast<QWidget*>(Produce(sName));
|
|
|
|
// this widget class is not registered
|
|
if (!w) {
|
|
#ifdef FC_DEBUG
|
|
Base::Console().Warning("\"%s\" is not registered\n", sName);
|
|
#else
|
|
Base::Console().Log("\"%s\" is not registered\n", sName);
|
|
#endif
|
|
return nullptr;
|
|
}
|
|
|
|
try {
|
|
#ifdef FC_DEBUG
|
|
const char* cName = dynamic_cast<QWidget*>(w)->metaObject()->className();
|
|
Base::Console().Log("Widget of type '%s' created.\n", cName);
|
|
#endif
|
|
}
|
|
catch (...) {
|
|
#ifdef FC_DEBUG
|
|
Base::Console().Error("%s does not inherit from \"QWidget\"\n", sName);
|
|
#else
|
|
Base::Console().Log("%s does not inherit from \"QWidget\"\n", sName);
|
|
#endif
|
|
delete w;
|
|
return nullptr;
|
|
}
|
|
|
|
// set the parent to the widget
|
|
if (parent)
|
|
w->setParent(parent);
|
|
|
|
return w;
|
|
}
|
|
|
|
/**
|
|
* Creates a widget with the name \a sName which is a child of \a parent.
|
|
* To create an instance of this widget once it must has been registered.
|
|
* If there is no appropriate widget registered nullptr is returned.
|
|
*/
|
|
Gui::Dialog::PreferencePage* WidgetFactoryInst::createPreferencePage (const char* sName, QWidget* parent) const
|
|
{
|
|
auto w = (Gui::Dialog::PreferencePage*)Produce(sName);
|
|
|
|
// this widget class is not registered
|
|
if (!w) {
|
|
#ifdef FC_DEBUG
|
|
Base::Console().Warning("Cannot create an instance of \"%s\"\n", sName);
|
|
#else
|
|
Base::Console().Log("Cannot create an instance of \"%s\"\n", sName);
|
|
#endif
|
|
return nullptr;
|
|
}
|
|
|
|
if (qobject_cast<Gui::Dialog::PreferencePage*>(w)) {
|
|
#ifdef FC_DEBUG
|
|
Base::Console().Log("Preference page of type '%s' created.\n", w->metaObject()->className());
|
|
#endif
|
|
}
|
|
else {
|
|
#ifdef FC_DEBUG
|
|
Base::Console().Error("%s does not inherit from 'Gui::Dialog::PreferencePage'\n", sName);
|
|
#endif
|
|
delete w;
|
|
return nullptr;
|
|
}
|
|
|
|
// set the parent to the widget
|
|
if (parent)
|
|
w->setParent(parent);
|
|
|
|
return w;
|
|
}
|
|
|
|
/**
|
|
* Creates a preference widget with the name \a sName and the preference name \a sPref
|
|
* which is a child of \a parent.
|
|
* To create an instance of this widget once it must has been registered.
|
|
* If there is no appropriate widget registered nullptr is returned.
|
|
* After creation of this widget its recent preferences are restored automatically.
|
|
*/
|
|
QWidget* WidgetFactoryInst::createPrefWidget(const char* sName, QWidget* parent, const char* sPref)
|
|
{
|
|
QWidget* w = createWidget(sName);
|
|
// this widget class is not registered
|
|
if (!w)
|
|
return nullptr; // no valid QWidget object
|
|
|
|
// set the parent to the widget
|
|
w->setParent(parent);
|
|
|
|
try {
|
|
auto pw = dynamic_cast<PrefWidget*>(w);
|
|
if (pw) {
|
|
pw->setEntryName(sPref);
|
|
pw->restorePreferences();
|
|
}
|
|
}
|
|
catch (...) {
|
|
#ifdef FC_DEBUG
|
|
Base::Console().Error("%s does not inherit from \"PrefWidget\"\n", w->metaObject()->className());
|
|
#endif
|
|
delete w;
|
|
return nullptr;
|
|
}
|
|
|
|
return w;
|
|
}
|
|
|
|
// ----------------------------------------------------
|
|
|
|
WidgetFactorySupplier* WidgetFactorySupplier::_pcSingleton = nullptr;
|
|
|
|
WidgetFactorySupplier & WidgetFactorySupplier::instance()
|
|
{
|
|
// not initialized?
|
|
if (!_pcSingleton)
|
|
_pcSingleton = new WidgetFactorySupplier;
|
|
return *_pcSingleton;
|
|
}
|
|
|
|
void WidgetFactorySupplier::destruct()
|
|
{
|
|
// delete the widget factory and all its producers first
|
|
WidgetFactoryInst::destruct();
|
|
delete _pcSingleton;
|
|
_pcSingleton=nullptr;
|
|
}
|
|
|
|
// ----------------------------------------------------
|
|
|
|
PrefPageUiProducer::PrefPageUiProducer (const char* filename, const char* group)
|
|
: fn(QString::fromUtf8(filename))
|
|
{
|
|
WidgetFactoryInst::instance().AddProducer(filename, this);
|
|
Gui::Dialog::DlgPreferencesImp::addPage(filename, group);
|
|
}
|
|
|
|
PrefPageUiProducer::~PrefPageUiProducer()
|
|
{
|
|
}
|
|
|
|
void* PrefPageUiProducer::Produce () const
|
|
{
|
|
QWidget* page = new Gui::Dialog::PreferenceUiForm(fn);
|
|
return static_cast<void*>(page);
|
|
}
|
|
|
|
// ----------------------------------------------------
|
|
|
|
PrefPagePyProducer::PrefPagePyProducer (const Py::Object& p, const char* group)
|
|
: type(p)
|
|
{
|
|
std::string str;
|
|
Base::PyGILStateLocker lock;
|
|
if (type.hasAttr("__name__")) {
|
|
str = static_cast<std::string>(Py::String(type.getAttr("__name__")));
|
|
}
|
|
|
|
WidgetFactoryInst::instance().AddProducer(str.c_str(), this);
|
|
Gui::Dialog::DlgPreferencesImp::addPage(str, group);
|
|
}
|
|
|
|
PrefPagePyProducer::~PrefPagePyProducer ()
|
|
{
|
|
Base::PyGILStateLocker lock;
|
|
type = Py::None();
|
|
}
|
|
|
|
void* PrefPagePyProducer::Produce () const
|
|
{
|
|
Base::PyGILStateLocker lock;
|
|
try {
|
|
Py::Callable method(type);
|
|
Py::Tuple args;
|
|
Py::Object page = method.apply(args);
|
|
QWidget* widget = new Gui::Dialog::PreferencePagePython(page);
|
|
if (!widget->layout()) {
|
|
delete widget;
|
|
widget = nullptr;
|
|
}
|
|
return widget;
|
|
}
|
|
catch (Py::Exception&) {
|
|
PyErr_Print();
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------
|
|
|
|
using namespace Gui::Dialog;
|
|
|
|
PreferencePagePython::PreferencePagePython(const Py::Object& p, QWidget* parent)
|
|
: PreferencePage(parent), page(p)
|
|
{
|
|
Base::PyGILStateLocker lock;
|
|
Gui::PythonWrapper wrap;
|
|
if (wrap.loadCoreModule()) {
|
|
|
|
// old style class must have a form attribute while
|
|
// new style classes can be the widget itself
|
|
Py::Object widget;
|
|
if (page.hasAttr(std::string("form")))
|
|
widget = page.getAttr(std::string("form"));
|
|
else
|
|
widget = page;
|
|
|
|
QObject* object = wrap.toQObject(widget);
|
|
if (object) {
|
|
QWidget* form = qobject_cast<QWidget*>(object);
|
|
if (form) {
|
|
this->setWindowTitle(form->windowTitle());
|
|
auto layout = new QVBoxLayout;
|
|
layout->addWidget(form);
|
|
setLayout(layout);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
PreferencePagePython::~PreferencePagePython()
|
|
{
|
|
Base::PyGILStateLocker lock;
|
|
page = Py::None();
|
|
}
|
|
|
|
void PreferencePagePython::changeEvent(QEvent *e)
|
|
{
|
|
QWidget::changeEvent(e);
|
|
}
|
|
|
|
void PreferencePagePython::loadSettings()
|
|
{
|
|
Base::PyGILStateLocker lock;
|
|
try {
|
|
if (page.hasAttr(std::string("loadSettings"))) {
|
|
Py::Callable method(page.getAttr(std::string("loadSettings")));
|
|
Py::Tuple args;
|
|
method.apply(args);
|
|
}
|
|
}
|
|
catch (Py::Exception&) {
|
|
Base::PyException e; // extract the Python error text
|
|
e.ReportException();
|
|
}
|
|
}
|
|
|
|
void PreferencePagePython::saveSettings()
|
|
{
|
|
Base::PyGILStateLocker lock;
|
|
try {
|
|
if (page.hasAttr(std::string("saveSettings"))) {
|
|
Py::Callable method(page.getAttr(std::string("saveSettings")));
|
|
Py::Tuple args;
|
|
method.apply(args);
|
|
}
|
|
}
|
|
catch (Py::Exception&) {
|
|
Base::PyException e; // extract the Python error text
|
|
e.ReportException();
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------
|
|
|
|
/* TRANSLATOR Gui::ContainerDialog */
|
|
|
|
/**
|
|
* Constructs a ContainerDialog which embeds the child \a templChild.
|
|
* The dialog will be modal.
|
|
*/
|
|
ContainerDialog::ContainerDialog( QWidget* templChild )
|
|
: QDialog( QApplication::activeWindow())
|
|
{
|
|
setModal(true);
|
|
setWindowTitle( templChild->objectName() );
|
|
setObjectName( templChild->objectName() );
|
|
|
|
setSizeGripEnabled( true );
|
|
MyDialogLayout = new QGridLayout(this);
|
|
|
|
buttonOk = new QPushButton(this);
|
|
buttonOk->setObjectName(QLatin1String("buttonOK"));
|
|
buttonOk->setText( tr( "&OK" ) );
|
|
buttonOk->setAutoDefault( true );
|
|
buttonOk->setDefault( true );
|
|
|
|
MyDialogLayout->addWidget( buttonOk, 1, 0 );
|
|
auto spacer = new QSpacerItem( 210, 20, QSizePolicy::Expanding, QSizePolicy::Minimum );
|
|
MyDialogLayout->addItem( spacer, 1, 1 );
|
|
|
|
buttonCancel = new QPushButton(this);
|
|
buttonCancel->setObjectName(QLatin1String("buttonCancel"));
|
|
buttonCancel->setText( tr( "&Cancel" ) );
|
|
buttonCancel->setAutoDefault( true );
|
|
|
|
MyDialogLayout->addWidget( buttonCancel, 1, 2 );
|
|
|
|
templChild->setParent(this);
|
|
|
|
MyDialogLayout->addWidget( templChild, 0, 0, 0, 2 );
|
|
resize( QSize(307, 197).expandedTo(minimumSizeHint()) );
|
|
|
|
// signals and slots connections
|
|
connect( buttonOk, &QPushButton::clicked, this, &QDialog::accept);
|
|
connect( buttonCancel, &QPushButton::clicked, this, &QDialog::reject);
|
|
}
|
|
|
|
/** Destroys the object and frees any allocated resources */
|
|
ContainerDialog::~ContainerDialog()
|
|
{
|
|
}
|
|
|
|
// ----------------------------------------------------
|
|
|
|
void PyResource::init_type()
|
|
{
|
|
behaviors().name("PyResource");
|
|
behaviors().doc("PyResource");
|
|
// you must have overwritten the virtual functions
|
|
behaviors().supportRepr();
|
|
behaviors().supportGetattr();
|
|
behaviors().supportSetattr();
|
|
add_varargs_method("value",&PyResource::value);
|
|
add_varargs_method("setValue",&PyResource::setValue);
|
|
add_varargs_method("show",&PyResource::show);
|
|
add_varargs_method("connect",&PyResource::connect);
|
|
}
|
|
|
|
PyResource::PyResource() : myDlg(nullptr)
|
|
{
|
|
}
|
|
|
|
PyResource::~PyResource()
|
|
{
|
|
delete myDlg;
|
|
for (std::vector<SignalConnect*>::iterator it = mySignals.begin(); it != mySignals.end(); ++it) {
|
|
SignalConnect* sc = *it;
|
|
delete sc;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Loads an .ui file with the name \a name. If the .ui file cannot be found or the QWidgetFactory
|
|
* cannot create an instance an exception is thrown. If the created resource does not inherit from
|
|
* QDialog an instance of ContainerDialog is created to embed it.
|
|
*/
|
|
void PyResource::load(const char* name)
|
|
{
|
|
QString fn = QString::fromUtf8(name);
|
|
QFileInfo fi(fn);
|
|
|
|
// checks whether it's a relative path
|
|
if (fi.isRelative()) {
|
|
QString cwd = QDir::currentPath ();
|
|
QString home= QDir(QString::fromStdString(App::Application::getHomePath())).path();
|
|
|
|
// search in cwd and home path for the file
|
|
//
|
|
// file does not reside in cwd, check home path now
|
|
if (!fi.exists()) {
|
|
if (cwd == home) {
|
|
QString what = QObject::tr("Cannot find file %1").arg(fi.absoluteFilePath());
|
|
throw Base::FileSystemError(what.toUtf8().constData());
|
|
}
|
|
else {
|
|
fi.setFile( QDir(home), fn );
|
|
|
|
if (!fi.exists()) {
|
|
QString what = QObject::tr("Cannot find file %1 neither in %2 nor in %3")
|
|
.arg(fn, cwd, home);
|
|
throw Base::FileSystemError(what.toUtf8().constData());
|
|
}
|
|
else {
|
|
fn = fi.absoluteFilePath(); // file resides in FreeCAD's home directory
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (!fi.exists()) {
|
|
QString what = QObject::tr("Cannot find file %1").arg(fn);
|
|
throw Base::FileSystemError(what.toUtf8().constData());
|
|
}
|
|
}
|
|
|
|
QWidget* w=nullptr;
|
|
try {
|
|
auto loader = UiLoader::newInstance();
|
|
QFile file(fn);
|
|
if (file.open(QFile::ReadOnly))
|
|
w = loader->load(&file, QApplication::activeWindow());
|
|
file.close();
|
|
}
|
|
catch (...) {
|
|
throw Base::RuntimeError("Cannot create resource");
|
|
}
|
|
|
|
if (!w)
|
|
throw Base::ValueError("Invalid widget.");
|
|
|
|
if (w->inherits("QDialog")) {
|
|
myDlg = static_cast<QDialog*>(w);
|
|
}
|
|
else {
|
|
myDlg = new ContainerDialog(w);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Makes a connection between the sender widget \a sender and its signal \a signal
|
|
* of the created resource and Python callback function \a cb.
|
|
* If the sender widget does not exist or no resource has been loaded this method returns false,
|
|
* otherwise it returns true.
|
|
*/
|
|
bool PyResource::connect(const char* sender, const char* signal, PyObject* cb)
|
|
{
|
|
if ( !myDlg )
|
|
return false;
|
|
|
|
QObject* objS=nullptr;
|
|
QList<QWidget*> list = myDlg->findChildren<QWidget*>();
|
|
QList<QWidget*>::const_iterator it = list.cbegin();
|
|
QObject *obj;
|
|
QString sigStr = QString::fromLatin1("2%1").arg(QString::fromLatin1(signal));
|
|
|
|
while ( it != list.cend() ) {
|
|
obj = *it;
|
|
++it;
|
|
if (obj->objectName() == QLatin1String(sender)) {
|
|
objS = obj;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (objS) {
|
|
auto sc = new SignalConnect(this, cb);
|
|
mySignals.push_back(sc);
|
|
return QObject::connect(objS, sigStr.toLatin1(), sc, SLOT ( onExecute() ) );
|
|
}
|
|
else
|
|
qWarning( "'%s' does not exist.\n", sender );
|
|
|
|
return false;
|
|
}
|
|
|
|
Py::Object PyResource::repr()
|
|
{
|
|
std::string s;
|
|
std::ostringstream s_out;
|
|
s_out << "Resource object";
|
|
return Py::String(s_out.str());
|
|
}
|
|
|
|
/**
|
|
* Searches for a widget and its value in the argument object \a args
|
|
* to returns its value as Python object.
|
|
* In the case it fails nullptr is returned.
|
|
*/
|
|
Py::Object PyResource::value(const Py::Tuple& args)
|
|
{
|
|
char *psName;
|
|
char *psProperty;
|
|
if (!PyArg_ParseTuple(args.ptr(), "ss", &psName, &psProperty))
|
|
throw Py::Exception();
|
|
|
|
QVariant v;
|
|
if (myDlg) {
|
|
QList<QWidget*> list = myDlg->findChildren<QWidget*>();
|
|
QList<QWidget*>::const_iterator it = list.cbegin();
|
|
QObject *obj;
|
|
|
|
bool fnd = false;
|
|
while ( it != list.cend() ) {
|
|
obj = *it;
|
|
++it;
|
|
if (obj->objectName() == QLatin1String(psName)) {
|
|
fnd = true;
|
|
v = obj->property(psProperty);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( !fnd )
|
|
qWarning( "'%s' not found.\n", psName );
|
|
}
|
|
|
|
Py::Object item = Py::None();
|
|
switch (v.userType())
|
|
{
|
|
case QMetaType::QStringList:
|
|
{
|
|
QStringList str = v.toStringList();
|
|
int nSize = str.count();
|
|
Py::List slist(nSize);
|
|
for (int i=0; i<nSize;++i) {
|
|
slist.setItem(i, Py::String(str[i].toLatin1()));
|
|
}
|
|
item = slist;
|
|
} break;
|
|
case QMetaType::QByteArray:
|
|
break;
|
|
case QMetaType::QString:
|
|
item = Py::String(v.toString().toLatin1());
|
|
break;
|
|
case QMetaType::Double:
|
|
item = Py::Float(v.toDouble());
|
|
break;
|
|
case QMetaType::Bool:
|
|
item = Py::Boolean(v.toBool() ? 1 : 0);
|
|
break;
|
|
case QMetaType::UInt:
|
|
item = Py::Long(static_cast<unsigned long>(v.toUInt()));
|
|
break;
|
|
case QMetaType::Int:
|
|
item = Py::Int(v.toInt());
|
|
break;
|
|
default:
|
|
item = Py::String("");
|
|
break;
|
|
}
|
|
|
|
return item;
|
|
}
|
|
|
|
/**
|
|
* Searches for a widget, its value name and the new value in the argument object \a args
|
|
* to set even this new value.
|
|
* In the case it fails nullptr is returned.
|
|
*/
|
|
Py::Object PyResource::setValue(const Py::Tuple& args)
|
|
{
|
|
char *psName;
|
|
char *psProperty;
|
|
PyObject *psValue;
|
|
if (!PyArg_ParseTuple(args.ptr(), "ssO", &psName, &psProperty, &psValue))
|
|
throw Py::Exception();
|
|
|
|
QVariant v;
|
|
if (PyUnicode_Check(psValue)) {
|
|
v = QString::fromUtf8(PyUnicode_AsUTF8(psValue));
|
|
|
|
}
|
|
else if (PyLong_Check(psValue)) {
|
|
unsigned int val = PyLong_AsLong(psValue);
|
|
v = val;
|
|
}
|
|
else if (PyFloat_Check(psValue)) {
|
|
v = PyFloat_AsDouble(psValue);
|
|
}
|
|
else if (PyList_Check(psValue)) {
|
|
QStringList str;
|
|
int nSize = PyList_Size(psValue);
|
|
for (int i=0; i<nSize;++i) {
|
|
PyObject* item = PyList_GetItem(psValue, i);
|
|
if (!PyUnicode_Check(item))
|
|
continue;
|
|
const char* pItem = PyUnicode_AsUTF8(item);
|
|
str.append(QString::fromUtf8(pItem));
|
|
}
|
|
|
|
v = str;
|
|
}
|
|
else {
|
|
throw Py::TypeError("Unsupported type");
|
|
}
|
|
|
|
if (myDlg) {
|
|
QList<QWidget*> list = myDlg->findChildren<QWidget*>();
|
|
QList<QWidget*>::const_iterator it = list.cbegin();
|
|
QObject *obj;
|
|
|
|
bool fnd = false;
|
|
while ( it != list.cend() ) {
|
|
obj = *it;
|
|
++it;
|
|
if (obj->objectName() == QLatin1String(psName)) {
|
|
fnd = true;
|
|
obj->setProperty(psProperty, v);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!fnd)
|
|
qWarning( "'%s' not found.\n", psName );
|
|
}
|
|
|
|
return Py::None();
|
|
}
|
|
|
|
/**
|
|
* If any resource has been loaded this methods shows it as a modal dialog.
|
|
*/
|
|
Py::Object PyResource::show(const Py::Tuple&)
|
|
{
|
|
if (myDlg) {
|
|
// small trick to get focus
|
|
myDlg->showMinimized();
|
|
|
|
#ifdef Q_WS_X11
|
|
// On X11 this may not work. For further information see QWidget::showMaximized
|
|
//
|
|
// workaround for X11
|
|
myDlg->hide();
|
|
myDlg->show();
|
|
#endif
|
|
|
|
myDlg->showNormal();
|
|
myDlg->exec();
|
|
}
|
|
|
|
return Py::None();
|
|
}
|
|
|
|
/**
|
|
* Searches for the sender, the signal and the callback function to connect with
|
|
* in the argument object \a args. In the case it fails nullptr is returned.
|
|
*/
|
|
Py::Object PyResource::connect(const Py::Tuple& args)
|
|
{
|
|
char *psSender;
|
|
char *psSignal;
|
|
|
|
PyObject *temp;
|
|
|
|
if (PyArg_ParseTuple(args.ptr(), "ssO", &psSender, &psSignal, &temp)) {
|
|
if (!PyCallable_Check(temp)) {
|
|
PyErr_SetString(PyExc_TypeError, "parameter must be callable");
|
|
throw Py::Exception();
|
|
}
|
|
|
|
Py_XINCREF(temp); /* Add a reference to new callback */
|
|
std::string sSender = psSender;
|
|
std::string sSignal = psSignal;
|
|
|
|
if (!connect(psSender, psSignal, temp)) {
|
|
// no signal object found => dispose the callback object
|
|
Py_XDECREF(temp); /* Dispose of callback */
|
|
}
|
|
|
|
return Py::None();
|
|
}
|
|
|
|
// error set by PyArg_ParseTuple
|
|
throw Py::Exception();
|
|
}
|
|
|
|
// ----------------------------------------------------
|
|
|
|
SignalConnect::SignalConnect(PyObject* res, PyObject* cb)
|
|
: myResource(res), myCallback(cb)
|
|
{
|
|
}
|
|
|
|
SignalConnect::~SignalConnect()
|
|
{
|
|
Base::PyGILStateLocker lock;
|
|
Py_XDECREF(myCallback); /* Dispose of callback */
|
|
}
|
|
|
|
/**
|
|
* Calls the callback function of the connected Python object.
|
|
*/
|
|
void SignalConnect::onExecute()
|
|
{
|
|
PyObject *arglist;
|
|
PyObject *result;
|
|
|
|
/* Time to call the callback */
|
|
arglist = Py_BuildValue("(O)", myResource);
|
|
#if PY_VERSION_HEX < 0x03090000
|
|
result = PyEval_CallObject(myCallback, arglist);
|
|
#else
|
|
result = PyObject_CallObject(myCallback, arglist);
|
|
#endif
|
|
Py_XDECREF(result);
|
|
Py_DECREF(arglist);
|
|
}
|
|
|
|
#include "moc_WidgetFactory.cpp"
|