2387 lines
73 KiB
C++
2387 lines
73 KiB
C++
/***************************************************************************
|
|
* Copyright (c) 2005 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 <QApplication>
|
|
#include <QDir>
|
|
#include <QPrinter>
|
|
#include <QFileInfo>
|
|
#include <Inventor/SoInput.h>
|
|
#include <Inventor/actions/SoGetPrimitiveCountAction.h>
|
|
#include <Inventor/nodes/SoSeparator.h>
|
|
#include <xercesc/util/TranscodingException.hpp>
|
|
#include <xercesc/util/XMLString.hpp>
|
|
|
|
#include <boost/regex.hpp>
|
|
|
|
#include <App/DocumentObjectPy.h>
|
|
#include <App/DocumentPy.h>
|
|
#include <App/PropertyFile.h>
|
|
#include <Base/Interpreter.h>
|
|
#include <Base/Console.h>
|
|
#include <Base/PyWrapParseTupleAndKeywords.h>
|
|
#include <CXX/Objects.hxx>
|
|
|
|
#include <Gui/PreferencePages/DlgSettingsPDF.h>
|
|
|
|
#include "Application.h"
|
|
#include "ApplicationPy.h"
|
|
#include "BitmapFactory.h"
|
|
#include "Command.h"
|
|
#include "Dialogs/DlgPreferencesImp.h"
|
|
#include "Document.h"
|
|
#include "DocumentObserverPython.h"
|
|
#include "DownloadManager.h"
|
|
#include "EditorView.h"
|
|
#include "FileHandler.h"
|
|
#include "Macro.h"
|
|
#include "MainWindow.h"
|
|
#include "MainWindowPy.h"
|
|
#include "PythonEditor.h"
|
|
#include "PythonWrapper.h"
|
|
#include "SoFCDB.h"
|
|
#include "SplitView3DInventor.h"
|
|
#include "View3DInventor.h"
|
|
#include "ViewProvider.h"
|
|
#include "WaitCursor.h"
|
|
#include "WidgetFactory.h"
|
|
#include "Workbench.h"
|
|
#include "WorkbenchManager.h"
|
|
#include "WorkbenchManipulatorPython.h"
|
|
#include "FileOriginPython.h"
|
|
#include "EditingContext.h"
|
|
#include "OriginManager.h"
|
|
#include "Inventor/MarkerBitmaps.h"
|
|
#include "Language/Translator.h"
|
|
|
|
|
|
using namespace Gui;
|
|
|
|
// Application methods structure
|
|
PyMethodDef ApplicationPy::Methods[] = {
|
|
{"activateWorkbench",
|
|
(PyCFunction)ApplicationPy::sActivateWorkbenchHandler,
|
|
METH_VARARGS,
|
|
"activateWorkbench(name) -> bool\n"
|
|
"\n"
|
|
"Activate workbench by its name. Return False if the workbench is\n"
|
|
"already active.\n"
|
|
"\n"
|
|
"name : str\n Name of the workbench to activate."},
|
|
{"addWorkbench",
|
|
(PyCFunction)ApplicationPy::sAddWorkbenchHandler,
|
|
METH_VARARGS,
|
|
"addWorkbench(workbench) -> None\n"
|
|
"\n"
|
|
"Add a workbench.\n"
|
|
"\n"
|
|
"workbench : Workbench, Workbench type\n"
|
|
" Instance of a Workbench subclass or subclass of the\n"
|
|
" Workbench class."},
|
|
{"removeWorkbench",
|
|
(PyCFunction)ApplicationPy::sRemoveWorkbenchHandler,
|
|
METH_VARARGS,
|
|
"removeWorkbench(name) -> None\n"
|
|
"\n"
|
|
"Remove a workbench.\n"
|
|
"\n"
|
|
"name : str\n Name of the workbench to remove."},
|
|
{"getWorkbench",
|
|
(PyCFunction)ApplicationPy::sGetWorkbenchHandler,
|
|
METH_VARARGS,
|
|
"getWorkbench(name) -> Workbench\n"
|
|
"\n"
|
|
"Get the workbench by its name.\n"
|
|
"\n"
|
|
"name : str\n Name of the workbench to return."},
|
|
{"listWorkbenches",
|
|
(PyCFunction)ApplicationPy::sListWorkbenchHandlers,
|
|
METH_VARARGS,
|
|
"listWorkbenches() -> dict\n"
|
|
"\n"
|
|
"Get a dictionary with all workbenches."},
|
|
{"activeWorkbench",
|
|
(PyCFunction)ApplicationPy::sActiveWorkbenchHandler,
|
|
METH_VARARGS,
|
|
"activeWorkbench() -> Workbench\n"
|
|
"\n"
|
|
"Return the active workbench object."},
|
|
{"addResourcePath",
|
|
(PyCFunction)ApplicationPy::sAddResPath,
|
|
METH_VARARGS,
|
|
"addResourcePath(path) -> None\n"
|
|
"\n"
|
|
"Add a new path to the system where to find resource files\n"
|
|
"like icons or localization files.\n"
|
|
"\n"
|
|
"path : str, bytes, bytearray\n Path to resource files."},
|
|
{"addLanguagePath",
|
|
(PyCFunction)ApplicationPy::sAddLangPath,
|
|
METH_VARARGS,
|
|
"addLanguagePath(path) -> None\n"
|
|
"\n"
|
|
"Add a new path to the system where to find language files.\n"
|
|
"\n"
|
|
"path : str, bytes, bytearray\n Path to language files."},
|
|
{"addIconPath",
|
|
(PyCFunction)ApplicationPy::sAddIconPath,
|
|
METH_VARARGS,
|
|
"addIconPath(path) -> None\n"
|
|
"\n"
|
|
"Add a new path to the system where to find icon files.\n"
|
|
"\n"
|
|
"path : str, bytes, bytearray\n Path to icon files."},
|
|
{"addIcon",
|
|
(PyCFunction)ApplicationPy::sAddIcon,
|
|
METH_VARARGS,
|
|
"addIcon(name, content, format='XPM') -> None\n"
|
|
"\n"
|
|
"Add an icon to the system.\n"
|
|
"\n"
|
|
"name : str\n Name of the icon.\n"
|
|
"content : str, bytes-like\n Content of the icon.\n"
|
|
"format : str\n Format of the icon."},
|
|
{"getIcon",
|
|
(PyCFunction)ApplicationPy::sGetIcon,
|
|
METH_VARARGS,
|
|
"getIcon(name) -> QIcon or None\n"
|
|
"\n"
|
|
"Get an icon in the system. If the pixmap is null, return None.\n"
|
|
"\n"
|
|
"name : str\n Name of the icon."},
|
|
{"isIconCached",
|
|
(PyCFunction)ApplicationPy::sIsIconCached,
|
|
METH_VARARGS,
|
|
"isIconCached(name) -> Bool\n"
|
|
"\n"
|
|
"Check if an icon with the given name is cached.\n"
|
|
"\n"
|
|
"name : str\n Name of the icon."},
|
|
{"getMainWindow",
|
|
(PyCFunction)ApplicationPy::sGetMainWindow,
|
|
METH_VARARGS,
|
|
"getMainWindow() -> QMainWindow\n"
|
|
"\n"
|
|
"Return the main window instance."},
|
|
{"updateGui",
|
|
(PyCFunction)ApplicationPy::sUpdateGui,
|
|
METH_VARARGS,
|
|
"updateGui() -> None\n"
|
|
"\n"
|
|
"Update the main window and all its windows."},
|
|
{"updateLocale",
|
|
(PyCFunction)ApplicationPy::sUpdateLocale,
|
|
METH_VARARGS,
|
|
"updateLocale() -> None\n"
|
|
"\n"
|
|
"Update the localization."},
|
|
{"getLocale",
|
|
(PyCFunction)ApplicationPy::sGetLocale,
|
|
METH_VARARGS,
|
|
"getLocale() -> str\n"
|
|
"\n"
|
|
"Returns the locale currently used by FreeCAD."},
|
|
{"setLocale",
|
|
(PyCFunction)ApplicationPy::sSetLocale,
|
|
METH_VARARGS,
|
|
"setLocale(name) -> None\n"
|
|
"\n"
|
|
"Sets the locale used by FreeCAD. Can be set by top-level\n"
|
|
"domain (e.g. \"de\") or the language name (e.g. \"German\").\n"
|
|
"\n"
|
|
"name : str\n Locale name."},
|
|
{"supportedLocales",
|
|
(PyCFunction)ApplicationPy::sSupportedLocales,
|
|
METH_VARARGS,
|
|
"supportedLocales() -> dict\n"
|
|
"\n"
|
|
"Returns a dict of all supported locales. The keys are the language\n"
|
|
"names and the values the top-level domains."},
|
|
{"createDialog",
|
|
(PyCFunction)ApplicationPy::sCreateDialog,
|
|
METH_VARARGS,
|
|
"createDialog(path) -> PyResource\n"
|
|
"\n"
|
|
"Open a UI file.\n"
|
|
"\n"
|
|
"path : str\n UI file path."},
|
|
{"addPreferencePage",
|
|
(PyCFunction)ApplicationPy::sAddPreferencePage,
|
|
METH_VARARGS,
|
|
"addPreferencePage(path, group) -> None\n"
|
|
"addPreferencePage(dialog, group) -> None\n"
|
|
"\n"
|
|
"Add a UI form to the preferences dialog in the specified group.\n"
|
|
"\n"
|
|
"path : str\n UI file path.\n"
|
|
"group : str\n Group name.\n"
|
|
"dialog : type\n Preference page."},
|
|
{"addCommand",
|
|
(PyCFunction)ApplicationPy::sAddCommand,
|
|
METH_VARARGS,
|
|
"addCommand(name, cmd, activation) -> None\n"
|
|
"\n"
|
|
"Add a command object.\n"
|
|
"\n"
|
|
"name : str\n Name of the command.\n"
|
|
"cmd : object\n Command instance.\n"
|
|
"activation : str\n Activation sequence. Optional."},
|
|
{"runCommand",
|
|
(PyCFunction)ApplicationPy::sRunCommand,
|
|
METH_VARARGS,
|
|
"runCommand(name, index=0) -> None\n"
|
|
"\n"
|
|
"Run command by its name.\n"
|
|
"\n"
|
|
"name : str\n Name of the command.\n"
|
|
"index : int\n Index of the child command."},
|
|
{"SendMsgToActiveView",
|
|
(PyCFunction)ApplicationPy::sSendActiveView,
|
|
METH_VARARGS,
|
|
"SendMsgToActiveView(name, suppress=False) -> str or None\n"
|
|
"\n"
|
|
"Send message to the active view. Deprecated, use class View.\n"
|
|
"\n"
|
|
"name : str\n Name of the view command.\n"
|
|
"suppress : bool\n If the sent message fail, suppress warning message."},
|
|
{"sendMsgToFocusView",
|
|
(PyCFunction)ApplicationPy::sSendFocusView,
|
|
METH_VARARGS,
|
|
"sendMsgToFocusView(name, suppress=False) -> str or None\n"
|
|
"\n"
|
|
"Send message to the focused view.\n"
|
|
"\n"
|
|
"name : str\n Name of the view command.\n"
|
|
"suppress : bool\n If send message fail, suppress warning message."},
|
|
{"hide",
|
|
(PyCFunction)ApplicationPy::sHide,
|
|
METH_VARARGS,
|
|
"hide(name) -> None\n"
|
|
"\n"
|
|
"Hide the given feature. Deprecated.\n"
|
|
"\n"
|
|
"name : str\n Feature name."},
|
|
{"show",
|
|
(PyCFunction)ApplicationPy::sShow,
|
|
METH_VARARGS,
|
|
"show(name) -> None\n"
|
|
"\n"
|
|
"Show the given feature. Deprecated.\n"
|
|
"\n"
|
|
"name : str\n Feature name."},
|
|
{"hideObject",
|
|
(PyCFunction)ApplicationPy::sHideObject,
|
|
METH_VARARGS,
|
|
"hideObject(obj) -> None\n"
|
|
"\n"
|
|
"Hide the view provider of the given object.\n"
|
|
"\n"
|
|
"obj : App.DocumentObject"},
|
|
{"showObject",
|
|
(PyCFunction)ApplicationPy::sShowObject,
|
|
METH_VARARGS,
|
|
"showObject(obj) -> None\n"
|
|
"\n"
|
|
"Show the view provider of the given object.\n"
|
|
"\n"
|
|
"obj : App.DocumentObject"},
|
|
{"open",
|
|
(PyCFunction)ApplicationPy::sOpen,
|
|
METH_VARARGS,
|
|
"open(fileName) -> None\n"
|
|
"\n"
|
|
"Open a macro, Inventor or VRML file.\n"
|
|
"\n"
|
|
"fileName : str, bytes, bytearray\n File name."},
|
|
{"insert",
|
|
(PyCFunction)ApplicationPy::sInsert,
|
|
METH_VARARGS,
|
|
"insert(fileName, docName) -> None\n"
|
|
"\n"
|
|
"Insert a macro, Inventor or VRML file. If no document name\n"
|
|
"is given the active document is used.\n"
|
|
"\n"
|
|
"fileName : str, bytes, bytearray\n File name.\n"
|
|
"docName : str\n Document name."},
|
|
{"export",
|
|
(PyCFunction)ApplicationPy::sExport,
|
|
METH_VARARGS,
|
|
"export(objs, fileName) -> None\n"
|
|
"\n"
|
|
"Save scene to Inventor or VRML file.\n"
|
|
"\n"
|
|
"objs : sequence of App.DocumentObject\n Sequence of objects to save.\n"
|
|
"fileName : str, bytes, bytearray\n File name."},
|
|
{"activeDocument",
|
|
(PyCFunction)ApplicationPy::sActiveDocument,
|
|
METH_VARARGS,
|
|
"activeDocument() -> Gui.Document or None\n"
|
|
"\n"
|
|
"Return the active document. If no one exists, return None."},
|
|
{"setActiveDocument",
|
|
(PyCFunction)ApplicationPy::sSetActiveDocument,
|
|
METH_VARARGS,
|
|
"setActiveDocument(doc) -> None\n"
|
|
"\n"
|
|
"Activate the specified document.\n"
|
|
"\n"
|
|
"doc : str, App.Document\n Document to activate."},
|
|
{"activeView",
|
|
(PyCFunction)ApplicationPy::sActiveView,
|
|
METH_VARARGS,
|
|
"activeView(typeName) -> object or None\n"
|
|
"\n"
|
|
"Return the active view of the active document. If no one\n"
|
|
"exists, return None.\n"
|
|
"\n"
|
|
"typeName : str\n Type name."},
|
|
{"activateView",
|
|
(PyCFunction)ApplicationPy::sActivateView,
|
|
METH_VARARGS,
|
|
"activateView(typeName, create=False) -> None\n"
|
|
"\n"
|
|
"Activate a view of the given type in the active document.\n"
|
|
"If a view of this type doesn't exist and create is True, a\n"
|
|
"new view of this type is created.\n"
|
|
"\n"
|
|
"type : str\n Type name.\n"
|
|
"create : bool"},
|
|
{"editDocument",
|
|
(PyCFunction)ApplicationPy::sEditDocument,
|
|
METH_VARARGS,
|
|
"editDocument() -> Gui.Document or None\n"
|
|
"\n"
|
|
"Return the current editing document. If no one exists,\n"
|
|
"return None."},
|
|
{"getDocument",
|
|
(PyCFunction)ApplicationPy::sGetDocument,
|
|
METH_VARARGS,
|
|
"getDocument(doc) -> Gui.Document\n"
|
|
"\n"
|
|
"Get a document.\n"
|
|
"\n"
|
|
"doc : str, App.Document\n `App.Document` name or `App.Document` object."},
|
|
{"doCommand",
|
|
(PyCFunction)ApplicationPy::sDoCommand,
|
|
METH_VARARGS,
|
|
"doCommand(cmd) -> None\n"
|
|
"\n"
|
|
"Prints the given string in the python console and runs it.\n"
|
|
"\n"
|
|
"cmd : str"},
|
|
{"doCommandGui",
|
|
(PyCFunction)ApplicationPy::sDoCommandGui,
|
|
METH_VARARGS,
|
|
"doCommandGui(cmd) -> None\n"
|
|
"\n"
|
|
"Prints the given string in the python console and runs it\n"
|
|
"but doesn't record it in macros.\n"
|
|
"\n"
|
|
"cmd : str"},
|
|
{"doCommandEval",
|
|
(PyCFunction)ApplicationPy::sDoCommandEval,
|
|
METH_VARARGS,
|
|
"doCommandEval(cmd) -> PyObject\n"
|
|
"\n"
|
|
"Runs the given string without showing in the python console or recording in\n"
|
|
"macros, and returns the result.\n"
|
|
"\n"
|
|
"cmd : str"},
|
|
{"doCommandSkip",
|
|
(PyCFunction)ApplicationPy::sDoCommandSkip,
|
|
METH_VARARGS,
|
|
"doCommandSkip(cmd) -> None\n"
|
|
"\n"
|
|
"Record the given string in the Macro but comment it out in the console\n"
|
|
"\n"
|
|
"cmd : str"},
|
|
{"addModule",
|
|
(PyCFunction)ApplicationPy::sAddModule,
|
|
METH_VARARGS,
|
|
"addModule(mod) -> None\n"
|
|
"\n"
|
|
"Prints the given module import only once in the macro recording.\n"
|
|
"\n"
|
|
"mod : str"},
|
|
{"showDownloads",
|
|
(PyCFunction)ApplicationPy::sShowDownloads,
|
|
METH_VARARGS,
|
|
"showDownloads() -> None\n\n"
|
|
"Show the downloads manager window."},
|
|
{"showPreferences",
|
|
(PyCFunction)ApplicationPy::sShowPreferences,
|
|
METH_VARARGS,
|
|
"showPreferences(grp, index=0) -> None\n"
|
|
"\n"
|
|
"Show the preferences window.\n"
|
|
"\n"
|
|
"grp: str\n Group to show.\n"
|
|
"index : int\n Page index."},
|
|
{"showPreferencesByName",
|
|
(PyCFunction)ApplicationPy::sShowPreferencesByName,
|
|
METH_VARARGS,
|
|
"showPreferencesByName(grp, pagename) -> None\n"
|
|
"\n"
|
|
"Show the preferences window.\n"
|
|
"\n"
|
|
"grp: str\n Group to show.\n"
|
|
"pagename : str\n Page to show."},
|
|
{"createViewer",
|
|
(PyCFunction)ApplicationPy::sCreateViewer,
|
|
METH_VARARGS,
|
|
"createViewer(views=1, name) -> View3DInventorPy or AbstractSplitViewPy\n"
|
|
"\n"
|
|
"Show and returns a viewer.\n"
|
|
"\n"
|
|
"views : int\n If > 1 a `AbstractSplitViewPy` object is returned.\n"
|
|
"name : str\n Viewer title."},
|
|
{"getMarkerIndex",
|
|
(PyCFunction)ApplicationPy::sGetMarkerIndex,
|
|
METH_VARARGS,
|
|
"getMarkerIndex(marker, size=9) -> int\n"
|
|
"\n"
|
|
"Get marker index according to marker name and size.\n"
|
|
"\n"
|
|
"marker : str\n Marker style name.\n"
|
|
"size : int\n Marker size."},
|
|
{"addDocumentObserver",
|
|
(PyCFunction)ApplicationPy::sAddDocObserver,
|
|
METH_VARARGS,
|
|
"addDocumentObserver(obj) -> None\n"
|
|
"\n"
|
|
"Add an observer to get notifications about changes on documents.\n"
|
|
"\n"
|
|
"obj : object"},
|
|
{"removeDocumentObserver",
|
|
(PyCFunction)ApplicationPy::sRemoveDocObserver,
|
|
METH_VARARGS,
|
|
"removeDocumentObserver(obj) -> None\n"
|
|
"\n"
|
|
"Remove an added document observer.\n"
|
|
"\n"
|
|
"obj : object"},
|
|
{"addWorkbenchManipulator",
|
|
(PyCFunction)ApplicationPy::sAddWbManipulator,
|
|
METH_VARARGS,
|
|
"addWorkbenchManipulator(obj) -> None\n"
|
|
"\n"
|
|
"Add a workbench manipulator to modify a workbench when it is activated.\n"
|
|
"\n"
|
|
"obj : object"},
|
|
{"removeWorkbenchManipulator",
|
|
(PyCFunction)ApplicationPy::sRemoveWbManipulator,
|
|
METH_VARARGS,
|
|
"removeWorkbenchManipulator(obj) -> None\n"
|
|
"\n"
|
|
"Remove an added workbench manipulator.\n"
|
|
"\n"
|
|
"obj : object"},
|
|
{"listUserEditModes",
|
|
(PyCFunction)ApplicationPy::sListUserEditModes,
|
|
METH_VARARGS,
|
|
"listUserEditModes() -> list\n"
|
|
"\n"
|
|
"List available user edit modes."},
|
|
{"getUserEditMode",
|
|
(PyCFunction)ApplicationPy::sGetUserEditMode,
|
|
METH_VARARGS,
|
|
"getUserEditMode() -> str\n"
|
|
"\n"
|
|
"Get current user edit mode."},
|
|
{"setUserEditMode",
|
|
(PyCFunction)ApplicationPy::sSetUserEditMode,
|
|
METH_VARARGS,
|
|
"setUserEditMode(mode) -> bool\n"
|
|
"\n"
|
|
"Set user edit mode. Returns True if exists, False otherwise.\n"
|
|
"\n"
|
|
"mode : str"},
|
|
{"reload",
|
|
(PyCFunction)ApplicationPy::sReload,
|
|
METH_VARARGS,
|
|
"reload(name) -> App.Document or None\n"
|
|
"\n"
|
|
"Reload a partial opened document. If the document is not open,\n"
|
|
"return None.\n"
|
|
"\n"
|
|
"name : str\n `App.Document` name."},
|
|
{"loadFile",
|
|
(PyCFunction)ApplicationPy::sLoadFile,
|
|
METH_VARARGS,
|
|
"loadFile(fileName, module) -> None\n"
|
|
"\n"
|
|
"Loads an arbitrary file by delegating to the given Python module.\n"
|
|
"If no module is given it will be determined by the file extension.\n"
|
|
"If more than one module can load a file the first one will be taken.\n"
|
|
"If no module exists to load the file an exception will be raised.\n"
|
|
"\n"
|
|
"fileName : str\n"
|
|
"module : str"},
|
|
{"coinRemoveAllChildren",
|
|
(PyCFunction)ApplicationPy::sCoinRemoveAllChildren,
|
|
METH_VARARGS,
|
|
"coinRemoveAllChildren(node) -> None\n"
|
|
"\n"
|
|
"Remove all children from a group node.\n"
|
|
"\n"
|
|
"node : object"},
|
|
{"suspendWaitCursor",
|
|
(PyCFunction)ApplicationPy::sSuspendWaitCursor,
|
|
METH_VARARGS,
|
|
"suspendWaitCursor() -> None\n\n"
|
|
"Temporarily suspends the application's wait cursor and event filter."},
|
|
{"resumeWaitCursor",
|
|
(PyCFunction)ApplicationPy::sResumeWaitCursor,
|
|
METH_VARARGS,
|
|
"resumeWaitCursor() -> None\n\n"
|
|
"Resumes the application's wait cursor and event filter."},
|
|
{"addOrigin",
|
|
(PyCFunction)ApplicationPy::sAddOrigin,
|
|
METH_VARARGS,
|
|
"addOrigin(obj) -> None\n"
|
|
"\n"
|
|
"Register a Python origin handler for document operations.\n"
|
|
"\n"
|
|
"obj : object\n Origin object implementing the FileOrigin interface."},
|
|
{"removeOrigin",
|
|
(PyCFunction)ApplicationPy::sRemoveOrigin,
|
|
METH_VARARGS,
|
|
"removeOrigin(obj) -> None\n"
|
|
"\n"
|
|
"Unregister a Python origin handler.\n"
|
|
"\n"
|
|
"obj : object\n Origin object to unregister."},
|
|
{"getOrigin",
|
|
(PyCFunction)ApplicationPy::sGetOrigin,
|
|
METH_VARARGS,
|
|
"getOrigin(id) -> object or None\n"
|
|
"\n"
|
|
"Get an origin by its ID.\n"
|
|
"\n"
|
|
"id : str\n The origin ID."},
|
|
{"listOrigins",
|
|
(PyCFunction)ApplicationPy::sListOrigins,
|
|
METH_VARARGS,
|
|
"listOrigins() -> list\n"
|
|
"\n"
|
|
"Get a list of all registered origin IDs."},
|
|
{"activeOrigin",
|
|
(PyCFunction)ApplicationPy::sActiveOrigin,
|
|
METH_VARARGS,
|
|
"activeOrigin() -> object or None\n"
|
|
"\n"
|
|
"Get the currently active origin."},
|
|
{"setActiveOrigin",
|
|
(PyCFunction)ApplicationPy::sSetActiveOrigin,
|
|
METH_VARARGS,
|
|
"setActiveOrigin(id) -> bool\n"
|
|
"\n"
|
|
"Set the active origin by ID.\n"
|
|
"\n"
|
|
"id : str\n The origin ID to activate."},
|
|
{"registerEditingContext",
|
|
(PyCFunction)ApplicationPy::sRegisterEditingContext,
|
|
METH_VARARGS,
|
|
"registerEditingContext(id, label, color, toolbars, match, priority=50) -> None\n"
|
|
"\n"
|
|
"Register an editing context for dynamic toolbar management.\n"
|
|
"\n"
|
|
"id : str\n Unique context identifier (e.g. 'fem.analysis').\n"
|
|
"label : str\n Display label template. Use {name} for object name.\n"
|
|
"color : str\n Hex color for breadcrumb (e.g. '#f38ba8').\n"
|
|
"toolbars : list of str\n Toolbar names to show when active.\n"
|
|
"match : callable\n Function returning True if context is active.\n"
|
|
"priority : int\n Higher values checked first (default 50)."},
|
|
{"unregisterEditingContext",
|
|
(PyCFunction)ApplicationPy::sUnregisterEditingContext,
|
|
METH_VARARGS,
|
|
"unregisterEditingContext(id) -> None\n"
|
|
"\n"
|
|
"Unregister an editing context.\n"
|
|
"\n"
|
|
"id : str\n Context identifier to remove."},
|
|
{"registerEditingOverlay",
|
|
(PyCFunction)ApplicationPy::sRegisterEditingOverlay,
|
|
METH_VARARGS,
|
|
"registerEditingOverlay(id, toolbars, match) -> None\n"
|
|
"\n"
|
|
"Register an overlay context that adds toolbars to any active context.\n"
|
|
"\n"
|
|
"id : str\n Unique overlay identifier.\n"
|
|
"toolbars : list of str\n Toolbar names to add.\n"
|
|
"match : callable\n Function returning True if overlay is active."},
|
|
{"unregisterEditingOverlay",
|
|
(PyCFunction)ApplicationPy::sUnregisterEditingOverlay,
|
|
METH_VARARGS,
|
|
"unregisterEditingOverlay(id) -> None\n"
|
|
"\n"
|
|
"Unregister an editing overlay.\n"
|
|
"\n"
|
|
"id : str\n Overlay identifier to remove."},
|
|
{"injectEditingCommands",
|
|
(PyCFunction)ApplicationPy::sInjectEditingCommands,
|
|
METH_VARARGS,
|
|
"injectEditingCommands(contextId, toolbarName, commands) -> None\n"
|
|
"\n"
|
|
"Inject additional commands into a context's toolbar.\n"
|
|
"\n"
|
|
"contextId : str\n Context to inject into.\n"
|
|
"toolbarName : str\n Toolbar within that context.\n"
|
|
"commands : list of str\n Command names to add."},
|
|
{"currentEditingContext",
|
|
(PyCFunction)ApplicationPy::sCurrentEditingContext,
|
|
METH_VARARGS,
|
|
"currentEditingContext() -> dict\n"
|
|
"\n"
|
|
"Get the current editing context as a dict with keys:\n"
|
|
"id, label, color, toolbars, breadcrumb, breadcrumbColors."},
|
|
{"refreshEditingContext",
|
|
(PyCFunction)ApplicationPy::sRefreshEditingContext,
|
|
METH_VARARGS,
|
|
"refreshEditingContext() -> None\n"
|
|
"\n"
|
|
"Force re-resolution of the editing context."},
|
|
{nullptr, nullptr, 0, nullptr} /* Sentinel */
|
|
};
|
|
|
|
PyObject* Gui::ApplicationPy::sEditDocument(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, "")) {
|
|
return nullptr;
|
|
}
|
|
|
|
Document* pcDoc = Application::Instance->editDocument();
|
|
if (pcDoc) {
|
|
return pcDoc->getPyObject();
|
|
}
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* Gui::ApplicationPy::sActiveDocument(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, "")) {
|
|
return nullptr;
|
|
}
|
|
|
|
Document* pcDoc = Application::Instance->activeDocument();
|
|
if (pcDoc) {
|
|
return pcDoc->getPyObject();
|
|
}
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* Gui::ApplicationPy::sActiveView(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
const char* typeName = nullptr;
|
|
if (!PyArg_ParseTuple(args, "|s", &typeName)) {
|
|
return nullptr;
|
|
}
|
|
|
|
PY_TRY
|
|
{
|
|
Base::Type type;
|
|
if (typeName) {
|
|
type = Base::Type::fromName(typeName);
|
|
if (type.isBad()) {
|
|
PyErr_Format(PyExc_TypeError, "Invalid type '%s'", typeName);
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
Gui::MDIView* mdiView = Application::Instance->activeView();
|
|
if (mdiView && (type.isBad() || mdiView->isDerivedFrom(type))) {
|
|
auto res = Py::asObject(mdiView->getPyObject());
|
|
if (!res.isNone() || !type.isBad()) {
|
|
return Py::new_reference_to(res);
|
|
}
|
|
}
|
|
|
|
if (type.isBad()) {
|
|
type = Gui::View3DInventor::getClassTypeId();
|
|
}
|
|
Application::Instance->activateView(type, true);
|
|
mdiView = Application::Instance->activeView();
|
|
if (mdiView) {
|
|
return mdiView->getPyObject();
|
|
}
|
|
|
|
Py_Return;
|
|
}
|
|
PY_CATCH
|
|
}
|
|
|
|
PyObject* Gui::ApplicationPy::sActivateView(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
char* typeStr = nullptr;
|
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
|
|
PyObject* create = Py_False;
|
|
if (!PyArg_ParseTuple(args, "sO!", &typeStr, &PyBool_Type, &create)) {
|
|
return nullptr;
|
|
}
|
|
|
|
Base::Type type = Base::Type::fromName(typeStr);
|
|
Application::Instance->activateView(type, Base::asBoolean(create));
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* Gui::ApplicationPy::sSetActiveDocument(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
Document* pcDoc = nullptr;
|
|
|
|
do {
|
|
char* pstr = nullptr;
|
|
if (PyArg_ParseTuple(args, "s", &pstr)) {
|
|
pcDoc = Application::Instance->getDocument(pstr);
|
|
if (!pcDoc) {
|
|
PyErr_Format(PyExc_NameError, "Unknown document '%s'", pstr);
|
|
return nullptr;
|
|
}
|
|
break;
|
|
}
|
|
|
|
PyErr_Clear();
|
|
PyObject* doc = nullptr;
|
|
if (PyArg_ParseTuple(args, "O!", &(App::DocumentPy::Type), &doc)) {
|
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast)
|
|
pcDoc = Application::Instance->getDocument(
|
|
static_cast<App::DocumentPy*>(doc)->getDocumentPtr()
|
|
);
|
|
if (!pcDoc) {
|
|
PyErr_Format(PyExc_KeyError, "Unknown document instance");
|
|
return nullptr;
|
|
}
|
|
break;
|
|
}
|
|
} while (false);
|
|
|
|
if (!pcDoc) {
|
|
PyErr_SetString(PyExc_TypeError, "Either string or App.Document expected");
|
|
return nullptr;
|
|
}
|
|
|
|
if (Application::Instance->activeDocument() != pcDoc) {
|
|
Gui::MDIView* view = pcDoc->getActiveView();
|
|
getMainWindow()->setActiveWindow(view);
|
|
}
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sGetDocument(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
char* pstr = nullptr;
|
|
if (PyArg_ParseTuple(args, "s", &pstr)) {
|
|
Document* pcDoc = Application::Instance->getDocument(pstr);
|
|
if (!pcDoc) {
|
|
PyErr_Format(PyExc_NameError, "Unknown document '%s'", pstr);
|
|
return nullptr;
|
|
}
|
|
return pcDoc->getPyObject();
|
|
}
|
|
|
|
PyErr_Clear();
|
|
PyObject* doc = nullptr;
|
|
if (PyArg_ParseTuple(args, "O!", &(App::DocumentPy::Type), &doc)) {
|
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast)
|
|
Document* pcDoc = Application::Instance->getDocument(
|
|
static_cast<App::DocumentPy*>(doc)->getDocumentPtr()
|
|
);
|
|
if (!pcDoc) {
|
|
PyErr_Format(PyExc_KeyError, "Unknown document instance");
|
|
return nullptr;
|
|
}
|
|
return pcDoc->getPyObject();
|
|
}
|
|
|
|
PyErr_SetString(PyExc_TypeError, "Either string or App.Document expected");
|
|
return nullptr;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sHide(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
char* psFeatStr = nullptr;
|
|
if (!PyArg_ParseTuple(args, "s;Name of the object to hide has to be given!", &psFeatStr)) {
|
|
return nullptr;
|
|
}
|
|
|
|
Document* pcDoc = Application::Instance->activeDocument();
|
|
|
|
if (pcDoc) {
|
|
pcDoc->setHide(psFeatStr);
|
|
}
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sShow(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
char* psFeatStr = nullptr;
|
|
if (!PyArg_ParseTuple(args, "s;Name of the object to show has to be given!", &psFeatStr)) {
|
|
return nullptr;
|
|
}
|
|
|
|
Document* pcDoc = Application::Instance->activeDocument();
|
|
|
|
if (pcDoc) {
|
|
pcDoc->setShow(psFeatStr);
|
|
}
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sHideObject(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
PyObject* object = nullptr;
|
|
if (!PyArg_ParseTuple(args, "O!", &(App::DocumentObjectPy::Type), &object)) {
|
|
return nullptr;
|
|
}
|
|
|
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast)
|
|
App::DocumentObject* obj = static_cast<App::DocumentObjectPy*>(object)->getDocumentObjectPtr();
|
|
Application::Instance->hideViewProvider(obj);
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sShowObject(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
PyObject* object = nullptr;
|
|
if (!PyArg_ParseTuple(args, "O!", &(App::DocumentObjectPy::Type), &object)) {
|
|
return nullptr;
|
|
}
|
|
|
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast)
|
|
App::DocumentObject* obj = static_cast<App::DocumentObjectPy*>(object)->getDocumentObjectPtr();
|
|
Application::Instance->showViewProvider(obj);
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sOpen(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
// only used to open Python files
|
|
char* Name = nullptr;
|
|
if (!PyArg_ParseTuple(args, "et", "utf-8", &Name)) {
|
|
return nullptr;
|
|
}
|
|
|
|
std::string Utf8Name = std::string(Name);
|
|
PyMem_Free(Name);
|
|
PY_TRY
|
|
{
|
|
QString fileName = QString::fromUtf8(Utf8Name.c_str());
|
|
FileHandler handler(fileName);
|
|
if (!handler.openFile()) {
|
|
QString ext = handler.extension();
|
|
Base::Console().error("File type '%s' not supported\n", ext.toLatin1().constData());
|
|
}
|
|
}
|
|
PY_CATCH;
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sInsert(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
char* Name = nullptr;
|
|
char* DocName = nullptr;
|
|
if (!PyArg_ParseTuple(args, "et|s", "utf-8", &Name, &DocName)) {
|
|
return nullptr;
|
|
}
|
|
|
|
std::string Utf8Name = std::string(Name);
|
|
PyMem_Free(Name);
|
|
|
|
PY_TRY
|
|
{
|
|
QString fileName = QString::fromUtf8(Utf8Name.c_str());
|
|
FileHandler handler(fileName);
|
|
if (!handler.importFile(std::string(DocName ? DocName : ""))) {
|
|
QString ext = handler.extension();
|
|
Base::Console().error("File type '%s' not supported\n", ext.toLatin1().constData());
|
|
}
|
|
}
|
|
PY_CATCH;
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sExport(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
PyObject* object = nullptr;
|
|
char* Name = nullptr;
|
|
if (!PyArg_ParseTuple(args, "Oet", &object, "utf-8", &Name)) {
|
|
return nullptr;
|
|
}
|
|
|
|
std::string Utf8Name = std::string(Name);
|
|
PyMem_Free(Name);
|
|
|
|
PY_TRY
|
|
{
|
|
App::Document* doc = nullptr;
|
|
Py::Sequence list(object);
|
|
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
|
|
PyObject* item = (*it).ptr();
|
|
if (PyObject_TypeCheck(item, &(App::DocumentObjectPy::Type))) {
|
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast)
|
|
App::DocumentObject* obj
|
|
= static_cast<App::DocumentObjectPy*>(item)->getDocumentObjectPtr();
|
|
doc = obj->getDocument();
|
|
break;
|
|
}
|
|
}
|
|
|
|
QString fileName = QString::fromUtf8(Utf8Name.c_str());
|
|
QFileInfo fi;
|
|
fi.setFile(fileName);
|
|
QString ext = fi.suffix().toLower();
|
|
if (ext == QLatin1String("iv") || ext == QLatin1String("wrl") || ext == QLatin1String("vrml")
|
|
|| ext == QLatin1String("wrz") || ext == QLatin1String("x3d")
|
|
|| ext == QLatin1String("x3dz") || ext == QLatin1String("xhtml")) {
|
|
|
|
// build up the graph
|
|
auto sep = new SoSeparator();
|
|
sep->ref();
|
|
|
|
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
|
|
PyObject* item = (*it).ptr();
|
|
if (PyObject_TypeCheck(item, &(App::DocumentObjectPy::Type))) {
|
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast)
|
|
App::DocumentObject* obj
|
|
= static_cast<App::DocumentObjectPy*>(item)->getDocumentObjectPtr();
|
|
|
|
Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(obj);
|
|
if (vp) {
|
|
sep->addChild(vp->getRoot());
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
SoGetPrimitiveCountAction action;
|
|
action.setCanApproximate(true);
|
|
action.apply(sep);
|
|
|
|
constexpr const int triangleLimit = 100000;
|
|
constexpr const int pointLimit = 30000;
|
|
constexpr const int lineLimit = 10000;
|
|
|
|
bool binary = false;
|
|
if (action.getTriangleCount() > triangleLimit || action.getPointCount() > pointLimit
|
|
|| action.getLineCount() > lineLimit) {
|
|
binary = true;
|
|
}
|
|
|
|
SoFCDB::writeToFile(sep, Utf8Name.c_str(), binary);
|
|
sep->unref();
|
|
}
|
|
else if (ext == QLatin1String("pdf")) {
|
|
// get the view that belongs to the found document
|
|
Gui::Document* gui_doc = Application::Instance->getDocument(doc);
|
|
if (gui_doc) {
|
|
Gui::MDIView* view = gui_doc->getActiveView();
|
|
if (view) {
|
|
auto view3d = qobject_cast<View3DInventor*>(view);
|
|
if (view3d) {
|
|
view3d->viewAll();
|
|
}
|
|
QPrinter printer(QPrinter::ScreenResolution);
|
|
// setPdfVersion sets the printed PDF Version to what is chosen in
|
|
// Preferences/Import-Export/PDF more details under:
|
|
// https://www.kdab.com/creating-pdfa-documents-qt/
|
|
printer.setPdfVersion(Gui::Dialog::DlgSettingsPDF::evaluatePDFVersion());
|
|
printer.setOutputFormat(QPrinter::PdfFormat);
|
|
printer.setOutputFileName(fileName);
|
|
printer.setCreator(QString::fromStdString(App::Application::getNameWithVersion()));
|
|
view->print(&printer);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
Base::Console().error("File type '%s' not supported\n", ext.toLatin1().constData());
|
|
}
|
|
}
|
|
PY_CATCH;
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sSendActiveView(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
char* psCommandStr = nullptr;
|
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
|
|
PyObject* suppress = Py_False;
|
|
if (!PyArg_ParseTuple(args, "s|O!", &psCommandStr, &PyBool_Type, &suppress)) {
|
|
return nullptr;
|
|
}
|
|
|
|
const char* ppReturn = nullptr;
|
|
if (!Application::Instance->sendMsgToActiveView(psCommandStr, &ppReturn)) {
|
|
if (!Base::asBoolean(suppress)) {
|
|
Base::Console().warning("Unknown view command: %s\n", psCommandStr);
|
|
}
|
|
}
|
|
|
|
// Print the return value to the output
|
|
if (ppReturn) {
|
|
return Py_BuildValue("s", ppReturn);
|
|
}
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sSendFocusView(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
char* psCommandStr = nullptr;
|
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
|
|
PyObject* suppress = Py_False;
|
|
if (!PyArg_ParseTuple(args, "s|O!", &psCommandStr, &PyBool_Type, &suppress)) {
|
|
return nullptr;
|
|
}
|
|
|
|
const char* ppReturn = nullptr;
|
|
if (!Application::Instance->sendMsgToFocusView(psCommandStr, &ppReturn)) {
|
|
if (!Base::asBoolean(suppress)) {
|
|
Base::Console().warning("Unknown view command: %s\n", psCommandStr);
|
|
}
|
|
}
|
|
|
|
// Print the return value to the output
|
|
if (ppReturn) {
|
|
return Py_BuildValue("s", ppReturn);
|
|
}
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sGetMainWindow(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, "")) {
|
|
return nullptr;
|
|
}
|
|
|
|
try {
|
|
return Py::new_reference_to(MainWindowPy::createWrapper(Gui::getMainWindow()));
|
|
}
|
|
catch (const Py::Exception&) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
PyObject* ApplicationPy::sUpdateGui(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, "")) {
|
|
return nullptr;
|
|
}
|
|
|
|
qApp->processEvents();
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sUpdateLocale(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, "")) {
|
|
return nullptr;
|
|
}
|
|
|
|
Translator::instance()->refresh();
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sGetLocale(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, "")) {
|
|
return nullptr;
|
|
}
|
|
|
|
std::string locale = Translator::instance()->activeLanguage();
|
|
return PyUnicode_FromString(locale.c_str());
|
|
}
|
|
|
|
PyObject* ApplicationPy::sSetLocale(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
char* name = nullptr;
|
|
if (!PyArg_ParseTuple(args, "s", &name)) {
|
|
return nullptr;
|
|
}
|
|
|
|
std::string cname(name);
|
|
TStringMap map = Translator::instance()->supportedLocales();
|
|
map["English"] = "en";
|
|
for (const auto& it : map) {
|
|
if (it.first == cname || it.second == cname) {
|
|
Translator::instance()->activateLanguage(it.first.c_str());
|
|
break;
|
|
}
|
|
}
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sSupportedLocales(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, "")) {
|
|
return nullptr;
|
|
}
|
|
|
|
TStringMap map = Translator::instance()->supportedLocales();
|
|
Py::Dict dict;
|
|
dict.setItem(Py::String("English"), Py::String("en"));
|
|
for (const auto& it : map) {
|
|
Py::String key(it.first);
|
|
Py::String val(it.second);
|
|
dict.setItem(key, val);
|
|
}
|
|
return Py::new_reference_to(dict);
|
|
}
|
|
|
|
PyObject* ApplicationPy::sCreateDialog(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
char* fn = nullptr;
|
|
if (!PyArg_ParseTuple(args, "s", &fn)) {
|
|
return nullptr;
|
|
}
|
|
|
|
PyObject* pPyResource = nullptr;
|
|
try {
|
|
pPyResource = new PyResource();
|
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast)
|
|
static_cast<PyResource*>(pPyResource)->load(fn);
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
PyErr_SetString(PyExc_AssertionError, e.what());
|
|
return nullptr;
|
|
}
|
|
|
|
return pPyResource;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sAddPreferencePage(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
char* fn = nullptr;
|
|
char* grp = nullptr;
|
|
if (PyArg_ParseTuple(args, "ss", &fn, &grp)) {
|
|
QFileInfo fi(QString::fromUtf8(fn));
|
|
if (!fi.exists()) {
|
|
PyErr_SetString(PyExc_RuntimeError, "UI file does not exist");
|
|
return nullptr;
|
|
}
|
|
|
|
// add to the preferences dialog
|
|
new PrefPageUiProducer(fn, grp);
|
|
Py_Return;
|
|
}
|
|
|
|
PyErr_Clear();
|
|
PyObject* dlg = nullptr;
|
|
// new style classes
|
|
if (PyArg_ParseTuple(args, "O!s", &PyType_Type, &dlg, &grp)) {
|
|
// add to the preferences dialog
|
|
new PrefPagePyProducer(Py::Object(dlg), grp);
|
|
Py_Return;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sActivateWorkbenchHandler(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
char* psKey = nullptr;
|
|
if (!PyArg_ParseTuple(args, "s", &psKey)) {
|
|
return nullptr;
|
|
}
|
|
|
|
// search for workbench handler from the dictionary
|
|
PyObject* pcWorkbench = PyDict_GetItemString(Application::Instance->_pcWorkbenchDictionary, psKey);
|
|
if (!pcWorkbench) {
|
|
PyErr_Format(PyExc_KeyError, "No such workbench '%s'", psKey);
|
|
return nullptr;
|
|
}
|
|
|
|
try {
|
|
bool ok = Application::Instance->activateWorkbench(psKey);
|
|
return Py::new_reference_to(Py::Boolean(ok));
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
std::stringstream err;
|
|
err << psKey << ": " << e.what();
|
|
PyErr_SetString(e.getPyExceptionType(), err.str().c_str());
|
|
return nullptr;
|
|
}
|
|
catch (const XERCES_CPP_NAMESPACE::TranscodingException& e) {
|
|
std::stringstream err;
|
|
char* pMsg = XERCES_CPP_NAMESPACE::XMLString::transcode(e.getMessage());
|
|
err << "Transcoding exception in Xerces-c:\n\n"
|
|
<< "Transcoding exception raised in activateWorkbench.\n"
|
|
<< "Check if your user configuration file is valid.\n"
|
|
<< " Exception message:" << pMsg;
|
|
XERCES_CPP_NAMESPACE::XMLString::release(&pMsg);
|
|
PyErr_SetString(PyExc_RuntimeError, err.str().c_str());
|
|
return nullptr;
|
|
}
|
|
catch (...) {
|
|
std::stringstream err;
|
|
err << "Unknown C++ exception raised in activateWorkbench('" << psKey << "')";
|
|
PyErr_SetString(Base::PyExc_FC_GeneralError, err.str().c_str());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
PyObject* ApplicationPy::sAddWorkbenchHandler(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
PyObject* pcObject = nullptr;
|
|
if (!PyArg_ParseTuple(args, "O", &pcObject)) {
|
|
return nullptr;
|
|
}
|
|
|
|
try {
|
|
// get the class object 'Workbench' from the main module that is expected
|
|
// to be base class for all workbench classes
|
|
Py::Module module("__main__");
|
|
Py::Object baseclass(module.getAttr(std::string("Workbench")));
|
|
|
|
// check whether it is an instance or class object
|
|
Py::Object object(pcObject);
|
|
Py::String name;
|
|
|
|
if (PyObject_IsSubclass(object.ptr(), baseclass.ptr()) == 1) {
|
|
// create an instance of this class
|
|
name = object.getAttr(std::string("__name__"));
|
|
Py::Tuple arg;
|
|
Py::Callable creation(object);
|
|
object = creation.apply(arg);
|
|
}
|
|
else if (PyObject_IsInstance(object.ptr(), baseclass.ptr()) == 1) {
|
|
// extract the class name of the instance
|
|
PyErr_Clear(); // PyObject_IsSubclass set an exception
|
|
Py::Object classobj = object.getAttr(std::string("__class__"));
|
|
name = classobj.getAttr(std::string("__name__"));
|
|
}
|
|
else {
|
|
PyErr_SetString(
|
|
PyExc_TypeError,
|
|
"arg must be a subclass or an instance of "
|
|
"a subclass of 'Workbench'"
|
|
);
|
|
return nullptr;
|
|
}
|
|
|
|
// NOLINTBEGIN(bugprone-unused-raii)
|
|
// Search for some methods and members without invoking them
|
|
Py::Callable(object.getAttr(std::string("Initialize")));
|
|
Py::Callable(object.getAttr(std::string("GetClassName")));
|
|
// NOLINTEND(bugprone-unused-raii)
|
|
|
|
std::string item = name.as_std_string("ascii");
|
|
PyObject* wb
|
|
= PyDict_GetItemString(Application::Instance->_pcWorkbenchDictionary, item.c_str());
|
|
if (wb) {
|
|
PyErr_Format(PyExc_KeyError, "'%s' already exists.", item.c_str());
|
|
return nullptr;
|
|
}
|
|
|
|
PyDict_SetItemString(Application::Instance->_pcWorkbenchDictionary, item.c_str(), object.ptr());
|
|
Application::Instance->signalRefreshWorkbenches();
|
|
}
|
|
catch (const Py::Exception&) {
|
|
return nullptr;
|
|
}
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sRemoveWorkbenchHandler(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
char* psKey = nullptr;
|
|
if (!PyArg_ParseTuple(args, "s", &psKey)) {
|
|
return nullptr;
|
|
}
|
|
|
|
PyObject* wb = PyDict_GetItemString(Application::Instance->_pcWorkbenchDictionary, psKey);
|
|
if (!wb) {
|
|
PyErr_Format(PyExc_KeyError, "No such workbench '%s'", psKey);
|
|
return nullptr;
|
|
}
|
|
|
|
WorkbenchManager::instance()->removeWorkbench(psKey);
|
|
PyDict_DelItemString(Application::Instance->_pcWorkbenchDictionary, psKey);
|
|
Application::Instance->signalRefreshWorkbenches();
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sGetWorkbenchHandler(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
char* psKey = nullptr;
|
|
if (!PyArg_ParseTuple(args, "s", &psKey)) {
|
|
return nullptr;
|
|
}
|
|
|
|
// get the python workbench object from the dictionary
|
|
PyObject* pcWorkbench = PyDict_GetItemString(Application::Instance->_pcWorkbenchDictionary, psKey);
|
|
if (!pcWorkbench) {
|
|
PyErr_Format(PyExc_KeyError, "No such workbench '%s'", psKey);
|
|
return nullptr;
|
|
}
|
|
|
|
Py_INCREF(pcWorkbench);
|
|
return pcWorkbench;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sListWorkbenchHandlers(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, "")) {
|
|
return nullptr;
|
|
}
|
|
|
|
Py_INCREF(Application::Instance->_pcWorkbenchDictionary);
|
|
return Application::Instance->_pcWorkbenchDictionary;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sActiveWorkbenchHandler(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, "")) {
|
|
return nullptr;
|
|
}
|
|
|
|
Workbench* actWb = WorkbenchManager::instance()->active();
|
|
if (!actWb) {
|
|
PyErr_SetString(PyExc_AssertionError, "No active workbench\n");
|
|
return nullptr;
|
|
}
|
|
|
|
// get the python workbench object from the dictionary
|
|
std::string key = actWb->name();
|
|
PyObject* pcWorkbench
|
|
= PyDict_GetItemString(Application::Instance->_pcWorkbenchDictionary, key.c_str());
|
|
if (!pcWorkbench) {
|
|
PyErr_Format(PyExc_KeyError, "No such workbench '%s'", key.c_str());
|
|
return nullptr;
|
|
}
|
|
|
|
// object get incremented
|
|
Py_INCREF(pcWorkbench);
|
|
return pcWorkbench;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sAddResPath(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
char* filePath = nullptr;
|
|
if (!PyArg_ParseTuple(args, "et", "utf-8", &filePath)) {
|
|
return nullptr;
|
|
}
|
|
|
|
QString path = QString::fromUtf8(filePath);
|
|
PyMem_Free(filePath);
|
|
if (QDir::isRelativePath(path)) {
|
|
// Home path ends with '/'
|
|
QString home = QString::fromStdString(App::Application::getHomePath());
|
|
path = home + path;
|
|
}
|
|
|
|
BitmapFactory().addPath(path);
|
|
Translator::instance()->addPath(path);
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sAddLangPath(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
char* filePath = nullptr;
|
|
if (!PyArg_ParseTuple(args, "et", "utf-8", &filePath)) {
|
|
return nullptr;
|
|
}
|
|
|
|
QString path = QString::fromUtf8(filePath);
|
|
PyMem_Free(filePath);
|
|
if (QDir::isRelativePath(path)) {
|
|
// Home path ends with '/'
|
|
QString home = QString::fromStdString(App::Application::getHomePath());
|
|
path = home + path;
|
|
}
|
|
|
|
Translator::instance()->addPath(path);
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sAddIconPath(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
char* filePath = nullptr;
|
|
if (!PyArg_ParseTuple(args, "et", "utf-8", &filePath)) {
|
|
return nullptr;
|
|
}
|
|
|
|
QString path = QString::fromUtf8(filePath);
|
|
PyMem_Free(filePath);
|
|
if (QDir::isRelativePath(path)) {
|
|
// Home path ends with '/'
|
|
QString home = QString::fromStdString(App::Application::getHomePath());
|
|
path = home + path;
|
|
}
|
|
|
|
BitmapFactory().addPath(path);
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sAddIcon(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
const char* iconName = nullptr;
|
|
Py_buffer content;
|
|
const char* format = "XPM";
|
|
if (!PyArg_ParseTuple(args, "ss*|s", &iconName, &content, &format)) {
|
|
return nullptr;
|
|
}
|
|
|
|
QPixmap icon;
|
|
if (BitmapFactory().findPixmapInCache(iconName, icon)) {
|
|
PyErr_SetString(PyExc_AssertionError, "Icon with this name already registered");
|
|
PyBuffer_Release(&content);
|
|
return nullptr;
|
|
}
|
|
|
|
const char* contentStr = static_cast<const char*>(content.buf);
|
|
QByteArray ary(contentStr, static_cast<int>(content.len));
|
|
icon.loadFromData(ary, format);
|
|
|
|
if (icon.isNull()) {
|
|
QString file = QString::fromUtf8(contentStr, static_cast<int>(content.len));
|
|
icon.load(file);
|
|
}
|
|
|
|
PyBuffer_Release(&content);
|
|
|
|
if (icon.isNull()) {
|
|
PyErr_SetString(Base::PyExc_FC_GeneralError, "Invalid icon added to application");
|
|
return nullptr;
|
|
}
|
|
|
|
BitmapFactory().addPixmapToCache(iconName, icon);
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sGetIcon(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
char* iconName = nullptr;
|
|
if (!PyArg_ParseTuple(args, "s", &iconName)) {
|
|
return nullptr;
|
|
}
|
|
|
|
PythonWrapper wrap;
|
|
wrap.loadGuiModule();
|
|
wrap.loadWidgetsModule();
|
|
auto pixmap = BitmapFactory().pixmap(iconName);
|
|
if (!pixmap.isNull()) {
|
|
return Py::new_reference_to(wrap.fromQIcon(new QIcon(pixmap)));
|
|
}
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sIsIconCached(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
char* iconName = nullptr;
|
|
if (!PyArg_ParseTuple(args, "s", &iconName)) {
|
|
return nullptr;
|
|
}
|
|
|
|
QPixmap icon;
|
|
|
|
return Py::new_reference_to(Py::Boolean(BitmapFactory().findPixmapInCache(iconName, icon)));
|
|
}
|
|
|
|
PyObject* ApplicationPy::sAddCommand(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
char* pName = nullptr;
|
|
char* pSource = nullptr;
|
|
PyObject* pcCmdObj = nullptr;
|
|
if (!PyArg_ParseTuple(args, "sO|s", &pName, &pcCmdObj, &pSource)) {
|
|
return nullptr;
|
|
}
|
|
|
|
// get the call stack to find the Python module name
|
|
//
|
|
std::string module;
|
|
std::string group;
|
|
try {
|
|
Base::PyGILStateLocker lock;
|
|
|
|
// Get the filename of the running code by using the low-level sys._getframe() method.
|
|
// We use this instead of the `inspect` module (which may actually cause imports to execute
|
|
// and can result in a circular import if sAddCommand is being called as part of an import
|
|
// statement itself), and the `traceback` module (which cannot access the filename of code
|
|
// that is being run through the C interface).
|
|
|
|
Py::Module sysMod(PyImport_ImportModule("sys"), /*owned=*/true);
|
|
Py::Callable getFrame(sysMod.getAttr("_getframe"));
|
|
|
|
Py::Object callerFrame;
|
|
Py::Tuple getFrameArgs(1);
|
|
getFrameArgs[0] = Py::Long(0);
|
|
callerFrame = getFrame.apply(getFrameArgs);
|
|
|
|
Py::Object codeObj(callerFrame.getAttr("f_code"));
|
|
|
|
Py::Object filenameObj(codeObj.getAttr("co_filename"));
|
|
std::string filename(Py::String(filenameObj).as_std_string());
|
|
|
|
Base::FileInfo fi(filename);
|
|
// convert backslashes to slashes
|
|
filename = fi.filePath();
|
|
module = fi.fileNamePure();
|
|
// for the group name get the directory name after 'Mod'
|
|
boost::regex rx("/Mod/(\\w+)/");
|
|
boost::smatch what;
|
|
if (boost::regex_search(filename, what, rx)) {
|
|
group = what[1];
|
|
}
|
|
else {
|
|
rx = "/Ext/freecad/(\\w+)/";
|
|
if (boost::regex_search(filename, what, rx)) {
|
|
group = what[1];
|
|
}
|
|
else {
|
|
group = module;
|
|
}
|
|
}
|
|
}
|
|
catch (Py::Exception& e) {
|
|
e.clear();
|
|
}
|
|
try {
|
|
Base::PyGILStateLocker lock;
|
|
|
|
Py::Object cmd(pcCmdObj);
|
|
if (cmd.hasAttr("GetCommands")) {
|
|
Command* cmd = new PythonGroupCommand(pName, pcCmdObj);
|
|
if (!module.empty()) {
|
|
cmd->setAppModuleName(module.c_str());
|
|
}
|
|
if (!group.empty()) {
|
|
cmd->setGroupName(group.c_str());
|
|
}
|
|
Application::Instance->commandManager().addCommand(cmd);
|
|
}
|
|
else {
|
|
Command* cmd = new PythonCommand(pName, pcCmdObj, pSource);
|
|
if (!module.empty()) {
|
|
cmd->setAppModuleName(module.c_str());
|
|
}
|
|
if (!group.empty()) {
|
|
cmd->setGroupName(group.c_str());
|
|
}
|
|
Application::Instance->commandManager().addCommand(cmd);
|
|
}
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
e.setPyException();
|
|
return nullptr;
|
|
}
|
|
catch (...) {
|
|
PyErr_SetString(
|
|
Base::PyExc_FC_GeneralError,
|
|
"Unknown C++ exception raised in ApplicationPy::sAddCommand()"
|
|
);
|
|
return nullptr;
|
|
}
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sRunCommand(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
char* pName = nullptr;
|
|
int item = 0;
|
|
if (!PyArg_ParseTuple(args, "s|i", &pName, &item)) {
|
|
return nullptr;
|
|
}
|
|
|
|
Gui::Command::LogDisabler d1;
|
|
Gui::SelectionLogDisabler d2;
|
|
|
|
Command* cmd = Application::Instance->commandManager().getCommandByName(pName);
|
|
if (cmd) {
|
|
cmd->invoke(item);
|
|
Py_Return;
|
|
}
|
|
|
|
PyErr_Format(Base::PyExc_FC_GeneralError, "No such command '%s'", pName);
|
|
return nullptr;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sDoCommand(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
char* sCmd = nullptr;
|
|
if (!PyArg_ParseTuple(args, "s", &sCmd)) {
|
|
return nullptr;
|
|
}
|
|
|
|
Gui::Command::LogDisabler d1;
|
|
Gui::SelectionLogDisabler d2;
|
|
|
|
Gui::Command::printPyCaller();
|
|
Gui::Application::Instance->macroManager()->addLine(MacroManager::App, sCmd);
|
|
|
|
PyObject* module = nullptr;
|
|
PyObject* dict = nullptr;
|
|
|
|
Base::PyGILStateLocker locker;
|
|
module = PyImport_AddModule("__main__");
|
|
if (!module) {
|
|
return nullptr;
|
|
}
|
|
|
|
dict = PyModule_GetDict(module);
|
|
if (!dict) {
|
|
return nullptr;
|
|
}
|
|
|
|
return PyRun_String(sCmd, Py_file_input, dict, dict);
|
|
}
|
|
|
|
PyObject* ApplicationPy::sDoCommandGui(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
char* sCmd = nullptr;
|
|
if (!PyArg_ParseTuple(args, "s", &sCmd)) {
|
|
return nullptr;
|
|
}
|
|
|
|
Gui::Command::LogDisabler d1;
|
|
Gui::SelectionLogDisabler d2;
|
|
|
|
Gui::Command::printPyCaller();
|
|
Gui::Application::Instance->macroManager()->addLine(MacroManager::Gui, sCmd);
|
|
|
|
PyObject* module = nullptr;
|
|
PyObject* dict = nullptr;
|
|
|
|
Base::PyGILStateLocker locker;
|
|
module = PyImport_AddModule("__main__");
|
|
if (!module) {
|
|
return nullptr;
|
|
}
|
|
|
|
dict = PyModule_GetDict(module);
|
|
if (!dict) {
|
|
return nullptr;
|
|
}
|
|
|
|
return PyRun_String(sCmd, Py_file_input, dict, dict);
|
|
}
|
|
|
|
PyObject* ApplicationPy::sDoCommandEval(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
char* sCmd = nullptr;
|
|
if (!PyArg_ParseTuple(args, "s", &sCmd)) {
|
|
return nullptr;
|
|
}
|
|
|
|
Gui::Command::LogDisabler d1;
|
|
Gui::SelectionLogDisabler d2;
|
|
|
|
PyObject* module = nullptr;
|
|
PyObject* dict = nullptr;
|
|
|
|
Base::PyGILStateLocker locker;
|
|
module = PyImport_AddModule("__main__");
|
|
if (!module) {
|
|
return nullptr;
|
|
}
|
|
|
|
dict = PyModule_GetDict(module);
|
|
if (!dict) {
|
|
return nullptr;
|
|
}
|
|
|
|
return PyRun_String(sCmd, Py_eval_input, dict, dict);
|
|
}
|
|
|
|
PyObject* ApplicationPy::sDoCommandSkip(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
char* sCmd = nullptr;
|
|
if (!PyArg_ParseTuple(args, "s", &sCmd)) {
|
|
return nullptr;
|
|
}
|
|
|
|
Gui::Command::LogDisabler d1;
|
|
Gui::SelectionLogDisabler d2;
|
|
|
|
Gui::Command::printPyCaller();
|
|
Gui::Application::Instance->macroManager()->addLine(MacroManager::App, sCmd);
|
|
return Py::None().ptr();
|
|
}
|
|
|
|
PyObject* ApplicationPy::sAddModule(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
char* pstr = nullptr;
|
|
if (!PyArg_ParseTuple(args, "s", &pstr)) {
|
|
return nullptr;
|
|
}
|
|
|
|
try {
|
|
Command::addModule(Command::Doc, pstr);
|
|
Py_Return;
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
PyErr_SetString(PyExc_ImportError, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
PyObject* ApplicationPy::sShowDownloads(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, "")) {
|
|
return nullptr;
|
|
}
|
|
|
|
Gui::Dialog::DownloadManager::getInstance();
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sShowPreferences(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
char* pstr = nullptr;
|
|
int idx = 0;
|
|
if (!PyArg_ParseTuple(args, "|si", &pstr, &idx)) {
|
|
return nullptr;
|
|
}
|
|
|
|
Gui::Dialog::DlgPreferencesImp cDlg(getMainWindow());
|
|
if (pstr) {
|
|
cDlg.activateGroupPage(QString::fromUtf8(pstr), idx);
|
|
}
|
|
|
|
WaitCursor wc;
|
|
wc.restoreCursor();
|
|
cDlg.exec();
|
|
wc.setWaitCursor();
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sShowPreferencesByName(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
char* pstr = nullptr;
|
|
const char* prefType = "";
|
|
if (!PyArg_ParseTuple(args, "s|s", &pstr, &prefType)) {
|
|
return nullptr;
|
|
}
|
|
|
|
Gui::Dialog::DlgPreferencesImp cDlg(getMainWindow());
|
|
if (pstr && prefType) {
|
|
cDlg.activateGroupPageByPageName(QString::fromUtf8(pstr), QString::fromUtf8(prefType));
|
|
}
|
|
|
|
WaitCursor wc;
|
|
wc.restoreCursor();
|
|
cDlg.exec();
|
|
wc.setWaitCursor();
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sCreateViewer(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
int num_of_views = 1;
|
|
char* title = nullptr;
|
|
// if one argument (int) is given
|
|
if (!PyArg_ParseTuple(args, "|is", &num_of_views, &title)) {
|
|
return nullptr;
|
|
}
|
|
|
|
if (num_of_views <= 0) {
|
|
PyErr_Format(PyExc_ValueError, "views must be > 0");
|
|
return nullptr;
|
|
}
|
|
if (num_of_views == 1) {
|
|
auto viewer = new View3DInventor(nullptr, nullptr);
|
|
if (title) {
|
|
viewer->setWindowTitle(QString::fromUtf8(title));
|
|
}
|
|
Gui::getMainWindow()->addWindow(viewer);
|
|
return viewer->getPyObject();
|
|
}
|
|
else {
|
|
auto viewer = new SplitView3DInventor(num_of_views, nullptr, nullptr);
|
|
if (title) {
|
|
viewer->setWindowTitle(QString::fromUtf8(title));
|
|
}
|
|
Gui::getMainWindow()->addWindow(viewer);
|
|
return viewer->getPyObject();
|
|
}
|
|
}
|
|
|
|
PyObject* ApplicationPy::sGetMarkerIndex(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
constexpr const int defaultSize = 9;
|
|
char* pstr {};
|
|
int defSize = defaultSize;
|
|
if (!PyArg_ParseTuple(args, "s|i", &pstr, &defSize)) {
|
|
return nullptr;
|
|
}
|
|
|
|
PY_TRY
|
|
{
|
|
ParameterGrp::handle const hGrp = App::GetApplication().GetParameterGroupByPath(
|
|
"User parameter:BaseApp/Preferences/View"
|
|
);
|
|
|
|
// find the appropriate marker style string token
|
|
std::string marker_arg = pstr;
|
|
|
|
std::list<std::pair<std::string, std::string>> markerList = {
|
|
{"square", "DIAMOND_FILLED"},
|
|
{"cross", "CROSS"},
|
|
{"hourglass", "HOURGLASS_FILLED"},
|
|
{"plus", "PLUS"},
|
|
{"empty", "SQUARE_LINE"},
|
|
{"quad", "SQUARE_FILLED"},
|
|
{"circle", "CIRCLE_LINE"},
|
|
{"default", "CIRCLE_FILLED"}
|
|
};
|
|
|
|
auto findIt = std::find_if(markerList.begin(), markerList.end(), [&marker_arg](const auto& it) {
|
|
return marker_arg == it.first || marker_arg == it.second;
|
|
});
|
|
|
|
marker_arg = (findIt != markerList.end() ? findIt->second : "CIRCLE_FILLED");
|
|
|
|
|
|
// get the marker size
|
|
auto sizeList = Gui::Inventor::MarkerBitmaps::getSupportedSizes(marker_arg);
|
|
|
|
if (std::ranges::find(sizeList, defSize) == std::end(sizeList)) {
|
|
defSize = defaultSize;
|
|
}
|
|
|
|
return Py_BuildValue("i", Gui::Inventor::MarkerBitmaps::getMarkerIndex(marker_arg, defSize));
|
|
}
|
|
PY_CATCH;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sReload(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
const char* name = nullptr;
|
|
if (!PyArg_ParseTuple(args, "s", &name)) {
|
|
return nullptr;
|
|
}
|
|
|
|
PY_TRY
|
|
{
|
|
auto doc = Application::Instance->reopen(App::GetApplication().getDocument(name));
|
|
if (doc) {
|
|
return doc->getPyObject();
|
|
}
|
|
Py_Return;
|
|
}
|
|
PY_CATCH;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sLoadFile(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
const char* path = "";
|
|
const char* mod = "";
|
|
if (!PyArg_ParseTuple(args, "s|s", &path, &mod)) {
|
|
return nullptr;
|
|
}
|
|
|
|
PY_TRY
|
|
{
|
|
Base::FileInfo fi(path);
|
|
if (!fi.isFile() || !fi.exists()) {
|
|
PyErr_Format(PyExc_IOError, "File %s doesn't exist.", path);
|
|
return nullptr;
|
|
}
|
|
|
|
std::string module = mod;
|
|
if (module.empty()) {
|
|
std::string ext = fi.extension();
|
|
std::vector<std::string> modules = App::GetApplication().getImportModules(ext.c_str());
|
|
if (modules.empty()) {
|
|
PyErr_Format(PyExc_IOError, "Filetype %s is not supported.", ext.c_str());
|
|
return nullptr;
|
|
}
|
|
|
|
module = modules.front();
|
|
}
|
|
|
|
Application::Instance->open(path, module.c_str());
|
|
|
|
Py_Return;
|
|
}
|
|
PY_CATCH
|
|
}
|
|
|
|
PyObject* ApplicationPy::sAddDocObserver(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
PyObject* o = nullptr;
|
|
if (!PyArg_ParseTuple(args, "O", &o)) {
|
|
return nullptr;
|
|
}
|
|
|
|
PY_TRY
|
|
{
|
|
DocumentObserverPython::addObserver(Py::Object(o));
|
|
Py_Return;
|
|
}
|
|
PY_CATCH;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sRemoveDocObserver(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
PyObject* o = nullptr;
|
|
if (!PyArg_ParseTuple(args, "O", &o)) {
|
|
return nullptr;
|
|
}
|
|
|
|
PY_TRY
|
|
{
|
|
DocumentObserverPython::removeObserver(Py::Object(o));
|
|
Py_Return;
|
|
}
|
|
PY_CATCH;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sAddWbManipulator(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
PyObject* o = nullptr;
|
|
if (!PyArg_ParseTuple(args, "O", &o)) {
|
|
return nullptr;
|
|
}
|
|
|
|
PY_TRY
|
|
{
|
|
WorkbenchManipulatorPython::installManipulator(Py::Object(o));
|
|
Py_Return;
|
|
}
|
|
PY_CATCH;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sRemoveWbManipulator(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
PyObject* o = nullptr;
|
|
if (!PyArg_ParseTuple(args, "O", &o)) {
|
|
return nullptr;
|
|
}
|
|
|
|
PY_TRY
|
|
{
|
|
WorkbenchManipulatorPython::removeManipulator(Py::Object(o));
|
|
Py_Return;
|
|
}
|
|
PY_CATCH;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sCoinRemoveAllChildren(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
PyObject* pynode = nullptr;
|
|
if (!PyArg_ParseTuple(args, "O", &pynode)) {
|
|
return nullptr;
|
|
}
|
|
|
|
PY_TRY
|
|
{
|
|
void* ptr = nullptr;
|
|
Base::Interpreter().convertSWIGPointerObj("pivy.coin", "_p_SoGroup", pynode, &ptr, 0);
|
|
if (!ptr) {
|
|
PyErr_SetString(PyExc_RuntimeError, "Conversion of coin.SoGroup failed");
|
|
return nullptr;
|
|
}
|
|
|
|
coinRemoveAllChildren(static_cast<SoGroup*>(ptr));
|
|
Py_Return;
|
|
}
|
|
PY_CATCH;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sListUserEditModes(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
Py::List ret;
|
|
if (!PyArg_ParseTuple(args, "")) {
|
|
return nullptr;
|
|
}
|
|
|
|
for (auto const& uem : Application::Instance->listUserEditModes()) {
|
|
ret.append(Py::String(uem.second.first));
|
|
}
|
|
|
|
return Py::new_reference_to(ret);
|
|
}
|
|
|
|
PyObject* ApplicationPy::sGetUserEditMode(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, "")) {
|
|
return nullptr;
|
|
}
|
|
|
|
return Py::new_reference_to(Py::String(Application::Instance->getUserEditModeUIStrings().first));
|
|
}
|
|
|
|
PyObject* ApplicationPy::sSetUserEditMode(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
const char* mode = "";
|
|
if (!PyArg_ParseTuple(args, "s", &mode)) {
|
|
return nullptr;
|
|
}
|
|
|
|
bool ok = Application::Instance->setUserEditMode(std::string(mode));
|
|
|
|
return Py::new_reference_to(Py::Boolean(ok));
|
|
}
|
|
|
|
PyObject* ApplicationPy::sSuspendWaitCursor(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, "")) {
|
|
return nullptr;
|
|
}
|
|
|
|
WaitCursor::suspend();
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sResumeWaitCursor(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, "")) {
|
|
return nullptr;
|
|
}
|
|
|
|
WaitCursor::resume();
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
// Origin management methods
|
|
|
|
PyObject* ApplicationPy::sAddOrigin(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
PyObject* o = nullptr;
|
|
if (!PyArg_ParseTuple(args, "O", &o)) {
|
|
return nullptr;
|
|
}
|
|
|
|
PY_TRY
|
|
{
|
|
FileOriginPython::addOrigin(Py::Object(o));
|
|
Py_Return;
|
|
}
|
|
PY_CATCH;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sRemoveOrigin(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
PyObject* o = nullptr;
|
|
if (!PyArg_ParseTuple(args, "O", &o)) {
|
|
return nullptr;
|
|
}
|
|
|
|
PY_TRY
|
|
{
|
|
FileOriginPython::removeOrigin(Py::Object(o));
|
|
Py_Return;
|
|
}
|
|
PY_CATCH;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sGetOrigin(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
const char* originId = nullptr;
|
|
if (!PyArg_ParseTuple(args, "s", &originId)) {
|
|
return nullptr;
|
|
}
|
|
|
|
PY_TRY
|
|
{
|
|
FileOrigin* origin = OriginManager::instance()->getOrigin(originId);
|
|
if (!origin) {
|
|
Py_Return; // Return None if not found
|
|
}
|
|
|
|
// Return origin info as a dictionary
|
|
Py::Dict result;
|
|
result.setItem("id", Py::String(origin->id()));
|
|
result.setItem("name", Py::String(origin->name()));
|
|
result.setItem("nickname", Py::String(origin->nickname()));
|
|
result.setItem("type", Py::Long(static_cast<int>(origin->type())));
|
|
result.setItem("tracksExternally", Py::Boolean(origin->tracksExternally()));
|
|
result.setItem("requiresAuthentication", Py::Boolean(origin->requiresAuthentication()));
|
|
result.setItem("supportsRevisions", Py::Boolean(origin->supportsRevisions()));
|
|
result.setItem("supportsBOM", Py::Boolean(origin->supportsBOM()));
|
|
result.setItem("supportsPartNumbers", Py::Boolean(origin->supportsPartNumbers()));
|
|
result.setItem("connectionState", Py::Long(static_cast<int>(origin->connectionState())));
|
|
|
|
return Py::new_reference_to(result);
|
|
}
|
|
PY_CATCH;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sListOrigins(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, "")) {
|
|
return nullptr;
|
|
}
|
|
|
|
PY_TRY
|
|
{
|
|
Py::List result;
|
|
for (const auto& id : OriginManager::instance()->originIds()) {
|
|
result.append(Py::String(id));
|
|
}
|
|
return Py::new_reference_to(result);
|
|
}
|
|
PY_CATCH;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sActiveOrigin(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, "")) {
|
|
return nullptr;
|
|
}
|
|
|
|
PY_TRY
|
|
{
|
|
FileOrigin* origin = OriginManager::instance()->currentOrigin();
|
|
if (!origin) {
|
|
Py_Return;
|
|
}
|
|
|
|
// Return origin info as a dictionary
|
|
Py::Dict result;
|
|
result.setItem("id", Py::String(origin->id()));
|
|
result.setItem("name", Py::String(origin->name()));
|
|
result.setItem("nickname", Py::String(origin->nickname()));
|
|
result.setItem("type", Py::Long(static_cast<int>(origin->type())));
|
|
result.setItem("tracksExternally", Py::Boolean(origin->tracksExternally()));
|
|
result.setItem("requiresAuthentication", Py::Boolean(origin->requiresAuthentication()));
|
|
result.setItem("supportsRevisions", Py::Boolean(origin->supportsRevisions()));
|
|
result.setItem("supportsBOM", Py::Boolean(origin->supportsBOM()));
|
|
result.setItem("supportsPartNumbers", Py::Boolean(origin->supportsPartNumbers()));
|
|
result.setItem("connectionState", Py::Long(static_cast<int>(origin->connectionState())));
|
|
|
|
return Py::new_reference_to(result);
|
|
}
|
|
PY_CATCH;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sSetActiveOrigin(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
const char* originId = nullptr;
|
|
if (!PyArg_ParseTuple(args, "s", &originId)) {
|
|
return nullptr;
|
|
}
|
|
|
|
PY_TRY
|
|
{
|
|
bool success = OriginManager::instance()->setCurrentOrigin(originId);
|
|
return Py::new_reference_to(Py::Boolean(success));
|
|
}
|
|
PY_CATCH;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Editing Context Python API
|
|
// ---------------------------------------------------------------------------
|
|
|
|
static QStringList pyListToQStringList(PyObject* listObj)
|
|
{
|
|
QStringList result;
|
|
if (!listObj || !PyList_Check(listObj)) {
|
|
return result;
|
|
}
|
|
Py_ssize_t size = PyList_Size(listObj);
|
|
for (Py_ssize_t i = 0; i < size; ++i) {
|
|
PyObject* item = PyList_GetItem(listObj, i);
|
|
if (PyUnicode_Check(item)) {
|
|
result << QString::fromUtf8(PyUnicode_AsUTF8(item));
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static PyObject* qStringListToPyList(const QStringList& list)
|
|
{
|
|
Py::List pyList;
|
|
for (const auto& s : list) {
|
|
pyList.append(Py::String(s.toUtf8().constData()));
|
|
}
|
|
return Py::new_reference_to(pyList);
|
|
}
|
|
|
|
PyObject* ApplicationPy::sRegisterEditingContext(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
const char* id = nullptr;
|
|
const char* label = nullptr;
|
|
const char* color = nullptr;
|
|
PyObject* toolbarsList = nullptr;
|
|
PyObject* matchCallable = nullptr;
|
|
int priority = 50;
|
|
|
|
if (!PyArg_ParseTuple(args, "sssOO|i", &id, &label, &color, &toolbarsList, &matchCallable, &priority)) {
|
|
return nullptr;
|
|
}
|
|
|
|
if (!PyCallable_Check(matchCallable)) {
|
|
PyErr_SetString(PyExc_TypeError, "match must be callable");
|
|
return nullptr;
|
|
}
|
|
|
|
QStringList toolbars = pyListToQStringList(toolbarsList);
|
|
|
|
// Hold a reference to the Python callable
|
|
Py::Callable pyMatch(matchCallable);
|
|
pyMatch.increment_reference_count();
|
|
|
|
ContextDefinition def;
|
|
def.id = QString::fromUtf8(id);
|
|
def.labelTemplate = QString::fromUtf8(label);
|
|
def.color = QString::fromUtf8(color);
|
|
def.toolbars = toolbars;
|
|
def.priority = priority;
|
|
def.match = [pyMatch]() -> bool {
|
|
Base::PyGILStateLocker lock;
|
|
try {
|
|
Py::Callable fn(pyMatch);
|
|
Py::Object result = fn.apply(Py::TupleN());
|
|
return result.isTrue();
|
|
}
|
|
catch (Py::Exception&) {
|
|
Base::PyException e;
|
|
e.reportException();
|
|
return false;
|
|
}
|
|
};
|
|
|
|
EditingContextResolver::instance()->registerContext(def);
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sUnregisterEditingContext(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
const char* id = nullptr;
|
|
if (!PyArg_ParseTuple(args, "s", &id)) {
|
|
return nullptr;
|
|
}
|
|
EditingContextResolver::instance()->unregisterContext(QString::fromUtf8(id));
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sRegisterEditingOverlay(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
const char* id = nullptr;
|
|
PyObject* toolbarsList = nullptr;
|
|
PyObject* matchCallable = nullptr;
|
|
|
|
if (!PyArg_ParseTuple(args, "sOO", &id, &toolbarsList, &matchCallable)) {
|
|
return nullptr;
|
|
}
|
|
|
|
if (!PyCallable_Check(matchCallable)) {
|
|
PyErr_SetString(PyExc_TypeError, "match must be callable");
|
|
return nullptr;
|
|
}
|
|
|
|
QStringList toolbars = pyListToQStringList(toolbarsList);
|
|
|
|
Py::Callable pyMatch(matchCallable);
|
|
pyMatch.increment_reference_count();
|
|
|
|
OverlayDefinition def;
|
|
def.id = QString::fromUtf8(id);
|
|
def.toolbars = toolbars;
|
|
def.match = [pyMatch]() -> bool {
|
|
Base::PyGILStateLocker lock;
|
|
try {
|
|
Py::Callable fn(pyMatch);
|
|
Py::Object result = fn.apply(Py::TupleN());
|
|
return result.isTrue();
|
|
}
|
|
catch (Py::Exception&) {
|
|
Base::PyException e;
|
|
e.reportException();
|
|
return false;
|
|
}
|
|
};
|
|
|
|
EditingContextResolver::instance()->registerOverlay(def);
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sUnregisterEditingOverlay(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
const char* id = nullptr;
|
|
if (!PyArg_ParseTuple(args, "s", &id)) {
|
|
return nullptr;
|
|
}
|
|
EditingContextResolver::instance()->unregisterOverlay(QString::fromUtf8(id));
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sInjectEditingCommands(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
const char* contextId = nullptr;
|
|
const char* toolbarName = nullptr;
|
|
PyObject* commandsList = nullptr;
|
|
|
|
if (!PyArg_ParseTuple(args, "ssO", &contextId, &toolbarName, &commandsList)) {
|
|
return nullptr;
|
|
}
|
|
|
|
QStringList commands = pyListToQStringList(commandsList);
|
|
EditingContextResolver::instance()
|
|
->injectCommands(QString::fromUtf8(contextId), QString::fromUtf8(toolbarName), commands);
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* ApplicationPy::sCurrentEditingContext(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, "")) {
|
|
return nullptr;
|
|
}
|
|
|
|
EditingContext ctx = EditingContextResolver::instance()->currentContext();
|
|
|
|
Py::Dict result;
|
|
result.setItem("id", Py::String(ctx.id.toUtf8().constData()));
|
|
result.setItem("label", Py::String(ctx.label.toUtf8().constData()));
|
|
result.setItem("color", Py::String(ctx.color.toUtf8().constData()));
|
|
result.setItem("toolbars", Py::Object(qStringListToPyList(ctx.toolbars), true));
|
|
result.setItem("breadcrumb", Py::Object(qStringListToPyList(ctx.breadcrumb), true));
|
|
result.setItem("breadcrumbColors", Py::Object(qStringListToPyList(ctx.breadcrumbColors), true));
|
|
|
|
return Py::new_reference_to(result);
|
|
}
|
|
|
|
PyObject* ApplicationPy::sRefreshEditingContext(PyObject* /*self*/, PyObject* args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, "")) {
|
|
return nullptr;
|
|
}
|
|
EditingContextResolver::instance()->refresh();
|
|
Py_Return;
|
|
}
|