From 949a50a0cd926d21f34215d0cd682407d5122ba2 Mon Sep 17 00:00:00 2001 From: jriegel Date: Mon, 2 Jan 2012 15:56:17 +0100 Subject: [PATCH] Run arbitrary scripts from Cmd command line --- .kdev4/.kdev4/FCMasterMerge.kdev4 | 10 + .kdev4/FCMasterMerge.kdev4 | 41 + FCMasterMerge.kdev4 | 3 + src/App/Application.cpp | 2 +- src/App/Application.cpp.orig | 2169 +++++++++++++++++++++++++++++ src/Mod/Assembly/DevAssembly.py | 3 + 6 files changed, 2227 insertions(+), 1 deletion(-) create mode 100644 .kdev4/.kdev4/FCMasterMerge.kdev4 create mode 100644 .kdev4/FCMasterMerge.kdev4 create mode 100644 FCMasterMerge.kdev4 create mode 100644 src/App/Application.cpp.orig create mode 100644 src/Mod/Assembly/DevAssembly.py diff --git a/.kdev4/.kdev4/FCMasterMerge.kdev4 b/.kdev4/.kdev4/FCMasterMerge.kdev4 new file mode 100644 index 0000000000..156919bbeb --- /dev/null +++ b/.kdev4/.kdev4/FCMasterMerge.kdev4 @@ -0,0 +1,10 @@ +[Buildset] +BuildItems=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x01\x00\x00\x00\x0b\x00\x00\x00\x00\x01\x00\x00\x00&\x00F\x00C\x00M\x00a\x00s\x00t\x00e\x00r\x00M\x00e\x00r\x00g\x00e\x00.\x00k\x00d\x00e\x00v\x004) + +[Defines And Includes][Compiler] +Name=GCC +Path=gcc +Type=GCC + +[Project] +VersionControlSupport=kdevgit diff --git a/.kdev4/FCMasterMerge.kdev4 b/.kdev4/FCMasterMerge.kdev4 new file mode 100644 index 0000000000..819035e25c --- /dev/null +++ b/.kdev4/FCMasterMerge.kdev4 @@ -0,0 +1,41 @@ +[CMake] +Build Directory Count=1 +Current Build Directory Index=0 +ProjectRootRelative=./ + +[CMake][CMake Build Directory 0] +Build Directory Path=file:///home/stefan/Projects/FCMasterMerge/build +Build Type=Debug +CMake Binary=file:///usr/bin/cmake +Environment Profile= +Extra Arguments= +Install Directory=file:///usr/local + +[Defines And Includes][Compiler] +Name=GCC +Path=gcc +Type=GCC + +[Launch] +Launch Configurations=Launch Configuration 0 + +[Launch][Launch Configuration 0] +Configured Launch Modes=execute +Configured Launchers=nativeAppLauncher +Name=FreeCADMain +Type=Native Application + +[Launch][Launch Configuration 0][Data] +Arguments= +Dependencies=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x01\x00\x00\x00\x0b\x00\x00\x00\x00\x04\x00\x00\x00\x1a\x00F\x00C\x00M\x00a\x00s\x00t\x00e\x00r\x00M\x00e\x00r\x00g\x00e\x00\x00\x00\x06\x00s\x00r\x00c\x00\x00\x00\x08\x00M\x00a\x00i\x00n\x00\x00\x00\x16\x00F\x00r\x00e\x00e\x00C\x00A\x00D\x00M\x00a\x00i\x00n) +Dependency Action=Nothing +EnvironmentGroup= +Executable=file:///home/stefan/Projects/FCMasterMerge/build/bin/FreeCAD +External Terminal=konsole --noclose --workdir %workdir -e %exe +Project Target=FCMasterMerge,src,Main,FreeCADMain +Use External Terminal=false +Working Directory= +isExecutable=true + +[Project] +VersionControlSupport=kdevgit diff --git a/FCMasterMerge.kdev4 b/FCMasterMerge.kdev4 new file mode 100644 index 0000000000..1aa8760a58 --- /dev/null +++ b/FCMasterMerge.kdev4 @@ -0,0 +1,3 @@ +[Project] +Manager=KDevCMakeManager +Name=FCMasterMerge diff --git a/src/App/Application.cpp b/src/App/Application.cpp index e8adf11327..333c680c1b 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -1334,7 +1334,7 @@ void Application::processFiles(const std::list& files) Base::Interpreter().runFile(file.filePath().c_str(), true); } else if (file.hasExtension("py")) { - try { + try{ Base::Interpreter().loadModule(file.fileNamePure().c_str()); } catch(const PyException&) { diff --git a/src/App/Application.cpp.orig b/src/App/Application.cpp.orig new file mode 100644 index 0000000000..e123c760cf --- /dev/null +++ b/src/App/Application.cpp.orig @@ -0,0 +1,2169 @@ +/*************************************************************************** + * (c) Juergen Riegel (juergen.riegel@web.de) 2002 * + * * + * 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 * + * * + * Juergen Riegel 2002 * + ***************************************************************************/ + + + +#include "PreCompiled.h" + +#ifndef _PreComp_ +# include +# include +# include +# if defined(FC_OS_LINUX) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD) +# include +# include +# include +# elif defined(__MINGW32__) +# define WINVER 0x502 // needed for SetDllDirectory +# include +# endif +# include +# include +# include +#endif + +#ifdef FC_OS_WIN32 +# include +#endif + + + +#include "Application.h" +#include "Document.h" + +// FreeCAD Base header +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "GeoFeature.h" +#include "FeatureTest.h" +#include "FeaturePython.h" +#include "ComplexGeoData.h" +#include "Property.h" +#include "PropertyContainer.h" +#include "PropertyUnits.h" +#include "PropertyFile.h" +#include "PropertyLinks.h" +#include "PropertyPythonObject.h" +#include "PropertyExpressionEngine.h" +#include "Document.h" +#include "DocumentObjectGroup.h" +#include "DocumentObjectFileIncluded.h" +#include "InventorObject.h" +#include "VRMLObject.h" +#include "Annotation.h" +#include "MeasureDistance.h" +#include "Placement.h" +#include "Plane.h" +#include "MaterialObject.h" +#include "Expression.h" + +// If you stumble here, run the target "BuildExtractRevision" on Windows systems +// or the Python script "SubWCRev.py" on Linux based systems which builds +// src/Build/Version.h. Or create your own from src/Build/Version.h.in! +#include +#include "Branding.h" + +#include +#include +#include +#include +#include +#include +#include + +using namespace App; +using namespace std; +using namespace boost; +using namespace boost::program_options; + + +// scriptings (scripts are build in but can be overridden by command line option) +#include "InitScript.h" +#include "TestScript.h" + +#ifdef _MSC_VER // New handler for Microsoft Visual C++ compiler +# include +# include // VC exception handling +#else // Ansi C/C++ new handler +# include +#endif + + +//using Base::GetConsole; +using namespace Base; +using namespace App; +using namespace std; + + +//========================================================================== +// Application +//========================================================================== + +ParameterManager *App::Application::_pcSysParamMngr; +ParameterManager *App::Application::_pcUserParamMngr; +Base::ConsoleObserverStd *Application::_pConsoleObserverStd =0; +Base::ConsoleObserverFile *Application::_pConsoleObserverFile =0; + +AppExport std::map Application::mConfig; +BaseExport extern PyObject* Base::BaseExceptionFreeCADError; + + +//************************************************************************** +// Construction and destruction + +PyDoc_STRVAR(FreeCAD_doc, + "The functions in the FreeCAD module allow working with documents.\n" + "The FreeCAD instance provides a list of references of documents which\n" + "can be addressed by a string. Hence the document name must be unique.\n" + "\n" + "The document has the read-only attribute FileName which points to the\n" + "file the document should be stored to.\n" + ); + +PyDoc_STRVAR(Console_doc, + "FreeCAD Console\n" + ); + +Application::Application(ParameterManager * /*pcSysParamMngr*/, + ParameterManager * /*pcUserParamMngr*/, + std::map &mConfig) + ://_pcSysParamMngr(pcSysParamMngr), + //_pcUserParamMngr(pcUserParamMngr), + _mConfig(mConfig), + _pActiveDoc(0) +{ + //_hApp = new ApplicationOCC; + mpcPramManager["System parameter"] = _pcSysParamMngr; + mpcPramManager["User parameter"] = _pcUserParamMngr; + + + // setting up Python binding + Base::PyGILStateLocker lock; + PyObject* pAppModule = Py_InitModule3("FreeCAD", Application::Methods, FreeCAD_doc); + Py::Module(pAppModule).setAttr(std::string("ActiveDocument"),Py::None()); + + PyObject* pConsoleModule = Py_InitModule3("__FreeCADConsole__", ConsoleSingleton::Methods, Console_doc); + + // introducing additional classes + + // NOTE: To finish the initialization of our own type objects we must + // call PyType_Ready, otherwise we run into a segmentation fault, later on. + // This function is responsible for adding inherited slots from a type's base class. + if (PyType_Ready(&Base::VectorPy::Type) < 0) return; + union PyType_Object pyVecType = {&Base::VectorPy::Type}; + PyModule_AddObject(pAppModule, "Vector", pyVecType.o); + + if (PyType_Ready(&Base::MatrixPy::Type) < 0) return; + union PyType_Object pyMtxType = {&Base::MatrixPy::Type}; + PyModule_AddObject(pAppModule, "Matrix", pyMtxType.o); + + if (PyType_Ready(&Base::BoundBoxPy::Type) < 0) return; + union PyType_Object pyBoundBoxType = {&Base::BoundBoxPy::Type}; + PyModule_AddObject(pAppModule, "BoundBox", pyBoundBoxType.o); + + if (PyType_Ready(&Base::PlacementPy::Type) < 0) return; + union PyType_Object pyPlacementPyType = {&Base::PlacementPy::Type}; + PyModule_AddObject(pAppModule, "Placement", pyPlacementPyType.o); + + if (PyType_Ready(&Base::RotationPy::Type) < 0) return; + union PyType_Object pyRotationPyType = {&Base::RotationPy::Type}; + PyModule_AddObject(pAppModule, "Rotation", pyRotationPyType.o); + + if (PyType_Ready(&Base::AxisPy::Type) < 0) return; + union PyType_Object pyAxisPyType = {&Base::AxisPy::Type}; + PyModule_AddObject(pAppModule, "Axis", pyAxisPyType.o); + + // Note: Create an own module 'Base' which should provide the python + // binding classes from the base module. At a later stage we should + // remove these types from the FreeCAD module. + PyObject* pBaseModule = Py_InitModule3("__FreeCADBase__", NULL, + "The Base module contains the classes for the geometric basics\n" + "like vector, matrix, bounding box, placement, rotation, axis, ..."); + Base::BaseExceptionFreeCADError = PyErr_NewException( + "Base.FreeCADError", PyExc_RuntimeError, NULL); + Py_INCREF(Base::BaseExceptionFreeCADError); + PyModule_AddObject(pBaseModule, "FreeCADError", + Base::BaseExceptionFreeCADError); + Base::Interpreter().addType(&Base::VectorPy ::Type,pBaseModule,"Vector"); + Base::Interpreter().addType(&Base::MatrixPy ::Type,pBaseModule,"Matrix"); + Base::Interpreter().addType(&Base::BoundBoxPy ::Type,pBaseModule,"BoundBox"); + Base::Interpreter().addType(&Base::PlacementPy ::Type,pBaseModule,"Placement"); + Base::Interpreter().addType(&Base::RotationPy ::Type,pBaseModule,"Rotation"); + Base::Interpreter().addType(&Base::AxisPy ::Type,pBaseModule,"Axis"); + + //insert Base and Console + Py_INCREF(pBaseModule); + PyModule_AddObject(pAppModule, "Base", pBaseModule); + Py_INCREF(pConsoleModule); + PyModule_AddObject(pAppModule, "Console", pConsoleModule); + + //insert Units module + PyObject* pUnitsModule = Py_InitModule3("Units", Base::UnitsApi::Methods, + "The Unit API"); + Base::Interpreter().addType(&Base::QuantityPy ::Type,pUnitsModule,"Quantity"); + // make sure to set the 'nb_true_divide' slot + Base::QuantityPy::Type.tp_as_number->nb_true_divide = Base::QuantityPy::Type.tp_as_number->nb_divide; + Base::Interpreter().addType(&Base::UnitPy ::Type,pUnitsModule,"Unit"); + + Py_INCREF(pUnitsModule); + PyModule_AddObject(pAppModule, "Units", pUnitsModule); + + Base::ProgressIndicatorPy::init_type(); + Base::Interpreter().addType(Base::ProgressIndicatorPy::type_object(), + pBaseModule,"ProgressIndicator"); +} + +Application::~Application() +{ +} + +//************************************************************************** +// Interface + +/// get called by the document when the name is changing +void Application::renameDocument(const char *OldName, const char *NewName) +{ + std::map::iterator pos; + pos = DocMap.find(OldName); + + if (pos != DocMap.end()) { + Document* temp; + temp = pos->second; + DocMap.erase(pos); + DocMap[NewName] = temp; + signalRenameDocument(*temp); + } + else { + throw Base::Exception("Application::renameDocument(): no document with this name to rename!"); + } +} + +Document* Application::newDocument(const char * Name, const char * UserName) +{ + // get a valid name anyway! + if (!Name || Name[0] == '\0') + Name = "Unnamed"; + string name = getUniqueDocumentName(Name); + + std::string userName; + if (UserName && UserName[0] != '\0') { + userName = UserName; + } + else { + userName = Name; + std::vector names; + names.reserve(DocMap.size()); + std::map::const_iterator pos; + for (pos = DocMap.begin();pos != DocMap.end();++pos) { + names.push_back(pos->second->Label.getValue()); + } + + if (!names.empty()) + userName = Base::Tools::getUniqueName(userName, names); + } + + // create the FreeCAD document + auto_ptr newDoc(new Document() ); + + // add the document to the internal list + DocMap[name] = newDoc.release(); // now owned by the Application + _pActiveDoc = DocMap[name]; + + + // connect the signals to the application for the new document + _pActiveDoc->signalNewObject.connect(boost::bind(&App::Application::slotNewObject, this, _1)); + _pActiveDoc->signalDeletedObject.connect(boost::bind(&App::Application::slotDeletedObject, this, _1)); + _pActiveDoc->signalChangedObject.connect(boost::bind(&App::Application::slotChangedObject, this, _1, _2)); + _pActiveDoc->signalRelabelObject.connect(boost::bind(&App::Application::slotRelabelObject, this, _1)); + _pActiveDoc->signalActivatedObject.connect(boost::bind(&App::Application::slotActivatedObject, this, _1)); + _pActiveDoc->signalUndo.connect(boost::bind(&App::Application::slotUndoDocument, this, _1)); + _pActiveDoc->signalRedo.connect(boost::bind(&App::Application::slotRedoDocument, this, _1)); + + // make sure that the active document is set in case no GUI is up + { + Base::PyGILStateLocker lock; + Py::Object active(_pActiveDoc->getPyObject(), true); + Py::Module("FreeCAD").setAttr(std::string("ActiveDocument"),active); + } + + signalNewDocument(*_pActiveDoc); + + // set the UserName after notifying all observers + _pActiveDoc->Label.setValue(userName); + + return _pActiveDoc; +} + +bool Application::closeDocument(const char* name) +{ + map::iterator pos = DocMap.find( name ); + if (pos == DocMap.end()) // no such document + return false; + + // Trigger observers before removing the document from the internal map. + // Some observers might rely on this document still being there. + signalDeleteDocument(*pos->second); + + // For exception-safety use a smart pointer + if (_pActiveDoc == pos->second) + setActiveDocument((Document*)0); + auto_ptr delDoc (pos->second); + DocMap.erase( pos ); + + // Trigger observers after removing the document from the internal map. + signalDeletedDocument(); + + return true; +} + +void Application::closeAllDocuments(void) +{ + std::map::iterator pos; + while((pos = DocMap.begin()) != DocMap.end()) + closeDocument(pos->first.c_str()); +} + +App::Document* Application::getDocument(const char *Name) const +{ + std::map::const_iterator pos; + + pos = DocMap.find(Name); + + if (pos == DocMap.end()) + return 0; + + return pos->second; +} + +const char * Application::getDocumentName(const App::Document* doc) const +{ + for (std::map::const_iterator it = DocMap.begin(); it != DocMap.end(); ++it) + if (it->second == doc) + return it->first.c_str(); + + return 0; +} + +std::vector Application::getDocuments() const +{ + std::vector docs; + for (std::map::const_iterator it = DocMap.begin(); it != DocMap.end(); ++it) + docs.push_back(it->second); + return docs; +} + +std::string Application::getUniqueDocumentName(const char *Name) const +{ + if (!Name || *Name == '\0') + return std::string(); + std::string CleanName = Base::Tools::getIdentifier(Name); + + // name in use? + std::map::const_iterator pos; + pos = DocMap.find(CleanName); + + if (pos == DocMap.end()) { + // if not, name is OK + return CleanName; + } + else { + std::vector names; + names.reserve(DocMap.size()); + for (pos = DocMap.begin();pos != DocMap.end();++pos) { + names.push_back(pos->first); + } + return Base::Tools::getUniqueName(CleanName, names); + } +} + +Document* Application::openDocument(const char * FileName) +{ + FileInfo File(FileName); + + if (!File.exists()) { + std::stringstream str; + str << "File '" << FileName << "' does not exist!"; + throw Base::Exception(str.str().c_str()); + } + + // Before creating a new document we check whether the document is already open + std::string filepath = File.filePath(); + for (std::map::iterator it = DocMap.begin(); it != DocMap.end(); ++it) { + // get unique path separators + std::string fi = FileInfo(it->second->FileName.getValue()).filePath(); + if (filepath == fi) { + std::stringstream str; + str << "The project '" << FileName << "' is already open!"; + throw Base::Exception(str.str().c_str()); + } + } + + // Use the same name for the internal and user name. + // The file name is UTF-8 encoded which means that the internal name will be modified + // to only contain valid ASCII characters but the user name will be kept. + Document* newDoc = newDocument(File.fileNamePure().c_str(), File.fileNamePure().c_str()); + + newDoc->FileName.setValue(File.filePath()); + + // read the document + newDoc->restore(); + + return newDoc; +} + +Document* Application::getActiveDocument(void) const +{ + return _pActiveDoc; +} + +void Application::setActiveDocument(Document* pDoc) +{ + _pActiveDoc = pDoc; + + // make sure that the active document is set in case no GUI is up + if (pDoc) { + Base::PyGILStateLocker lock; + Py::Object active(pDoc->getPyObject(), true); + Py::Module("FreeCAD").setAttr(std::string("ActiveDocument"),active); + } + else { + Base::PyGILStateLocker lock; + Py::Module("FreeCAD").setAttr(std::string("ActiveDocument"),Py::None()); + } + + if (pDoc) + signalActiveDocument(*pDoc); +} + +void Application::setActiveDocument(const char *Name) +{ + // If no active document is set, resort to a default. + if (*Name == '\0') { + _pActiveDoc = 0; + return; + } + + std::map::iterator pos; + pos = DocMap.find(Name); + + if (pos != DocMap.end()) { + setActiveDocument(pos->second); + } + else { + std::stringstream s; + s << "Try to activate unknown document '" << Name << "'"; + throw Base::Exception(s.str()); + } +} + +const char* Application::getHomePath(void) const +{ + return _mConfig["AppHomePath"].c_str(); +} + +const char* Application::getExecutableName(void) const +{ + return _mConfig["ExeName"].c_str(); +} + +std::string Application::getTempPath() +{ + return mConfig["AppTempPath"]; +} + +std::string Application::getTempFileName(const char* FileName) +{ + return Base::FileInfo::getTempFileName(FileName, getTempPath().c_str()); +} + +std::string Application::getUserAppDataDir() +{ + return mConfig["UserAppData"]; +} + +std::string Application::getUserMacroDir() +{ + std::string path("Macro/"); + return mConfig["UserAppData"] + path; +} + +std::string Application::getResourceDir() +{ +#ifdef RESOURCEDIR + std::string path(RESOURCEDIR); + path.append("/"); + QDir dir(QString::fromUtf8(RESOURCEDIR)); + if (dir.isAbsolute()) + return path; + else + return mConfig["AppHomePath"] + path; +#else + return mConfig["AppHomePath"]; +#endif +} + +std::string Application::getHelpDir() +{ +#ifdef DOCDIR + std::string path(DOCDIR); + path.append("/"); + QDir dir(QString::fromUtf8(DOCDIR)); + if (dir.isAbsolute()) + return path; + else + return mConfig["AppHomePath"] + path; +#else + return mConfig["DocPath"]; +#endif +} + +ParameterManager & Application::GetSystemParameter(void) +{ + return *_pcSysParamMngr; +} + +ParameterManager & Application::GetUserParameter(void) +{ + return *_pcUserParamMngr; +} + +ParameterManager * Application::GetParameterSet(const char* sName) const +{ + std::map::const_iterator it = mpcPramManager.find(sName); + if ( it != mpcPramManager.end() ) + return it->second; + else + return 0; +} + +const std::map & Application::GetParameterSetList(void) const +{ + return mpcPramManager; +} + +void Application::AddParameterSet(const char* sName) +{ + std::map::const_iterator it = mpcPramManager.find(sName); + if ( it != mpcPramManager.end() ) + return; + mpcPramManager[sName] = new ParameterManager(); +} + +void Application::RemoveParameterSet(const char* sName) +{ + std::map::iterator it = mpcPramManager.find(sName); + // Must not delete user or system parameter + if ( it == mpcPramManager.end() || it->second == _pcUserParamMngr || it->second == _pcSysParamMngr ) + return; + delete it->second; + mpcPramManager.erase(it); +} + +Base::Reference Application::GetParameterGroupByPath(const char* sName) +{ + std::string cName = sName,cTemp; + + std::string::size_type pos = cName.find(':'); + + // is there a path seperator ? + if (pos == std::string::npos) { + throw Base::Exception("Application::GetParameterGroupByPath() no parameter set name specified"); + } + // assigning the parameter set name + cTemp.assign(cName,0,pos); + cName.erase(0,pos+1); + + // test if name is valid + std::map::iterator It = mpcPramManager.find(cTemp.c_str()); + if (It == mpcPramManager.end()) + throw Base::Exception("Application::GetParameterGroupByPath() unknown parameter set name specified"); + + return It->second->GetGroup(cName.c_str()); +} + +void Application::addImportType(const char* Type, const char* ModuleName) +{ + FileTypeItem item; + item.filter = Type; + item.module = ModuleName; + + // Extract each filetype from 'Type' literal + std::string::size_type pos = item.filter.find("*."); + while ( pos != std::string::npos ) { + std::string::size_type next = item.filter.find_first_of(" )", pos+1); + std::string::size_type len = next-pos-2; + std::string type = item.filter.substr(pos+2,len); + item.types.push_back(type); + pos = item.filter.find("*.", next); + } + + // Due to branding stuff replace "FreeCAD" with the branded application name + if (strncmp(Type, "FreeCAD", 7) == 0) { + std::string AppName = Config()["ExeName"]; + AppName += item.filter.substr(7); + item.filter = AppName; + // put to the front of the array + _mImportTypes.insert(_mImportTypes.begin(),item); + } + else { + _mImportTypes.push_back(item); + } +} + +std::vector Application::getImportModules(const char* Type) const +{ + std::vector modules; + for (std::vector::const_iterator it = _mImportTypes.begin(); it != _mImportTypes.end(); ++it) { + const std::vector& types = it->types; + for (std::vector::const_iterator jt = types.begin(); jt != types.end(); ++jt) { +#ifdef __GNUC__ + if (strcasecmp(Type,jt->c_str()) == 0) +#else + if (_stricmp(Type,jt->c_str()) == 0) +#endif + modules.push_back(it->module); + } + } + + return modules; +} + +std::vector Application::getImportModules() const +{ + std::vector modules; + for (std::vector::const_iterator it = _mImportTypes.begin(); it != _mImportTypes.end(); ++it) + modules.push_back(it->module); + std::sort(modules.begin(), modules.end()); + modules.erase(std::unique(modules.begin(), modules.end()), modules.end()); + return modules; +} + +std::vector Application::getImportTypes(const char* Module) const +{ + std::vector types; + for (std::vector::const_iterator it = _mImportTypes.begin(); it != _mImportTypes.end(); ++it) { +#ifdef __GNUC__ + if (strcasecmp(Module,it->module.c_str()) == 0) +#else + if (_stricmp(Module,it->module.c_str()) == 0) +#endif + types.insert(types.end(), it->types.begin(), it->types.end()); + } + + return types; +} + +std::vector Application::getImportTypes(void) const +{ + std::vector types; + for (std::vector::const_iterator it = _mImportTypes.begin(); it != _mImportTypes.end(); ++it) { + types.insert(types.end(), it->types.begin(), it->types.end()); + } + + std::sort(types.begin(), types.end()); + types.erase(std::unique(types.begin(), types.end()), types.end()); + + return types; +} + +std::map Application::getImportFilters(const char* Type) const +{ + std::map moduleFilter; + for (std::vector::const_iterator it = _mImportTypes.begin(); it != _mImportTypes.end(); ++it) { + const std::vector& types = it->types; + for (std::vector::const_iterator jt = types.begin(); jt != types.end(); ++jt) { +#ifdef __GNUC__ + if (strcasecmp(Type,jt->c_str()) == 0) +#else + if (_stricmp(Type,jt->c_str()) == 0) +#endif + moduleFilter[it->filter] = it->module; + } + } + + return moduleFilter; +} + +std::map Application::getImportFilters(void) const +{ + std::map filter; + for (std::vector::const_iterator it = _mImportTypes.begin(); it != _mImportTypes.end(); ++it) { + filter[it->filter] = it->module; + } + + return filter; +} + +void Application::addExportType(const char* Type, const char* ModuleName) +{ + FileTypeItem item; + item.filter = Type; + item.module = ModuleName; + + // Extract each filetype from 'Type' literal + std::string::size_type pos = item.filter.find("*."); + while ( pos != std::string::npos ) { + std::string::size_type next = item.filter.find_first_of(" )", pos+1); + std::string::size_type len = next-pos-2; + std::string type = item.filter.substr(pos+2,len); + item.types.push_back(type); + pos = item.filter.find("*.", next); + } + + // Due to branding stuff replace "FreeCAD" with the branded application name + if (strncmp(Type, "FreeCAD", 7) == 0) { + std::string AppName = Config()["ExeName"]; + AppName += item.filter.substr(7); + item.filter = AppName; + // put to the front of the array + _mExportTypes.insert(_mExportTypes.begin(),item); + } + else { + _mExportTypes.push_back(item); + } +} + +std::vector Application::getExportModules(const char* Type) const +{ + std::vector modules; + for (std::vector::const_iterator it = _mExportTypes.begin(); it != _mExportTypes.end(); ++it) { + const std::vector& types = it->types; + for (std::vector::const_iterator jt = types.begin(); jt != types.end(); ++jt) { +#ifdef __GNUC__ + if (strcasecmp(Type,jt->c_str()) == 0) +#else + if (_stricmp(Type,jt->c_str()) == 0) +#endif + modules.push_back(it->module); + } + } + + return modules; +} + +std::vector Application::getExportModules() const +{ + std::vector modules; + for (std::vector::const_iterator it = _mExportTypes.begin(); it != _mExportTypes.end(); ++it) + modules.push_back(it->module); + std::sort(modules.begin(), modules.end()); + modules.erase(std::unique(modules.begin(), modules.end()), modules.end()); + return modules; +} + +std::vector Application::getExportTypes(const char* Module) const +{ + std::vector types; + for (std::vector::const_iterator it = _mExportTypes.begin(); it != _mExportTypes.end(); ++it) { +#ifdef __GNUC__ + if (strcasecmp(Module,it->module.c_str()) == 0) +#else + if (_stricmp(Module,it->module.c_str()) == 0) +#endif + types.insert(types.end(), it->types.begin(), it->types.end()); + } + + return types; +} + +std::vector Application::getExportTypes(void) const +{ + std::vector types; + for (std::vector::const_iterator it = _mExportTypes.begin(); it != _mExportTypes.end(); ++it) { + types.insert(types.end(), it->types.begin(), it->types.end()); + } + + std::sort(types.begin(), types.end()); + types.erase(std::unique(types.begin(), types.end()), types.end()); + + return types; +} + +std::map Application::getExportFilters(const char* Type) const +{ + std::map moduleFilter; + for (std::vector::const_iterator it = _mExportTypes.begin(); it != _mExportTypes.end(); ++it) { + const std::vector& types = it->types; + for (std::vector::const_iterator jt = types.begin(); jt != types.end(); ++jt) { +#ifdef __GNUC__ + if (strcasecmp(Type,jt->c_str()) == 0) +#else + if (_stricmp(Type,jt->c_str()) == 0) +#endif + moduleFilter[it->filter] = it->module; + } + } + + return moduleFilter; +} + +std::map Application::getExportFilters(void) const +{ + std::map filter; + for (std::vector::const_iterator it = _mExportTypes.begin(); it != _mExportTypes.end(); ++it) { + filter[it->filter] = it->module; + } + + return filter; +} + +//************************************************************************** +// signaling +void Application::slotNewObject(const App::DocumentObject&O) +{ + this->signalNewObject(O); +} + +void Application::slotDeletedObject(const App::DocumentObject&O) +{ + this->signalDeletedObject(O); +} + +void Application::slotChangedObject(const App::DocumentObject&O, const App::Property& P) +{ + this->signalChangedObject(O,P); +} + +void Application::slotRelabelObject(const App::DocumentObject&O) +{ + this->signalRelabelObject(O); +} + +void Application::slotActivatedObject(const App::DocumentObject&O) +{ + this->signalActivatedObject(O); +} + +void Application::slotUndoDocument(const App::Document& d) +{ + this->signalUndoDocument(d); +} + +void Application::slotRedoDocument(const App::Document& d) +{ + this->signalRedoDocument(d); +} + +//************************************************************************** +// Init, Destruct and singleton + +Application * Application::_pcSingleton = 0; + +int Application::_argc; +char ** Application::_argv; + + +void Application::destruct(void) +{ + // saving system parameter + Console().Log("Saving system parameter...\n"); + _pcSysParamMngr->SaveDocument(mConfig["SystemParameter"].c_str()); + // saving the User parameter + Console().Log("Saving system parameter...done\n"); + Console().Log("Saving user parameter...\n"); + _pcUserParamMngr->SaveDocument(mConfig["UserParameter"].c_str()); + Console().Log("Saving user parameter...done\n"); + // clean up + delete _pcSysParamMngr; + delete _pcUserParamMngr; + + // not initialized or doubel destruct! + assert(_pcSingleton); + delete _pcSingleton; + + // We must detach from console and delete the observer to save our file + destructObserver(); + + Base::Interpreter().finalize(); + + ScriptFactorySingleton::Destruct(); + InterpreterSingleton::Destruct(); + Base::Type::destruct(); +} + +void Application::destructObserver(void) +{ + if ( _pConsoleObserverFile ) { + Console().DetachObserver(_pConsoleObserverFile); + delete _pConsoleObserverFile; + _pConsoleObserverFile = 0; + } + if ( _pConsoleObserverStd ) { + Console().DetachObserver(_pConsoleObserverStd); + delete _pConsoleObserverStd; + _pConsoleObserverStd = 0; + } +} + +/** freecadNewHandler() + * prints an error message and throws an exception + */ +#ifdef _MSC_VER // New handler for Microsoft Visual C++ compiler +int __cdecl freecadNewHandler(size_t size ) +{ + // throw an exception + throw Base::MemoryException(); + return 0; +} +#else // Ansi C/C++ new handler +static void freecadNewHandler () +{ + // throw an exception + throw Base::MemoryException(); +} +#endif + +void segmentation_fault_handler(int sig) +{ + switch (sig) { + case SIGSEGV: + std::cerr << "Illegal storage access..." << std::endl; +#if !defined(_DEBUG) + throw Base::Exception("Illegal storage access! Please save your work under a new file name and restart the application!"); +#endif + break; + case SIGABRT: + std::cerr << "Abnormal program termination..." << std::endl; +#if !defined(_DEBUG) + throw Base::Exception("Break signal occoured"); +#endif + break; + default: + std::cerr << "Unknown error occurred..." << std::endl; + break; + } +} + +void my_terminate_handler() +{ + std::cerr << "Terminating..." << std::endl; +} + +void unexpection_error_handler() +{ + std::cerr << "Unexpected error occurred..." << std::endl; + // try to throw an exception and give the user chance to save their work +#if !defined(_DEBUG) + throw Base::Exception("Unexpected error occurred! Please save your work under a new file name and restart the application!"); +#endif + + terminate(); +} + +#ifdef _MSC_VER // Microsoft compiler + +void my_trans_func( unsigned int code, EXCEPTION_POINTERS* pExp ) +{ + + //switch (code) + //{ + // case FLT_DIVIDE_BY_ZERO : + // //throw CMyFunkyDivideByZeroException(code, pExp); + // throw Base::Exception("Devision by zero!"); + // break; + //} + + // general C++ SEH exception for things we don't need to handle separately.... + throw Base::Exception("my_trans_func()"); +} +#endif +void Application::init(int argc, char ** argv) +{ + try { + // install our own new handler +#ifdef _MSC_VER // Microsoft compiler + _set_new_handler ( freecadNewHandler ); // Setup new handler + _set_new_mode( 1 ); // Re-route malloc failures to new handler ! +#else // Ansi compiler + std::set_new_handler (freecadNewHandler); // ANSI new handler +#endif + // if an unexpected crash occurs we can install a handler function to + // write some additional information +#ifdef _MSC_VER // Microsoft compiler + std::signal(SIGSEGV,segmentation_fault_handler); + std::signal(SIGABRT,segmentation_fault_handler); + std::set_terminate(my_terminate_handler); + std::set_unexpected(unexpection_error_handler); +// _set_se_translator(my_trans_func); +#endif + + initTypes(); + +#if (BOOST_VERSION < 104600) || (BOOST_FILESYSTEM_VERSION == 2) + boost::filesystem::path::default_name_check(boost::filesystem::no_check); +#endif + + initConfig(argc,argv); + initApplication(); + } + catch (...) { + // force the log to flush + destructObserver(); + throw; + } +} + +void Application::initTypes(void) +{ + // Base types + Base::Type ::init(); + Base::BaseClass ::init(); + Base::Exception ::init(); + Base::Persistence ::init(); + + // Complex data classes + Data::ComplexGeoData ::init(); + Data::Segment ::init(); + + // Properties + App ::Property ::init(); + App ::PropertyContainer ::init(); + App ::PropertyLists ::init(); + App ::PropertyBool ::init(); + App ::PropertyBoolList ::init(); + App ::PropertyFloat ::init(); + App ::PropertyFloatList ::init(); + App ::PropertyFloatConstraint ::init(); + App ::PropertyQuantity ::init(); + App ::PropertyQuantityConstraint::init(); + App ::PropertyAngle ::init(); + App ::PropertyDistance ::init(); + App ::PropertyLength ::init(); + App ::PropertySpeed ::init(); + App ::PropertyAcceleration ::init(); + App ::PropertyForce ::init(); + App ::PropertyPressure ::init(); + App ::PropertyInteger ::init(); + App ::PropertyIntegerConstraint ::init(); + App ::PropertyPercent ::init(); + App ::PropertyEnumeration ::init(); + App ::PropertyIntegerList ::init(); + App ::PropertyIntegerSet ::init(); + App ::PropertyMap ::init(); + App ::PropertyString ::init(); + App ::PropertyUUID ::init(); + App ::PropertyFont ::init(); + App ::PropertyStringList ::init(); + App ::PropertyLink ::init(); + App ::PropertyLinkSub ::init(); + App ::PropertyLinkList ::init(); + App ::PropertyLinkSubList ::init(); + App ::PropertyMatrix ::init(); + App ::PropertyVector ::init(); + App ::PropertyVectorDistance ::init(); + App ::PropertyVectorList ::init(); + App ::PropertyPlacement ::init(); + App ::PropertyPlacementLink ::init(); + App ::PropertyGeometry ::init(); + App ::PropertyComplexGeoData ::init(); + App ::PropertyColor ::init(); + App ::PropertyColorList ::init(); + App ::PropertyMaterial ::init(); + App ::PropertyPath ::init(); + App ::PropertyFile ::init(); + App ::PropertyFileIncluded ::init(); + App ::PropertyPythonObject ::init(); + App ::PropertyExpressionEngine ::init(); + + // Document classes + App ::DocumentObject ::init(); + App ::GeoFeature ::init(); + App ::FeatureTest ::init(); + App ::FeatureTestException ::init(); + App ::FeaturePython ::init(); + App ::GeometryPython ::init(); + App ::Document ::init(); + App ::DocumentObjectGroup ::init(); + App ::DocumentObjectGroupPython ::init(); + App ::DocumentObjectFileIncluded::init(); + App ::InventorObject ::init(); + App ::VRMLObject ::init(); + App ::Annotation ::init(); + App ::AnnotationLabel ::init(); + App ::MeasureDistance ::init(); + App ::MaterialObject ::init(); + App ::MaterialObjectPython ::init(); + App ::Placement ::init(); + App ::Plane ::init(); + + // Expression classes + App ::Expression ::init(); + App ::UnitExpression ::init(); + App ::NumberExpression ::init(); + App ::ConstantExpression ::init(); + App ::OperatorExpression ::init(); + App ::VariableExpression ::init(); + App ::ConditionalExpression ::init(); + App ::StringExpression ::init(); + App ::FunctionExpression ::init(); + +} + +void Application::initConfig(int argc, char ** argv) +{ + // find the home path.... + mConfig["AppHomePath"] = FindHomePath(argv[0]); + + // Version of the application extracted from SubWCRef into src/Build/Version.h + // We only set these keys if not yet defined. Therefore it suffices to search + // only for 'BuildVersionMajor'. + if (App::Application::Config().find("BuildVersionMajor") == App::Application::Config().end()) { + std::stringstream str; str << FCVersionMajor << "." << FCVersionMinor; + App::Application::Config()["ExeVersion" ] = str.str(); + App::Application::Config()["BuildVersionMajor" ] = FCVersionMajor; + App::Application::Config()["BuildVersionMinor" ] = FCVersionMinor; + App::Application::Config()["BuildRevision" ] = FCRevision; + App::Application::Config()["BuildRepositoryURL" ] = FCRepositoryURL; + App::Application::Config()["BuildRevisionDate" ] = FCRevisionDate; +#if defined(FCRepositoryHash) + App::Application::Config()["BuildRevisionHash" ] = FCRepositoryHash; +#endif +#if defined(FCRepositoryBranch) + App::Application::Config()["BuildRevisionBranch"] = FCRepositoryBranch; +#endif + } + + _argc = argc; + _argv = argv; + + // Now it's time to read-in the file branding.xml if it exists + Branding brand; + QString binDir = QString::fromUtf8((mConfig["AppHomePath"] + "bin").c_str()); + QFileInfo fi(binDir, QString::fromLatin1("branding.xml")); + if (brand.readFile(fi.absoluteFilePath())) { + Branding::XmlConfig cfg = brand.getUserDefines(); + for (Branding::XmlConfig::iterator it = cfg.begin(); it != cfg.end(); ++it) { + App::Application::Config()[it.key()] = it.value(); + } + } + + // extract home paths + ExtractUserPath(); + +# ifdef FC_DEBUG + mConfig["Debug"] = "1"; +# else + mConfig["Debug"] = "0"; +# endif + + // init python + mConfig["PythonSearchPath"] = Interpreter().init(argc,argv); + + // Parse the options which have impact to the init process + ParseOptions(argc,argv); + + // Init console =========================================================== + Base::PyGILStateLocker lock; + _pConsoleObserverStd = new ConsoleObserverStd(); + Console().AttachObserver(_pConsoleObserverStd); + if (mConfig["Verbose"] == "Strict") + Console().SetMode(ConsoleSingleton::Verbose); + + // file logging Init =========================================================== + if (mConfig["LoggingFile"] == "1") { + _pConsoleObserverFile = new ConsoleObserverFile(mConfig["LoggingFileName"].c_str()); + Console().AttachObserver(_pConsoleObserverFile); + } + else + _pConsoleObserverFile = 0; + + // Banner =========================================================== + if (!(mConfig["Verbose"] == "Strict")) + Console().Message("%s %s, Libs: %s.%sR%s\n%s",mConfig["ExeName"].c_str(), + mConfig["ExeVersion"].c_str(), + mConfig["BuildVersionMajor"].c_str(), + mConfig["BuildVersionMinor"].c_str(), + mConfig["BuildRevision"].c_str(), + mConfig["CopyrightInfo"].c_str()); + else + Console().Message("%s %s, Libs: %s.%sB%s\n",mConfig["ExeName"].c_str(), + mConfig["ExeVersion"].c_str(), + mConfig["BuildVersionMajor"].c_str(), + mConfig["BuildVersionMinor"].c_str(), + mConfig["BuildRevision"].c_str()); + + LoadParameters(); + + // Set application tmp. directory + mConfig["AppTempPath"] = Base::FileInfo::getTempPath(); + std::string tmpPath = _pcUserParamMngr->GetGroup("BaseApp/Preferences/General")->GetASCII("TempPath"); + Base::FileInfo di(tmpPath); + if (di.exists() && di.isDir()) { + mConfig["AppTempPath"] = tmpPath + "/"; + } + + + // capture python variables + SaveEnv("PYTHONPATH"); + SaveEnv("PYTHONHOME"); + SaveEnv("TCL_LIBRARY"); + SaveEnv("TCLLIBPATH"); + + // capture CasCade variables + SaveEnv("CSF_MDTVFontDirectory"); + SaveEnv("CSF_MDTVTexturesDirectory"); + SaveEnv("CSF_UnitsDefinition"); + SaveEnv("CSF_UnitsLexicon"); + SaveEnv("CSF_StandardDefaults"); + SaveEnv("CSF_PluginDefaults"); + SaveEnv("CSF_LANGUAGE"); + SaveEnv("CSF_SHMessage"); + SaveEnv("CSF_XCAFDefaults"); + SaveEnv("CSF_GraphicShr"); + SaveEnv("CSF_IGESDefaults"); + SaveEnv("CSF_STEPDefaults"); + + // capture path + SaveEnv("PATH"); + logStatus(); +} + +void Application::SaveEnv(const char* s) +{ + char *c = getenv(s); + if (c) + mConfig[s] = c; +} + +void Application::initApplication(void) +{ + // interpreter and Init script ========================================================== + // register scripts + new ScriptProducer( "FreeCADInit", FreeCADInit ); + new ScriptProducer( "FreeCADTest", FreeCADTest ); + + // creating the application + if (!(mConfig["Verbose"] == "Strict")) Console().Log("Create Application\n"); + Application::_pcSingleton = new Application(0,0,mConfig); + + // set up Unit system default + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath + ("User parameter:BaseApp/Preferences/Units"); + UnitsApi::setSchema((UnitSystem)hGrp->GetInt("UserSchema",0)); + +#if defined (_DEBUG) + Console().Log("Application is built with debug information\n"); +#endif + + // starting the init script + Console().Log("Run App init script\n"); + Interpreter().runString(Base::ScriptFactory().ProduceScript("FreeCADInit")); +} + +std::list Application::getCmdLineFiles() +{ + std::list files; + + // cycling through all the open files + unsigned short count = 0; + count = atoi(mConfig["OpenFileCount"].c_str()); + std::string File; + + for (unsigned short i=0; i& files) +{ + Base::Console().Log("Init: Processing command line files\n"); + for (std::list::const_iterator it = files.begin(); it != files.end(); ++it) { + Base::FileInfo file(*it); + + Base::Console().Log("Init: Processing file: %s\n",file.filePath().c_str()); + + try { + if (file.hasExtension("fcstd") || file.hasExtension("std")) { + // try to open + Application::_pcSingleton->openDocument(file.filePath().c_str()); + } + else if (file.hasExtension("fcscript") || file.hasExtension("fcmacro")) { + Base::Interpreter().runFile(file.filePath().c_str(), true); + } +<<<<<<< d9efca578bac2e53f02f6d1807be05cf950b405f + else if (file.hasExtension("py")) { + try { + Base::Interpreter().loadModule(file.fileNamePure().c_str()); +======= + else if (File.hasExtension("py")) { + try{ + Base::Interpreter().loadModule(File.fileNamePure().c_str()); +>>>>>>> Run arbitrary scripts from Cmd command line + } + catch(const PyException&) { + // if loading the module does not work, try just running the script (run in __main__) + Base::Interpreter().runFile(file.filePath().c_str(),true); + } + } + else { + std::string ext = file.extension(); + std::vector mods = App::GetApplication().getImportModules(ext.c_str()); + if (!mods.empty()) { + std::string escapedstr = Base::Tools::escapedUnicodeFromUtf8(file.filePath().c_str()); + Base::Interpreter().loadModule(mods.front().c_str()); + Base::Interpreter().runStringArg("import %s",mods.front().c_str()); + Base::Interpreter().runStringArg("%s.open(u\"%s\")",mods.front().c_str(), + escapedstr.c_str()); + Base::Console().Log("Command line open: %s.open(u\"%s\")\n",mods.front().c_str(),escapedstr.c_str()); + } + else { + Console().Warning("File format not supported: %s \n", file.filePath().c_str()); + } + } + } + catch (const Base::SystemExitException&) { + throw; // re-throw to main() function + } + catch (const Base::Exception& e) { + Console().Error("Exception while processing file: %s [%s]\n", file.filePath().c_str(), e.what()); + } + catch (...) { + Console().Error("Unknown exception while processing file: %s \n", file.filePath().c_str()); + } + } +} + +void Application::processCmdLineFiles(void) +{ + // process files passed to command line + std::list files = getCmdLineFiles(); + processFiles(files); + + if (files.empty()) { + if (mConfig["RunMode"] == "Exit") + mConfig["RunMode"] = "Cmd"; + } + + const std::map& cfg = Application::Config(); + std::map::const_iterator it = cfg.find("SaveFile"); + if (it != cfg.end()) { + std::string output = it->second; + Base::FileInfo fi(output); + std::string ext = fi.extension(); + try { + std::vector mods = App::GetApplication().getExportModules(ext.c_str()); + if (!mods.empty()) { + Base::Interpreter().loadModule(mods.front().c_str()); + Base::Interpreter().runStringArg("import %s",mods.front().c_str()); + Base::Interpreter().runStringArg("%s.export(App.ActiveDocument.Objects, '%s')" + ,mods.front().c_str(),output.c_str()); + } + else { + Console().Warning("File format not supported: %s \n", output.c_str()); + } + } + catch (const Base::Exception& e) { + Console().Error("Exception while saving to file: %s [%s]\n", output.c_str(), e.what()); + } + catch (...) { + Console().Error("Unknown exception while saving to file: %s \n", output.c_str()); + } + } +} + +void Application::runApplication() +{ + // process all files given through command line interface + processCmdLineFiles(); + + if (mConfig["RunMode"] == "Cmd") { + // Run the comandline interface + Interpreter().runCommandLine("FreeCAD Console mode"); + } + else if (mConfig["RunMode"] == "Internal") { + // run internal script + Console().Log("Running internal script:\n"); + Interpreter().runString(Base::ScriptFactory().ProduceScript(mConfig["ScriptFileName"].c_str())); + } + else if (mConfig["RunMode"] == "Exit") { + // geting out + Console().Log("Exiting on purpose\n"); + } + else { + Console().Log("Unknown Run mode (%d) in main()?!?\n\n",mConfig["RunMode"].c_str()); + } +} + +void Application::logStatus() +{ + time_t now; + time(&now); + Console().Log("Time = %s", ctime(&now)); + + for (std::map::iterator It = mConfig.begin();It!= mConfig.end();++It) { + Console().Log("%s = %s\n",It->first.c_str(),It->second.c_str()); + } +} + +void Application::LoadParameters(void) +{ + // create standard parameter sets + _pcSysParamMngr = new ParameterManager(); + _pcUserParamMngr = new ParameterManager(); + + // Init parameter sets =========================================================== + // + if (mConfig.find("UserParameter") == mConfig.end()) + mConfig["UserParameter"] = mConfig["UserAppData"] + "user.cfg"; + if (mConfig.find("SystemParameter") == mConfig.end()) + mConfig["SystemParameter"] = mConfig["UserAppData"] + "system.cfg"; + + + try { + if (_pcSysParamMngr->LoadOrCreateDocument(mConfig["SystemParameter"].c_str()) && !(mConfig["Verbose"] == "Strict")) { + // Configuration file optional when using as Python module + if (!Py_IsInitialized()) { + Console().Warning(" Parameter does not exist, writing initial one\n"); + Console().Message(" This warning normally means that FreeCAD is running for the first time\n" + " or the configuration was deleted or moved. FreeCAD is generating the standard\n" + " configuration.\n"); + } + } + } + catch (const Base::Exception& e) { + // try to proceed with an empty XML document + Base::Console().Error("%s in file %s.\n" + "Continue with an empty configuration.\n", + e.what(), mConfig["SystemParameter"].c_str()); + _pcSysParamMngr->CreateDocument(); + } + + try { + if (_pcUserParamMngr->LoadOrCreateDocument(mConfig["UserParameter"].c_str()) && !(mConfig["Verbose"] == "Strict")) { + // The user parameter file doesn't exist. When an alternative parameter file is offered + // this will be used. + std::map::iterator it = mConfig.find("UserParameterTemplate"); + if (it != mConfig.end()) { + QString path = QString::fromUtf8(it->second.c_str()); + if (QDir(path).isRelative()) { + QString home = QString::fromUtf8(mConfig["AppHomePath"].c_str()); + path = QFileInfo(QDir(home), path).absoluteFilePath(); + } + QFileInfo fi(path); + if (fi.exists()) { + _pcUserParamMngr->LoadDocument(path.toUtf8().constData()); + } + } + + // Configuration file optional when using as Python module + if (!Py_IsInitialized()) { + Console().Warning(" User settings do not exist, writing initial one\n"); + Console().Message(" This warning normally means that FreeCAD is running for the first time\n" + " or your configuration was deleted or moved. The system defaults\n" + " will be automatically generated for you.\n"); + } + } + } + catch (const Base::Exception& e) { + // try to proceed with an empty XML document + Base::Console().Error("%s in file %s.\n" + "Continue with an empty configuration.\n", + e.what(), mConfig["UserParameter"].c_str()); + _pcUserParamMngr->CreateDocument(); + } +} + + +#if defined(_MSC_VER) +// fix weird error while linking boost (all versions of VC) +// VS2010: http://forum.freecadweb.org/viewtopic.php?f=4&t=1886&p=12553&hilit=boost%3A%3Afilesystem%3A%3Aget#p12553 +namespace boost { namespace program_options { std::string arg="arg"; } } +#if (defined (BOOST_VERSION) && (BOOST_VERSION >= 104100)) +namespace boost { namespace program_options { + const unsigned options_description::m_default_line_length = 80; +} } +#endif +#endif + +#if 0 // it seems that SUSE has fixed the broken boost package +// reported for SUSE in issue #0000208 +#if defined(__GNUC__) +#if BOOST_VERSION == 104400 +namespace boost { namespace filesystem { + bool no_check( const std::string & ) { return true; } +} } +#endif +#endif +#endif + +pair customSyntax(const string& s) +{ +#if defined(FC_OS_MACOSX) + if (s.find("-psn_") == 0) + return make_pair(string("psn"), s.substr(5)); +#endif + if (s.find("-display") == 0) + return make_pair(string("display"), string("null")); + else if (s.find("-style") == 0) + return make_pair(string("style"), string("null")); + else if (s.find("-geometry") == 0) + return make_pair(string("geometry"), string("null")); + else if (s.find("-font") == 0) + return make_pair(string("font"), string("null")); + else if (s.find("-fn") == 0) + return make_pair(string("fn"), string("null")); + else if (s.find("-background") == 0) + return make_pair(string("background"), string("null")); + else if (s.find("-bg") == 0) + return make_pair(string("bg"), string("null")); + else if (s.find("-foreground") == 0) + return make_pair(string("foreground"), string("null")); + else if (s.find("-fg") == 0) + return make_pair(string("fg"), string("null")); + else if (s.find("-button") == 0) + return make_pair(string("button"), string("null")); + else if (s.find("-btn") == 0) + return make_pair(string("btn"), string("null")); + else if (s.find("-name") == 0) + return make_pair(string("name"), string("null")); + else if (s.find("-title") == 0) + return make_pair(string("title"), string("null")); + else if (s.find("-visual") == 0) + return make_pair(string("visual"), string("null")); +// else if (s.find("-ncols") == 0) +// return make_pair(string("ncols"), boost::program_options::value(1)); +// else if (s.find("-cmap") == 0) +// return make_pair(string("cmap"), string("null")); + else if ('@' == s[0]) + return std::make_pair(string("response-file"), s.substr(1)); + else + return make_pair(string(), string()); + +} + +// A helper function to simplify the main part. +template +ostream& operator<<(ostream& os, const vector& v) +{ + copy(v.begin(), v.end(), ostream_iterator(cout, " ")); + return os; +} + +void Application::ParseOptions(int ac, char ** av) +{ + // Declare a group of options that will be + // allowed only on the command line + options_description generic("Generic options"); + generic.add_options() + ("version,v", "Prints version string") + ("help,h", "Prints help message") + ("console,c", "Starts in console mode") + ("response-file", value(),"Can be specified with '@name', too") + ("dump-config", "Dumps configuration") + ("get-config", value(), "Prints the value of the requested configuration key") + ; + + // Declare a group of options that will be + // allowed both on the command line and in + // the config file + std::string descr("Writes a log file to:\n"); + descr += mConfig["UserAppData"]; + descr += mConfig["ExeName"]; + descr += ".log"; + boost::program_options::options_description config("Configuration"); + config.add_options() + //("write-log,l", value(), "write a log file") + ("write-log,l", descr.c_str()) + ("log-file", value(), "Unlike to --write-log this allows to log to an arbitrary file") + ("user-cfg,u", value(),"User config file to load/save user settings") + ("system-cfg,s", value(),"Systen config file to load/save system settings") + ("run-test,t", value() ,"Test level") + ("module-path,M", value< vector >()->composing(),"Additional module paths") + ("python-path,P", value< vector >()->composing(),"Additional python paths") + ("single-instance", "Allow to run a single instance of the application") + ; + + + // Hidden options, will be allowed both on the command line and + // in the config file, but will not be shown to the user. + boost::program_options::options_description hidden("Hidden options"); + hidden.add_options() + ("input-file", boost::program_options::value< vector >(), "input file") + ("output", boost::program_options::value(),"output file") + ("hidden", "don't show the main window") + // this are to ignore for the window system (QApplication) + ("style", boost::program_options::value< string >(), "set the application GUI style") + ("stylesheet", boost::program_options::value< string >(), "set the application stylesheet") + ("session", boost::program_options::value< string >(), "restore the application from an earlier session") + ("reverse", "set the application's layout direction from right to left") + ("display", boost::program_options::value< string >(), "set the X-Server") + ("geometry ", boost::program_options::value< string >(), "set the X-Window geometry") + ("font", boost::program_options::value< string >(), "set the X-Window font") + ("fn", boost::program_options::value< string >(), "set the X-Window font") + ("background", boost::program_options::value< string >(), "set the X-Window background color") + ("bg", boost::program_options::value< string >(), "set the X-Window background color") + ("foreground", boost::program_options::value< string >(), "set the X-Window foreground color") + ("fg", boost::program_options::value< string >(), "set the X-Window foreground color") + ("button", boost::program_options::value< string >(), "set the X-Window button color") + ("btn", boost::program_options::value< string >(), "set the X-Window button color") + ("name", boost::program_options::value< string >(), "set the X-Window name") + ("title", boost::program_options::value< string >(), "set the X-Window title") + ("visual", boost::program_options::value< string >(), "set the X-Window to color scema") + ("ncols", boost::program_options::value< int >(), "set the X-Window to color scema") + ("cmap", "set the X-Window to color scema") +#if defined(FC_OS_MACOSX) + ("psn", boost::program_options::value< string >(), "process serial number") +#endif + ; + + // Ignored options, will be safely ignored. Mostly used by underlaying libs. + //boost::program_options::options_description x11("X11 options"); + //x11.add_options() + // ("display", boost::program_options::value< string >(), "set the X-Server") + // ; + //0000723: improper handling of qt specific comand line arguments + std::vector args; + bool merge=false; + for (int i=1; i().c_str()); + if (!ifs) { + Base::Console().Error("Could no open the response file\n"); + std::stringstream str; + str << "Could no open the response file: '" + << vm["response-file"].as() << "'" << endl; + throw Base::UnknownProgramOption(str.str()); + } + // Read the whole file into a string + stringstream ss; + ss << ifs.rdbuf(); + // Split the file content + char_separator sep(" \n\r"); + tokenizer > tok(ss.str(), sep); + vector args; + copy(tok.begin(), tok.end(), back_inserter(args)); + // Parse the file and store the options + store( boost::program_options::command_line_parser(args). + options(cmdline_options).positional(p).extra_parser(customSyntax).run(), vm); + } + + if (vm.count("version")) { + std::stringstream str; + str << mConfig["ExeName"] << " " << mConfig["ExeVersion"] + << " Revision: " << mConfig["BuildRevision"] << std::endl; + throw Base::ProgramInformation(str.str()); + } + + if (vm.count("console")) { + mConfig["RunMode"] = "Cmd"; + } + + if (vm.count("module-path")) { + vector Mods = vm["module-path"].as< vector >(); + string temp; + for (vector::const_iterator It= Mods.begin();It != Mods.end();++It) + temp += *It + ";"; + temp.erase(temp.end()-1); + mConfig["AdditionalModulePaths"] = temp; + } + + if (vm.count("python-path")) { + vector Paths = vm["python-path"].as< vector >(); + for (vector::const_iterator It= Paths.begin();It != Paths.end();++It) + Base::Interpreter().addPythonPath(It->c_str()); + } + + if (vm.count("input-file")) { + vector files(vm["input-file"].as< vector >()); + int OpenFileCount=0; + for (vector::const_iterator It = files.begin();It != files.end();++It) { + + //cout << "Input files are: " + // << vm["input-file"].as< vector >() << "\n"; + + std::ostringstream temp; + temp << "OpenFile" << OpenFileCount; + mConfig[temp.str()] = *It; + OpenFileCount++; + } + std::ostringstream buffer; + buffer << OpenFileCount; + mConfig["OpenFileCount"] = buffer.str(); + } + + if (vm.count("output")) { + string file = vm["output"].as(); + mConfig["SaveFile"] = file; + } + + if (vm.count("hidden")) { + mConfig["StartHidden"] = "1"; + } + + if (vm.count("write-log")) { + mConfig["LoggingFile"] = "1"; + //mConfig["LoggingFileName"] = vm["write-log"].as(); + mConfig["LoggingFileName"] = mConfig["UserAppData"] + mConfig["ExeName"] + ".log"; + } + + if (vm.count("log-file")) { + mConfig["LoggingFile"] = "1"; + mConfig["LoggingFileName"] = vm["log-file"].as(); + } + + if (vm.count("user-cfg")) { + mConfig["UserParameter"] = vm["user-cfg"].as(); + } + + if (vm.count("system-cfg")) { + mConfig["SystemParameter"] = vm["system-cfg"].as(); + } + + if (vm.count("run-test")) { + int level = vm["run-test"].as(); + switch (level) { + case '0': + // test script level 0 + mConfig["RunMode"] = "Internal"; + mConfig["ScriptFileName"] = "FreeCADTest"; + //sScriptName = FreeCADTest; + break; + default: + //default testing level 0 + mConfig["RunMode"] = "Internal"; + mConfig["ScriptFileName"] = "FreeCADTest"; + //sScriptName = FreeCADTest; + break; + }; + } + + if (vm.count("single-instance")) { + mConfig["SingleInstance"] = "1"; + } + + if (vm.count("dump-config")) { + std::stringstream str; + for (std::map::iterator it=mConfig.begin(); it != mConfig.end(); ++it) { + str << it->first << "=" << it->second << std::endl; + } + throw Base::ProgramInformation(str.str()); + } + + if (vm.count("get-config")) { + std::string configKey = vm["get-config"].as(); + std::stringstream str; + std::map::iterator pos; + pos = mConfig.find(configKey); + if (pos != mConfig.end()) { + str << pos->second; + } + str << std::endl; + throw Base::ProgramInformation(str.str()); + } +} + +void Application::ExtractUserPath() +{ + // std paths + mConfig["BinPath"] = mConfig["AppHomePath"] + "bin" + PATHSEP; + mConfig["DocPath"] = mConfig["AppHomePath"] + "doc" + PATHSEP; + +#if defined(FC_OS_LINUX) || defined(FC_OS_CYGWIN) || defined(FC_OS_BSD) + // Default paths for the user specific stuff + struct passwd *pwd = getpwuid(getuid()); + if (pwd == NULL) + throw Base::Exception("Getting HOME path from system failed!"); + mConfig["UserHomePath"] = pwd->pw_dir; + std::string appData = pwd->pw_dir; + Base::FileInfo fi(appData.c_str()); + if (!fi.exists()) { + // This should never ever happen + std::stringstream str; + str << "Application data directory " << appData << " does not exist!"; + throw Base::Exception(str.str()); + } + + // In order to write into our data path, we must create some directories, first. + // If 'AppDataSkipVendor' is defined, the value of 'ExeVendor' must not be part of + // the path. + appData += PATHSEP; + appData += "."; + if (mConfig.find("AppDataSkipVendor") == mConfig.end()) { + appData += mConfig["ExeVendor"]; + fi.setFile(appData.c_str()); + if (!fi.exists() && !Py_IsInitialized()) { + if (!fi.createDirectory()) { + std::string error = "Cannot create directory "; + error += appData; + // Want more details on console + std::cerr << error << std::endl; + throw Base::Exception(error); + } + } + appData += PATHSEP; + } + + appData += mConfig["ExeName"]; + fi.setFile(appData.c_str()); + if (!fi.exists() && !Py_IsInitialized()) { + if (!fi.createDirectory()) { + std::string error = "Cannot create directory "; + error += appData; + // Want more details on console + std::cerr << error << std::endl; + throw Base::Exception(error); + } + } + + // Actually the name of the directory where the parameters are stored should be the name of + // the application due to branding reasons. + appData += PATHSEP; + mConfig["UserAppData"] = appData; + +#elif defined(FC_OS_MACOSX) + // Default paths for the user specific stuff on the platform + struct passwd *pwd = getpwuid(getuid()); + if (pwd == NULL) + throw Base::Exception("Getting HOME path from system failed!"); + mConfig["UserHomePath"] = pwd->pw_dir; + std::string appData = pwd->pw_dir; + appData += PATHSEP; + appData += "Library"; + appData += PATHSEP; + appData += "Preferences"; + Base::FileInfo fi(appData.c_str()); + if (!fi.exists()) { + // This should never ever happen + std::stringstream str; + str << "Application data directory " << appData << " does not exist!"; + throw Base::Exception(str.str()); + } + + // In order to write to our data path, we must create some directories, first. + // If 'AppDataSkipVendor' is defined the value of 'ExeVendor' must not be part of + // the path. + appData += PATHSEP; + if (mConfig.find("AppDataSkipVendor") == mConfig.end()) { + appData += mConfig["ExeVendor"]; + fi.setFile(appData.c_str()); + if (!fi.exists() && !Py_IsInitialized()) { + if (!fi.createDirectory()) { + std::string error = "Cannot create directory "; + error += appData; + // Want more details on console + std::cerr << error << std::endl; + throw Base::Exception(error); + } + } + appData += PATHSEP; + } + + appData += mConfig["ExeName"]; + fi.setFile(appData.c_str()); + if (!fi.exists() && !Py_IsInitialized()) { + if (!fi.createDirectory()) { + std::string error = "Cannot create directory "; + error += appData; + // Want more details on console + std::cerr << error << std::endl; + throw Base::Exception(error); + } + } + + // Actually the name of the directory where the parameters are stored should be the name of + // the application due to branding reasons. + appData += PATHSEP; + mConfig["UserAppData"] = appData; + +#elif defined(FC_OS_WIN32) + WCHAR szPath[MAX_PATH]; + TCHAR dest[MAX_PATH*3]; + // Get the default path where we can save our documents. It seems that + // 'CSIDL_MYDOCUMENTS' doesn't work on all machines, so we use 'CSIDL_PERSONAL' + // which does the same. + if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PERSONAL, NULL, 0, szPath))) { + WideCharToMultiByte(CP_UTF8, 0, szPath, -1,dest, 256, NULL, NULL); + mConfig["UserHomePath"] = dest; + } + else + mConfig["UserHomePath"] = mConfig["AppHomePath"]; + + // In the second step we want the directory where user settings of the application can be + // kept. There we create a directory with name of the vendor and a sub-directory with name + // of the application. + if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, 0, szPath))) { + // convert to UTF8 + WideCharToMultiByte(CP_UTF8, 0, szPath, -1,dest, 256, NULL, NULL); + + std::string appData = dest; + Base::FileInfo fi(appData.c_str()); + if (!fi.exists()) { + // This should never ever happen + std::stringstream str; + str << "Application data directory " << appData << " does not exist!"; + throw Base::Exception(str.str()); + } + + // In order to write to our data path we must create some directories first. + // If 'AppDataSkipVendor' is defined the value of 'ExeVendor' must not be part of + // the path. + if (mConfig.find("AppDataSkipVendor") == mConfig.end()) { + appData += PATHSEP; + appData += mConfig["ExeVendor"]; + fi.setFile(appData.c_str()); + if (!fi.exists() && !Py_IsInitialized()) { + if (!fi.createDirectory()) { + std::string error = "Cannot create directory "; + error += appData; + // Want more details on console + std::cerr << error << std::endl; + throw Base::Exception(error); + } + } + } + + appData += PATHSEP; + appData += mConfig["ExeName"]; + fi.setFile(appData.c_str()); + if (!fi.exists() && !Py_IsInitialized()) { + if (!fi.createDirectory()) { + std::string error = "Cannot create directory "; + error += appData; + // Want more details on console + std::cerr << error << std::endl; + throw Base::Exception(error); + } + } + + // Actually the name of the directory where the parameters are stored should be the name of + // the application due to branding reasons. + appData += PATHSEP; + mConfig["UserAppData"] = appData; + } +#else +# error "Implement ExtractUserPath() for your platform." +#endif +} + +#if defined (FC_OS_LINUX) || defined(FC_OS_CYGWIN) || defined(FC_OS_BSD) +#include +#include +#include + +std::string Application::FindHomePath(const char* sCall) +{ + // We have three ways to start this application either use one of the two executables or + // import the FreeCAD.so module from a running Python session. In the latter case the + // Python interpreter is already initialized. + std::string absPath; + std::string homePath; + if (Py_IsInitialized()) { + // Note: realpath is known to cause a buffer overflow because it + // expands the given path to an absolute path of unknown length. + // Even setting PATH_MAX does not necessarily solve the problem + // for sure but the risk of overflow is rather small. + char resolved[PATH_MAX]; + char* path = realpath(sCall, resolved); + if (path) + absPath = path; + } + else { + // Find the path of the executable. Theoretically, there could occur a + // race condition when using readlink, but we only use this method to + // get the absolute path of the executable to compute the actual home + // path. In the worst case we simply get q wrong path and FreeCAD is not + // able to load its modules. + char resolved[PATH_MAX]; + int nchars = readlink("/proc/self/exe", resolved, PATH_MAX); + if (nchars < 0 || nchars >= PATH_MAX) + throw Base::Exception("Cannot determine the absolute path of the executable"); + resolved[nchars] = '\0'; // enfore null termination + absPath = resolved; + } + + // should be an absolute path now + std::string::size_type pos = absPath.find_last_of("/"); + homePath.assign(absPath,0,pos); + pos = homePath.find_last_of("/"); + homePath.assign(homePath,0,pos+1); + + return homePath; +} + +#elif defined(FC_OS_MACOSX) +#include +#include +#include +#include + +std::string Application::FindHomePath(const char* call) +{ + uint32_t sz = 0; + char *buf; + + _NSGetExecutablePath(NULL, &sz); //function only returns "sz" if first arg is to small to hold value + buf = (char*) malloc(++sz); + + if (_NSGetExecutablePath(buf, &sz) == 0) { + char resolved[PATH_MAX]; + char* path = realpath(buf, resolved); + free(buf); + + if (path) { + std::string Call(resolved), TempHomePath; + std::string::size_type pos = Call.find_last_of(PATHSEP); + TempHomePath.assign(Call,0,pos); + pos = TempHomePath.find_last_of(PATHSEP); + TempHomePath.assign(TempHomePath,0,pos+1); + return TempHomePath; + } + } + + return call; // error +} + +#elif defined (FC_OS_WIN32) +std::string Application::FindHomePath(const char* sCall) +{ + // We have three ways to start this application either use one of the two executables or + // import the FreeCAD.pyd module from a running Python session. In the latter case the + // Python interpreter is already initialized. + wchar_t szFileName [MAX_PATH]; + if (Py_IsInitialized()) { + GetModuleFileNameW(GetModuleHandle(sCall),szFileName, MAX_PATH-1); + } + else { + GetModuleFileNameW(0, szFileName, MAX_PATH-1); + } + + std::wstring Call(szFileName), homePath; + std::wstring::size_type pos = Call.find_last_of(PATHSEP); + homePath.assign(Call,0,pos); + pos = homePath.find_last_of(PATHSEP); + homePath.assign(homePath,0,pos+1); + + // switch to posix style + for (std::wstring::iterator it = homePath.begin(); it != homePath.end(); ++it) { + if (*it == '\\') + *it = '/'; + } + + // fixes #0001638 to avoid to load DLLs from Windows' system directories before FreeCAD's bin folder + std::wstring binPath = homePath; + binPath += L"bin"; + SetDllDirectoryW(binPath.c_str()); + + // http://stackoverflow.com/questions/5625884/conversion-of-stdwstring-to-qstring-throws-linker-error +#ifdef _MSC_VER + QString str = QString::fromUtf16(reinterpret_cast(homePath.c_str())); +#else + QString str = QString::fromStdWString(homePath); +#endif + return str.toStdString(); +} + +#else +# error "std::string Application::FindHomePath(const char*) not implemented" +#endif diff --git a/src/Mod/Assembly/DevAssembly.py b/src/Mod/Assembly/DevAssembly.py new file mode 100644 index 0000000000..43e12aafcc --- /dev/null +++ b/src/Mod/Assembly/DevAssembly.py @@ -0,0 +1,3 @@ +import FreeCAD,Assembly + +print "Script to test the assembly development"