/*************************************************************************** * Copyright (c) 2021 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 "DocumentPy.h" #include "MainWindowPy.h" #include "MainWindow.h" #include "MDIView.h" #include "MDIViewPy.h" #include "MDIViewPyWrap.h" #include "PythonWrapper.h" using namespace Gui; void MainWindowPy::init_type() { behaviors().name("MainWindowPy"); behaviors().doc("Python binding class for the MainWindow class"); // you must have overwritten the virtual functions behaviors().supportRepr(); behaviors().supportGetattr(); behaviors().supportSetattr(); behaviors().set_tp_new(extension_object_new); add_varargs_method("getWindows", &MainWindowPy::getWindows, "getWindows()"); add_varargs_method("getWindowsOfType", &MainWindowPy::getWindowsOfType, "getWindowsOfType(typeid)"); add_varargs_method("setActiveWindow", &MainWindowPy::setActiveWindow, "setActiveWindow(MDIView)"); add_varargs_method("getActiveWindow", &MainWindowPy::getActiveWindow, "getActiveWindow()"); add_varargs_method("addWindow", &MainWindowPy::addWindow, "addWindow(MDIView)"); add_varargs_method("removeWindow", &MainWindowPy::removeWindow, "removeWindow(MDIView)"); add_varargs_method("showHint", &MainWindowPy::showHint, "showHint(hint)"); add_varargs_method("hideHint", &MainWindowPy::hideHint, "hideHint()"); } PyObject* MainWindowPy::extension_object_new(struct _typeobject* /*type*/, PyObject* /*args*/, PyObject* /*kwds*/) { return new MainWindowPy(nullptr); } Py::Object MainWindowPy::type() { return Py::Object(reinterpret_cast(behaviors().type_object())); } Py::ExtensionObject MainWindowPy::create(MainWindow* mw) { Py::Callable class_type(type()); Py::Tuple arg; auto inst = Py::ExtensionObject(class_type.apply(arg, Py::Dict())); inst.extensionObject()->_mw = mw; return inst; } Py::Object MainWindowPy::createWrapper(MainWindow* mw) { PythonWrapper wrap; if (!wrap.loadCoreModule() || !wrap.loadGuiModule() || !wrap.loadWidgetsModule()) { throw Py::RuntimeError("Failed to load Python wrapper for Qt"); } // copy attributes static constexpr std::initializer_list attr = { "getWindows", "getWindowsOfType", "setActiveWindow", "getActiveWindow", "addWindow", "removeWindow", "showHint", "hideHint", }; Py::Object py = wrap.fromQWidget(mw, "QMainWindow"); Py::ExtensionObject inst(create(mw)); for (const auto& it : attr) { py.setAttr(it, inst.getAttr(it)); } return py; } MainWindowPy::MainWindowPy(MainWindow* mw) : _mw(mw) {} MainWindowPy::~MainWindowPy() { // in case the class is instantiated on the stack ob_refcnt = 0; } Py::Object MainWindowPy::repr() { if (!_mw) { throw Py::RuntimeError("Cannot print representation of deleted object"); } return Py::String("MainWindow"); } Py::Object MainWindowPy::getWindows(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) { throw Py::Exception(); } Py::List mdis; if (_mw) { QList windows = _mw->windows(); for (auto it : windows) { auto view = dynamic_cast(it); if (view) { mdis.append(Py::asObject(view->getPyObject())); } } } return mdis; } Py::Object MainWindowPy::getWindowsOfType(const Py::Tuple& args) { PyObject* t; if (!PyArg_ParseTuple(args.ptr(), "O!", &Base::TypePy::Type, &t)) { throw Py::Exception(); } Base::Type typeId = *static_cast(t)->getBaseTypePtr(); Py::List mdis; if (_mw) { QList windows = _mw->windows(); for (auto it : windows) { auto view = dynamic_cast(it); if (view && view->isDerivedFrom(typeId)) { mdis.append(Py::asObject(view->getPyObject())); } } } return mdis; } Py::Object MainWindowPy::setActiveWindow(const Py::Tuple& args) { Py::ExtensionObject mdi(args[0].callMemberFunction("cast_to_base")); if (_mw) { _mw->setActiveWindow(mdi.extensionObject()->getMDIViewPtr()); } return Py::None(); } Py::Object MainWindowPy::getActiveWindow(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) { throw Py::Exception(); } if (_mw) { MDIView* mdi = _mw->activeWindow(); if (mdi) { return Py::asObject(mdi->getPyObject()); } } return Py::None(); } Py::Object MainWindowPy::addWindow(const Py::Tuple& args) { PyObject* obj; if (!PyArg_ParseTuple(args.ptr(), "O", &obj)) { throw Py::Exception(); } if (_mw) { Py::Object py(obj); Gui::Document* document {nullptr}; // Check if the py object has a reference to a Gui document if (py.hasAttr("document")) { Py::Object attr(py.getAttr("document")); if (PyObject_TypeCheck(attr.ptr(), &DocumentPy::Type)) { document = static_cast(attr.ptr())->getDocumentPtr(); } } MDIViewPyWrap* mdi = new MDIViewPyWrap(py, document); _mw->addWindow(mdi); return Py::asObject(mdi->getPyObject()); } return Py::None(); } Py::Object MainWindowPy::removeWindow(const Py::Tuple& args) { Py::ExtensionObject mdi(args[0].callMemberFunction("cast_to_base")); if (_mw) { _mw->removeWindow(mdi.extensionObject()->getMDIViewPtr()); } return Py::None(); } Py::Object MainWindowPy::showHint(const Py::Tuple& args) { static auto userInputFromPyObject = [](const Py::Object& object) -> InputHint::UserInput { Py::Long value(object.getAttr("value")); return static_cast(value.as_long()); }; static auto inputSequenceFromPyObject = [](const Py::Object& sequence) -> InputHint::InputSequence { if (sequence.isTuple()) { Py::Tuple pyInputs(sequence); std::list inputs; for (auto pyInput : pyInputs) { inputs.push_back(userInputFromPyObject(pyInput)); } return InputHint::InputSequence(inputs); } return userInputFromPyObject(sequence); }; static auto hintFromPyObject = [](const Py::Object& object) -> InputHint { Py::List pySequences = object.getAttr("sequences"); std::list sequences; for (auto pySequence : pySequences) { sequences.push_back(inputSequenceFromPyObject(pySequence)); } return InputHint { .message = QString::fromStdString(object.getAttr("message").as_string()), .sequences = sequences }; }; std::list hints; for (auto arg : args) { hints.push_back(hintFromPyObject(arg)); } _mw->showHints(hints); return Py::None(); } Py::Object MainWindowPy::hideHint(const Py::Tuple&) { _mw->hideHints(); return Py::None(); }