KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_scripting_tool.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.TXT for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 3
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/gpl-3.0.html
19 * or you may search the http://www.gnu.org website for the version 3 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24#include "pcb_scripting_tool.h"
25
26#include <Python.h>
27
28#include <wx/string.h>
29#include <wx/filename.h>
30#include <wx/msgdlg.h>
31
32#include <pybind11/eval.h>
33
34#include <action_plugin.h>
35#include <kiface_ids.h>
36#include <kiway.h>
37#include <macros.h>
38#include <pgm_base.h>
39#include <python_scripting.h>
40#include <string_utils.h>
41#include <tools/pcb_actions.h>
42#include <launch_ext.h>
43
44#ifdef KICAD_IPC_API
46#endif
47
48using initfunc = PyObject* (*)(void);
49
51 PCB_TOOL_BASE( "pcbnew.ScriptingTool" )
52{}
53
54
57
58
60{
61}
62
63
65{
66 PyLOCK lock;
67 std::string pymodule( "_pcbnew" );
68
69 if( !SCRIPTING::IsModuleLoaded( pymodule ) )
70 {
71 KIFACE* kiface = frame()->Kiway().KiFACE( KIWAY::FACE_PCB );
72 initfunc pcbnew_init = reinterpret_cast<initfunc>( kiface->IfaceOrAddress( KIFACE_SCRIPTING_LEGACY ) );
73 PyImport_AddModule( pymodule.c_str() );
74 PyObject* mod = pcbnew_init();
75 PyObject* sys_mod = PyImport_GetModuleDict();
76 PyDict_SetItemString( sys_mod, "_pcbnew", mod );
77 Py_DECREF( mod );
78
79 // plugins will be loaded later via ReloadPlugins()
80 }
81
82 return true;
83}
84
85
87{
88 // Reload Python plugins if they are newer than the already loaded, and load new plugins
89 // Remove all action plugins so that we don't keep references to old versions
91
92 try
93 {
94 PyLOCK lock;
96 }
97 catch( ... )
98 {}
99}
100
101
103{
104 // Reload Python plugins if they are newer than the already loaded, and load new plugins
105 // Remove all action plugins so that we don't keep references to old versions
107
108 try
109 {
110 PyLOCK lock;
112 }
113 catch( ... )
114 {
115 return -1;
116 }
117
118#ifdef KICAD_IPC_API
119 // TODO move this elsewhere when SWIG plugins are removed
120 if( Pgm().GetCommonSettings()->m_Api.enable_server )
121 Pgm().GetPluginManager().ReloadPlugins();
122#endif
123
125 {
126 // Action plugins can be modified, therefore the plugins menu must be updated:
127 frame()->ReCreateMenuBar();
128 // Recreate top toolbar to add action plugin buttons
129 frame()->ReCreateHToolbar();
130 // Post a size event to force resizing toolbar by the AUI manager:
131 frame()->PostSizeEvent();
132 }
133
134 return 0;
135}
136
137
139{
140 // Load pcbnew inside Python and load all the user plugins and package-based plugins
141 using namespace pybind11::literals;
142
143 auto locals = pybind11::dict(
144 "sys_path"_a = TO_UTF8( SCRIPTING::PyScriptingPath( SCRIPTING::PATH_TYPE::STOCK ) ),
145 "user_path"_a = TO_UTF8( SCRIPTING::PyScriptingPath( SCRIPTING::PATH_TYPE::USER ) ),
146 "third_party_path"_a =
147 TO_UTF8( SCRIPTING::PyPluginsPath( SCRIPTING::PATH_TYPE::THIRDPARTY ) ) );
148
149 pybind11::exec( R"(
150import sys
151import pcbnew
152pcbnew.LoadPlugins( sys_path, user_path, third_party_path )
153 )",
154 pybind11::globals(), locals );
155}
156
157
159{
160 wxString pluginpath( SCRIPTING::PyPluginsPath( SCRIPTING::PATH_TYPE::USER ) );
161
162 if( wxFileName::DirExists( pluginpath ) )
163 {
164 if( !LaunchExternal( pluginpath ) )
165 {
166 wxMessageBox( wxString::Format( _( "Unable to open plugin directory '%s'." ), pluginpath ),
167 _( "Plugin Directory" ), wxOK | wxICON_ERROR );
168 }
169
170 return;
171 }
172
173 wxString msg = wxString::Format( _( "The plugin directory '%s' does not exist. Create it?" ), pluginpath );
174
175 wxMessageDialog dlg( nullptr, msg, _( "Plugin Directory" ), wxYES_NO | wxICON_QUESTION );
176
177 if( dlg.ShowModal() == wxID_YES )
178 {
179 if( wxFileName::Mkdir( pluginpath, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) )
180 {
181 if( !LaunchExternal( pluginpath ) )
182 {
183 wxMessageBox( wxString::Format( _( "Unable to open plugin directory '%s'." ), pluginpath ),
184 _( "Plugin Directory" ), wxOK | wxICON_ERROR );
185 }
186 }
187 else
188 {
189 wxMessageBox( wxString::Format( _( "Unable to create plugin directory '%s'." ), pluginpath ),
190 _( "Plugin Directory" ), wxOK | wxICON_ERROR );
191 }
192 }
193}
194
195
197{
199 return 0;
200}
201
202
Class PCBNEW_ACTION_PLUGINS.
static TOOL_ACTION pluginsReload
Definition actions.h:295
static void UnloadAll()
Unload (deregister) all action plugins.
@ FACE_PCB
pcbnew DSO
Definition kiway.h:294
static TOOL_ACTION pluginsShowFolder
Scripting Actions.
T * frame() const
PCB_TOOL_BASE(TOOL_ID aId, const std::string &aName)
Constructor.
int reloadPlugins(const TOOL_EVENT &aEvent)
< Reload Python plugins and reset toolbar (if in pcbnew)
~SCRIPTING_TOOL()
React to model/view changes.
void Reset(RESET_REASON aReason) override
Basic initialization.
bool Init() override
Init() is called once upon a registration of the tool.
static void callLoadPlugins()
Open the user's plugin folder in the system browser.
int showPluginFolder(const TOOL_EVENT &aEvent)
Bind handlers to corresponding TOOL_ACTIONs.
static void ShowPluginFolder()
static void ReloadPlugins()
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
RESET_REASON
Determine the reason of reset for a tool.
Definition tool_base.h:78
Generic, UI-independent tool event.
Definition tool_event.h:171
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
#define _(s)
@ KIFACE_SCRIPTING_LEGACY
Definition kiface_ids.h:57
bool LaunchExternal(const wxString &aPath)
Launches the given file or folder in the host OS.
This file contains miscellaneous commonly used macros and functions.
PyObject *(*)(void) initfunc
PGM_BASE & Pgm()
The global program "get" accessor.
Definition pgm_base.cpp:913
see class PGM_BASE
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Implement a participant in the KIWAY alchemy.
Definition kiway.h:153
IFACE KIFACE_BASE kiface("pcb_test_frame", KIWAY::FACE_PCB)