1
/***************************************************************************
2
* Copyright (c) 2005 Werner Mayer <wmayer[at]users.sourceforge.net> *
4
* This file is part of the FreeCAD CAx development system. *
6
* This library is free software; you can redistribute it and/or *
7
* modify it under the terms of the GNU Library General Public *
8
* License as published by the Free Software Foundation; either *
9
* version 2 of the License, or (at your option) any later version. *
11
* This library is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU Library General Public License for more details. *
16
* You should have received a copy of the GNU Library General Public *
17
* License along with this library; see the file COPYING.LIB. If not, *
18
* write to the Free Software Foundation, Inc., 59 Temple Place, *
19
* Suite 330, Boston, MA 02111-1307, USA *
21
***************************************************************************/
23
#include "PreCompiled.h"
26
# include <QApplication>
30
# include <Inventor/SoInput.h>
31
# include <Inventor/actions/SoGetPrimitiveCountAction.h>
32
# include <Inventor/nodes/SoSeparator.h>
33
# include <xercesc/util/TranscodingException.hpp>
34
# include <xercesc/util/XMLString.hpp>
37
#include <boost/regex.hpp>
39
#include <App/DocumentObjectPy.h>
40
#include <App/DocumentPy.h>
41
#include <App/PropertyFile.h>
42
#include <Base/Interpreter.h>
43
#include <Base/Console.h>
44
#include <Base/PyWrapParseTupleAndKeywords.h>
45
#include <CXX/Objects.hxx>
47
#include "Application.h"
48
#include "BitmapFactory.h"
50
#include "DlgPreferencesImp.h"
52
#include "DocumentObserverPython.h"
53
#include "DownloadManager.h"
54
#include "EditorView.h"
55
#include "FileHandler.h"
57
#include "MainWindow.h"
58
#include "MainWindowPy.h"
59
#include "PythonEditor.h"
60
#include "PythonWrapper.h"
62
#include "SplitView3DInventor.h"
63
#include "View3DInventor.h"
64
#include "ViewProvider.h"
65
#include "WaitCursor.h"
66
#include "WidgetFactory.h"
68
#include "WorkbenchManager.h"
69
#include "WorkbenchManipulatorPython.h"
70
#include "Inventor/MarkerBitmaps.h"
71
#include "Language/Translator.h"
76
// Application methods structure
77
PyMethodDef Application::Methods[] = {
78
{"activateWorkbench",(PyCFunction) Application::sActivateWorkbenchHandler, METH_VARARGS,
79
"activateWorkbench(name) -> bool\n"
81
"Activate workbench by its name. Return False if the workbench is\n"
84
"name : str\n Name of the workbench to activate."},
85
{"addWorkbench", (PyCFunction) Application::sAddWorkbenchHandler, METH_VARARGS,
86
"addWorkbench(workbench) -> None\n"
90
"workbench : Workbench, Workbench type\n"
91
" Instance of a Workbench subclass or subclass of the\n"
93
{"removeWorkbench", (PyCFunction) Application::sRemoveWorkbenchHandler, METH_VARARGS,
94
"removeWorkbench(name) -> None\n"
96
"Remove a workbench.\n"
98
"name : str\n Name of the workbench to remove."},
99
{"getWorkbench", (PyCFunction) Application::sGetWorkbenchHandler, METH_VARARGS,
100
"getWorkbench(name) -> Workbench\n"
102
"Get the workbench by its name.\n"
104
"name : str\n Name of the workbench to return."},
105
{"listWorkbenches", (PyCFunction) Application::sListWorkbenchHandlers, METH_VARARGS,
106
"listWorkbenches() -> dict\n"
108
"Get a dictionary with all workbenches."},
109
{"activeWorkbench", (PyCFunction) Application::sActiveWorkbenchHandler, METH_VARARGS,
110
"activeWorkbench() -> Workbench\n"
112
"Return the active workbench object."},
113
{"addResourcePath", (PyCFunction) Application::sAddResPath, METH_VARARGS,
114
"addResourcePath(path) -> None\n"
116
"Add a new path to the system where to find resource files\n"
117
"like icons or localization files.\n"
119
"path : str, bytes, bytearray\n Path to resource files."},
120
{"addLanguagePath", (PyCFunction) Application::sAddLangPath, METH_VARARGS,
121
"addLanguagePath(path) -> None\n"
123
"Add a new path to the system where to find language files.\n"
125
"path : str, bytes, bytearray\n Path to language files."},
126
{"addIconPath", (PyCFunction) Application::sAddIconPath, METH_VARARGS,
127
"addIconPath(path) -> None\n"
129
"Add a new path to the system where to find icon files.\n"
131
"path : str, bytes, bytearray\n Path to icon files."},
132
{"addIcon", (PyCFunction) Application::sAddIcon, METH_VARARGS,
133
"addIcon(name, content, format='XPM') -> None\n"
135
"Add an icon to the system.\n"
137
"name : str\n Name of the icon.\n"
138
"content : str, bytes-like\n Content of the icon.\n"
139
"format : str\n Format of the icon."},
140
{"getIcon", (PyCFunction) Application::sGetIcon, METH_VARARGS,
141
"getIcon(name) -> QIcon or None\n"
143
"Get an icon in the system. If the pixmap is null, return None.\n"
145
"name : str\n Name of the icon."},
146
{"isIconCached", (PyCFunction) Application::sIsIconCached, METH_VARARGS,
147
"isIconCached(name) -> Bool\n"
149
"Check if an icon with the given name is cached.\n"
151
"name : str\n Name of the icon."},
152
{"getMainWindow", (PyCFunction) Application::sGetMainWindow, METH_VARARGS,
153
"getMainWindow() -> QMainWindow\n"
155
"Return the main window instance."},
156
{"updateGui", (PyCFunction) Application::sUpdateGui, METH_VARARGS,
157
"updateGui() -> None\n"
159
"Update the main window and all its windows."},
160
{"updateLocale", (PyCFunction) Application::sUpdateLocale, METH_VARARGS,
161
"updateLocale() -> None\n"
163
"Update the localization."},
164
{"getLocale", (PyCFunction) Application::sGetLocale, METH_VARARGS,
165
"getLocale() -> str\n"
167
"Returns the locale currently used by FreeCAD."},
168
{"setLocale", (PyCFunction) Application::sSetLocale, METH_VARARGS,
169
"setLocale(name) -> None\n"
171
"Sets the locale used by FreeCAD. Can be set by top-level\n"
172
"domain (e.g. \"de\") or the language name (e.g. \"German\").\n"
174
"name : str\n Locale name."},
175
{"supportedLocales", (PyCFunction) Application::sSupportedLocales, METH_VARARGS,
176
"supportedLocales() -> dict\n"
178
"Returns a dict of all supported locales. The keys are the language\n"
179
"names and the values the top-level domains."},
180
{"createDialog", (PyCFunction) Application::sCreateDialog, METH_VARARGS,
181
"createDialog(path) -> PyResource\n"
185
"path : str\n UI file path."},
186
{"addPreferencePage", (PyCFunction) Application::sAddPreferencePage, METH_VARARGS,
187
"addPreferencePage(path, group) -> None\n"
188
"addPreferencePage(dialog, group) -> None\n"
190
"Add a UI form to the preferences dialog in the specified group.\n"
192
"path : str\n UI file path.\n"
193
"group : str\n Group name.\n"
194
"dialog : type\n Preference page."},
195
{"addCommand", (PyCFunction) Application::sAddCommand, METH_VARARGS,
196
"addCommand(name, cmd, activation) -> None\n"
198
"Add a command object.\n"
200
"name : str\n Name of the command.\n"
201
"cmd : object\n Command instance.\n"
202
"activation : str\n Activation sequence. Optional."},
203
{"runCommand", (PyCFunction) Application::sRunCommand, METH_VARARGS,
204
"runCommand(name, index=0) -> None\n"
206
"Run command by its name.\n"
208
"name : str\n Name of the command.\n"
209
"index : int\n Index of the child command."},
210
{"SendMsgToActiveView", (PyCFunction) Application::sSendActiveView, METH_VARARGS,
211
"SendMsgToActiveView(name, suppress=False) -> str or None\n"
213
"Send message to the active view. Deprecated, use class View.\n"
215
"name : str\n Name of the view command.\n"
216
"suppress : bool\n If the sent message fail, suppress warning message."},
217
{"sendMsgToFocusView", (PyCFunction) Application::sSendFocusView, METH_VARARGS,
218
"sendMsgToFocusView(name, suppress=False) -> str or None\n"
220
"Send message to the focused view.\n"
222
"name : str\n Name of the view command.\n"
223
"suppress : bool\n If send message fail, suppress warning message."},
224
{"hide", (PyCFunction) Application::sHide, METH_VARARGS,
225
"hide(name) -> None\n"
227
"Hide the given feature. Deprecated.\n"
229
"name : str\n Feature name."},
230
{"show", (PyCFunction) Application::sShow, METH_VARARGS,
231
"show(name) -> None\n"
233
"Show the given feature. Deprecated.\n"
235
"name : str\n Feature name."},
236
{"hideObject", (PyCFunction) Application::sHideObject, METH_VARARGS,
237
"hideObject(obj) -> None\n"
239
"Hide the view provider of the given object.\n"
241
"obj : App.DocumentObject"},
242
{"showObject", (PyCFunction) Application::sShowObject, METH_VARARGS,
243
"showObject(obj) -> None\n"
245
"Show the view provider of the given object.\n"
247
"obj : App.DocumentObject"},
248
{"open", (PyCFunction) Application::sOpen, METH_VARARGS,
249
"open(fileName) -> None\n"
251
"Open a macro, Inventor or VRML file.\n"
253
"fileName : str, bytes, bytearray\n File name."},
254
{"insert", (PyCFunction) Application::sInsert, METH_VARARGS,
255
"insert(fileName, docName) -> None\n"
257
"Insert a macro, Inventor or VRML file. If no document name\n"
258
"is given the active document is used.\n"
260
"fileName : str, bytes, bytearray\n File name.\n"
261
"docName : str\n Document name."},
262
{"export", (PyCFunction) Application::sExport, METH_VARARGS,
263
"export(objs, fileName) -> None\n"
265
"Save scene to Inventor or VRML file.\n"
267
"objs : sequence of App.DocumentObject\n Sequence of objects to save.\n"
268
"fileName : str, bytes, bytearray\n File name."},
269
{"activeDocument", (PyCFunction) Application::sActiveDocument, METH_VARARGS,
270
"activeDocument() -> Gui.Document or None\n"
272
"Return the active document. If no one exists, return None."},
273
{"setActiveDocument", (PyCFunction) Application::sSetActiveDocument, METH_VARARGS,
274
"setActiveDocument(doc) -> None\n"
276
"Activate the specified document.\n"
278
"doc : str, App.Document\n Document to activate."},
279
{"activeView", (PyCFunction)Application::sActiveView, METH_VARARGS,
280
"activeView(typeName) -> object or None\n"
282
"Return the active view of the active document. If no one\n"
283
"exists, return None.\n"
285
"typeName : str\n Type name."},
286
{"activateView", (PyCFunction)Application::sActivateView, METH_VARARGS,
287
"activateView(typeName, create=False) -> None\n"
289
"Activate a view of the given type in the active document.\n"
290
"If a view of this type doesn't exist and create is True, a\n"
291
"new view of this type is created.\n"
293
"type : str\n Type name.\n"
295
{"editDocument", (PyCFunction)Application::sEditDocument, METH_VARARGS,
296
"editDocument() -> Gui.Document or None\n"
298
"Return the current editing document. If no one exists,\n"
300
{"getDocument", (PyCFunction) Application::sGetDocument, METH_VARARGS,
301
"getDocument(doc) -> Gui.Document\n"
305
"doc : str, App.Document\n `App.Document` name or `App.Document` object."},
306
{"doCommand", (PyCFunction) Application::sDoCommand, METH_VARARGS,
307
"doCommand(cmd) -> None\n"
309
"Prints the given string in the python console and runs it.\n"
312
{"doCommandGui", (PyCFunction) Application::sDoCommandGui, METH_VARARGS,
313
"doCommandGui(cmd) -> None\n"
315
"Prints the given string in the python console and runs it\n"
316
"but doesn't record it in macros.\n"
319
{"addModule", (PyCFunction) Application::sAddModule, METH_VARARGS,
320
"addModule(mod) -> None\n"
322
"Prints the given module import only once in the macro recording.\n"
325
{"showDownloads", (PyCFunction) Application::sShowDownloads, METH_VARARGS,
326
"showDownloads() -> None\n\n"
327
"Show the downloads manager window."},
328
{"showPreferences", (PyCFunction) Application::sShowPreferences, METH_VARARGS,
329
"showPreferences(grp, index=0) -> None\n"
331
"Show the preferences window.\n"
333
"grp: str\n Group to show.\n"
334
"index : int\n Page index."},
335
{"createViewer", (PyCFunction) Application::sCreateViewer, METH_VARARGS,
336
"createViewer(views=1, name) -> View3DInventorPy or AbstractSplitViewPy\n"
338
"Show and returns a viewer.\n"
340
"views : int\n If > 1 a `AbstractSplitViewPy` object is returned.\n"
341
"name : str\n Viewer title."},
342
{"getMarkerIndex", (PyCFunction) Application::sGetMarkerIndex, METH_VARARGS,
343
"getMarkerIndex(marker, size=9) -> int\n"
345
"Get marker index according to marker name and size.\n"
347
"marker : str\n Marker style name.\n"
348
"size : int\n Marker size."},
349
{"addDocumentObserver", (PyCFunction) Application::sAddDocObserver, METH_VARARGS,
350
"addDocumentObserver(obj) -> None\n"
352
"Add an observer to get notifications about changes on documents.\n"
355
{"removeDocumentObserver", (PyCFunction) Application::sRemoveDocObserver, METH_VARARGS,
356
"removeDocumentObserver(obj) -> None\n"
358
"Remove an added document observer.\n"
361
{"addWorkbenchManipulator", (PyCFunction) Application::sAddWbManipulator, METH_VARARGS,
362
"addWorkbenchManipulator(obj) -> None\n"
364
"Add a workbench manipulator to modify a workbench when it is activated.\n"
367
{"removeWorkbenchManipulator", (PyCFunction) Application::sRemoveWbManipulator, METH_VARARGS,
368
"removeWorkbenchManipulator(obj) -> None\n"
370
"Remove an added workbench manipulator.\n"
373
{"listUserEditModes", (PyCFunction) Application::sListUserEditModes, METH_VARARGS,
374
"listUserEditModes() -> list\n"
376
"List available user edit modes."},
377
{"getUserEditMode", (PyCFunction) Application::sGetUserEditMode, METH_VARARGS,
378
"getUserEditMode() -> str\n"
380
"Get current user edit mode."},
381
{"setUserEditMode", (PyCFunction) Application::sSetUserEditMode, METH_VARARGS,
382
"setUserEditMode(mode) -> bool\n"
384
"Set user edit mode. Returns True if exists, False otherwise.\n"
387
{"reload", (PyCFunction) Application::sReload, METH_VARARGS,
388
"reload(name) -> App.Document or None\n"
390
"Reload a partial opened document. If the document is not open,\n"
393
"name : str\n `App.Document` name."},
394
{"loadFile", (PyCFunction) Application::sLoadFile, METH_VARARGS,
395
"loadFile(fileName, module) -> None\n"
397
"Loads an arbitrary file by delegating to the given Python module.\n"
398
"If no module is given it will be determined by the file extension.\n"
399
"If more than one module can load a file the first one will be taken.\n"
400
"If no module exists to load the file an exception will be raised.\n"
404
{"coinRemoveAllChildren", (PyCFunction) Application::sCoinRemoveAllChildren, METH_VARARGS,
405
"coinRemoveAllChildren(node) -> None\n"
407
"Remove all children from a group node.\n"
410
{nullptr, nullptr, 0, nullptr} /* Sentinel */
413
PyObject* Gui::Application::sEditDocument(PyObject * /*self*/, PyObject *args)
415
if (!PyArg_ParseTuple(args, ""))
418
Document *pcDoc = Instance->editDocument();
420
return pcDoc->getPyObject();
425
PyObject* Gui::Application::sActiveDocument(PyObject * /*self*/, PyObject *args)
427
if (!PyArg_ParseTuple(args, ""))
430
Document *pcDoc = Instance->activeDocument();
432
return pcDoc->getPyObject();
437
PyObject* Gui::Application::sActiveView(PyObject * /*self*/, PyObject *args)
439
const char *typeName = nullptr;
440
if (!PyArg_ParseTuple(args, "|s", &typeName))
446
type = Base::Type::fromName(typeName);
448
PyErr_Format(PyExc_TypeError, "Invalid type '%s'", typeName);
453
Gui::MDIView* mdiView = Instance->activeView();
454
if (mdiView && (type.isBad() || mdiView->isDerivedFrom(type))) {
455
auto res = Py::asObject(mdiView->getPyObject());
456
if(!res.isNone() || !type.isBad())
457
return Py::new_reference_to(res);
461
type = Gui::View3DInventor::getClassTypeId();
462
Instance->activateView(type, true);
463
mdiView = Instance->activeView();
465
return mdiView->getPyObject();
473
PyObject* Gui::Application::sActivateView(PyObject * /*self*/, PyObject *args)
476
PyObject *create = Py_False;
477
if (!PyArg_ParseTuple(args, "sO!", &typeStr, &PyBool_Type, &create))
480
Base::Type type = Base::Type::fromName(typeStr);
481
Instance->activateView(type, Base::asBoolean(create));
486
PyObject* Gui::Application::sSetActiveDocument(PyObject * /*self*/, PyObject *args)
488
Document *pcDoc = nullptr;
491
char *pstr = nullptr;
492
if (PyArg_ParseTuple(args, "s", &pstr)) {
493
pcDoc = Instance->getDocument(pstr);
495
PyErr_Format(PyExc_NameError, "Unknown document '%s'", pstr);
503
if (PyArg_ParseTuple(args, "O!", &(App::DocumentPy::Type), &doc)) {
504
pcDoc = Instance->getDocument(static_cast<App::DocumentPy*>(doc)->getDocumentPtr());
506
PyErr_Format(PyExc_KeyError, "Unknown document instance");
515
PyErr_SetString(PyExc_TypeError, "Either string or App.Document expected");
519
if (Instance->activeDocument() != pcDoc) {
520
Gui::MDIView* view = pcDoc->getActiveView();
521
getMainWindow()->setActiveWindow(view);
527
PyObject* Application::sGetDocument(PyObject * /*self*/, PyObject *args)
529
char *pstr = nullptr;
530
if (PyArg_ParseTuple(args, "s", &pstr)) {
531
Document *pcDoc = Instance->getDocument(pstr);
533
PyErr_Format(PyExc_NameError, "Unknown document '%s'", pstr);
536
return pcDoc->getPyObject();
541
if (PyArg_ParseTuple(args, "O!", &(App::DocumentPy::Type), &doc)) {
542
Document *pcDoc = Instance->getDocument(static_cast<App::DocumentPy*>(doc)->getDocumentPtr());
544
PyErr_Format(PyExc_KeyError, "Unknown document instance");
547
return pcDoc->getPyObject();
550
PyErr_SetString(PyExc_TypeError, "Either string or App.Document expected");
554
PyObject* Application::sHide(PyObject * /*self*/, PyObject *args)
557
if (!PyArg_ParseTuple(args, "s;Name of the object to hide has to be given!",&psFeatStr))
560
Document *pcDoc = Instance->activeDocument();
563
pcDoc->setHide(psFeatStr);
568
PyObject* Application::sShow(PyObject * /*self*/, PyObject *args)
571
if (!PyArg_ParseTuple(args, "s;Name of the object to show has to be given!",&psFeatStr))
574
Document *pcDoc = Instance->activeDocument();
577
pcDoc->setShow(psFeatStr);
582
PyObject* Application::sHideObject(PyObject * /*self*/, PyObject *args)
585
if (!PyArg_ParseTuple(args, "O!",&(App::DocumentObjectPy::Type),&object))
588
App::DocumentObject* obj = static_cast<App::DocumentObjectPy*>(object)->getDocumentObjectPtr();
589
Instance->hideViewProvider(obj);
594
PyObject* Application::sShowObject(PyObject * /*self*/, PyObject *args)
597
if (!PyArg_ParseTuple(args, "O!",&(App::DocumentObjectPy::Type),&object))
600
App::DocumentObject* obj = static_cast<App::DocumentObjectPy*>(object)->getDocumentObjectPtr();
601
Instance->showViewProvider(obj);
606
PyObject* Application::sOpen(PyObject * /*self*/, PyObject *args)
608
// only used to open Python files
610
if (!PyArg_ParseTuple(args, "et","utf-8",&Name))
613
std::string Utf8Name = std::string(Name);
616
QString fileName = QString::fromUtf8(Utf8Name.c_str());
617
FileHandler handler(fileName);
618
if (!handler.openFile()) {
619
QString ext = handler.extension();
620
Base::Console().Error("File type '%s' not supported\n", ext.toLatin1().constData());
628
PyObject* Application::sInsert(PyObject * /*self*/, PyObject *args)
631
char* DocName = nullptr;
632
if (!PyArg_ParseTuple(args, "et|s","utf-8",&Name,&DocName))
635
std::string Utf8Name = std::string(Name);
639
QString fileName = QString::fromUtf8(Utf8Name.c_str());
640
FileHandler handler(fileName);
641
if (!handler.importFile(std::string(DocName ? DocName : ""))) {
642
QString ext = handler.extension();
643
Base::Console().Error("File type '%s' not supported\n", ext.toLatin1().constData());
650
PyObject* Application::sExport(PyObject * /*self*/, PyObject *args)
654
if (!PyArg_ParseTuple(args, "Oet",&object,"utf-8",&Name))
657
std::string Utf8Name = std::string(Name);
661
App::Document* doc = nullptr;
662
Py::Sequence list(object);
663
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
664
PyObject* item = (*it).ptr();
665
if (PyObject_TypeCheck(item, &(App::DocumentObjectPy::Type))) {
666
App::DocumentObject* obj = static_cast<App::DocumentObjectPy*>(item)->getDocumentObjectPtr();
667
doc = obj->getDocument();
672
QString fileName = QString::fromUtf8(Utf8Name.c_str());
674
fi.setFile(fileName);
675
QString ext = fi.suffix().toLower();
676
if (ext == QLatin1String("iv") ||
677
ext == QLatin1String("wrl") ||
678
ext == QLatin1String("vrml") ||
679
ext == QLatin1String("wrz") ||
680
ext == QLatin1String("x3d") ||
681
ext == QLatin1String("x3dz") ||
682
ext == QLatin1String("xhtml")) {
684
// build up the graph
685
auto sep = new SoSeparator();
688
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
689
PyObject* item = (*it).ptr();
690
if (PyObject_TypeCheck(item, &(App::DocumentObjectPy::Type))) {
691
App::DocumentObject* obj = static_cast<App::DocumentObjectPy*>(item)->getDocumentObjectPtr();
693
Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(obj);
695
sep->addChild(vp->getRoot());
701
SoGetPrimitiveCountAction action;
702
action.setCanApproximate(true);
706
if (action.getTriangleCount() > 100000 ||
707
action.getPointCount() > 30000 ||
708
action.getLineCount() > 10000)
711
SoFCDB::writeToFile(sep, Utf8Name.c_str(), binary);
714
else if (ext == QLatin1String("pdf")) {
715
// get the view that belongs to the found document
716
Gui::Document* gui_doc = Application::Instance->getDocument(doc);
718
Gui::MDIView* view = gui_doc->getActiveView();
720
auto view3d = qobject_cast<View3DInventor*>(view);
723
QPrinter printer(QPrinter::ScreenResolution);
724
// setPdfVersion sets the printied PDF Version to comply with PDF/A-1b, more details under: https://www.kdab.com/creating-pdfa-documents-qt/
725
printer.setPdfVersion(QPagedPaintDevice::PdfVersion_A1b);
726
printer.setOutputFormat(QPrinter::PdfFormat);
727
printer.setOutputFileName(fileName);
728
view->print(&printer);
733
Base::Console().Error("File type '%s' not supported\n", ext.toLatin1().constData());
740
PyObject* Application::sSendActiveView(PyObject * /*self*/, PyObject *args)
743
PyObject *suppress=Py_False;
744
if (!PyArg_ParseTuple(args, "s|O!",&psCommandStr,&PyBool_Type,&suppress))
747
const char* ppReturn = nullptr;
748
if (!Instance->sendMsgToActiveView(psCommandStr,&ppReturn)) {
749
if (!Base::asBoolean(suppress))
750
Base::Console().Warning("Unknown view command: %s\n",psCommandStr);
753
// Print the return value to the output
755
return Py_BuildValue("s",ppReturn);
761
PyObject* Application::sSendFocusView(PyObject * /*self*/, PyObject *args)
764
PyObject *suppress=Py_False;
765
if (!PyArg_ParseTuple(args, "s|O!",&psCommandStr,&PyBool_Type,&suppress))
768
const char* ppReturn = nullptr;
769
if (!Instance->sendMsgToFocusView(psCommandStr,&ppReturn)) {
770
if (!Base::asBoolean(suppress))
771
Base::Console().Warning("Unknown view command: %s\n",psCommandStr);
774
// Print the return value to the output
776
return Py_BuildValue("s",ppReturn);
782
PyObject* Application::sGetMainWindow(PyObject * /*self*/, PyObject *args)
784
if (!PyArg_ParseTuple(args, ""))
788
return Py::new_reference_to(MainWindowPy::createWrapper(Gui::getMainWindow()));
790
catch (const Py::Exception&) {
795
PyObject* Application::sUpdateGui(PyObject * /*self*/, PyObject *args)
797
if (!PyArg_ParseTuple(args, ""))
800
qApp->processEvents();
805
PyObject* Application::sUpdateLocale(PyObject * /*self*/, PyObject *args)
807
if (!PyArg_ParseTuple(args, ""))
810
Translator::instance()->refresh();
815
PyObject* Application::sGetLocale(PyObject * /*self*/, PyObject *args)
817
if (!PyArg_ParseTuple(args, ""))
820
std::string locale = Translator::instance()->activeLanguage();
821
return PyUnicode_FromString(locale.c_str());
824
PyObject* Application::sSetLocale(PyObject * /*self*/, PyObject *args)
827
if (!PyArg_ParseTuple(args, "s", &name))
830
std::string cname(name);
831
TStringMap map = Translator::instance()->supportedLocales();
832
map["English"] = "en";
833
for (const auto& it : map) {
834
if (it.first == cname || it.second == cname) {
835
Translator::instance()->activateLanguage(it.first.c_str());
843
PyObject* Application::sSupportedLocales(PyObject * /*self*/, PyObject *args)
845
if (!PyArg_ParseTuple(args, ""))
848
TStringMap map = Translator::instance()->supportedLocales();
850
dict.setItem(Py::String("English"), Py::String("en"));
851
for (const auto& it : map) {
852
Py::String key(it.first);
853
Py::String val(it.second);
854
dict.setItem(key, val);
856
return Py::new_reference_to(dict);
859
PyObject* Application::sCreateDialog(PyObject * /*self*/, PyObject *args)
862
if (!PyArg_ParseTuple(args, "s", &fn))
865
PyObject* pPyResource = nullptr;
867
pPyResource = new PyResource();
868
static_cast<PyResource*>(pPyResource)->load(fn);
870
catch (const Base::Exception& e) {
871
PyErr_SetString(PyExc_AssertionError, e.what());
878
PyObject* Application::sAddPreferencePage(PyObject * /*self*/, PyObject *args)
881
if (PyArg_ParseTuple(args, "ss", &fn,&grp)) {
882
QFileInfo fi(QString::fromUtf8(fn));
884
PyErr_SetString(PyExc_RuntimeError, "UI file does not exist");
888
// add to the preferences dialog
889
new PrefPageUiProducer(fn, grp);
896
if (PyArg_ParseTuple(args, "O!s", &PyType_Type, &dlg, &grp)) {
897
// add to the preferences dialog
898
new PrefPagePyProducer(Py::Object(dlg), grp);
905
PyObject* Application::sActivateWorkbenchHandler(PyObject * /*self*/, PyObject *args)
908
if (!PyArg_ParseTuple(args, "s", &psKey))
911
// search for workbench handler from the dictionary
912
PyObject* pcWorkbench = PyDict_GetItemString(Instance->_pcWorkbenchDictionary, psKey);
914
PyErr_Format(PyExc_KeyError, "No such workbench '%s'", psKey);
919
bool ok = Instance->activateWorkbench(psKey);
920
return Py::new_reference_to(Py::Boolean(ok));
922
catch (const Base::Exception& e) {
923
std::stringstream err;
924
err << psKey << ": " << e.what();
925
PyErr_SetString(e.getPyExceptionType(), err.str().c_str());
928
catch (const XERCES_CPP_NAMESPACE_QUALIFIER TranscodingException& e) {
929
std::stringstream err;
930
char *pMsg = XERCES_CPP_NAMESPACE_QUALIFIER XMLString::transcode(e.getMessage());
931
err << "Transcoding exception in Xerces-c:\n\n"
932
<< "Transcoding exception raised in activateWorkbench.\n"
933
<< "Check if your user configuration file is valid.\n"
934
<< " Exception message:"
936
XERCES_CPP_NAMESPACE_QUALIFIER XMLString::release(&pMsg);
937
PyErr_SetString(PyExc_RuntimeError, err.str().c_str());
941
std::stringstream err;
942
err << "Unknown C++ exception raised in activateWorkbench('" << psKey << "')";
943
PyErr_SetString(Base::PyExc_FC_GeneralError, err.str().c_str());
948
PyObject* Application::sAddWorkbenchHandler(PyObject * /*self*/, PyObject *args)
951
if (!PyArg_ParseTuple(args, "O", &pcObject))
955
// get the class object 'Workbench' from the main module that is expected
956
// to be base class for all workbench classes
957
Py::Module module("__main__");
958
Py::Object baseclass(module.getAttr(std::string("Workbench")));
960
// check whether it is an instance or class object
961
Py::Object object(pcObject);
964
if (PyObject_IsSubclass(object.ptr(), baseclass.ptr()) == 1) {
965
// create an instance of this class
966
name = object.getAttr(std::string("__name__"));
968
Py::Callable creation(object);
969
object = creation.apply(arg);
971
else if (PyObject_IsInstance(object.ptr(), baseclass.ptr()) == 1) {
972
// extract the class name of the instance
973
PyErr_Clear(); // PyObject_IsSubclass set an exception
974
Py::Object classobj = object.getAttr(std::string("__class__"));
975
name = classobj.getAttr(std::string("__name__"));
978
PyErr_SetString(PyExc_TypeError, "arg must be a subclass or an instance of "
979
"a subclass of 'Workbench'");
983
// Search for some methods and members without invoking them
984
Py::Callable(object.getAttr(std::string("Initialize")));
985
Py::Callable(object.getAttr(std::string("GetClassName")));
986
std::string item = name.as_std_string("ascii");
988
PyObject* wb = PyDict_GetItemString(Instance->_pcWorkbenchDictionary,item.c_str());
990
PyErr_Format(PyExc_KeyError, "'%s' already exists.", item.c_str());
994
PyDict_SetItemString(Instance->_pcWorkbenchDictionary,item.c_str(),object.ptr());
995
Instance->signalRefreshWorkbenches();
997
catch (const Py::Exception&) {
1004
PyObject* Application::sRemoveWorkbenchHandler(PyObject * /*self*/, PyObject *args)
1007
if (!PyArg_ParseTuple(args, "s", &psKey))
1010
PyObject* wb = PyDict_GetItemString(Instance->_pcWorkbenchDictionary,psKey);
1012
PyErr_Format(PyExc_KeyError, "No such workbench '%s'", psKey);
1016
WorkbenchManager::instance()->removeWorkbench(psKey);
1017
PyDict_DelItemString(Instance->_pcWorkbenchDictionary,psKey);
1018
Instance->signalRefreshWorkbenches();
1023
PyObject* Application::sGetWorkbenchHandler(PyObject * /*self*/, PyObject *args)
1026
if (!PyArg_ParseTuple(args, "s", &psKey))
1029
// get the python workbench object from the dictionary
1030
PyObject* pcWorkbench = PyDict_GetItemString(Instance->_pcWorkbenchDictionary, psKey);
1032
PyErr_Format(PyExc_KeyError, "No such workbench '%s'", psKey);
1036
Py_INCREF(pcWorkbench);
1040
PyObject* Application::sListWorkbenchHandlers(PyObject * /*self*/, PyObject *args)
1042
if (!PyArg_ParseTuple(args, ""))
1045
Py_INCREF(Instance->_pcWorkbenchDictionary);
1046
return Instance->_pcWorkbenchDictionary;
1049
PyObject* Application::sActiveWorkbenchHandler(PyObject * /*self*/, PyObject *args)
1051
if (!PyArg_ParseTuple(args, ""))
1054
Workbench* actWb = WorkbenchManager::instance()->active();
1056
PyErr_SetString(PyExc_AssertionError, "No active workbench\n");
1060
// get the python workbench object from the dictionary
1061
std::string key = actWb->name();
1062
PyObject* pcWorkbench = PyDict_GetItemString(Instance->_pcWorkbenchDictionary, key.c_str());
1064
PyErr_Format(PyExc_KeyError, "No such workbench '%s'", key.c_str());
1068
// object get incremented
1069
Py_INCREF(pcWorkbench);
1073
PyObject* Application::sAddResPath(PyObject * /*self*/, PyObject *args)
1076
if (!PyArg_ParseTuple(args, "et", "utf-8", &filePath))
1079
QString path = QString::fromUtf8(filePath);
1080
PyMem_Free(filePath);
1081
if (QDir::isRelativePath(path)) {
1082
// Home path ends with '/'
1083
QString home = QString::fromStdString(App::Application::getHomePath());
1087
BitmapFactory().addPath(path);
1088
Translator::instance()->addPath(path);
1093
PyObject* Application::sAddLangPath(PyObject * /*self*/, PyObject *args)
1096
if (!PyArg_ParseTuple(args, "et", "utf-8", &filePath))
1099
QString path = QString::fromUtf8(filePath);
1100
PyMem_Free(filePath);
1101
if (QDir::isRelativePath(path)) {
1102
// Home path ends with '/'
1103
QString home = QString::fromStdString(App::Application::getHomePath());
1107
Translator::instance()->addPath(path);
1112
PyObject* Application::sAddIconPath(PyObject * /*self*/, PyObject *args)
1115
if (!PyArg_ParseTuple(args, "et", "utf-8", &filePath))
1118
QString path = QString::fromUtf8(filePath);
1119
PyMem_Free(filePath);
1120
if (QDir::isRelativePath(path)) {
1121
// Home path ends with '/'
1122
QString home = QString::fromStdString(App::Application::getHomePath());
1126
BitmapFactory().addPath(path);
1131
PyObject* Application::sAddIcon(PyObject * /*self*/, PyObject *args)
1133
const char *iconName;
1135
const char *format = "XPM";
1136
if (!PyArg_ParseTuple(args, "ss*|s", &iconName, &content, &format))
1140
if (BitmapFactory().findPixmapInCache(iconName, icon)) {
1141
PyErr_SetString(PyExc_AssertionError, "Icon with this name already registered");
1142
PyBuffer_Release(&content);
1146
const char* contentStr = static_cast<const char*>(content.buf);
1147
QByteArray ary(contentStr, content.len);
1148
icon.loadFromData(ary, format);
1151
QString file = QString::fromUtf8(contentStr, content.len);
1155
PyBuffer_Release(&content);
1157
if (icon.isNull()) {
1158
PyErr_SetString(Base::PyExc_FC_GeneralError, "Invalid icon added to application");
1162
BitmapFactory().addPixmapToCache(iconName, icon);
1167
PyObject* Application::sGetIcon(PyObject * /*self*/, PyObject *args)
1170
if (!PyArg_ParseTuple(args, "s", &iconName))
1174
wrap.loadGuiModule();
1175
wrap.loadWidgetsModule();
1176
auto pixmap = BitmapFactory().pixmap(iconName);
1177
if(!pixmap.isNull())
1178
return Py::new_reference_to(wrap.fromQIcon(new QIcon(pixmap)));
1183
PyObject* Application::sIsIconCached(PyObject * /*self*/, PyObject *args)
1186
if (!PyArg_ParseTuple(args, "s", &iconName))
1191
return Py::new_reference_to(Py::Boolean(BitmapFactory().findPixmapInCache(iconName, icon)));
1194
PyObject* Application::sAddCommand(PyObject * /*self*/, PyObject *args)
1197
char* pSource = nullptr;
1199
if (!PyArg_ParseTuple(args, "sO|s", &pName,&pcCmdObj,&pSource))
1202
// get the call stack to find the Python module name
1204
std::string module, group;
1206
Base::PyGILStateLocker lock;
1207
Py::Module mod(PyImport_ImportModule("inspect"), true);
1209
PyErr_SetString(PyExc_ImportError, "Cannot load inspect module");
1212
Py::Callable inspect(mod.getAttr("stack"));
1213
Py::List list(inspect.apply());
1216
// usually this is the file name of the calling script
1217
Py::Object info = list.getItem(0);
1218
PyObject *pyfile = PyStructSequence_GET_ITEM(*info,1);
1220
throw Py::Exception();
1222
file = Py::Object(pyfile).as_string();
1223
Base::FileInfo fi(file);
1224
// convert backslashes to slashes
1225
file = fi.filePath();
1226
module = fi.fileNamePure();
1228
// for the group name get the directory name after 'Mod'
1229
boost::regex rx("/Mod/(\\w+)/");
1231
if (boost::regex_search(file, what, rx)) {
1235
boost::regex rx("/Ext/freecad/(\\w+)/");
1236
if (boost::regex_search(file, what, rx))
1242
catch (Py::Exception& e) {
1246
Base::PyGILStateLocker lock;
1248
Py::Object cmd(pcCmdObj);
1249
if (cmd.hasAttr("GetCommands")) {
1250
Command* cmd = new PythonGroupCommand(pName, pcCmdObj);
1251
if (!module.empty()) {
1252
cmd->setAppModuleName(module.c_str());
1254
if (!group.empty()) {
1255
cmd->setGroupName(group.c_str());
1257
Application::Instance->commandManager().addCommand(cmd);
1260
Command* cmd = new PythonCommand(pName, pcCmdObj, pSource);
1261
if (!module.empty()) {
1262
cmd->setAppModuleName(module.c_str());
1264
if (!group.empty()) {
1265
cmd->setGroupName(group.c_str());
1267
Application::Instance->commandManager().addCommand(cmd);
1270
catch (const Base::Exception& e) {
1275
PyErr_SetString(Base::PyExc_FC_GeneralError, "Unknown C++ exception raised in Application::sAddCommand()");
1282
PyObject* Application::sRunCommand(PyObject * /*self*/, PyObject *args)
1286
if (!PyArg_ParseTuple(args, "s|i", &pName, &item))
1289
Gui::Command::LogDisabler d1;
1290
Gui::SelectionLogDisabler d2;
1292
Command* cmd = Application::Instance->commandManager().getCommandByName(pName);
1298
PyErr_Format(Base::PyExc_FC_GeneralError, "No such command '%s'", pName);
1303
PyObject* Application::sDoCommand(PyObject * /*self*/, PyObject *args)
1305
char *sCmd = nullptr;
1306
if (!PyArg_ParseTuple(args, "s", &sCmd))
1309
Gui::Command::LogDisabler d1;
1310
Gui::SelectionLogDisabler d2;
1312
Gui::Command::printPyCaller();
1313
Gui::Application::Instance->macroManager()->addLine(MacroManager::App, sCmd);
1315
PyObject *module, *dict;
1317
Base::PyGILStateLocker locker;
1318
module = PyImport_AddModule("__main__");
1322
dict = PyModule_GetDict(module);
1326
return PyRun_String(sCmd, Py_file_input, dict, dict);
1329
PyObject* Application::sDoCommandGui(PyObject * /*self*/, PyObject *args)
1331
char *sCmd = nullptr;
1332
if (!PyArg_ParseTuple(args, "s", &sCmd))
1335
Gui::Command::LogDisabler d1;
1336
Gui::SelectionLogDisabler d2;
1338
Gui::Command::printPyCaller();
1339
Gui::Application::Instance->macroManager()->addLine(MacroManager::Gui, sCmd);
1341
PyObject *module, *dict;
1343
Base::PyGILStateLocker locker;
1344
module = PyImport_AddModule("__main__");
1348
dict = PyModule_GetDict(module);
1352
return PyRun_String(sCmd, Py_file_input, dict, dict);
1355
PyObject* Application::sAddModule(PyObject * /*self*/, PyObject *args)
1358
if (!PyArg_ParseTuple(args, "s", &pstr))
1362
Command::addModule(Command::Doc,pstr);
1365
catch (const Base::Exception& e) {
1366
PyErr_SetString(PyExc_ImportError, e.what());
1371
PyObject* Application::sShowDownloads(PyObject * /*self*/, PyObject *args)
1373
if (!PyArg_ParseTuple(args, ""))
1376
Gui::Dialog::DownloadManager::getInstance();
1381
PyObject* Application::sShowPreferences(PyObject * /*self*/, PyObject *args)
1383
char *pstr = nullptr;
1385
if (!PyArg_ParseTuple(args, "|si", &pstr, &idx))
1388
Gui::Dialog::DlgPreferencesImp cDlg(getMainWindow());
1390
cDlg.activateGroupPage(QString::fromUtf8(pstr),idx);
1400
PyObject* Application::sCreateViewer(PyObject * /*self*/, PyObject *args)
1402
int num_of_views = 1;
1403
char* title = nullptr;
1404
// if one argument (int) is given
1405
if (!PyArg_ParseTuple(args, "|is", &num_of_views, &title))
1408
if (num_of_views <= 0) {
1409
PyErr_Format(PyExc_ValueError, "views must be > 0");
1412
else if (num_of_views == 1) {
1413
auto viewer = new View3DInventor(nullptr, nullptr);
1415
viewer->setWindowTitle(QString::fromUtf8(title));
1416
Gui::getMainWindow()->addWindow(viewer);
1417
return viewer->getPyObject();
1420
auto viewer = new SplitView3DInventor(num_of_views, nullptr, nullptr);
1422
viewer->setWindowTitle(QString::fromUtf8(title));
1423
Gui::getMainWindow()->addWindow(viewer);
1424
return viewer->getPyObject();
1428
PyObject* Application::sGetMarkerIndex(PyObject * /*self*/, PyObject *args)
1432
if (!PyArg_ParseTuple(args, "s|i", &pstr, &defSize))
1436
ParameterGrp::handle const hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View");
1438
//find the appropriate marker style string token
1439
std::string marker_arg = pstr;
1441
std::list<std::pair<std::string, std::string> > markerList = {
1442
{"square", "DIAMOND_FILLED"},
1444
{"hourglass", "HOURGLASS_FILLED"},
1446
{"empty", "SQUARE_LINE"},
1447
{"quad", "SQUARE_FILLED"},
1448
{"circle", "CIRCLE_LINE"},
1449
{"default", "CIRCLE_FILLED"}
1452
auto findIt = std::find_if(markerList.begin(), markerList.end(), [&marker_arg](const auto& it) {
1453
return marker_arg == it.first || marker_arg == it.second;
1456
marker_arg = (findIt != markerList.end() ? findIt->second : "CIRCLE_FILLED");
1459
//get the marker size
1460
auto sizeList = Gui::Inventor::MarkerBitmaps::getSupportedSizes(marker_arg);
1462
if (std::find(std::begin(sizeList), std::end(sizeList), defSize) == std::end(sizeList))
1465
return Py_BuildValue("i", Gui::Inventor::MarkerBitmaps::getMarkerIndex(marker_arg, defSize));
1470
PyObject* Application::sReload(PyObject * /*self*/, PyObject *args)
1473
if (!PyArg_ParseTuple(args, "s", &name))
1477
auto doc = Application::Instance->reopen(App::GetApplication().getDocument(name));
1479
return doc->getPyObject();
1485
PyObject* Application::sLoadFile(PyObject * /*self*/, PyObject *args)
1487
const char *path = "";
1488
const char *mod = "";
1489
if (!PyArg_ParseTuple(args, "s|s", &path, &mod))
1493
Base::FileInfo fi(path);
1494
if (!fi.isFile() || !fi.exists()) {
1495
PyErr_Format(PyExc_IOError, "File %s doesn't exist.", path);
1499
std::string module = mod;
1500
if (module.empty()) {
1501
std::string ext = fi.extension();
1502
std::vector<std::string> modules = App::GetApplication().getImportModules(ext.c_str());
1503
if (modules.empty()) {
1504
PyErr_Format(PyExc_IOError, "Filetype %s is not supported.", ext.c_str());
1508
module = modules.front();
1512
Application::Instance->open(path,module.c_str());
1519
PyObject* Application::sAddDocObserver(PyObject * /*self*/, PyObject *args)
1522
if (!PyArg_ParseTuple(args, "O",&o))
1526
DocumentObserverPython::addObserver(Py::Object(o));
1532
PyObject* Application::sRemoveDocObserver(PyObject * /*self*/, PyObject *args)
1535
if (!PyArg_ParseTuple(args, "O",&o))
1539
DocumentObserverPython::removeObserver(Py::Object(o));
1545
PyObject* Application::sAddWbManipulator(PyObject * /*self*/, PyObject *args)
1548
if (!PyArg_ParseTuple(args, "O",&o))
1552
WorkbenchManipulatorPython::installManipulator(Py::Object(o));
1558
PyObject* Application::sRemoveWbManipulator(PyObject * /*self*/, PyObject *args)
1561
if (!PyArg_ParseTuple(args, "O",&o))
1565
WorkbenchManipulatorPython::removeManipulator(Py::Object(o));
1571
PyObject* Application::sCoinRemoveAllChildren(PyObject * /*self*/, PyObject *args)
1574
if (!PyArg_ParseTuple(args, "O", &pynode))
1578
void* ptr = nullptr;
1579
Base::Interpreter().convertSWIGPointerObj("pivy.coin","_p_SoGroup", pynode, &ptr, 0);
1580
coinRemoveAllChildren(static_cast<SoGroup*>(ptr));
1586
PyObject* Application::sListUserEditModes(PyObject * /*self*/, PyObject *args)
1589
if (!PyArg_ParseTuple(args, ""))
1592
for (auto const &uem : Instance->listUserEditModes()) {
1593
ret.append(Py::String(uem.second.first));
1596
return Py::new_reference_to(ret);
1599
PyObject* Application::sGetUserEditMode(PyObject * /*self*/, PyObject *args)
1601
if (!PyArg_ParseTuple(args, ""))
1604
return Py::new_reference_to(Py::String(Instance->getUserEditModeUIStrings().first));
1607
PyObject* Application::sSetUserEditMode(PyObject * /*self*/, PyObject *args)
1609
const char *mode = "";
1610
if (!PyArg_ParseTuple(args, "s", &mode))
1613
bool ok = Instance->setUserEditMode(std::string(mode));
1615
return Py::new_reference_to(Py::Boolean(ok));