diff --git a/common/kiway.cpp b/common/kiway.cpp index e6cbbbdce8..d936bfec77 100644 --- a/common/kiway.cpp +++ b/common/kiway.cpp @@ -473,9 +473,9 @@ void KIWAY::SetLanguage( int aLanguage ) } } + void KIWAY::CommonSettingsChanged( bool aEnvVarsChanged, bool aTextVarsChanged ) { -#if 1 if( m_ctl & KFCTL_CPP_PROJECT_SUITE ) { // A dynamic_cast could be better, but creates link issues @@ -486,7 +486,6 @@ void KIWAY::CommonSettingsChanged( bool aEnvVarsChanged, bool aTextVarsChanged ) if( top ) top->CommonSettingsChanged( aEnvVarsChanged, aTextVarsChanged ); } -#endif for( unsigned i=0; i < KIWAY_PLAYER_COUNT; ++i ) { @@ -498,6 +497,29 @@ void KIWAY::CommonSettingsChanged( bool aEnvVarsChanged, bool aTextVarsChanged ) } +void KIWAY::ProjectChanged() +{ + if( m_ctl & KFCTL_CPP_PROJECT_SUITE ) + { + // A dynamic_cast could be better, but creates link issues + // (some basic_frame functions not found) on some platforms, + // so a static_cast is used. + EDA_BASE_FRAME* top = static_cast<EDA_BASE_FRAME*>( m_top ); + + if( top ) + top->ProjectChanged(); + } + + for( unsigned i=0; i < KIWAY_PLAYER_COUNT; ++i ) + { + KIWAY_PLAYER* frame = GetPlayerFrame( ( FRAME_T )i ); + + if( frame ) + frame->ProjectChanged(); + } +} + + bool KIWAY::ProcessEvent( wxEvent& aEvent ) { KIWAY_EXPRESS* mail = dynamic_cast<KIWAY_EXPRESS*>( &aEvent ); diff --git a/common/settings/settings_manager.cpp b/common/settings/settings_manager.cpp index 780bfe063d..f6c85075aa 100644 --- a/common/settings/settings_manager.cpp +++ b/common/settings/settings_manager.cpp @@ -28,6 +28,7 @@ #include <confirm.h> #include <dialogs/dialog_migrate_settings.h> #include <gestfich.h> +#include <kiway.h> #include <macros.h> #include <project.h> #include <project/project_archiver.h> @@ -53,6 +54,7 @@ const char* traceSettings = "SETTINGS"; SETTINGS_MANAGER::SETTINGS_MANAGER( bool aHeadless ) : m_headless( aHeadless ), + m_kiway( nullptr ), m_common_settings( nullptr ), m_migration_source() { @@ -715,6 +717,9 @@ bool SETTINGS_MANAGER::LoadProject( const wxString& aFullPath, bool aSetActive ) m_projects[fullPath]->setLocalSettings( settings ); settings->SetProject( m_projects[fullPath].get() ); + if( m_kiway ) + m_kiway->ProjectChanged(); + return success; } @@ -731,6 +736,12 @@ bool SETTINGS_MANAGER::UnloadProject( PROJECT* aProject, bool aSave ) m_projects.erase( aProject->GetProjectFullName() ); + // Remove the reference in the environment to the previous project + wxSetEnv( PROJECT_VAR_NAME, "" ); + + if( m_kiway ) + m_kiway->ProjectChanged(); + return true; } diff --git a/common/single_top.cpp b/common/single_top.cpp index 3293d13c53..e1e4d7fe16 100644 --- a/common/single_top.cpp +++ b/common/single_top.cpp @@ -359,6 +359,8 @@ bool PGM_SINGLE_TOP::OnPgmInit() } } + // Tell the settings manager about the current Kiway + GetSettingsManager().SetKiway( &Kiway ); // Use KIWAY to create a top window, which registers its existence also. // "TOP_FRAME" is a macro that is passed on compiler command line from CMake, diff --git a/include/eda_base_frame.h b/include/eda_base_frame.h index 8233056491..cc30128951 100644 --- a/include/eda_base_frame.h +++ b/include/eda_base_frame.h @@ -496,6 +496,11 @@ public: */ void CommonSettingsChanged( bool aEnvVarsChanged, bool aTextVarsChanged ) override; + /** + * Notification event that the project has changed. + */ + virtual void ProjectChanged() {} + const wxString& GetAboutTitle() const { return m_AboutTitle; } /** diff --git a/include/kiway.h b/include/kiway.h index 57bf52fa60..c26436cbf2 100644 --- a/include/kiway.h +++ b/include/kiway.h @@ -382,6 +382,12 @@ public: */ VTBL_ENTRY void CommonSettingsChanged( bool aEnvVarsChanged, bool aTextVarsChanged ); + /** + * Calls ProjectChanged() on all KIWAY_PLAYERs. + * Used after changing the project to ensure all players are updated correctly. + */ + VTBL_ENTRY void ProjectChanged(); + KIWAY( PGM_BASE* aProgram, int aCtlBits, wxFrame* aTop = NULL ); /** diff --git a/include/settings/settings_manager.h b/include/settings/settings_manager.h index 0d90956da6..ad4fc5026a 100644 --- a/include/settings/settings_manager.h +++ b/include/settings/settings_manager.h @@ -26,6 +26,7 @@ class COLOR_SETTINGS; class COMMON_SETTINGS; +class KIWAY; class PROJECT; class PROJECT_FILE; class REPORTER; @@ -43,6 +44,13 @@ public: */ bool IsOK() { return m_ok; } + /** + * Associate this setting manager with the given Kiway. + * + * @param aKiway is the kiway this settings manager should use + */ + void SetKiway( KIWAY* aKiway ) { m_kiway = aKiway; } + /** * Takes ownership of the pointer passed in * @param aSettings is a settings object to register @@ -350,6 +358,9 @@ private: /// True if running outside a UI context bool m_headless; + /// The kiway this settings manager interacts with + KIWAY* m_kiway; + std::vector<std::unique_ptr<JSON_SETTINGS>> m_settings; std::unordered_map<wxString, COLOR_SETTINGS*> m_color_settings; diff --git a/kicad/kicad.cpp b/kicad/kicad.cpp index 37bcaf4d66..e64641b640 100644 --- a/kicad/kicad.cpp +++ b/kicad/kicad.cpp @@ -92,6 +92,7 @@ bool PGM_KICAD::OnPgmInit() m_bm.InitSettings( new KICAD_SETTINGS ); GetSettingsManager().RegisterSettings( PgmSettings() ); + GetSettingsManager().SetKiway( &Kiway ); m_bm.Init(); // Add search paths to feed the PGM_KICAD::SysSearch() function, diff --git a/pcbnew/pcb_edit_frame.cpp b/pcbnew/pcb_edit_frame.cpp index c6821ccaa7..b32d4d39ec 100644 --- a/pcbnew/pcb_edit_frame.cpp +++ b/pcbnew/pcb_edit_frame.cpp @@ -51,6 +51,7 @@ #include <functional> #include <project/project_file.h> #include <project/net_settings.h> +#include <settings/common_settings.h> #include <settings/settings_manager.h> #include <swig/python_scripting.h> #include <tool/tool_manager.h> @@ -323,6 +324,10 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) : InitExitKey(); + // Ensure the Python interpreter is up to date with its environment variables + PythonSyncEnvironmentVariables(); + PythonSyncProjectName(); + GetCanvas()->SwitchBackend( m_canvasType ); ActivateGalCanvas(); @@ -1265,6 +1270,27 @@ void PCB_EDIT_FRAME::PythonPluginsShowFolder() } +void PCB_EDIT_FRAME::PythonSyncEnvironmentVariables() +{ +#if defined( KICAD_SCRIPTING ) + COMMON_SETTINGS* settings = Pgm().GetCommonSettings(); + + for( auto& var : settings->m_Env.vars ) + pcbnewUpdatePythonEnvVar( var.first, var.second ); +#endif +} + + +void PCB_EDIT_FRAME::PythonSyncProjectName() +{ +#if defined( KICAD_SCRIPTING ) + wxString evValue; + wxGetEnv( PROJECT_VAR_NAME, &evValue ); + pcbnewUpdatePythonEnvVar( wxString( PROJECT_VAR_NAME ).ToStdString(), evValue ); +#endif +} + + void PCB_EDIT_FRAME::InstallFootprintPropertiesDialog( MODULE* Module ) { if( Module == NULL ) @@ -1338,11 +1364,21 @@ void PCB_EDIT_FRAME::CommonSettingsChanged( bool aEnvVarsChanged, bool aTextVars if( aTextVarsChanged ) GetCanvas()->GetView()->UpdateAllItems( KIGFX::ALL ); + // Update the environment variables in the Python interpreter + if( aEnvVarsChanged ) + PythonSyncEnvironmentVariables(); + Layout(); SendSizeEvent(); } +void PCB_EDIT_FRAME::ProjectChanged() +{ + PythonSyncProjectName(); +} + + void PCB_EDIT_FRAME::LockModule( MODULE* aModule, bool aLocked ) { const wxString ModulesMaskSelection = wxT( "*" ); diff --git a/pcbnew/pcb_edit_frame.h b/pcbnew/pcb_edit_frame.h index f7aa2db494..5d22bd0f5e 100644 --- a/pcbnew/pcb_edit_frame.h +++ b/pcbnew/pcb_edit_frame.h @@ -304,6 +304,18 @@ public: */ void PythonPluginsShowFolder(); + /** + * Synchronize the environment variables from KiCad's environment into the Python interpreter. + * Do nothing if KICAD_SCRIPTING is not defined. + */ + void PythonSyncEnvironmentVariables(); + + /** + * Synchronize the project name from KiCad's environment into the Python interpreter. + * Do nothing if KICAD_SCRIPTING is not defined. + */ + void PythonSyncProjectName(); + /** * Update the layer manager and other widgets from the board setup * (layer and items visibility, colors ...) @@ -948,6 +960,8 @@ public: */ void CommonSettingsChanged( bool aEnvVarsChanged, bool aTextVarsChanged ) override; + void ProjectChanged() override; + void SyncToolbars() override; wxString GetCurrentFileName() const override; diff --git a/pcbnew/swig/python_scripting.cpp b/pcbnew/swig/python_scripting.cpp index aef4076e3a..4f53afa1fc 100644 --- a/pcbnew/swig/python_scripting.cpp +++ b/pcbnew/swig/python_scripting.cpp @@ -210,7 +210,8 @@ bool pcbnewInitPythonScripting( const char * aUserScriptingPath ) { PyLOCK lock; - snprintf( cmd, sizeof( cmd ), "import sys, traceback\n" + // Load os so that we can modify the environment variables through python + snprintf( cmd, sizeof( cmd ), "import sys, os, traceback\n" "sys.path.append(\".\")\n" "import pcbnew\n" "pcbnew.LoadPlugins(\"%s\")", aUserScriptingPath ); @@ -318,6 +319,30 @@ void pcbnewFinishPythonScripting() } +void pcbnewUpdatePythonEnvVar( const std::string& aVar, const wxString& aValue ) +{ + char cmd[1024]; + + // Ensure the interpreter is initalized before we try to interact with it + if( !Py_IsInitialized() ) + return; + + snprintf( cmd, sizeof( cmd ), + "# coding=utf-8\n" // The values could potentially be UTF8 + "os.environ[\"%s\"]=\"%s\"\n", + aVar.c_str(), + TO_UTF8( aValue ) ); + + PyLOCK lock; + + int retv = PyRun_SimpleString( cmd ); + + if( retv != 0 ) + wxLogError( "Python error %d occurred running command:\n\n`%s`", retv, cmd ); +} + + + #if defined( KICAD_SCRIPTING_WXPYTHON ) void RedirectStdio() { diff --git a/pcbnew/swig/python_scripting.h b/pcbnew/swig/python_scripting.h index 369d50c8d4..c577734a30 100644 --- a/pcbnew/swig/python_scripting.h +++ b/pcbnew/swig/python_scripting.h @@ -78,6 +78,15 @@ void pcbnewGetScriptsSearchPaths( wxString& aNames ); */ void pcbnewGetWizardsBackTrace( wxString& aNames ); +/** + * Set an environment variable in the current Python interpreter. + * + * @param aVar is the variable to set + * @param aValue is the value to give it + */ +void pcbnewUpdatePythonEnvVar( const std::string& aVar, const wxString& aValue ); + + #ifdef KICAD_SCRIPTING_WXPYTHON void RedirectStdio(); wxWindow* CreatePythonShellWindow( wxWindow* parent, const wxString& aFramenameId );