Eeschema: overhaul storage of BOM plugin settings

CHANGED: BOM generator plugins are no longer loaded by
         searching all plugin directories; instead a
         fixed default set of plugins is provided.

Also:

- Move from sexpr to JSON
- Support both full-path and no-path specifications of plugins
- Add a Reset to Defaults button to reset the list

Fixes https://gitlab.com/kicad/code/kicad/-/issues/7633
This commit is contained in:
Jon Evans 2021-02-24 22:37:30 -05:00
parent c077612163
commit 8d62c73b86
8 changed files with 479 additions and 234 deletions

View File

@ -23,14 +23,23 @@
*/
#include "bom_plugins.h"
#include <paths.h>
#include <wx/ffile.h>
#include <wx/log.h>
constexpr wxChar BOM_TRACE[] = wxT( "BOM_GENERATORS" );
BOM_GENERATOR_HANDLER::BOM_GENERATOR_HANDLER( const wxString& aFile )
: m_file( aFile )
{
m_isOk = false;
if( !wxFile::Exists( aFile ) )
if( !wxFile::Exists( m_file.GetFullPath() ) )
m_file = FindFilePath();
if( !wxFile::Exists( m_file.GetFullPath() ) )
{
m_info.Printf( _("Script file:\n%s\nnot found. Script not available."), aFile );
return;
@ -77,6 +86,8 @@ BOM_GENERATOR_HANDLER::BOM_GENERATOR_HANDLER( const wxString& aFile )
{
m_cmd = m_file.GetFullPath();
}
wxLogTrace( BOM_TRACE, "%s: extracted command line %s", m_name, m_cmd );
}
@ -147,3 +158,36 @@ wxString BOM_GENERATOR_HANDLER::getOutputExtension( const wxString& aHeader )
return aHeader.SubString( strstart, strend - 1 );
}
wxFileName BOM_GENERATOR_HANDLER::FindFilePath() const
{
if( m_file.IsAbsolute() && m_file.Exists( wxFILE_EXISTS_REGULAR ) )
{
wxLogTrace( BOM_TRACE, "%s found directly", m_file.GetFullPath() );
return m_file;
}
wxFileName test( PATHS::GetUserPluginsPath(), m_file.GetName(), m_file.GetExt() );
if( test.Exists( wxFILE_EXISTS_REGULAR ) )
{
wxLogTrace( BOM_TRACE, "%s found in user plugins path %s", m_file.GetFullName(),
PATHS::GetUserPluginsPath() );
return test;
}
test = wxFileName( PATHS::GetStockPluginsPath(), m_file.GetName(), m_file.GetExt() );
if( test.Exists( wxFILE_EXISTS_REGULAR ) )
{
wxLogTrace( BOM_TRACE, "%s found in stock plugins path %s", m_file.GetFullName(),
PATHS::GetStockPluginsPath() );
return test;
}
wxLogTrace( BOM_TRACE, "Could not find %s (checked %s, %s)", m_file.GetFullName(),
PATHS::GetUserPluginsPath(), PATHS::GetStockPluginsPath() );
return m_file;
}

View File

@ -33,6 +33,8 @@
#include <memory>
extern const wxChar BOM_TRACE[];
/**
* Bill of material output generator.
*
@ -78,6 +80,16 @@ public:
return m_file;
}
/**
* Returns the calculated path to the plugin: if the path is already absolute and exists,
* just return it. Otherwise if the path is just a filename, look for that file in the user
* and system plugin directories and return the first one found. If neither is found, just
* return m_file.
*
* @return the full path to the plugin
*/
wxFileName FindFilePath() const;
/**
* Return the customisable plugin name.
*/
@ -140,7 +152,7 @@ protected:
bool m_isOk;
///< Path to the plugin
const wxFileName m_file;
wxFileName m_file;
///< User customisable name
wxString m_name;

View File

@ -46,131 +46,18 @@
#include <schematic.h>
#include <paths.h>
#include <dialogs/dialog_bom_cfg_lexer.h>
#include <wx/filedlg.h>
#include <wx/textdlg.h>
static constexpr wxChar BOM_TRACE[] = wxT( "BOM_GENERATORS" );
wxString s_bomHelpInfo =
#include <dialog_bom_help_md.h>
;
using namespace T_BOMCFG_T; // for the BOM_CFG_PARSER parser and its keywords
// BOM "plugins" are not actually plugins. They are external tools
// (scripts or executables) called by this dialog.
typedef std::vector<BOM_GENERATOR_HANDLER::PTR> BOM_GENERATOR_ARRAY;
/**
* Holds data and functions pertinent to parsing a S-expression file
*/
class BOM_CFG_PARSER : public DIALOG_BOM_CFG_LEXER
{
BOM_GENERATOR_ARRAY* m_generatorsList;
public:
BOM_CFG_PARSER( BOM_GENERATOR_ARRAY* aGenerators, const char* aData, const wxString& aSource );
void Parse();
private:
void parseGenerator();
};
BOM_CFG_PARSER::BOM_CFG_PARSER( BOM_GENERATOR_ARRAY* aGenerators, const char* aLine,
const wxString& aSource ) :
DIALOG_BOM_CFG_LEXER( aLine, aSource )
{
m_generatorsList = aGenerators;
}
void BOM_CFG_PARSER::Parse()
{
T token;
while( ( token = NextTok() ) != T_RIGHT )
{
if( token == T_EOF)
break;
if( token == T_LEFT )
token = NextTok();
if( token == T_plugins )
continue;
switch( token )
{
case T_plugin: // Defines a new plugin
parseGenerator();
break;
default:
// Unexpected( CurText() );
break;
}
}
}
void BOM_CFG_PARSER::parseGenerator()
{
NeedSYMBOLorNUMBER();
wxString name = FromUTF8();
auto plugin = std::make_unique<BOM_GENERATOR_HANDLER>( name );
T token;
while( ( token = NextTok() ) != T_RIGHT )
{
if( token == T_EOF)
break;
switch( token )
{
case T_LEFT:
break;
case T_cmd:
NeedSYMBOLorNUMBER();
if( plugin )
plugin->SetCommand( FromUTF8() );
NeedRIGHT();
break;
case T_opts:
NeedSYMBOLorNUMBER();
if( plugin )
{
wxString option = FromUTF8();
if( option.StartsWith( "nickname=", &name ) )
plugin->SetName( name );
else
plugin->Options().Add( option );
}
NeedRIGHT();
break;
default:
Unexpected( CurText() );
break;
}
}
if( plugin )
m_generatorsList->push_back( std::move( plugin ) );
}
// The main dialog frame to run scripts to build bom
class DIALOG_BOM : public DIALOG_BOM_BASE
{
@ -251,56 +138,44 @@ DIALOG_BOM::DIALOG_BOM( SCH_EDIT_FRAME* parent ) :
// Now all widgets have the size fixed, call FinishDialogSettings
finishDialogSettings();
m_buttonReset->Bind( wxEVT_BUTTON,
[&]( wxCommandEvent& )
{
EESCHEMA_SETTINGS* cfg = m_parent->eeconfig();
cfg->m_BomPanel.selected_plugin = wxEmptyString;
cfg->m_BomPanel.plugins = cfg->DefaultBomPlugins();
installGeneratorsList();
} );
}
DIALOG_BOM::~DIALOG_BOM()
{
if( m_helpWindow )
m_helpWindow->Destroy();
// TODO(JE) maybe unpack this into JSON instead of sexpr
EESCHEMA_SETTINGS* cfg = m_parent->eeconfig();
// Save the plugin descriptions in config.
// The config stores only one string, so we save the plugins inside a S-expr:
// ( plugins
// ( plugin "plugin name 1" (cmd "command line 1") )
// ( plugin "plugin name 2" (cmd "command line 2") (opts "option1") (opts "option2") )
// ....
// )
cfg->m_BomPanel.plugins.clear();
STRING_FORMATTER writer;
writer.Print( 0, "(plugins" );
for( auto& plugin : m_generators )
for( const std::unique_ptr<BOM_GENERATOR_HANDLER>& plugin : m_generators )
{
writer.Print( 1, "(plugin %s (cmd %s)",
writer.Quotew( plugin->GetFile().GetFullPath() ).c_str(),
writer.Quotew( plugin->GetCommand() ).c_str() );
wxString name = plugin->GetName();
wxFileName path = plugin->GetFile();
for( unsigned jj = 0; jj < plugin->Options().GetCount(); jj++ )
{
writer.Print( 1, "(opts %s)",
writer.Quotew( plugin->Options().Item( jj ) ).c_str() );
}
// handle empty nickname by stripping path
if( name.IsEmpty() )
name = path.GetName();
if( !plugin->GetName().IsEmpty() )
{
wxString option = wxString::Format( "nickname=%s", plugin->GetName() );
EESCHEMA_SETTINGS::BOM_PLUGIN_SETTINGS setting( name, path.GetFullPath() );
setting.command = plugin->GetCommand();
writer.Print( 1, "(opts %s)",
writer.Quotew( option ).c_str() );
}
writer.Print( 0, ")" );
cfg->m_BomPanel.plugins.emplace_back( setting );
}
writer.Print( 0, ")" );
wxString list( FROM_UTF8( writer.GetString().c_str() ) );
auto cfg = static_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
cfg->m_BomPanel.plugins = list.ToStdString();
cfg->m_BomPanel.selected_plugin = m_lbGenerators->GetStringSelection().ToStdString();
}
@ -308,33 +183,36 @@ DIALOG_BOM::~DIALOG_BOM()
// Read the initialized plugins in config and fill the list of names
void DIALOG_BOM::installGeneratorsList()
{
auto cfg = static_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
EESCHEMA_SETTINGS* cfg = m_parent->eeconfig();
wxString list = cfg->m_BomPanel.plugins;
wxString active_plugin_name = cfg->m_BomPanel.selected_plugin;
if( !list.IsEmpty() )
m_generators.clear();
for( EESCHEMA_SETTINGS::BOM_PLUGIN_SETTINGS& setting : cfg->m_BomPanel.plugins )
{
BOM_CFG_PARSER cfg_parser( &m_generators, TO_UTF8( list ), wxT( "plugins" ) );
auto plugin = std::make_unique<BOM_GENERATOR_HANDLER>( setting.path );
try
{
cfg_parser.Parse();
}
catch( const IO_ERROR& )
{
// wxLogMessage( ioe.What() );
}
catch( std::runtime_error& e )
{
DisplayError( nullptr, e.what() );
}
plugin->SetName( setting.name );
// Populate list box
if( !setting.command.IsEmpty() )
plugin->SetCommand( setting.command );
m_generators.emplace_back( std::move( plugin ) );
}
m_lbGenerators->Clear();
if( !m_generators.empty() )
{
for( unsigned ii = 0; ii < m_generators.size(); ii++ )
{
if( !m_generators[ii]->GetFile().Exists( wxFILE_EXISTS_REGULAR ) )
if( !m_generators[ii]->FindFilePath().Exists( wxFILE_EXISTS_REGULAR ) )
{
wxLogTrace( BOM_TRACE, "BOM plugin %s not found",
m_generators[ii]->FindFilePath().GetFullName() );
continue;
}
m_lbGenerators->Append( m_generators[ii]->GetName() );
@ -343,53 +221,6 @@ void DIALOG_BOM::installGeneratorsList()
}
}
if( m_generators.empty() ) // No plugins found?
{
// Load plugins from the default locations
std::vector<wxString> pluginPaths = {
#if defined(__WXGTK__)
"/usr/share/kicad/plugins",
"/usr/local/share/kicad/plugins",
#elif defined(__WXMSW__)
wxString::Format( "%s\\scripting\\plugins", Pgm().GetExecutablePath() ),
#elif defined(__WXMAC__)
wxString::Format( "%s/plugins", PATHS::GetOSXKicadDataDir() ),
#endif
};
wxFileName pluginPath;
for( const auto& path : pluginPaths )
{
wxDir dir( path );
if( !dir.IsOpened() )
continue;
pluginPath.AssignDir( dir.GetName() );
wxString fileName;
bool cont = dir.GetFirst( &fileName, wxFileSelectorDefaultWildcardStr, wxDIR_FILES );
while( cont )
{
try
{
wxLogTrace( BOM_TRACE,"Checking if %s is a BOM generator", fileName );
if( BOM_GENERATOR_HANDLER::IsValidGenerator( fileName ) )
{
pluginPath.SetFullName( fileName );
addGenerator( pluginPath.GetFullPath() );
}
}
catch( ... ) { /* well, no big deal */ }
cont = dir.GetNext( &fileName );
}
}
}
pluginInit();
}

View File

@ -109,6 +109,17 @@ DIALOG_BOM_BASE::DIALOG_BOM_BASE( wxWindow* parent, wxWindowID id, const wxStrin
m_staticline = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
bMainSizer->Add( m_staticline, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 );
wxBoxSizer* bSizer8;
bSizer8 = new wxBoxSizer( wxHORIZONTAL );
m_buttonReset = new wxButton( this, wxID_ANY, _("Reset to Defaults"), wxDefaultPosition, wxDefaultSize, 0 );
m_buttonReset->SetToolTip( _("Reset the list of BOM generator scripts to the default settings") );
bSizer8->Add( m_buttonReset, 0, wxALL, 5 );
bSizer8->Add( 0, 0, 1, wxEXPAND, 5 );
m_sdbSizer = new wxStdDialogButtonSizer();
m_sdbSizerOK = new wxButton( this, wxID_OK );
m_sdbSizer->AddButton( m_sdbSizerOK );
@ -118,7 +129,10 @@ DIALOG_BOM_BASE::DIALOG_BOM_BASE( wxWindow* parent, wxWindowID id, const wxStrin
m_sdbSizer->AddButton( m_sdbSizerHelp );
m_sdbSizer->Realize();
bMainSizer->Add( m_sdbSizer, 0, wxEXPAND|wxALL, 5 );
bSizer8->Add( m_sdbSizer, 0, wxEXPAND|wxALL, 5 );
bMainSizer->Add( bSizer8, 0, wxEXPAND, 5 );
this->SetSizer( bMainSizer );

View File

@ -920,22 +920,115 @@
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND|wxALL</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxStdDialogButtonSizer" expanded="1">
<property name="Apply">0</property>
<property name="Cancel">1</property>
<property name="ContextHelp">0</property>
<property name="Help">1</property>
<property name="No">0</property>
<property name="OK">1</property>
<property name="Save">0</property>
<property name="Yes">0</property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">m_sdbSizer</property>
<property name="permission">protected</property>
<event name="OnHelpButtonClick">OnHelp</event>
<event name="OnOKButtonClick">OnRunGenerator</event>
<property name="name">bSizer8</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxButton" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="bitmap"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="current"></property>
<property name="default">0</property>
<property name="default_pane">0</property>
<property name="disabled"></property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="focus"></property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Reset to Defaults</property>
<property name="margins"></property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_buttonReset</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="position"></property>
<property name="pressed"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip">Reset the list of BOM generator scripts to the default settings</property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="spacer" expanded="1">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND|wxALL</property>
<property name="proportion">0</property>
<object class="wxStdDialogButtonSizer" expanded="1">
<property name="Apply">0</property>
<property name="Cancel">1</property>
<property name="ContextHelp">0</property>
<property name="Help">1</property>
<property name="No">0</property>
<property name="OK">1</property>
<property name="Save">0</property>
<property name="Yes">0</property>
<property name="minimum_size"></property>
<property name="name">m_sdbSizer</property>
<property name="permission">protected</property>
<event name="OnHelpButtonClick">OnHelp</event>
<event name="OnOKButtonClick">OnRunGenerator</event>
</object>
</object>
</object>
</object>
</object>

View File

@ -57,6 +57,7 @@ class DIALOG_BOM_BASE : public DIALOG_SHIM
wxTextCtrl* m_textCtrlCommand;
wxCheckBox* m_checkBoxShowConsole;
wxStaticLine* m_staticline;
wxButton* m_buttonReset;
wxStdDialogButtonSizer* m_sdbSizer;
wxButton* m_sdbSizerOK;
wxButton* m_sdbSizerCancel;

View File

@ -21,6 +21,9 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <functional>
#include <dialogs/dialog_bom_cfg_lexer.h>
#include <eeschema_settings.h>
#include <layers_id_colors_and_visibility.h>
#include <symbol_editor_settings.h>
@ -32,8 +35,22 @@
#include <widgets/ui_common.h>
#include <default_values.h> // For some default values
using namespace T_BOMCFG_T; // for the BOM_CFG_PARSER parser and its keywords
///! Update the schema version whenever a migration is required
const int eeschemaSchemaVersion = 0;
const int eeschemaSchemaVersion = 1;
/// Default value for bom.plugins
const nlohmann::json defaultBomPlugins = {
{
{ "name", "bom_csv_grouped_by_value" },
{ "path", "bom_csv_grouped_by_value.py" }
},
{
{ "name", "bom_csv_grouped_by_value_with_fp" },
{ "path", "bom_csv_grouped_by_value_with_fp.py" }
},
};
EESCHEMA_SETTINGS::EESCHEMA_SETTINGS() :
@ -184,8 +201,18 @@ EESCHEMA_SETTINGS::EESCHEMA_SETTINGS() :
m_params.emplace_back( new PARAM<wxString>( "bom.selected_plugin",
&m_BomPanel.selected_plugin, "" ) );
m_params.emplace_back( new PARAM<wxString>( "bom.plugins",
&m_BomPanel.plugins, "" ) );
m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "bom.plugins",
std::bind( &EESCHEMA_SETTINGS::bomSettingsToJson, this ),
[&]( const nlohmann::json& aObj )
{
if( !aObj.is_array() )
return;
const nlohmann::json& list = aObj.empty() ? defaultBomPlugins : aObj;
m_BomPanel.plugins = bomSettingsFromJson( list );
},
defaultBomPlugins ) );
m_params.emplace_back( new PARAM<bool>( "page_settings.export_paper",
&m_PageSettings.export_paper, false ) );
@ -352,6 +379,15 @@ EESCHEMA_SETTINGS::EESCHEMA_SETTINGS() :
m_params.emplace_back( new PARAM<wxString>( "system.last_symbol_lib_dir",
&m_lastSymbolLibDir, "" ) );
// Migrations
registerMigration( 0, 1,
[&]() -> bool
{
// Version 0 to 1: BOM plugin settings moved from sexpr to JSON
return migrateBomSettings();
} );
}
@ -415,6 +451,8 @@ bool EESCHEMA_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
ret &= fromLegacyString( aCfg, "bom_plugin_selected", "bom.selected_plugin" );
ret &= fromLegacyString( aCfg, "bom_plugins", "bom.plugins" );
migrateBomSettings();
ret &= fromLegacyString( aCfg, "SymbolFieldsShownColumns",
"edit_sch_component.visible_columns" );
@ -595,3 +633,191 @@ bool EESCHEMA_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
return ret;
}
/**
* Used for parsing legacy-format bom plugin configurations. Only used for migrating into
* EESCHEMA_SETTINGS JSON format.
*/
class BOM_CFG_PARSER : public DIALOG_BOM_CFG_LEXER
{
std::vector<EESCHEMA_SETTINGS::BOM_PLUGIN_SETTINGS>* m_pluginList;
public:
BOM_CFG_PARSER( std::vector<EESCHEMA_SETTINGS::BOM_PLUGIN_SETTINGS>* aPluginList,
const char* aData, const wxString& aSource );
void Parse();
private:
void parseGenerator();
};
std::vector<EESCHEMA_SETTINGS::BOM_PLUGIN_SETTINGS> EESCHEMA_SETTINGS::DefaultBomPlugins()
{
return bomSettingsFromJson( defaultBomPlugins );
}
bool EESCHEMA_SETTINGS::migrateBomSettings()
{
nlohmann::json::json_pointer ptr = PointerFromString( "bom.plugins" );
if( !contains( ptr ) )
return false;
wxString list = at( ptr ).get<wxString>();
BOM_CFG_PARSER cfg_parser( &m_BomPanel.plugins, TO_UTF8( list ), wxT( "plugins" ) );
try
{
cfg_parser.Parse();
}
catch( const IO_ERROR& )
{
return false;
}
// Parser will have loaded up our array, let's dump it out to JSON
at( ptr ) = bomSettingsToJson();
return true;
}
nlohmann::json EESCHEMA_SETTINGS::bomSettingsToJson() const
{
nlohmann::json js = nlohmann::json::array();
for( const BOM_PLUGIN_SETTINGS& plugin : m_BomPanel.plugins )
{
nlohmann::json pluginJson;
pluginJson["name"] = plugin.name.ToUTF8();
pluginJson["path"] = plugin.path.ToUTF8();
pluginJson["command"] = plugin.command.ToUTF8();
js.push_back( pluginJson );
}
return js;
}
std::vector<EESCHEMA_SETTINGS::BOM_PLUGIN_SETTINGS> EESCHEMA_SETTINGS::bomSettingsFromJson(
const nlohmann::json& aObj )
{
std::vector<EESCHEMA_SETTINGS::BOM_PLUGIN_SETTINGS> ret;
wxASSERT( aObj.is_array() );
for( const nlohmann::json& entry : aObj )
{
if( entry.empty() || !entry.is_object() )
continue;
if( !entry.contains( "name" ) || !entry.contains( "path" ) )
continue;
BOM_PLUGIN_SETTINGS plugin( entry.at( "name" ).get<wxString>(),
entry.at( "path" ).get<wxString>() );
if( entry.contains( "command" ) )
plugin.command = entry.at( "command" ).get<wxString>();
ret.emplace_back( plugin );
}
return ret;
}
BOM_CFG_PARSER::BOM_CFG_PARSER( std::vector<EESCHEMA_SETTINGS::BOM_PLUGIN_SETTINGS>* aPluginList,
const char* aLine, const wxString& aSource ) :
DIALOG_BOM_CFG_LEXER( aLine, aSource )
{
wxASSERT( aPluginList );
m_pluginList = aPluginList;
}
void BOM_CFG_PARSER::Parse()
{
T token;
while( ( token = NextTok() ) != T_RIGHT )
{
if( token == T_EOF)
break;
if( token == T_LEFT )
token = NextTok();
if( token == T_plugins )
continue;
switch( token )
{
case T_plugin: // Defines a new plugin
parseGenerator();
break;
default:
// Unexpected( CurText() );
break;
}
}
}
void BOM_CFG_PARSER::parseGenerator()
{
wxString str;
EESCHEMA_SETTINGS::BOM_PLUGIN_SETTINGS settings;
NeedSYMBOLorNUMBER();
settings.path = FromUTF8();
T token;
while( ( token = NextTok() ) != T_RIGHT )
{
if( token == T_EOF)
break;
switch( token )
{
case T_LEFT:
break;
case T_cmd:
NeedSYMBOLorNUMBER();
settings.command = FromUTF8();
NeedRIGHT();
break;
case T_opts:
{
NeedSYMBOLorNUMBER();
wxString option = FromUTF8();
if( option.StartsWith( "nickname=", &str ) )
settings.name = str;
NeedRIGHT();
break;
}
default:
Unexpected( CurText() );
break;
}
}
m_pluginList->emplace_back( settings );
}

View File

@ -57,6 +57,20 @@ public:
bool align_to_grid;
};
struct BOM_PLUGIN_SETTINGS
{
BOM_PLUGIN_SETTINGS() = default;
BOM_PLUGIN_SETTINGS( const wxString& aName, const wxString& aPath ) :
name( aName ),
path( aPath )
{}
wxString name;
wxString path;
wxString command;
};
struct DRAWING
{
int default_bus_thickness;
@ -126,7 +140,7 @@ public:
struct PANEL_BOM
{
wxString selected_plugin;
wxString plugins;
std::vector<BOM_PLUGIN_SETTINGS> plugins;
};
struct PANEL_FIELD_EDITOR
@ -188,6 +202,8 @@ public:
virtual bool MigrateFromLegacy( wxConfigBase* aLegacyConfig ) override;
static std::vector<BOM_PLUGIN_SETTINGS> DefaultBomPlugins();
APPEARANCE m_Appearance;
AUTOPLACE_FIELDS m_AutoplaceFields;
@ -223,6 +239,14 @@ public:
protected:
virtual std::string getLegacyFrameName() const override { return "SchematicFrame"; }
private:
bool migrateBomSettings();
nlohmann::json bomSettingsToJson() const;
static std::vector<BOM_PLUGIN_SETTINGS> bomSettingsFromJson( const nlohmann::json& aObj );
};