// SPDX-License-Identifier: LGPL-2.1-or-later /*************************************************************************** * Copyright (c) 2011 Werner Mayer * * * * 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 #include #include #include #include #include #include #include #include #include #include #include "TaskDialogPython.h" #include "TaskView.h" using namespace Gui; using namespace Gui::TaskView; ControlPy* ControlPy::instance = nullptr; ControlPy* ControlPy::getInstance() { if (!instance) { instance = new ControlPy(); } return instance; } void ControlPy::init_type() { behaviors().name("Control"); behaviors().doc("Control for task dialogs"); // you must have overwritten the virtual functions behaviors().supportRepr(); behaviors().supportGetattr(); behaviors().supportSetattr(); add_varargs_method( "showDialog", &ControlPy::showDialog, "show the given dialog in the task panel\n" "showDialog(dialog)\n" "--\n" "if a task is already active a RuntimeError is raised" ); add_varargs_method( "activeDialog", &ControlPy::activeDialog, "check if a dialog is active in the task panel\n" "activeDialog() --> bool" ); add_varargs_method( "activeTaskDialog", &ControlPy::activeTaskDialog, "return the active task dialog if there is one\n" "activeTaskDialog() --> TaskDialog or None" ); add_varargs_method( "closeDialog", &ControlPy::closeDialog, "close the active dialog\n" "closeDialog()" ); add_varargs_method( "addTaskWatcher", &ControlPy::addTaskWatcher, "install a (list of) TaskWatcher\n" "addTaskWatcher(TaskWatcher | list)" ); add_varargs_method( "clearTaskWatcher", &ControlPy::clearTaskWatcher, "remove all TaskWatchers\n" "clearTaskWatcher()" ); add_varargs_method( "isAllowedAlterDocument", &ControlPy::isAllowedAlterDocument, "return the permission to alter the current Document\n" "isAllowedAlterDocument() --> bool" ); add_varargs_method( "isAllowedAlterView", &ControlPy::isAllowedAlterView, "return the permission to alter the current View\n" "isAllowedAlterView() --> bool" ); add_varargs_method( "isAllowedAlterSelection", &ControlPy::isAllowedAlterSelection, "return the permission to alter the current Selection\n" "isAllowedAlterSelection() --> bool" ); add_varargs_method( "showTaskView", &ControlPy::showTaskView, "show the Task panel\n" "showTaskView()" ); add_varargs_method( "showModelView", &ControlPy::showModelView, "show the Model panel\n" "showModelView()" ); } ControlPy::ControlPy() = default; ControlPy::~ControlPy() = default; Py::Object ControlPy::repr() { return Py::String("Control Task Dialog"); } Py::Object ControlPy::showDialog(const Py::Tuple& args) { PyObject* arg0; if (!PyArg_ParseTuple(args.ptr(), "O", &arg0)) { throw Py::Exception(); } Gui::TaskView::TaskDialog* act = Gui::Control().activeDialog(); if (act) { throw Py::RuntimeError("Active task dialog found"); } auto dlg = new TaskDialogPython(Py::Object(arg0)); Gui::Control().showDialog(dlg); return (Py::asObject(new TaskDialogPy(dlg))); } Py::Object ControlPy::activeDialog(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) { throw Py::Exception(); } Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog(); return Py::Boolean(dlg != nullptr); } Py::Object ControlPy::activeTaskDialog(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) { throw Py::Exception(); } Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog(); return (dlg ? Py::asObject(new TaskDialogPy(dlg)) : Py::None()); } Py::Object ControlPy::closeDialog(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) { throw Py::Exception(); } Gui::Control().closeDialog(); return Py::None(); } Py::Object ControlPy::addTaskWatcher(const Py::Tuple& args) { PyObject* arg0; if (!PyArg_ParseTuple(args.ptr(), "O", &arg0)) { throw Py::Exception(); } std::vector watcher; Py::Sequence list(arg0); for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { auto w = new TaskWatcherPython(*it); watcher.push_back(w); } Gui::TaskView::TaskView* taskView = Gui::Control().taskPanel(); if (taskView) { taskView->addTaskWatcher(watcher); } return Py::None(); } Py::Object ControlPy::clearTaskWatcher(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) { throw Py::Exception(); } Gui::TaskView::TaskView* taskView = Gui::Control().taskPanel(); if (taskView) { taskView->clearTaskWatcher(); } return Py::None(); } Py::Object ControlPy::isAllowedAlterDocument(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) { throw Py::Exception(); } bool ok = Gui::Control().isAllowedAlterDocument(); return Py::Boolean(ok); } Py::Object ControlPy::isAllowedAlterView(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) { throw Py::Exception(); } bool ok = Gui::Control().isAllowedAlterView(); return Py::Boolean(ok); } Py::Object ControlPy::isAllowedAlterSelection(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) { throw Py::Exception(); } bool ok = Gui::Control().isAllowedAlterSelection(); return Py::Boolean(ok); } Py::Object ControlPy::showTaskView(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) { throw Py::Exception(); } Gui::Control().showTaskView(); return Py::None(); } Py::Object ControlPy::showModelView(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) { throw Py::Exception(); } Gui::Control().showModelView(); return Py::None(); } // ------------------------------------------------------------------ TaskWatcherPython::TaskWatcherPython(const Py::Object& o) : TaskWatcher(nullptr) , watcher(o) { QString title; if (watcher.hasAttr(std::string("title"))) { Py::String name(watcher.getAttr(std::string("title"))); std::string s = static_cast(name); title = QString::fromUtf8(s.c_str()); } QPixmap icon; if (watcher.hasAttr(std::string("icon"))) { Py::String name(watcher.getAttr(std::string("icon"))); std::string s = static_cast(name); icon = BitmapFactory().pixmap(s.c_str()); } Gui::TaskView::TaskBox* tb = nullptr; if (watcher.hasAttr(std::string("commands"))) { tb = new Gui::TaskView::TaskBox(icon, title, true, nullptr); Py::Sequence cmds(watcher.getAttr(std::string("commands"))); CommandManager& mgr = Gui::Application::Instance->commandManager(); for (Py::Sequence::iterator it = cmds.begin(); it != cmds.end(); ++it) { Py::String name(*it); std::string s = static_cast(name); Command* c = mgr.getCommandByName(s.c_str()); if (c) { c->addTo(tb); } } } if (watcher.hasAttr(std::string("widgets"))) { if (!tb && !title.isEmpty()) { tb = new Gui::TaskView::TaskBox(icon, title, true, nullptr); } Py::Sequence list(watcher.getAttr(std::string("widgets"))); Gui::PythonWrapper wrap; if (wrap.loadCoreModule()) { for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { QObject* object = wrap.toQObject(*it); if (object) { QWidget* w = qobject_cast(object); if (w) { if (tb) { tb->groupLayout()->addWidget(w); } else { Content.push_back(w); } } } } } } if (tb) { Content.push_back(tb); } if (watcher.hasAttr(std::string("filter"))) { Py::String name(watcher.getAttr(std::string("filter"))); std::string s = static_cast(name); this->setFilter(s.c_str()); } } TaskWatcherPython::~TaskWatcherPython() { std::vector> guarded; guarded.insert(guarded.begin(), Content.begin(), Content.end()); Content.clear(); Base::PyGILStateLocker lock; this->watcher = Py::None(); Content.insert(Content.begin(), guarded.begin(), guarded.end()); } bool TaskWatcherPython::shouldShow() { Base::PyGILStateLocker lock; try { if (watcher.hasAttr(std::string("shouldShow"))) { Py::Callable method(watcher.getAttr(std::string("shouldShow"))); Py::Tuple args; Py::Boolean ret(method.apply(args)); return (bool)ret; } } catch (Py::Exception&) { Base::PyException e; // extract the Python error text e.reportException(); } if (!this->Filter.empty()) { return match(); } else { return TaskWatcher::shouldShow(); } } // ------------------------------------------------------------------ void TaskDialogPy::init_type() { behaviors().name("TaskDialog"); behaviors().doc("Task dialog"); // you must have overwritten the virtual functions behaviors().supportRepr(); behaviors().supportGetattr(); behaviors().supportSetattr(); add_varargs_method( "getDialogContent", &TaskDialogPy::getDialogContent, "Returns the widgets of the task dialog -> list" ); add_varargs_method( "getStandardButtons", &TaskDialogPy::getStandardButtons, "Get the standard buttons of the box -> flags" ); add_varargs_method( "setEscapeButtonEnabled", &TaskDialogPy::setEscapeButtonEnabled, "Defines whether the task dialog can be rejected by pressing Esc" ); add_varargs_method( "isEscapeButtonEnabled", &TaskDialogPy::isEscapeButtonEnabled, "Checks if the task dialog can be rejected by pressing Esc -> bool" ); add_varargs_method( "setAutoCloseOnTransactionChange", &TaskDialogPy::setAutoCloseOnTransactionChange, "Defines whether a task dialog must be closed if the document changes the\n" "active transaction" ); add_varargs_method( "isAutoCloseOnTransactionChange", &TaskDialogPy::isAutoCloseOnTransactionChange, "Checks if the task dialog will be closed when the active transaction has changed -> bool" ); add_varargs_method( "setAutoCloseOnDeletedDocument", &TaskDialogPy::setAutoCloseOnDeletedDocument, "Defines whether a task dialog must be closed if the document is deleted" ); add_varargs_method( "isAutoCloseOnDeletedDocument", &TaskDialogPy::isAutoCloseOnDeletedDocument, "Checks if the task dialog will be closed if the document is deleted -> bool" ); add_varargs_method( "getDocumentName", &TaskDialogPy::getDocumentName, "Get the name of the document the task dialog is attached to -> str" ); add_varargs_method( "setDocumentName", &TaskDialogPy::setDocumentName, "Set the name of the document the task dialog is attached to" ); add_varargs_method( "isAllowedAlterDocument", &TaskDialogPy::isAllowedAlterDocument, "Indicates whether this task dialog allows other commands to modify\n" "the document while it is open -> bool" ); add_varargs_method( "isAllowedAlterView", &TaskDialogPy::isAllowedAlterView, "Indicates whether this task dialog allows other commands to modify\n" "the 3d view while it is open -> bool" ); add_varargs_method( "isAllowedAlterSelection", &TaskDialogPy::isAllowedAlterSelection, "Indicates whether this task dialog allows other commands to modify\n" "the selection while it is open -> bool" ); add_varargs_method( "needsFullSpace", &TaskDialogPy::needsFullSpace, "Indicates whether the task dialog fully requires the available space -> bool" ); add_varargs_method("accept", &TaskDialogPy::accept, "Accept the task dialog"); add_varargs_method("reject", &TaskDialogPy::reject, "Reject the task dialog"); } TaskDialogPy::TaskDialogPy(TaskDialog* dlg) : dialog(dlg) {} TaskDialogPy::~TaskDialogPy() = default; Py::Object TaskDialogPy::repr() { std::stringstream str; str << "getDocumentName() << "' >"; return Py::String(str.str()); } Py::Object TaskDialogPy::getattr(const char* attr) { if (!dialog) { std::ostringstream s_out; s_out << "Cannot access attribute '" << attr << "' of deleted object"; throw Py::RuntimeError(s_out.str()); } return BaseType::getattr(attr); } int TaskDialogPy::setattr(const char* attr, const Py::Object& value) { if (!dialog) { std::ostringstream s_out; s_out << "Cannot access attribute '" << attr << "' of deleted object"; throw Py::RuntimeError(s_out.str()); } return BaseType::setattr(attr, value); } Py::Object TaskDialogPy::getDialogContent(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) { throw Py::Exception(); } PythonWrapper wrap; wrap.loadWidgetsModule(); Py::List list; auto widgets = dialog->getDialogContent(); for (auto it : widgets) { list.append(wrap.fromQWidget(it)); } return list; } Py::Object TaskDialogPy::getStandardButtons(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) { throw Py::Exception(); } auto buttons = dialog->getStandardButtons(); return Py::Long(static_cast(buttons)); } Py::Object TaskDialogPy::setEscapeButtonEnabled(const Py::Tuple& args) { Py::Boolean value(args[0]); dialog->setEscapeButtonEnabled(static_cast(value)); return Py::None(); } Py::Object TaskDialogPy::isEscapeButtonEnabled(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) { throw Py::Exception(); } return Py::Boolean(dialog->isEscapeButtonEnabled()); } Py::Object TaskDialogPy::setAutoCloseOnTransactionChange(const Py::Tuple& args) { Py::Boolean value(args[0]); dialog->setAutoCloseOnTransactionChange(static_cast(value)); return Py::None(); } Py::Object TaskDialogPy::isAutoCloseOnTransactionChange(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) { throw Py::Exception(); } return Py::Boolean(dialog->isAutoCloseOnTransactionChange()); } Py::Object TaskDialogPy::setAutoCloseOnDeletedDocument(const Py::Tuple& args) { Py::Boolean value(args[0]); dialog->setAutoCloseOnDeletedDocument(static_cast(value)); return Py::None(); } Py::Object TaskDialogPy::isAutoCloseOnDeletedDocument(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) { throw Py::Exception(); } return Py::Boolean(dialog->isAutoCloseOnDeletedDocument()); } Py::Object TaskDialogPy::getDocumentName(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) { throw Py::Exception(); } return Py::String(dialog->getDocumentName()); } Py::Object TaskDialogPy::setDocumentName(const Py::Tuple& args) { const char* name {""}; if (!PyArg_ParseTuple(args.ptr(), "s", &name)) { throw Py::Exception(); } dialog->setDocumentName(name); return Py::None(); } Py::Object TaskDialogPy::isAllowedAlterDocument(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) { throw Py::Exception(); } return Py::Boolean(dialog->isAllowedAlterDocument()); } Py::Object TaskDialogPy::isAllowedAlterView(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) { throw Py::Exception(); } return Py::Boolean(dialog->isAllowedAlterView()); } Py::Object TaskDialogPy::isAllowedAlterSelection(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) { throw Py::Exception(); } return Py::Boolean(dialog->isAllowedAlterSelection()); } Py::Object TaskDialogPy::needsFullSpace(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) { throw Py::Exception(); } return Py::Boolean(dialog->needsFullSpace()); } namespace { auto clickButton = [](QDialogButtonBox* buttonBox, QDialogButtonBox::ButtonRole role) { if (buttonBox) { QList list = buttonBox->buttons(); for (auto pb : list) { if (buttonBox->buttonRole(pb) == role) { if (pb->isEnabled()) { pb->click(); break; } } } } }; } // namespace Py::Object TaskDialogPy::accept(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) { throw Py::Exception(); } auto buttonBox = TaskDialogAttorney::getButtonBox(dialog); clickButton(buttonBox, QDialogButtonBox::AcceptRole); return Py::None(); } Py::Object TaskDialogPy::reject(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) { throw Py::Exception(); } auto buttonBox = TaskDialogAttorney::getButtonBox(dialog); clickButton(buttonBox, QDialogButtonBox::RejectRole); return Py::None(); } // ------------------------------------------------------------------ TaskDialogPython::TaskDialogPython(const Py::Object& o) : dlg(o) { if (!tryLoadUiFile()) { tryLoadForm(); } } TaskDialogPython::~TaskDialogPython() { std::vector> guarded; guarded.insert(guarded.begin(), Content.begin(), Content.end()); Content.clear(); Base::PyGILStateLocker lock; clearForm(); // Assigning None to 'dlg' may destroy some of the stored widgets. // By guarding them with QPointer their pointers will be set to null // so that the destructor of the base class can reliably call 'delete'. Content.insert(Content.begin(), guarded.begin(), guarded.end()); } bool TaskDialogPython::tryLoadUiFile() { if (dlg.hasAttr(std::string("ui"))) { auto loader = UiLoader::newInstance(); QString fn, icon; Py::String ui(dlg.getAttr(std::string("ui"))); std::string path = static_cast(ui); fn = QString::fromUtf8(path.c_str()); QFile file(fn); QWidget* form = nullptr; if (file.open(QFile::ReadOnly)) { form = loader->load(&file, nullptr); } file.close(); if (form) { appendForm(form, QPixmap(icon)); } else { Base::Console().error("Failed to load UI file from '%s'\n", (const char*)fn.toUtf8()); } return true; } return false; } bool TaskDialogPython::tryLoadForm() { if (dlg.hasAttr(std::string("form"))) { Py::Object f(dlg.getAttr(std::string("form"))); Py::List widgets; if (f.isList()) { widgets = f; } else { widgets.append(f); } Gui::PythonWrapper wrap; if (wrap.loadCoreModule()) { for (Py::List::iterator it = widgets.begin(); it != widgets.end(); ++it) { QObject* object = wrap.toQObject(*it); if (object) { QWidget* form = qobject_cast(object); if (form) { appendForm(form, form->windowIcon().pixmap(32)); } } } } return true; } return false; } void TaskDialogPython::appendForm(QWidget* form, const QPixmap& icon) { form->installEventFilter(this); auto taskbox = new Gui::TaskView::TaskBox(icon, form->windowTitle(), true, nullptr); taskbox->groupLayout()->addWidget(form); Content.push_back(taskbox); } void TaskDialogPython::clearForm() { Base::PyGILStateLocker lock; try { // The widgets stored in the 'form' attribute will be deleted. // Thus, set this attribute to None to make sure that when using // the same dialog instance for a task panel won't segfault. if (this->dlg.hasAttr(std::string("form"))) { this->dlg.setAttr(std::string("form"), Py::None()); } this->dlg = Py::None(); } catch (Py::AttributeError& e) { e.clear(); } } void TaskDialogPython::open() { Base::PyGILStateLocker lock; try { if (dlg.hasAttr(std::string("open"))) { Py::Callable method(dlg.getAttr(std::string("open"))); Py::Tuple args; method.apply(args); } } catch (Py::Exception&) { Base::PyException e; // extract the Python error text e.reportException(); } } void TaskDialogPython::clicked(int i) { Base::PyGILStateLocker lock; try { if (dlg.hasAttr(std::string("clicked"))) { Py::Callable method(dlg.getAttr(std::string("clicked"))); PythonWrapper wrap; Py::Tuple args(1); args.setItem(0, wrap.toStandardButton(i)); method.apply(args); } } catch (Py::Exception&) { Base::PyException e; // extract the Python error text e.reportException(); } } bool TaskDialogPython::accept() { Base::PyGILStateLocker lock; try { if (dlg.hasAttr(std::string("accept"))) { Py::Callable method(dlg.getAttr(std::string("accept"))); Py::Tuple args; Py::Boolean ret(method.apply(args)); return (bool)ret; } } catch (Py::Exception&) { Base::PyException e; // extract the Python error text e.reportException(); } return TaskDialog::accept(); } bool TaskDialogPython::reject() { Base::PyGILStateLocker lock; try { if (dlg.hasAttr(std::string("reject"))) { Py::Callable method(dlg.getAttr(std::string("reject"))); Py::Tuple args; Py::Boolean ret(method.apply(args)); return (bool)ret; } } catch (Py::Exception&) { Base::PyException e; // extract the Python error text e.reportException(); } return TaskDialog::reject(); } void TaskDialogPython::helpRequested() { Base::PyGILStateLocker lock; try { if (dlg.hasAttr(std::string("helpRequested"))) { Py::Callable method(dlg.getAttr(std::string("helpRequested"))); Py::Tuple args; method.apply(args); } } catch (Py::Exception&) { Base::PyException e; // extract the Python error text e.reportException(); } } bool TaskDialogPython::eventFilter(QObject* watched, QEvent* event) { if (event->type() == QEvent::LanguageChange) { Base::PyGILStateLocker lock; try { if (dlg.hasAttr(std::string("changeEvent"))) { Py::Callable method(dlg.getAttr(std::string("changeEvent"))); Py::Tuple args {1}; args.setItem(0, Py::Long(static_cast(event->type()))); method.apply(args); } } catch (Py::Exception&) { Base::PyException e; // extract the Python error text e.reportException(); } } return TaskDialog::eventFilter(watched, event); } QDialogButtonBox::StandardButtons TaskDialogPython::getStandardButtons() const { Base::PyGILStateLocker lock; try { if (dlg.hasAttr(std::string("getStandardButtons"))) { Py::Callable method(dlg.getAttr(std::string("getStandardButtons"))); Py::Tuple args; Gui::PythonWrapper wrap; wrap.loadWidgetsModule(); int value = wrap.toEnum(method.apply(args)); return {value}; } } catch (Py::Exception&) { Base::PyException e; // extract the Python error text e.reportException(); } return TaskDialog::getStandardButtons(); } void TaskDialogPython::modifyStandardButtons(QDialogButtonBox* buttonBox) { Base::PyGILStateLocker lock; try { if (dlg.hasAttr(std::string("modifyStandardButtons"))) { Gui::PythonWrapper wrap; wrap.loadGuiModule(); wrap.loadWidgetsModule(); Py::Callable method(dlg.getAttr(std::string("modifyStandardButtons"))); Py::Tuple args(1); args.setItem(0, wrap.fromQWidget(buttonBox, "QDialogButtonBox")); method.apply(args); } } catch (Py::Exception&) { Base::PyException e; // extract the Python error text e.reportException(); } } bool TaskDialogPython::isAllowedAlterDocument() const { Base::PyGILStateLocker lock; try { if (dlg.hasAttr(std::string("isAllowedAlterDocument"))) { Py::Callable method(dlg.getAttr(std::string("isAllowedAlterDocument"))); Py::Tuple args; Py::Boolean ret(method.apply(args)); return (bool)ret; } } catch (Py::Exception&) { Base::PyException e; // extract the Python error text e.reportException(); } return TaskDialog::isAllowedAlterDocument(); } bool TaskDialogPython::isAllowedAlterView() const { Base::PyGILStateLocker lock; try { if (dlg.hasAttr(std::string("isAllowedAlterView"))) { Py::Callable method(dlg.getAttr(std::string("isAllowedAlterView"))); Py::Tuple args; Py::Boolean ret(method.apply(args)); return (bool)ret; } } catch (Py::Exception&) { Base::PyException e; // extract the Python error text e.reportException(); } return TaskDialog::isAllowedAlterView(); } bool TaskDialogPython::isAllowedAlterSelection() const { Base::PyGILStateLocker lock; try { if (dlg.hasAttr(std::string("isAllowedAlterSelection"))) { Py::Callable method(dlg.getAttr(std::string("isAllowedAlterSelection"))); Py::Tuple args; Py::Boolean ret(method.apply(args)); return (bool)ret; } } catch (Py::Exception&) { Base::PyException e; // extract the Python error text e.reportException(); } return TaskDialog::isAllowedAlterSelection(); } bool TaskDialogPython::needsFullSpace() const { Base::PyGILStateLocker lock; try { if (dlg.hasAttr(std::string("needsFullSpace"))) { Py::Callable method(dlg.getAttr(std::string("needsFullSpace"))); Py::Tuple args; Py::Boolean ret(method.apply(args)); return (bool)ret; } } catch (Py::Exception&) { Base::PyException e; // extract the Python error text e.reportException(); } return TaskDialog::needsFullSpace(); } void TaskDialogPython::autoClosedOnTransactionChange() { Base::PyGILStateLocker lock; try { if (dlg.hasAttr(std::string("autoClosedOnTransactionChange"))) { Py::Callable method(dlg.getAttr(std::string("autoClosedOnTransactionChange"))); Py::Tuple args; method.apply(args); } } catch (Py::Exception&) { Base::PyException e; // extract the Python error text e.reportException(); } } void TaskDialogPython::autoClosedOnDeletedDocument() { Base::PyGILStateLocker lock; try { if (dlg.hasAttr(std::string("autoClosedOnDeletedDocument"))) { Py::Callable method(dlg.getAttr(std::string("autoClosedOnDeletedDocument"))); Py::Tuple args; method.apply(args); } } catch (Py::Exception&) { Base::PyException e; // extract the Python error text e.reportException(); } }