972 lines
35 KiB
C++
972 lines
35 KiB
C++
/***************************************************************************
|
|
* Copyright (c) 2002 Jürgen Riegel <juergen.riegel@web.de> *
|
|
* *
|
|
* This file is part of the FreeCAD CAx development system. *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU Library General Public License (LGPL) *
|
|
* as published by the Free Software Foundation; either version 2 of *
|
|
* the License, or (at your option) any later version. *
|
|
* for detail see the LICENCE text file. *
|
|
* *
|
|
* FreeCAD 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 FreeCAD; if not, write to the Free Software *
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
|
* USA *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
|
|
#include "PreCompiled.h"
|
|
|
|
#include <Base/Console.h>
|
|
#include <Base/Exception.h>
|
|
#include <Base/FileInfo.h>
|
|
#include <Base/Interpreter.h>
|
|
#include <Base/Parameter.h>
|
|
#include <Base/PyWrapParseTupleAndKeywords.h>
|
|
#include <Base/Sequencer.h>
|
|
|
|
#include "Application.h"
|
|
#include "DocumentPy.h"
|
|
#include "DocumentObserverPython.h"
|
|
#include "DocumentObjectPy.h"
|
|
|
|
|
|
//using Base::GetConsole;
|
|
using namespace Base;
|
|
using namespace App;
|
|
|
|
|
|
//**************************************************************************
|
|
// Python stuff
|
|
|
|
// Application methods structure
|
|
PyMethodDef Application::Methods[] = {
|
|
{"ParamGet", (PyCFunction) Application::sGetParam, METH_VARARGS,
|
|
"Get parameters by path"},
|
|
{"saveParameter", (PyCFunction) Application::sSaveParameter, METH_VARARGS,
|
|
"saveParameter(config='User parameter') -> None\n"
|
|
"Save parameter set to file. The default set is 'User parameter'"},
|
|
{"Version", (PyCFunction) Application::sGetVersion, METH_VARARGS,
|
|
"Print the version to the output."},
|
|
{"ConfigGet", (PyCFunction) Application::sGetConfig, METH_VARARGS,
|
|
"ConfigGet(string) -- Get the value for the given key."},
|
|
{"ConfigSet", (PyCFunction) Application::sSetConfig, METH_VARARGS,
|
|
"ConfigSet(string, string) -- Set the given key to the given value."},
|
|
{"ConfigDump", (PyCFunction) Application::sDumpConfig, METH_VARARGS,
|
|
"Dump the configuration to the output."},
|
|
{"addImportType", (PyCFunction) Application::sAddImportType, METH_VARARGS,
|
|
"Register filetype for import"},
|
|
{"changeImportModule", (PyCFunction) Application::sChangeImportModule, METH_VARARGS,
|
|
"Change the import module name of a registered filetype"},
|
|
{"getImportType", (PyCFunction) Application::sGetImportType, METH_VARARGS,
|
|
"Get the name of the module that can import the filetype"},
|
|
{"addExportType", (PyCFunction) Application::sAddExportType, METH_VARARGS,
|
|
"Register filetype for export"},
|
|
{"changeExportModule", (PyCFunction) Application::sChangeExportModule, METH_VARARGS,
|
|
"Change the export module name of a registered filetype"},
|
|
{"getExportType", (PyCFunction) Application::sGetExportType, METH_VARARGS,
|
|
"Get the name of the module that can export the filetype"},
|
|
{"getResourceDir", (PyCFunction) Application::sGetResourcePath, METH_VARARGS,
|
|
"Get the root directory of all resources"},
|
|
{"getLibraryDir", (PyCFunction) Application::sGetLibraryPath, METH_VARARGS,
|
|
"Get the directory of all extension modules"},
|
|
{"getTempPath", (PyCFunction) Application::sGetTempPath, METH_VARARGS,
|
|
"Get the root directory of cached files"},
|
|
{"getUserCachePath", (PyCFunction) Application::sGetUserCachePath, METH_VARARGS,
|
|
"Get the root path of cached files"},
|
|
{"getUserConfigDir", (PyCFunction) Application::sGetUserConfigPath, METH_VARARGS,
|
|
"Get the root path of user config files"},
|
|
{"getUserAppDataDir", (PyCFunction) Application::sGetUserAppDataPath, METH_VARARGS,
|
|
"Get the root directory of application data"},
|
|
{"getUserMacroDir", (PyCFunction) Application::sGetUserMacroPath, METH_VARARGS,
|
|
"getUserMacroDir(bool=False) -> string"
|
|
"Get the directory of the user's macro directory\n"
|
|
"If parameter is False (the default) it returns the standard path in the"
|
|
"user's home directory, otherwise it returns the user-defined path."},
|
|
{"getHelpDir", (PyCFunction) Application::sGetHelpPath, METH_VARARGS,
|
|
"Get the directory of the documentation"},
|
|
{"getHomePath", (PyCFunction) Application::sGetHomePath, METH_VARARGS,
|
|
"Get the home path, i.e. the parent directory of the executable"},
|
|
|
|
{"loadFile", (PyCFunction) Application::sLoadFile, METH_VARARGS,
|
|
"loadFile(string=filename,[string=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."},
|
|
{"open", reinterpret_cast<PyCFunction>(reinterpret_cast<void (*) ()>( Application::sOpenDocument )), METH_VARARGS|METH_KEYWORDS,
|
|
"See openDocument(string)"},
|
|
{"openDocument", reinterpret_cast<PyCFunction>(reinterpret_cast<void (*) ()>( Application::sOpenDocument )), METH_VARARGS|METH_KEYWORDS,
|
|
"openDocument(filepath,hidden=False) -> object\n"
|
|
"Create a document and load the project file into the document.\n\n"
|
|
"filepath: file path to an existing file. If the file doesn't exist\n"
|
|
" or the file cannot be loaded an I/O exception is thrown.\n"
|
|
" In this case the document is kept alive.\n"
|
|
"hidden: whether to hide document 3D view."},
|
|
// {"saveDocument", (PyCFunction) Application::sSaveDocument, METH_VARARGS,
|
|
// "saveDocument(string) -- Save the document to a file."},
|
|
// {"saveDocumentAs", (PyCFunction) Application::sSaveDocumentAs, METH_VARARGS},
|
|
{"newDocument", reinterpret_cast<PyCFunction>(reinterpret_cast<void (*) ()>( Application::sNewDocument )), METH_VARARGS|METH_KEYWORDS,
|
|
"newDocument(name, label=None, hidden=False, temp=False) -> object\n"
|
|
"Create a new document with a given name.\n\n"
|
|
"name: unique document name which is checked automatically.\n"
|
|
"label: optional user changeable label for the document.\n"
|
|
"hidden: whether to hide document 3D view.\n"
|
|
"temp: mark the document as temporary so that it will not be saved"},
|
|
{"closeDocument", (PyCFunction) Application::sCloseDocument, METH_VARARGS,
|
|
"closeDocument(string) -> None\n\n"
|
|
"Close the document with a given name."},
|
|
{"activeDocument", (PyCFunction) Application::sActiveDocument, METH_VARARGS,
|
|
"activeDocument() -> object or None\n\n"
|
|
"Return the active document or None if there is no one."},
|
|
{"setActiveDocument", (PyCFunction) Application::sSetActiveDocument, METH_VARARGS,
|
|
"setActiveDocement(string) -> None\n\n"
|
|
"Set the active document by its name."},
|
|
{"getDocument", (PyCFunction) Application::sGetDocument, METH_VARARGS,
|
|
"getDocument(string) -> object\n\n"
|
|
"Get a document by its name or raise an exception\n"
|
|
"if there is no document with the given name."},
|
|
{"listDocuments", (PyCFunction) Application::sListDocuments, METH_VARARGS,
|
|
"listDocuments(sort=False) -> list\n\n"
|
|
"Return a list of names of all documents, optionally sort in dependency order."},
|
|
{"addDocumentObserver", (PyCFunction) Application::sAddDocObserver, METH_VARARGS,
|
|
"addDocumentObserver() -> None\n\n"
|
|
"Add an observer to get notified about changes on documents."},
|
|
{"removeDocumentObserver", (PyCFunction) Application::sRemoveDocObserver, METH_VARARGS,
|
|
"removeDocumentObserver() -> None\n\n"
|
|
"Remove an added document observer."},
|
|
{"setLogLevel", (PyCFunction) Application::sSetLogLevel, METH_VARARGS,
|
|
"setLogLevel(tag, level) -- Set the log level for a string tag.\n"
|
|
"'level' can either be string 'Log', 'Msg', 'Wrn', 'Error', or an integer value"},
|
|
{"getLogLevel", (PyCFunction) Application::sGetLogLevel, METH_VARARGS,
|
|
"getLogLevel(tag) -- Get the log level of a string tag"},
|
|
{"checkLinkDepth", (PyCFunction) Application::sCheckLinkDepth, METH_VARARGS,
|
|
"checkLinkDepth(depth) -- check link recursion depth"},
|
|
{"getLinksTo", (PyCFunction) Application::sGetLinksTo, METH_VARARGS,
|
|
"getLinksTo(obj,options=0,maxCount=0) -- return the objects linked to 'obj'\n\n"
|
|
"options: 1: recursive, 2: check link array. Options can combine.\n"
|
|
"maxCount: to limit the number of links returned\n"},
|
|
{"getDependentObjects", (PyCFunction) Application::sGetDependentObjects, METH_VARARGS,
|
|
"getDependentObjects(obj|[obj,...], options=0)\n"
|
|
"Return a list of dependent objects including the given objects.\n\n"
|
|
"options: can have the following bit flags,\n"
|
|
" 1: to sort the list in topological order.\n"
|
|
" 2: to exclude dependency of Link type object."},
|
|
{"setActiveTransaction", (PyCFunction) Application::sSetActiveTransaction, METH_VARARGS,
|
|
"setActiveTransaction(name, persist=False) -- setup active transaction with the given name\n\n"
|
|
"name: the transaction name\n"
|
|
"persist(False): by default, if the calling code is inside any invocation of a command, it\n"
|
|
" will be auto closed once all commands within the current stack exists. To\n"
|
|
" disable auto closing, set persist=True\n"
|
|
"Returns the transaction ID for the active transaction. An application-wide\n"
|
|
"active transaction causes any document changes to open a transaction with\n"
|
|
"the given name and ID."},
|
|
{"getActiveTransaction", (PyCFunction) Application::sGetActiveTransaction, METH_VARARGS,
|
|
"getActiveTransaction() -> (name,id) return the current active transaction name and ID"},
|
|
{"closeActiveTransaction", (PyCFunction) Application::sCloseActiveTransaction, METH_VARARGS,
|
|
"closeActiveTransaction(abort=False) -- commit or abort current active transaction"},
|
|
{"isRestoring", (PyCFunction) Application::sIsRestoring, METH_VARARGS,
|
|
"isRestoring() -> Bool -- Test if the application is opening some document"},
|
|
{"checkAbort", (PyCFunction) Application::sCheckAbort, METH_VARARGS,
|
|
"checkAbort() -- check for user abort in length operation.\n\n"
|
|
"This only works if there is an active sequencer (or ProgressIndicator in Python).\n"
|
|
"There is an active sequencer during document restore and recomputation. User may\n"
|
|
"abort the operation by pressing the ESC key. Once detected, this function will\n"
|
|
"trigger a Base.FreeCADAbort exception."},
|
|
{nullptr, nullptr, 0, nullptr} /* Sentinel */
|
|
};
|
|
|
|
|
|
PyObject* Application::sLoadFile(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
const char *path;
|
|
const char *doc="";
|
|
const char *mod="";
|
|
if (!PyArg_ParseTuple(args, "s|ss", &path, &doc, &mod))
|
|
return nullptr;
|
|
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 = GetApplication().getImportModules(ext.c_str());
|
|
if (modules.empty()) {
|
|
PyErr_Format(PyExc_IOError, "Filetype %s is not supported.", ext.c_str());
|
|
return nullptr;
|
|
}
|
|
else {
|
|
module = modules.front();
|
|
}
|
|
}
|
|
|
|
// path could contain characters that need escaping, such as quote signs
|
|
// therefore use its representation in the Python code string
|
|
PyObject *pathObj = PyUnicode_FromString(path);
|
|
PyObject *pathReprObj = PyObject_Repr(pathObj);
|
|
const char *pathRepr = PyUnicode_AsUTF8(pathReprObj);
|
|
|
|
std::stringstream str;
|
|
str << "import " << module << std::endl;
|
|
if (fi.hasExtension("FCStd"))
|
|
str << module << ".openDocument(" << pathRepr << ")" << std::endl;
|
|
else
|
|
str << module << ".insert(" << pathRepr << ",'" << doc << "')" << std::endl;
|
|
|
|
Py_DECREF(pathObj);
|
|
Py_DECREF(pathReprObj);
|
|
|
|
Base::Interpreter().runString(str.str().c_str());
|
|
Py_Return;
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
e.setPyException();
|
|
return nullptr;
|
|
}
|
|
catch (const std::exception& e) {
|
|
// might be subclass from zipios
|
|
PyErr_Format(PyExc_IOError, "Invalid project file %s: %s", path, e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
PyObject* Application::sIsRestoring(PyObject * /*self*/, PyObject *args) {
|
|
if (!PyArg_ParseTuple(args, ""))
|
|
return nullptr;
|
|
return Py::new_reference_to(Py::Boolean(GetApplication().isRestoring()));
|
|
}
|
|
|
|
PyObject* Application::sOpenDocument(PyObject * /*self*/, PyObject *args, PyObject *kwd)
|
|
{
|
|
char* Name;
|
|
PyObject *hidden = Py_False;
|
|
static const std::array<const char *, 3> kwlist {"name", "hidden", nullptr};
|
|
if (!Base::Wrapped_ParseTupleAndKeywords(args, kwd, "et|O!", kwlist,
|
|
"utf-8", &Name, &PyBool_Type, &hidden)) {
|
|
return nullptr;
|
|
}
|
|
std::string EncodedName = std::string(Name);
|
|
PyMem_Free(Name);
|
|
try {
|
|
// return new document
|
|
return (GetApplication().openDocument(EncodedName.c_str(), !Base::asBoolean(hidden))->getPyObject());
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
PyErr_SetString(PyExc_IOError, e.what());
|
|
return nullptr;
|
|
}
|
|
catch (const std::exception& e) {
|
|
// might be subclass from zipios
|
|
PyErr_Format(PyExc_IOError, "Invalid project file %s: %s\n", EncodedName.c_str(), e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
PyObject* Application::sNewDocument(PyObject * /*self*/, PyObject *args, PyObject *kwd)
|
|
{
|
|
char *docName = nullptr;
|
|
char *usrName = nullptr;
|
|
PyObject *hidden = Py_False;
|
|
PyObject *temp = Py_False;
|
|
static const std::array<const char *, 5> kwlist {"name", "label", "hidden", "temp", nullptr};
|
|
if (!Base::Wrapped_ParseTupleAndKeywords(args, kwd, "|etetO!O!", kwlist,
|
|
"utf-8", &docName, "utf-8", &usrName, &PyBool_Type, &hidden, &PyBool_Type, &temp)) {
|
|
return nullptr;
|
|
}
|
|
|
|
PY_TRY {
|
|
App::Document* doc = GetApplication().newDocument(docName, usrName, !Base::asBoolean(hidden), Base::asBoolean(temp));
|
|
PyMem_Free(docName);
|
|
PyMem_Free(usrName);
|
|
return doc->getPyObject();
|
|
}PY_CATCH;
|
|
}
|
|
|
|
PyObject* Application::sSetActiveDocument(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
char *pstr = nullptr;
|
|
if (!PyArg_ParseTuple(args, "s", &pstr))
|
|
return nullptr;
|
|
|
|
try {
|
|
GetApplication().setActiveDocument(pstr);
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
e.setPyException();
|
|
return nullptr;
|
|
}
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* Application::sCloseDocument(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
char *pstr = nullptr;
|
|
if (!PyArg_ParseTuple(args, "s", &pstr))
|
|
return nullptr;
|
|
|
|
Document* doc = GetApplication().getDocument(pstr);
|
|
if (!doc) {
|
|
PyErr_Format(PyExc_NameError, "Unknown document '%s'", pstr);
|
|
return nullptr;
|
|
}
|
|
if (!doc->isClosable()) {
|
|
PyErr_Format(PyExc_RuntimeError, "The document '%s' is not closable for the moment", pstr);
|
|
return nullptr;
|
|
}
|
|
|
|
if (!GetApplication().closeDocument(pstr)) {
|
|
PyErr_Format(PyExc_RuntimeError, "Closing the document '%s' failed", pstr);
|
|
return nullptr;
|
|
}
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* Application::sSaveDocument(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
char *pDoc;
|
|
if (!PyArg_ParseTuple(args, "s", &pDoc))
|
|
return nullptr;
|
|
|
|
Document* doc = GetApplication().getDocument(pDoc);
|
|
if ( doc ) {
|
|
if (!doc->save()) {
|
|
PyErr_Format(Base::PyExc_FC_GeneralError, "Cannot save document '%s'", pDoc);
|
|
return nullptr;
|
|
}
|
|
}
|
|
else {
|
|
PyErr_Format(PyExc_NameError, "Unknown document '%s'", pDoc);
|
|
return nullptr;
|
|
}
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* Application::sActiveDocument(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, ""))
|
|
return nullptr;
|
|
|
|
Document* doc = GetApplication().getActiveDocument();
|
|
if (doc) {
|
|
return doc->getPyObject();
|
|
}
|
|
else {
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
}
|
|
|
|
PyObject* Application::sGetDocument(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
char *pstr=nullptr;
|
|
if (!PyArg_ParseTuple(args, "s", &pstr))
|
|
return nullptr;
|
|
|
|
Document* doc = GetApplication().getDocument(pstr);
|
|
if ( !doc ) {
|
|
PyErr_Format(PyExc_NameError, "Unknown document '%s'", pstr);
|
|
return nullptr;
|
|
}
|
|
|
|
return doc->getPyObject();
|
|
}
|
|
|
|
PyObject* Application::sGetParam(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
char *pstr=nullptr;
|
|
if (!PyArg_ParseTuple(args, "s", &pstr))
|
|
return nullptr;
|
|
|
|
PY_TRY {
|
|
return GetPyObject(GetApplication().GetParameterGroupByPath(pstr));
|
|
}PY_CATCH;
|
|
}
|
|
|
|
PyObject* Application::sSaveParameter(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
const char *pstr = "User parameter";
|
|
if (!PyArg_ParseTuple(args, "|s", &pstr))
|
|
return nullptr;
|
|
|
|
PY_TRY {
|
|
ParameterManager* param = App::GetApplication().GetParameterSet(pstr);
|
|
if (!param) {
|
|
std::stringstream str;
|
|
str << "No parameter set found with name: " << pstr;
|
|
PyErr_SetString(PyExc_ValueError, str.str().c_str());
|
|
return nullptr;
|
|
}
|
|
else if (!param->HasSerializer()) {
|
|
std::stringstream str;
|
|
str << "Parameter set cannot be serialized: " << pstr;
|
|
PyErr_SetString(PyExc_RuntimeError, str.str().c_str());
|
|
return nullptr;
|
|
}
|
|
|
|
param->SaveDocument();
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}PY_CATCH;
|
|
}
|
|
|
|
|
|
PyObject* Application::sGetConfig(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
char *pstr;
|
|
|
|
if (!PyArg_ParseTuple(args, "s", &pstr))
|
|
return nullptr;
|
|
const std::map<std::string, std::string>& Map = GetApplication().Config();
|
|
|
|
std::map<std::string, std::string>::const_iterator it = Map.find(pstr);
|
|
if (it != Map.end()) {
|
|
return Py_BuildValue("s", it->second.c_str());
|
|
}
|
|
else {
|
|
// do not set an error because this may break existing python code
|
|
return PyUnicode_FromString("");
|
|
}
|
|
}
|
|
|
|
PyObject* Application::sDumpConfig(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, ""))
|
|
return nullptr;
|
|
|
|
PyObject *dict = PyDict_New();
|
|
for (const auto & It : GetApplication()._mConfig) {
|
|
PyDict_SetItemString(dict, It.first.c_str(), PyUnicode_FromString(It.second.c_str()));
|
|
}
|
|
return dict;
|
|
}
|
|
|
|
PyObject* Application::sSetConfig(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
char *pstr, *pstr2;
|
|
|
|
if (!PyArg_ParseTuple(args, "ss", &pstr, &pstr2))
|
|
return nullptr;
|
|
|
|
GetApplication()._mConfig[pstr] = pstr2;
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
PyObject* Application::sGetVersion(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, ""))
|
|
return nullptr;
|
|
|
|
Py::List list;
|
|
const std::map<std::string, std::string>& cfg = Application::Config();
|
|
std::map<std::string, std::string>::const_iterator it;
|
|
|
|
it = cfg.find("BuildVersionMajor");
|
|
list.append(Py::String(it != cfg.end() ? it->second : ""));
|
|
|
|
it = cfg.find("BuildVersionMinor");
|
|
list.append(Py::String(it != cfg.end() ? it->second : ""));
|
|
|
|
it = cfg.find("BuildVersionPoint");
|
|
list.append(Py::String(it != cfg.end() ? it->second : ""));
|
|
|
|
it = cfg.find("BuildRevision");
|
|
list.append(Py::String(it != cfg.end() ? it->second : ""));
|
|
|
|
it = cfg.find("BuildRepositoryURL");
|
|
list.append(Py::String(it != cfg.end() ? it->second : ""));
|
|
|
|
it = cfg.find("BuildRevisionDate");
|
|
list.append(Py::String(it != cfg.end() ? it->second : ""));
|
|
|
|
it = cfg.find("BuildRevisionBranch");
|
|
if (it != cfg.end())
|
|
list.append(Py::String(it->second));
|
|
|
|
it = cfg.find("BuildRevisionHash");
|
|
if (it != cfg.end())
|
|
list.append(Py::String(it->second));
|
|
|
|
return Py::new_reference_to(list);
|
|
}
|
|
|
|
PyObject* Application::sAddImportType(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
char *psKey,*psMod;
|
|
|
|
if (!PyArg_ParseTuple(args, "ss", &psKey,&psMod))
|
|
return nullptr;
|
|
|
|
GetApplication().addImportType(psKey,psMod);
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* Application::sChangeImportModule(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
char *key,*oldMod,*newMod;
|
|
|
|
if (!PyArg_ParseTuple(args, "sss", &key,&oldMod,&newMod))
|
|
return nullptr;
|
|
|
|
GetApplication().changeImportModule(key,oldMod,newMod);
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* Application::sGetImportType(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
char* psKey=nullptr;
|
|
|
|
if (!PyArg_ParseTuple(args, "|s", &psKey))
|
|
return nullptr;
|
|
|
|
if (psKey) {
|
|
Py::List list;
|
|
std::vector<std::string> modules = GetApplication().getImportModules(psKey);
|
|
for (const auto & it : modules) {
|
|
list.append(Py::String(it));
|
|
}
|
|
|
|
return Py::new_reference_to(list);
|
|
}
|
|
else {
|
|
Py::Dict dict;
|
|
std::vector<std::string> types = GetApplication().getImportTypes();
|
|
for (const auto & it : types) {
|
|
std::vector<std::string> modules = GetApplication().getImportModules(it.c_str());
|
|
if (modules.empty()) {
|
|
dict.setItem(it.c_str(), Py::None());
|
|
}
|
|
else if (modules.size() == 1) {
|
|
dict.setItem(it.c_str(), Py::String(modules.front()));
|
|
}
|
|
else {
|
|
Py::List list;
|
|
for (const auto & jt : modules) {
|
|
list.append(Py::String(jt));
|
|
}
|
|
dict.setItem(it.c_str(), list);
|
|
}
|
|
}
|
|
|
|
return Py::new_reference_to(dict);
|
|
}
|
|
}
|
|
|
|
PyObject* Application::sAddExportType(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
char *psKey,*psMod;
|
|
|
|
if (!PyArg_ParseTuple(args, "ss", &psKey,&psMod))
|
|
return nullptr;
|
|
|
|
GetApplication().addExportType(psKey,psMod);
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* Application::sChangeExportModule(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
char *key,*oldMod,*newMod;
|
|
|
|
if (!PyArg_ParseTuple(args, "sss", &key,&oldMod,&newMod))
|
|
return nullptr;
|
|
|
|
GetApplication().changeExportModule(key,oldMod,newMod);
|
|
|
|
Py_Return;
|
|
}
|
|
|
|
PyObject* Application::sGetExportType(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
char* psKey=nullptr;
|
|
|
|
if (!PyArg_ParseTuple(args, "|s", &psKey))
|
|
return nullptr;
|
|
|
|
if (psKey) {
|
|
Py::List list;
|
|
std::vector<std::string> modules = GetApplication().getExportModules(psKey);
|
|
for (const auto & it : modules) {
|
|
list.append(Py::String(it));
|
|
}
|
|
|
|
return Py::new_reference_to(list);
|
|
}
|
|
else {
|
|
Py::Dict dict;
|
|
std::vector<std::string> types = GetApplication().getExportTypes();
|
|
for (const auto & it : types) {
|
|
std::vector<std::string> modules = GetApplication().getExportModules(it.c_str());
|
|
if (modules.empty()) {
|
|
dict.setItem(it.c_str(), Py::None());
|
|
}
|
|
else if (modules.size() == 1) {
|
|
dict.setItem(it.c_str(), Py::String(modules.front()));
|
|
}
|
|
else {
|
|
Py::List list;
|
|
for (const auto & jt : modules) {
|
|
list.append(Py::String(jt));
|
|
}
|
|
dict.setItem(it.c_str(), list);
|
|
}
|
|
}
|
|
|
|
return Py::new_reference_to(dict);
|
|
}
|
|
}
|
|
|
|
PyObject* Application::sGetResourcePath(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, ""))
|
|
return nullptr;
|
|
|
|
Py::String datadir(Application::getResourceDir(),"utf-8");
|
|
return Py::new_reference_to(datadir);
|
|
}
|
|
|
|
PyObject* Application::sGetLibraryPath(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, ""))
|
|
return nullptr;
|
|
|
|
Py::String datadir(Application::getLibraryDir(),"utf-8");
|
|
return Py::new_reference_to(datadir);
|
|
}
|
|
|
|
PyObject* Application::sGetTempPath(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, ""))
|
|
return nullptr;
|
|
|
|
Py::String datadir(Application::getTempPath(),"utf-8");
|
|
return Py::new_reference_to(datadir);
|
|
}
|
|
|
|
PyObject* Application::sGetUserCachePath(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, ""))
|
|
return nullptr;
|
|
|
|
Py::String datadir(Application::getUserCachePath(),"utf-8");
|
|
return Py::new_reference_to(datadir);
|
|
}
|
|
|
|
PyObject* Application::sGetUserConfigPath(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, ""))
|
|
return nullptr;
|
|
|
|
Py::String datadir(Application::getUserConfigPath(),"utf-8");
|
|
return Py::new_reference_to(datadir);
|
|
}
|
|
|
|
PyObject* Application::sGetUserAppDataPath(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, ""))
|
|
return nullptr;
|
|
|
|
Py::String user_data_dir(Application::getUserAppDataDir(),"utf-8");
|
|
return Py::new_reference_to(user_data_dir);
|
|
}
|
|
|
|
PyObject* Application::sGetUserMacroPath(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
PyObject *actual = Py_False;
|
|
if (!PyArg_ParseTuple(args, "|O!", &PyBool_Type, &actual))
|
|
return nullptr;
|
|
|
|
std::string macroDir = Application::getUserMacroDir();
|
|
if (Base::asBoolean(actual)) {
|
|
macroDir = App::GetApplication().
|
|
GetParameterGroupByPath("User parameter:BaseApp/Preferences/Macro")
|
|
->GetASCII("MacroPath", macroDir.c_str());
|
|
std::replace(macroDir.begin(), macroDir.end(), '/', PATHSEP);
|
|
}
|
|
|
|
Py::String user_macro_dir(macroDir,"utf-8");
|
|
return Py::new_reference_to(user_macro_dir);
|
|
}
|
|
|
|
PyObject* Application::sGetHelpPath(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, ""))
|
|
return nullptr;
|
|
|
|
Py::String user_macro_dir(Application::getHelpDir(),"utf-8");
|
|
return Py::new_reference_to(user_macro_dir);
|
|
}
|
|
|
|
PyObject* Application::sGetHomePath(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, ""))
|
|
return nullptr;
|
|
|
|
Py::String homedir(Application::getHomePath(),"utf-8");
|
|
return Py::new_reference_to(homedir);
|
|
}
|
|
|
|
PyObject* Application::sListDocuments(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
PyObject *sort = Py_False;
|
|
if (!PyArg_ParseTuple(args, "|O!", &PyBool_Type, &sort))
|
|
return nullptr;
|
|
PY_TRY {
|
|
PyObject *pDict = PyDict_New();
|
|
PyObject *pKey;
|
|
Base::PyObjectBase* pValue;
|
|
|
|
std::vector<Document*> docs = GetApplication().getDocuments();;
|
|
if (Base::asBoolean(sort))
|
|
docs = Document::getDependentDocuments(docs,true);
|
|
|
|
for (auto doc : docs) {
|
|
pKey = PyUnicode_FromString(doc->getName());
|
|
// GetPyObject() increments
|
|
pValue = static_cast<Base::PyObjectBase*>(doc->getPyObject());
|
|
PyDict_SetItem(pDict, pKey, pValue);
|
|
// now we can decrement again as PyDict_SetItem also has incremented
|
|
pValue->DecRef();
|
|
}
|
|
|
|
return pDict;
|
|
} PY_CATCH;
|
|
}
|
|
|
|
PyObject* Application::sAddDocObserver(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
PyObject* o;
|
|
if (!PyArg_ParseTuple(args, "O",&o))
|
|
return nullptr;
|
|
PY_TRY {
|
|
DocumentObserverPython::addObserver(Py::Object(o));
|
|
Py_Return;
|
|
} PY_CATCH;
|
|
}
|
|
|
|
PyObject* Application::sRemoveDocObserver(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
PyObject* o;
|
|
if (!PyArg_ParseTuple(args, "O",&o))
|
|
return nullptr;
|
|
PY_TRY {
|
|
DocumentObserverPython::removeObserver(Py::Object(o));
|
|
Py_Return;
|
|
} PY_CATCH;
|
|
}
|
|
|
|
PyObject *Application::sSetLogLevel(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
char *tag;
|
|
PyObject *pcObj;
|
|
if (!PyArg_ParseTuple(args, "sO", &tag, &pcObj))
|
|
return nullptr;
|
|
PY_TRY{
|
|
int l;
|
|
if (PyUnicode_Check(pcObj)) {
|
|
const char *pstr = PyUnicode_AsUTF8(pcObj);
|
|
if(strcmp(pstr,"Log") == 0)
|
|
l = FC_LOGLEVEL_LOG;
|
|
else if(strcmp(pstr,"Warning") == 0)
|
|
l = FC_LOGLEVEL_WARN;
|
|
else if(strcmp(pstr,"Message") == 0)
|
|
l = FC_LOGLEVEL_MSG;
|
|
else if(strcmp(pstr,"Error") == 0)
|
|
l = FC_LOGLEVEL_ERR;
|
|
else if(strcmp(pstr,"Trace") == 0)
|
|
l = FC_LOGLEVEL_TRACE;
|
|
else if(strcmp(pstr,"Default") == 0)
|
|
l = FC_LOGLEVEL_DEFAULT;
|
|
else {
|
|
Py_Error(PyExc_ValueError,
|
|
"Unknown Log Level (use 'Default', 'Error', 'Warning', 'Message', 'Log', 'Trace' or an integer)");
|
|
return nullptr;
|
|
}
|
|
}else
|
|
l = PyLong_AsLong(pcObj);
|
|
GetApplication().GetParameterGroupByPath("User parameter:BaseApp/LogLevels")->SetInt(tag,l);
|
|
if(strcmp(tag,"Default") == 0) {
|
|
#ifndef FC_DEBUG
|
|
if(l>=0) Base::Console().SetDefaultLogLevel(l);
|
|
#endif
|
|
}else if(strcmp(tag,"DebugDefault") == 0) {
|
|
#ifdef FC_DEBUG
|
|
if(l>=0) Base::Console().SetDefaultLogLevel(l);
|
|
#endif
|
|
}else
|
|
*Base::Console().GetLogLevel(tag) = l;
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}PY_CATCH;
|
|
}
|
|
|
|
PyObject *Application::sGetLogLevel(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
char *tag;
|
|
if (!PyArg_ParseTuple(args, "s", &tag))
|
|
return nullptr;
|
|
|
|
PY_TRY{
|
|
int l = -1;
|
|
if(strcmp(tag,"Default")==0) {
|
|
#ifdef FC_DEBUG
|
|
l = _pcUserParamMngr->GetGroup("BaseApp/LogLevels")->GetInt(tag,-1);
|
|
#endif
|
|
}else if(strcmp(tag,"DebugDefault")==0) {
|
|
#ifndef FC_DEBUG
|
|
l = _pcUserParamMngr->GetGroup("BaseApp/LogLevels")->GetInt(tag,-1);
|
|
#endif
|
|
}else{
|
|
int *pl = Base::Console().GetLogLevel(tag,false);
|
|
l = pl?*pl:-1;
|
|
}
|
|
// For performance reason, we only output integer value
|
|
return Py_BuildValue("i",Base::Console().LogLevel(l));
|
|
} PY_CATCH;
|
|
}
|
|
|
|
PyObject *Application::sCheckLinkDepth(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
short depth = 0;
|
|
if (!PyArg_ParseTuple(args, "h", &depth))
|
|
return nullptr;
|
|
|
|
PY_TRY {
|
|
return Py::new_reference_to(Py::Int(GetApplication().checkLinkDepth(depth, MessageOption::Throw)));
|
|
}PY_CATCH;
|
|
}
|
|
|
|
PyObject *Application::sGetLinksTo(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
PyObject *pyobj = Py_None;
|
|
int options = 0;
|
|
short count = 0;
|
|
if (!PyArg_ParseTuple(args, "|Oih",&pyobj,&options, &count))
|
|
return nullptr;
|
|
|
|
PY_TRY {
|
|
Base::PyTypeCheck(&pyobj, &DocumentObjectPy::Type, "Expect the first argument of type App.DocumentObject or None");
|
|
DocumentObject *obj = nullptr;
|
|
if (pyobj)
|
|
obj = static_cast<DocumentObjectPy*>(pyobj)->getDocumentObjectPtr();
|
|
|
|
auto links = GetApplication().getLinksTo(obj,options,count);
|
|
Py::Tuple ret(links.size());
|
|
int i=0;
|
|
for(auto o : links)
|
|
ret.setItem(i++,Py::Object(o->getPyObject(),true));
|
|
|
|
return Py::new_reference_to(ret);
|
|
}
|
|
PY_CATCH;
|
|
}
|
|
|
|
PyObject *Application::sGetDependentObjects(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
PyObject *obj;
|
|
int options = 0;
|
|
if (!PyArg_ParseTuple(args, "O|i", &obj,&options))
|
|
return nullptr;
|
|
|
|
std::vector<App::DocumentObject*> objs;
|
|
if (PySequence_Check(obj)) {
|
|
Py::Sequence seq(obj);
|
|
for (Py_ssize_t i=0;i<seq.size();++i) {
|
|
if(!PyObject_TypeCheck(seq[i].ptr(),&DocumentObjectPy::Type)) {
|
|
PyErr_SetString(PyExc_TypeError, "Expect element in sequence to be of type document object");
|
|
return nullptr;
|
|
}
|
|
objs.push_back(static_cast<DocumentObjectPy*>(seq[i].ptr())->getDocumentObjectPtr());
|
|
}
|
|
}
|
|
else if(!PyObject_TypeCheck(obj,&DocumentObjectPy::Type)) {
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"Expect first argument to be either a document object or sequence of document objects");
|
|
return nullptr;
|
|
}
|
|
else {
|
|
objs.push_back(static_cast<DocumentObjectPy*>(obj)->getDocumentObjectPtr());
|
|
}
|
|
|
|
PY_TRY {
|
|
auto ret = App::Document::getDependencyList(objs,options);
|
|
|
|
Py::Tuple tuple(ret.size());
|
|
for(size_t i=0;i<ret.size();++i)
|
|
tuple.setItem(i,Py::Object(ret[i]->getPyObject(),true));
|
|
return Py::new_reference_to(tuple);
|
|
} PY_CATCH;
|
|
}
|
|
|
|
|
|
PyObject *Application::sSetActiveTransaction(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
char *name;
|
|
PyObject *persist = Py_False;
|
|
if (!PyArg_ParseTuple(args, "s|O!", &name, &PyBool_Type, &persist))
|
|
return nullptr;
|
|
|
|
PY_TRY {
|
|
Py::Int ret(GetApplication().setActiveTransaction(name, Base::asBoolean(persist)));
|
|
return Py::new_reference_to(ret);
|
|
}PY_CATCH;
|
|
}
|
|
|
|
PyObject *Application::sGetActiveTransaction(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, ""))
|
|
return nullptr;
|
|
|
|
PY_TRY {
|
|
int id = 0;
|
|
const char *name = GetApplication().getActiveTransaction(&id);
|
|
if(!name || id<=0)
|
|
Py_Return;
|
|
Py::Tuple ret(2);
|
|
ret.setItem(0,Py::String(name));
|
|
ret.setItem(1,Py::Int(id));
|
|
return Py::new_reference_to(ret);
|
|
}PY_CATCH;
|
|
}
|
|
|
|
PyObject *Application::sCloseActiveTransaction(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
PyObject *abort = Py_False;
|
|
int id = 0;
|
|
if (!PyArg_ParseTuple(args, "|O!i", &PyBool_Type, &abort,&id))
|
|
return nullptr;
|
|
|
|
PY_TRY {
|
|
GetApplication().closeActiveTransaction(Base::asBoolean(abort), id);
|
|
Py_Return;
|
|
} PY_CATCH;
|
|
}
|
|
|
|
PyObject *Application::sCheckAbort(PyObject * /*self*/, PyObject *args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, ""))
|
|
return nullptr;
|
|
|
|
PY_TRY {
|
|
Base::Sequencer().checkAbort();
|
|
Py_Return;
|
|
}PY_CATCH
|
|
}
|