#include "fctsys.h" #include "common.h" #include #include #include #include using namespace boost::python; /*****************************************************************************/ /* Common Python Binding */ /*****************************************************************************/ static int GetLastID() { return ID_END_LIST; } static object ChooseFile( str objTitle, str objMask, object objOpen ) { wxString mask = PyHandler::MakeStr( objMask ); int open = extract( objOpen ); wxString script = EDA_FileSelector( PyHandler::MakeStr( objTitle ), wxEmptyString, /* Chemin par defaut */ wxEmptyString, /* nom fichier par defaut */ mask, /* extension par defaut */ mask, /* Masque d'affichage */ NULL, open ? wxFD_OPEN : wxFD_SAVE, TRUE ); return PyHandler::Convert( script ); } static void Print( str message ) { std::cout << extract(message) << std::endl; } static void Clear() {} static void RegisterCb( str objKey, object callback ) { PyHandler::GetInstance()->RegisterCallback( PyHandler::MakeStr(objKey), callback ); } static void UnRegisterCb( str objKey, object callback ) { PyHandler::GetInstance()->UnRegisterCallback( PyHandler::MakeStr(objKey), callback ); } static void init_base_utils() { def ( "ChooseFile", &ChooseFile ); def ( "RegisterCallback", &RegisterCb ); def ( "UnRegisterCallback", &UnRegisterCb ); def ( "GetLastID", &GetLastID ); def ( "Print", &Print ); def ( "Clear", &Clear); } static void InitPyModules() { PyHandler::GetInstance()->InitNextModule(); } // Dummy boost callback /*****************************************************************************/ /* PyHandler */ /*****************************************************************************/ // std::vector< T > -> python object implicit conversion template struct std_vector_to_tuple { static PyObject * makeItem( const wxString & str ) { return boost::python::incref( PyHandler::Convert( str ).ptr() ); } static PyObject * makeItem( const std::string & str ) { return boost::python::incref( boost::python::str( str.c_str() ).ptr() ); } static PyObject * makeItem( int item ) { return boost::python::incref( PyInt_FromLong( item ) ); } static PyObject * convert( const T& vect ) { PyObject * tuple = PyTuple_New( vect.size() ); for ( unsigned int i = 0; i < vect.size() ; i++ ) { PyTuple_SET_ITEM( tuple, i, makeItem( vect[i] ) ); } return tuple; } }; PyHandler* PyHandler::m_instance = NULL; PyHandler * PyHandler::GetInstance() /* Singleton implementation */ { if ( !PyHandler::m_instance ) { PyHandler::m_instance = new PyHandler(); } return PyHandler::m_instance; } PyHandler::PyHandler() /* Init the Python env */ { Py_Initialize(); PyEval_InitThreads(); m_ModulesLoaded = false; m_current = 0; if ( !wxPyCoreAPI_IMPORT() ) { std::cerr << "Can't get wx Python binding\n" ; PyErr_Print(); } // m_mainTState = wxPyBeginAllowThreads(); // I can't figure out why this make py crash ... m_mainTState = NULL; // Make the console appear in a window: wxString initConsole; initConsole += wxT( "import sys\n" ); initConsole += wxT( "import wx\n" ); initConsole += wxT( "output = wx.PyOnDemandOutputWindow()\n" ); initConsole += wxT( "sys.stdout = sys.stderr = output\n" ); RunSimpleString( initConsole ); AddToModule ( wxT( "common" ), &init_base_utils ); // Register converters to_python_converter < std::vector< std::string >, std_vector_to_tuple< const std::vector < std::string > > > (); to_python_converter < std::vector< wxString >, std_vector_to_tuple< const std::vector < wxString > > > (); } void PyHandler::DoInitModules() { if ( m_ModulesLoaded ) return; m_ModulesLoaded = true; for ( unsigned int i = 0; i < m_ModuleRegistry.size(); i ++ ) { detail::init_module( m_ModuleRegistry[i].name.mb_str(), &InitPyModules ); } } int PyHandler::GetModuleIndex( const wxString & name ) const /* Returns the module index in the registry, -1 if not found*/ { for ( unsigned int i = 0; i < m_ModuleRegistry.size(); i ++ ) { if ( m_ModuleRegistry[i].name == name ) return i; } return -1; } void PyHandler::AddToModule( const wxString & name, PyHandler::initfunc_t initfunc ) /* Adds an init function to a python module */ { if (!initfunc) return; int i = GetModuleIndex( name ); if ( -1 == i ) { m_ModuleRegistry.push_back( ModuleRecord( name ) ); i = m_ModuleRegistry.size() - 1; } m_ModuleRegistry[i].registry.push_back( initfunc ); } void PyHandler::InitNextModule() /* Called to initialize a module on py 'import module' */ { for ( unsigned int j = 0; j < m_ModuleRegistry[m_current].registry.size() ; j ++ ) { m_ModuleRegistry[m_current].registry[j](); } m_current++; } PyHandler::~PyHandler() /* Closes the Python env */ { wxPyEndAllowThreads(m_mainTState); Py_Finalize(); } void PyHandler::RunBaseScripts( const wxString & base ) /* Run scripts looking in 'base' directory */ { const wxString sep = wxFileName().GetPathSeparator(); // check if we can have a kicad_startup.py around ? wxString script = base + wxT( "scripts" ) + sep + wxT( "kicad_startup.py" ); if ( wxFileExists( script ) ) RunScript( script ); // First find scripts/.py and run it if found : script = base + wxString::FromAscii( "scripts" ) + sep + m_appName + wxString::FromAscii(".py"); if ( wxFileExists( script ) ) RunScript( script ); // Now lets see if we can find a suitable plugin directory (plugin/) somewhere wxString pluginDir = base + wxT( "plugins" ) + sep + m_appName; if ( wxDirExists( pluginDir ) ) { // We do have a systemwide plugin dir, let's find files in it wxArrayString pluginList; wxDir::GetAllFiles( pluginDir, &pluginList, wxT("*.py") ); for ( unsigned int i = 0; i < pluginList.Count() ; i++ ) { RunScript( pluginList[i] ); } } } void PyHandler::RunScripts() /* Run application startup scripts */ { // SYSTEMWIDE: const wxString sep = wxFileName().GetPathSeparator(); wxString dataPath = ReturnKicadDatasPath(); if ( wxDirExists( dataPath ) ) RunBaseScripts( dataPath ); // USER Scripts: wxString userDir = wxGetUserHome() + sep + wxString::FromAscii(".kicad.d") + sep; if ( wxDirExists( userDir ) ) RunBaseScripts( userDir ); userDir = wxGetUserHome() + sep + wxString::FromAscii("_kicad_d") + sep; if ( wxDirExists( userDir ) ) RunBaseScripts( userDir ); } bool PyHandler::RunScript( const wxString & name ) /* Run the script specified by 'name' */ { DoInitModules(); object module( handle<>(borrowed(PyImport_AddModule("__main__")))); object ns = module.attr( "__dict__" ); bool ret = true; FILE * file = fopen( name.mb_str(), "r" ); wxPyBlock_t blocked = wxPyBeginBlockThreads(); if ( !file ) { // do something std::cout << "Unable to Load " << name.mb_str() << "\n"; ret = false; } else { wxString currDir = wxGetCwd(); wxFileName fname( name ); wxString pyDir = fname.GetPath(); wxSetWorkingDirectory( pyDir ); try { ns["currentScript"] = Convert( name ); handle<> ignored( PyRun_File( file, name.mb_str(), Py_file_input, ns.ptr(), ns.ptr() ) ); } catch ( error_already_set ) { PyErr_Print(); // should be printed into an error message ... ret = false; } wxSetWorkingDirectory( currDir ); } fclose( file ); wxPyEndBlockThreads(blocked); return ret; } bool PyHandler::RunSimpleString( const wxString & code ) /* Run the code in 'code' */ { wxPyBlock_t blocked = wxPyBeginBlockThreads(); try { PyRun_SimpleString( code.mb_str() ); } catch ( error_already_set ) { PyErr_Print(); // should be printed into an error message ... wxPyEndBlockThreads(blocked); return false; } wxPyEndBlockThreads(blocked); return true; } void PyHandler::SetAppName( const wxString & name ) /* Set the application name in the python scope */ { m_appName = name; object module(( handle<>(borrowed(PyImport_AddModule("__main__"))))); object ns = module.attr( "__dict__" ); try { ns["kicadApp"] = std::string( name.ToAscii() ); } catch (error_already_set) { PyErr_Print(); } } const char * PyHandler::GetVersion() { return Py_GetVersion(); } // Event handling : void PyHandler::DeclareEvent( const wxString & key ) { m_EventRegistry.push_back( Event( key ) ); } int PyHandler::GetEventIndex( const wxString & key ) { for ( unsigned int i = 0; i < m_EventRegistry.size(); i ++ ) { if ( m_EventRegistry[i].key == key ) return i; } return -1; } void PyHandler::TriggerEvent( const wxString & key ) { TriggerEvent( key, str( "" ) ); } void PyHandler::TriggerEvent( const wxString & key, const object & param ) { int i = GetEventIndex( key ); if ( -1 == i ) return; wxPyBlock_t blocked = wxPyBeginBlockThreads(); for ( unsigned int j = 0; j < m_EventRegistry[i].functors.size(); j++ ) { try { m_EventRegistry[i].functors[j]( param ); } catch (error_already_set) { std::cout << "Error in event " << key.mb_str() << " callback" << std::endl; PyErr_Print(); } } wxPyEndBlockThreads(blocked); } void PyHandler::RegisterCallback( const wxString & key, const object & callback ) { int i = GetEventIndex( key ); if ( -1 == i ) return; m_EventRegistry[i].functors.push_back( callback ); } void PyHandler::UnRegisterCallback( const wxString & key, const object & callback ) { int i = GetEventIndex( key ); if ( -1 == i ) return; for ( unsigned int j = 0; j < m_EventRegistry[i].functors.size() ; j++ ) { if ( callback == m_EventRegistry[i].functors[j] ) { m_EventRegistry[i].functors.erase( m_EventRegistry[i].functors.begin() + j ); break; } } } // Object conversion: wxString PyHandler::MakeStr( const object & objStr ) { return wxString( extract( objStr ), wxConvLocal ); } object PyHandler::Convert( const wxString & wxStr ) { return str( std::string( wxStr.mb_str() ).c_str() ); } // vim: set tabstop=4 :