468 lines
11 KiB
C++
468 lines
11 KiB
C++
#include "fctsys.h"
|
|
#include "common.h"
|
|
|
|
#include <id.h>
|
|
|
|
#include <wx/dir.h>
|
|
|
|
#include <pyhandler.h>
|
|
#include <iostream>
|
|
|
|
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<int>( objOpen );
|
|
|
|
wxString script = EDA_FileSelector( PyHandler::MakeStr( objTitle ),
|
|
wxEmptyString,
|
|
wxEmptyString,
|
|
mask,
|
|
mask,
|
|
NULL,
|
|
open ? wxFD_OPEN : wxFD_SAVE,
|
|
TRUE );
|
|
|
|
return PyHandler::Convert( script );
|
|
}
|
|
|
|
static void Print( str message )
|
|
{
|
|
std::cout << extract<char *>(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);
|
|
}
|
|
|
|
|
|
// Dummy boost callback
|
|
static void InitPyModules()
|
|
{
|
|
PyHandler::GetInstance()->InitNextModule();
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* PyHandler */
|
|
/*****************************************************************************/
|
|
|
|
// std::vector< T > -> python object implicit conversion
|
|
template <typename T> 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;
|
|
|
|
|
|
/* Singleton implementation */
|
|
PyHandler * PyHandler::GetInstance()
|
|
{
|
|
if( !PyHandler::m_instance )
|
|
{
|
|
PyHandler::m_instance = new PyHandler();
|
|
}
|
|
return PyHandler::m_instance;
|
|
}
|
|
|
|
|
|
/* Init the Python env */
|
|
PyHandler::PyHandler()
|
|
{
|
|
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 );
|
|
}
|
|
}
|
|
|
|
|
|
/* Returns the module index in the registry, -1 if not found*/
|
|
int PyHandler::GetModuleIndex( const wxString & name ) const
|
|
{
|
|
for ( unsigned int i = 0; i < m_ModuleRegistry.size(); i ++ )
|
|
{
|
|
if ( m_ModuleRegistry[i].name == name ) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
/* Adds an init function to a python module */
|
|
void PyHandler::AddToModule( const wxString & name,
|
|
PyHandler::initfunc_t initfunc )
|
|
{
|
|
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 );
|
|
}
|
|
|
|
|
|
/* Called to initialize a module on py 'import module' */
|
|
void PyHandler::InitNextModule()
|
|
{
|
|
for ( unsigned int j = 0;
|
|
j < m_ModuleRegistry[m_current].registry.size();
|
|
j++ )
|
|
{
|
|
m_ModuleRegistry[m_current].registry[j]();
|
|
}
|
|
|
|
m_current++;
|
|
}
|
|
|
|
|
|
/* Closes the Python env */
|
|
PyHandler::~PyHandler()
|
|
{
|
|
wxPyEndAllowThreads(m_mainTState);
|
|
Py_Finalize();
|
|
}
|
|
|
|
|
|
/* Run scripts looking in 'base' directory */
|
|
void PyHandler::RunBaseScripts( const wxString & base )
|
|
{
|
|
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/<name>.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/<name>) 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] );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* Run application startup scripts */
|
|
void PyHandler::RunScripts()
|
|
{
|
|
// 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 );
|
|
|
|
}
|
|
|
|
|
|
/* Run the script specified by 'name' */
|
|
bool PyHandler::RunScript( const wxString & 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<const char *>( objStr ), wxConvLocal );
|
|
}
|
|
|
|
|
|
object PyHandler::Convert( const wxString & wxStr )
|
|
{
|
|
return str( std::string( wxStr.mb_str() ).c_str() );
|
|
}
|