Eeschema: add dialog and utilities to create BOMs from generic netlist

This commit is contained in:
jean-pierre charras 2013-06-14 16:59:52 +02:00
parent 2810f5a5fe
commit 26b7bdc35c
22 changed files with 2667 additions and 360 deletions

View File

@ -8,5 +8,6 @@ file( STRINGS ${inputFile} lines )
file( WRITE ${outputFile} "// Do not edit this file, it is autogenerated by CMake from an HTML file\n" ) file( WRITE ${outputFile} "// Do not edit this file, it is autogenerated by CMake from an HTML file\n" )
foreach( line ${lines} ) foreach( line ${lines} )
file( APPEND ${outputFile} "\"" ${line} "\"\n" ) STRING(REGEX REPLACE "\"" "\\\\\"" linem ${line})
file( APPEND ${outputFile} "\"" ${linem} "\\n\"\n" )
endforeach( line ${lines} ) endforeach( line ${lines} )

View File

@ -14,6 +14,9 @@ set(EESCHEMA_DLGS
dialogs/dialog_color_config.cpp dialogs/dialog_color_config.cpp
dialogs/dialog_annotate.cpp dialogs/dialog_annotate.cpp
dialogs/dialog_annotate_base.cpp dialogs/dialog_annotate_base.cpp
dialogs/dialog_bom.cpp
dialogs/dialog_bom_base.cpp
dialogs/dialog_bom_cfg_keywords.cpp
dialogs/dialog_lib_edit_text.cpp dialogs/dialog_lib_edit_text.cpp
dialogs/dialog_lib_edit_text_base.cpp dialogs/dialog_lib_edit_text_base.cpp
dialogs/dialog_edit_component_in_lib.cpp dialogs/dialog_edit_component_in_lib.cpp
@ -203,6 +206,33 @@ make_lexer(
template_fieldnames.h template_fieldnames.h
) )
make_lexer(
${CMAKE_CURRENT_SOURCE_DIR}/dialogs/dialog_bom_cfg.keywords
${CMAKE_CURRENT_SOURCE_DIR}/dialogs/dialog_bom_cfg_lexer.h
${CMAKE_CURRENT_SOURCE_DIR}/dialogs/dialog_bom_cfg_keywords.cpp
T_BOMCFG_T
# Pass header file with dependency on *_lexer.h as extra_arg
/dialogs/dialog_bom_cfg.h
)
# Create a C++ compilable string initializer containing html text into a *.h file:
add_custom_command(
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/dialogs/dialog_bom_help_html.h
COMMAND ${CMAKE_COMMAND}
-DinputFile=${CMAKE_CURRENT_SOURCE_DIR}/dialogs/dialog_bom_help.html
-DoutputFile=${CMAKE_CURRENT_SOURCE_DIR}/dialogs/dialog_bom_help_html.h
-P ${CMAKE_MODULE_PATH}/Html2C.cmake
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/dialogs/dialog_bom_help.html
COMMENT "creating ${CMAKE_CURRENT_SOURCE_DIR}/dialogs/dialog_bom_help_html.h
from ${CMAKE_CURRENT_SOURCE_DIR}/dialogs/dialog_bom_help.html"
)
set_source_files_properties( dialogs/dialog_bom.cpp
PROPERTIES
OBJECT_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/dialogs/dialog_bom_help_html.h
)
add_executable(eeschema WIN32 MACOSX_BUNDLE add_executable(eeschema WIN32 MACOSX_BUNDLE
${EESCHEMA_SRCS} ${EESCHEMA_SRCS}
${EESCHEMA_COMMON_SRCS} ${EESCHEMA_COMMON_SRCS}

View File

@ -67,7 +67,6 @@ bool SCH_REFERENCE_LIST::sortByXPosition( const SCH_REFERENCE& item1,
return ii < 0; return ii < 0;
} }
bool SCH_REFERENCE_LIST::sortByYPosition( const SCH_REFERENCE& item1, bool SCH_REFERENCE_LIST::sortByYPosition( const SCH_REFERENCE& item1,
const SCH_REFERENCE& item2 ) const SCH_REFERENCE& item2 )
{ {
@ -106,252 +105,6 @@ bool SCH_REFERENCE_LIST::sortByRefAndValue( const SCH_REFERENCE& item1,
return ii < 0; return ii < 0;
} }
bool SCH_REFERENCE_LIST::sortByValueAndRef( const SCH_REFERENCE& item1,
const SCH_REFERENCE& item2 )
{
int ii = item1.CompareValue( item2 );
if( ii == 0 )
ii = RefDesStringCompare( item1.GetRef(), item2.GetRef() );
if( ii == 0 )
ii = item1.m_Unit - item2.m_Unit;
if( ii == 0 )
ii = item1.m_SheetNum - item2.m_SheetNum;
if( ii == 0 )
ii = item1.m_CmpPos.x - item2.m_CmpPos.x;
if( ii == 0 )
ii = item1.m_CmpPos.y - item2.m_CmpPos.y;
if( ii == 0 )
ii = item1.m_TimeStamp - item2.m_TimeStamp;
return ii < 0;
}
/*
* Helper function to calculate in a component value string
* the value, depending on multiplier symbol:
* pico
* nano
* micro (u)
* milli (m)
* kilo (k ou K)
* Mega
* Giga
* Tera
*
* with notations like 1K; 1.5K; 1,5K; 1k5
* returns true if the string is a value, false if not
* (a value is a string starting by a number)
*/
static bool engStrToDouble( wxString aStr, double* aDouble )
{
// A trick to take care of strings without a multiplier
aStr.Append( wxT( "R" ) );
// Regular expression for a value string, e.g., 47k2
#if defined(KICAD_GOST)
static wxRegEx valueRegEx( wxT( "^([0-9]+)(мк|[pnumRkKMGT.,кнМГ])([0-9]*)(мк*|[pnumRkKMGTкнМГ]*)" ) );
#else
static wxRegEx valueRegEx( wxT( "^([0-9]+)([pnumRkKMGT.,])([0-9]*)([pnumRkKMGT]*)" ) );
#endif
if( !valueRegEx.Matches( aStr ) )
return false;
wxString valueStr = wxString( valueRegEx.GetMatch( aStr, 1 )
+ wxT( "." )
+ valueRegEx.GetMatch( aStr, 3 ) );
wxString multiplierString = valueRegEx.GetMatch( aStr, 2 );
#if defined(KICAD_GOST)
if ( multiplierString == wxT( "мк" ) )
multiplierString = wxT( "u" );
else if ( multiplierString == wxT( "к" ) )
multiplierString = wxT( "k" );
else if ( multiplierString == wxT( "н" ) )
multiplierString = wxT( "n" );
else if ( multiplierString == wxT( "М" ) )
multiplierString = wxT( "M" );
else if ( multiplierString == wxT( "Г" ) )
multiplierString = wxT( "G" );
#endif
wxString post_multiplierString = valueRegEx.GetMatch( aStr, 4 );
#if defined(KICAD_GOST)
if ( post_multiplierString == wxT( "мк" ) )
multiplierString = wxT( "u" );
else if ( post_multiplierString == wxT( "к" ) )
multiplierString = wxT( "k" );
else if ( post_multiplierString == wxT( "н" ) )
multiplierString = wxT( "n" );
else if ( post_multiplierString == wxT( "М" ) )
multiplierString = wxT( "M" );
else if ( post_multiplierString == wxT( "Г" ) )
multiplierString = wxT( "G" );
#endif
double multiplier;
switch( (wxChar)multiplierString[0] )
{
case 'p':
multiplier = 1e-12;
break;
case 'n':
multiplier = 1e-9;
break;
case 'u':
multiplier = 1e-6;
break;
case 'm':
multiplier = 1e-3;
break;
case 'k':
case 'K':
multiplier = 1e3;
break;
case 'M':
multiplier = 1e6;
break;
case 'G':
multiplier = 1e9;
break;
case 'T':
multiplier = 1e12;
break;
case 'R':
case '.': // floating point separator
case ',': // floating point separator (some languages)
default:
multiplier = 1;
break;
}
switch( (wxChar)post_multiplierString[0] )
{
case 'p':
multiplier = 1e-12;
break;
case 'n':
multiplier = 1e-9;
break;
case 'u':
multiplier = 1e-6;
break;
case 'm':
multiplier = 1e-3;
break;
case 'k':
case 'K':
multiplier = 1e3;
break;
case 'M':
multiplier = 1e6;
break;
case 'G':
multiplier = 1e9;
break;
case 'T':
multiplier = 1e12;
break;
case 'R':
default:
break;
}
LOCALE_IO dummy; // set to C floating point standard
valueStr.ToDouble( aDouble );
*aDouble *= multiplier;
return true;
}
static bool splitRefStr( const wxString& aRef, wxString* aStr, int* aNumber )
{
static wxRegEx refRegEx( wxT( "^([a-zA-Z]+)([0-9]+)" ) );
if( !refRegEx.Matches( aRef ) )
return false;
*aStr = refRegEx.GetMatch( aRef, 1 );
*aNumber = wxAtoi( refRegEx.GetMatch( aRef, 2 ) );
return true;
}
/* sort the list of references by value.
* Components are grouped by type and are sorted by value:
* The value of a component accept multiplier symbols (p, n, K ..)
* groups are made by first letter of reference
*/
bool SCH_REFERENCE_LIST::sortByValueOnly( const SCH_REFERENCE& item1,
const SCH_REFERENCE& item2 )
{
// First, group by type according to reference text part (R, C, etc.)
wxString text1 = item1.GetComponent()->GetField( REFERENCE )->GetText();
wxString text2 = item2.GetComponent()->GetField( REFERENCE )->GetText();
wxString refNameStr1, refNameStr2;
int refNumber1, refNumber2;
if( !splitRefStr( text1, &refNameStr1, &refNumber1 ) )
return false;
if( !splitRefStr( text2, &refNameStr2, &refNumber2 ) )
return false;
int ii = refNameStr1.CmpNoCase( refNameStr2 );
if( ii != 0 )
return ii < 0;
// We can compare here 2 values relative to components of the same type
// assuming references are correctly chosen
text1 = item1.GetComponent()->GetField( VALUE )->GetText();
text2 = item2.GetComponent()->GetField( VALUE )->GetText();
double value1, value2;
// Try to convert value to double (4k7 -> 4700 etc.)
bool match1 = engStrToDouble( text1, &value1 );
bool match2 = engStrToDouble( text2, &value2 );
// Values come before other strings
if( match1 && !match2 )
return true;
// Values come before other strings
if( !match1 && match2 )
return false;
if( match1 && match2 && (value1 != value2) )
return value1 < value2;
// Inside a group of components of same value, it could be good to group per footprints
text1 = item1.GetComponent()->GetField( FOOTPRINT )->GetText();
text2 = item2.GetComponent()->GetField( FOOTPRINT )->GetText();
ii = text1.CmpNoCase( text2 );
if( ii != 0 )
return ii < 0;
if( refNumber1 != refNumber2 )
return refNumber1 < refNumber2;
// Fall back to normal string compare
ii = text1.CmpNoCase( text2 );
if( ii == 0 )
ii = RefDesStringCompare( item1.GetRef(), item2.GetRef() );
if( ii == 0 )
ii = item1.m_Unit - item2.m_Unit;
return ii < 0;
}
bool SCH_REFERENCE_LIST::sortByReferenceOnly( const SCH_REFERENCE& item1, bool SCH_REFERENCE_LIST::sortByReferenceOnly( const SCH_REFERENCE& item1,
const SCH_REFERENCE& item2 ) const SCH_REFERENCE& item2 )
@ -385,7 +138,6 @@ bool SCH_REFERENCE_LIST::sortByTimeStamp( const SCH_REFERENCE& item1,
return ii < 0; return ii < 0;
} }
int SCH_REFERENCE_LIST::FindUnit( size_t aIndex, int aUnit ) int SCH_REFERENCE_LIST::FindUnit( size_t aIndex, int aUnit )
{ {
int NumRef; int NumRef;

View File

@ -0,0 +1,476 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 Jean-Pierre Charras, jp.charras@wanadoo.fr
* Copyright (C) 1992-2013 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file eeschema/dialogs/dialog_bom.cpp
* @brief Dialog box for creating bom and other documents from generic netlist.
*/
#include <fctsys.h>
#include <appl_wxstruct.h>
#include <confirm.h>
#include <gestfich.h>
#include <wxEeschemaStruct.h>
#include <netlist.h>
#include <sch_sheet.h>
#include <invoke_sch_dialog.h>
#include <dialog_helpers.h>
#include <dialog_bom_base.h>
#include <../common/dialogs/dialog_display_info_HTML_base.h>
#define BOM_PLUGINS_KEY wxT("bom_plugins")
#define BOM_PLUGIN_SELECTED_KEY wxT("bom_plugin_selected")
const char * s_bomHelpInfo =
#include <dialog_bom_help_html.h>
;
#include <dialog_bom_cfg_lexer.h>
using namespace T_BOMCFG_T;
/**
* Class BOM_CFG_READER_PARSER
* holds data and functions pertinent to parsing a S-expression file
* for a WORKSHEET_LAYOUT.
*/
class BOM_CFG_READER_PARSER : public DIALOG_BOM_CFG_LEXER
{
wxArrayString* m_pluginsList;
public:
BOM_CFG_READER_PARSER( wxArrayString* aPlugins,
const char* aData, const wxString& aSource );
void Parse() throw( PARSE_ERROR, IO_ERROR );
private:
void parsePlugin() throw( IO_ERROR, PARSE_ERROR );
};
// PCB_PLOT_PARAMS_PARSER
BOM_CFG_READER_PARSER::BOM_CFG_READER_PARSER( wxArrayString* aPlugins,
const char* aLine,
const wxString& aSource ) :
DIALOG_BOM_CFG_LEXER( aLine, aSource )
{
m_pluginsList = aPlugins;
}
void BOM_CFG_READER_PARSER::Parse() throw( PARSE_ERROR, IO_ERROR )
{
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
parsePlugin();
break;
default:
// Unexpected( CurText() );
break;
}
}
}
void BOM_CFG_READER_PARSER::parsePlugin() throw( IO_ERROR, PARSE_ERROR )
{
wxString title, command;
NeedSYMBOLorNUMBER();
title = FromUTF8();
T token;
while( ( token = NextTok() ) != T_RIGHT )
{
if( token == T_EOF)
break;
switch( token )
{
case T_LEFT:
break;
case T_cmd:
NeedSYMBOLorNUMBER();
command = FromUTF8();
NeedRIGHT();
break;
case T_opts:
while( ( token = NextTok() ) != T_RIGHT && token != T_EOF );
break;
default:
Unexpected( CurText() );
break;
}
}
if( ! title.IsEmpty() )
{
m_pluginsList->Add( title );
m_pluginsList->Add( command );
}
}
// The main dialog frame tu run scripts to build bom
class DIALOG_BOM : public DIALOG_BOM_BASE
{
private:
SCH_EDIT_FRAME* m_parent;
// The list of scripts (or plugins):
// a script descr uses 2 lines:
// the first is the title
// the second is the command line
wxArrayString m_plugins;
wxConfig* m_config; // to store the "plugins"
public:
// Constructor and destructor
DIALOG_BOM( SCH_EDIT_FRAME* parent );
~DIALOG_BOM();
private:
void OnPluginSelected( wxCommandEvent& event );
void OnRunPlugin( wxCommandEvent& event );
void OnCancelClick( wxCommandEvent& event );
void OnHelp( wxCommandEvent& event );
void OnAddPlugin( wxCommandEvent& event );
void OnChoosePlugin( wxCommandEvent& event );
void OnRemovePlugin( wxCommandEvent& event );
void OnEditPlugin( wxCommandEvent& event );
void OnCommandLineEdited( wxCommandEvent& event );
void OnNameEdited( wxCommandEvent& event );
void pluginInit();
void installPluginsList();
};
// Create and show DIALOG_BOM.
int InvokeDialogCreateBOM( SCH_EDIT_FRAME* aCaller )
{
DIALOG_BOM dlg( aCaller );
return dlg.ShowModal();
}
DIALOG_BOM::DIALOG_BOM( SCH_EDIT_FRAME* parent ) :
DIALOG_BOM_BASE( parent )
{
m_parent = parent;
m_config = wxGetApp().GetSettings();
installPluginsList();
GetSizer()->SetSizeHints( this );
Centre();
}
DIALOG_BOM::~DIALOG_BOM()
{
wxString list;
// Save the plugin descriptions in config.
// the config stores only one string.
// plugins are saved inside a S expr:
// ( plugins
// ( plugin "plugin name" (cmd "command line") )
// ....
// )
STRING_FORMATTER writer;
list << wxT("(plugins");
for( unsigned ii = 0; ii < m_plugins.GetCount(); ii += 2 )
{
writer.Print( 1, "(plugin %s (cmd %s))",
writer.Quotew( m_plugins[ii] ).c_str(),
writer.Quotew( m_plugins[ii+1] ).c_str() );
}
list << writer.GetString();
list << wxT(")");
m_config->Write( BOM_PLUGINS_KEY, list );
wxString active_plugin_name = m_lbPlugins->GetStringSelection( );
m_config->Write( BOM_PLUGIN_SELECTED_KEY, active_plugin_name );
}
/* Read the initialized plugins in config and fill the list
* of names
*/
void DIALOG_BOM::installPluginsList()
{
wxString list, text, active_plugin_name;
m_config->Read( BOM_PLUGINS_KEY, &list );
m_config->Read( BOM_PLUGIN_SELECTED_KEY, &active_plugin_name );
if( !list.IsEmpty() )
{
BOM_CFG_READER_PARSER cfg_parser( &m_plugins, list.c_str(), wxT( "plugins" ) );
try
{
cfg_parser.Parse();
}
catch( IO_ERROR ioe )
{
// wxLogMessage( ioe.errorText );
}
}
// Populate list box
for( unsigned ii = 0; ii < m_plugins.GetCount(); ii+=2 )
{
m_lbPlugins->Append( m_plugins[ii] );
if( active_plugin_name == m_plugins[ii] )
m_lbPlugins->SetSelection( ii/2 );
}
pluginInit();
}
void DIALOG_BOM::OnPluginSelected( wxCommandEvent& event )
{
pluginInit();
}
void DIALOG_BOM::pluginInit()
{
int ii = m_lbPlugins->GetSelection();
if( ii < 0 )
return;
m_textCtrlName->SetValue( m_plugins[2 * ii] );
m_textCtrlCommand->SetValue( m_plugins[(2 * ii)+1] );
}
/**
* Function RunPlugin
* run the plugin command line
*/
void DIALOG_BOM::OnRunPlugin( wxCommandEvent& event )
{
wxFileName fn;
wxString fileWildcard;
wxString title = _( "Save Netlist File" );
// Calculate the xml netlist filename
fn = g_RootSheet->GetScreen()->GetFileName();
if( fn.GetPath().IsEmpty() )
fn.SetPath( wxGetCwd() );
fn.ClearExt();
wxString fullfilename = fn.GetFullPath();
m_parent->ClearMsgPanel();
m_parent->SetNetListerCommand( m_textCtrlCommand->GetValue() );
m_parent->CreateNetlist( -1, fullfilename, 0 );
}
void DIALOG_BOM::OnCancelClick( wxCommandEvent& event )
{
EndModal( wxID_CANCEL );
}
/**
* Function OnRemovePlugin
* Remove a plugin from the list
*/
void DIALOG_BOM::OnRemovePlugin( wxCommandEvent& event )
{
int ii = m_lbPlugins->GetSelection();
if( ii < 0 )
return;
m_lbPlugins->Delete( ii );
m_plugins.RemoveAt( 2*ii, 2 ); // Remove title and command line
}
/**
* Function OnAddPlugin
* Add a new panel for a new netlist plugin
*/
void DIALOG_BOM::OnAddPlugin( wxCommandEvent& event )
{
// Creates a new plugin entry
wxString name = wxGetTextFromUser( _("Plugin") );
if( name.IsEmpty() )
return;
// Verify if it does not exists
for( unsigned ii = 0; ii < m_plugins.GetCount(); ii += 2 )
{
if( name == m_plugins[ii] )
{
wxMessageBox( _("This plugin already exists. Abort") );
return;
}
}
m_plugins.Add( name );
m_plugins.Add( wxEmptyString );
m_lbPlugins->Append( name );
m_lbPlugins->SetSelection( m_lbPlugins->GetCount() - 1 );
}
/*
* Browse plugin files, and set m_CommandStringCtrl field
*/
void DIALOG_BOM::OnChoosePlugin( wxCommandEvent& event )
{
wxString FullFileName, Mask, Path;
Mask = wxT( "*" );
Path = wxGetApp().GetExecutablePath();
FullFileName = EDA_FileSelector( _( "Plugin files:" ),
Path,
FullFileName,
wxEmptyString,
Mask,
this,
wxFD_OPEN,
true
);
if( FullFileName.IsEmpty() )
return;
// Creates a default command line,
// suitable to run the external tool xslproc or python
// The default command line depending on plugin extension, currently
// "xsl" or "exe" or "py"
wxString cmdLine;
wxFileName fn( FullFileName );
wxString ext = fn.GetExt();
if( ext == wxT("xsl" ) )
cmdLine.Printf(wxT("xsltproc -o \"%%O\" \"%s\" \"%%I\""), GetChars(FullFileName) );
else if( ext == wxT("exe" ) || ext.IsEmpty() )
cmdLine.Printf(wxT("\"%s\" > \"%%O\" < \"%%I\""), GetChars(FullFileName) );
else if( ext == wxT("py" ) || ext.IsEmpty() )
cmdLine.Printf(wxT("python \"%s\" \"%%I\" \"%%O\""), GetChars(FullFileName) );
else
cmdLine.Printf(wxT("\"%s\""), GetChars(FullFileName) );
m_textCtrlCommand->SetValue( cmdLine );
}
void DIALOG_BOM::OnEditPlugin( wxCommandEvent& event )
{
wxString pluginName, cmdline;
// Try to find the plugin name.
// This is possible if the name ends by .py or .xsl
cmdline = m_textCtrlCommand->GetValue();
int pos = -1;
if( (pos = cmdline.Find( wxT(".py") )) != wxNOT_FOUND )
pos += 2;
else if( (pos = cmdline.Find( wxT(".xsl") )) != wxNOT_FOUND )
pos += 3;
// the end of plugin name is at position pos.
if( pos > 0 )
{
// Be sure this is the end of the name: the next char is " or space
int eos = cmdline[pos+1];
if( eos == ' '|| eos == '\"' )
{
// search for the starting point of the name
int jj = pos-1;
while( jj >= 0 )
if( cmdline[jj] != eos )
jj--;
else
break;
// extract the name
if( jj >= 0 )
pluginName = cmdline.SubString( jj, pos );
}
}
AddDelimiterString( pluginName );
wxString editorname = wxGetApp().GetEditorName();
if( !editorname.IsEmpty() )
ExecuteFile( this, editorname, pluginName );
else
wxMessageBox( _("No text editor selected in KiCad. Please choose it") );
}
void DIALOG_BOM::OnHelp( wxCommandEvent& event )
{
DIALOG_DISPLAY_HTML_TEXT_BASE help_Dlg( this, wxID_ANY,
_("Bom generation Help"),wxDefaultPosition, wxSize( 750,550 ) );
wxString msg = FROM_UTF8(s_bomHelpInfo);
help_Dlg.m_htmlWindow->AppendToPage( msg );
help_Dlg.ShowModal();
}
void DIALOG_BOM::OnCommandLineEdited( wxCommandEvent& event )
{
int ii = m_lbPlugins->GetSelection();
if( ii < 0 )
return;
m_plugins[(2 * ii)+1] = m_textCtrlCommand->GetValue();
}
void DIALOG_BOM::OnNameEdited( wxCommandEvent& event )
{
int ii = m_lbPlugins->GetSelection();
if( ii < 0 )
return;
m_plugins[2 * ii] = m_textCtrlName->GetValue();
m_lbPlugins->SetString( ii, m_plugins[2 * ii] );
}

View File

@ -0,0 +1,117 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Oct 8 2012)
// http://www.wxformbuilder.org/
//
// PLEASE DO "NOT" EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#include "dialog_bom_base.h"
///////////////////////////////////////////////////////////////////////////
BEGIN_EVENT_TABLE( DIALOG_BOM_BASE, DIALOG_SHIM )
EVT_LISTBOX( wxID_ANY, DIALOG_BOM_BASE::_wxFB_OnPluginSelected )
EVT_TEXT( ID_CMDLINE, DIALOG_BOM_BASE::_wxFB_OnCommandLineEdited )
EVT_TEXT( IN_NAMELINE, DIALOG_BOM_BASE::_wxFB_OnNameEdited )
EVT_BUTTON( ID_CREATE_BOM, DIALOG_BOM_BASE::_wxFB_OnRunPlugin )
EVT_BUTTON( wxID_CANCEL, DIALOG_BOM_BASE::_wxFB_OnCancelClick )
EVT_BUTTON( ID_HELP, DIALOG_BOM_BASE::_wxFB_OnHelp )
EVT_BUTTON( ID_ADD_PLUGIN, DIALOG_BOM_BASE::_wxFB_OnAddPlugin )
EVT_BUTTON( wxID_BROWSE_PLUGINS, DIALOG_BOM_BASE::_wxFB_OnChoosePlugin )
EVT_BUTTON( ID_REMOVEL_PLUGIN, DIALOG_BOM_BASE::_wxFB_OnRemovePlugin )
EVT_BUTTON( wxID_ANY, DIALOG_BOM_BASE::_wxFB_OnEditPlugin )
END_EVENT_TABLE()
DIALOG_BOM_BASE::DIALOG_BOM_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : DIALOG_SHIM( parent, id, title, pos, size, style )
{
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
wxBoxSizer* bMainSizer;
bMainSizer = new wxBoxSizer( wxVERTICAL );
wxBoxSizer* bUpperSizer;
bUpperSizer = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* bLeftSizer;
bLeftSizer = new wxBoxSizer( wxVERTICAL );
m_staticTextPluginTitle = new wxStaticText( this, wxID_ANY, _("Plugins"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextPluginTitle->Wrap( -1 );
bLeftSizer->Add( m_staticTextPluginTitle, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
m_lbPlugins = new wxListBox( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
bLeftSizer->Add( m_lbPlugins, 1, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_staticTextCmd = new wxStaticText( this, wxID_ANY, _("Command line:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextCmd->Wrap( -1 );
bLeftSizer->Add( m_staticTextCmd, 0, wxRIGHT|wxLEFT, 5 );
m_textCtrlCommand = new wxTextCtrl( this, ID_CMDLINE, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_textCtrlCommand->SetMaxLength( 0 );
m_textCtrlCommand->SetMinSize( wxSize( 300,-1 ) );
bLeftSizer->Add( m_textCtrlCommand, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_staticTextName = new wxStaticText( this, wxID_ANY, _("Name:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextName->Wrap( -1 );
bLeftSizer->Add( m_staticTextName, 0, wxRIGHT|wxLEFT, 5 );
m_textCtrlName = new wxTextCtrl( this, IN_NAMELINE, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_textCtrlName->SetMaxLength( 0 );
bLeftSizer->Add( m_textCtrlName, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
bUpperSizer->Add( bLeftSizer, 1, wxEXPAND, 5 );
wxBoxSizer* bRightSizer;
bRightSizer = new wxBoxSizer( wxVERTICAL );
m_buttonNetlist = new wxButton( this, ID_CREATE_BOM, _("Generate"), wxDefaultPosition, wxDefaultSize, 0 );
m_buttonNetlist->SetDefault();
bRightSizer->Add( m_buttonNetlist, 0, wxALL|wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5 );
m_buttonCancel = new wxButton( this, wxID_CANCEL, _("Close"), wxDefaultPosition, wxDefaultSize, 0 );
bRightSizer->Add( m_buttonCancel, 0, wxALL|wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5 );
m_buttonHelp = new wxButton( this, ID_HELP, _("Help"), wxDefaultPosition, wxDefaultSize, 0 );
bRightSizer->Add( m_buttonHelp, 0, wxALL|wxEXPAND, 5 );
m_staticline2 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
bRightSizer->Add( m_staticline2, 0, wxEXPAND | wxALL, 5 );
m_buttonAddPlugin = new wxButton( this, ID_ADD_PLUGIN, _("Add Plugin"), wxDefaultPosition, wxDefaultSize, 0 );
bRightSizer->Add( m_buttonAddPlugin, 0, wxALL|wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5 );
m_buttonBrowsePlugin = new wxButton( this, wxID_BROWSE_PLUGINS, _("Set Plugin"), wxDefaultPosition, wxDefaultSize, 0 );
bRightSizer->Add( m_buttonBrowsePlugin, 0, wxALL|wxEXPAND, 5 );
m_buttonDelPlugin = new wxButton( this, ID_REMOVEL_PLUGIN, _("Remove Plugin"), wxDefaultPosition, wxDefaultSize, 0 );
bRightSizer->Add( m_buttonDelPlugin, 0, wxALL|wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5 );
m_buttonEdit = new wxButton( this, wxID_ANY, _("Edit Plugin"), wxDefaultPosition, wxDefaultSize, 0 );
bRightSizer->Add( m_buttonEdit, 0, wxALL|wxEXPAND, 5 );
bUpperSizer->Add( bRightSizer, 0, wxALIGN_CENTER_VERTICAL, 5 );
bMainSizer->Add( bUpperSizer, 1, wxEXPAND, 5 );
m_staticTextDefaultFN = new wxStaticText( this, wxID_ANY, _("Output filename:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextDefaultFN->Wrap( -1 );
bMainSizer->Add( m_staticTextDefaultFN, 0, wxRIGHT|wxLEFT, 5 );
m_textCtrlDefaultFileName = new wxTextCtrl( this, ID_FN, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY );
m_textCtrlDefaultFileName->SetMaxLength( 0 );
bMainSizer->Add( m_textCtrlDefaultFileName, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
this->SetSizer( bMainSizer );
this->Layout();
this->Centre( wxBOTH );
}
DIALOG_BOM_BASE::~DIALOG_BOM_BASE()
{
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,103 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Oct 8 2012)
// http://www.wxformbuilder.org/
//
// PLEASE DO "NOT" EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#ifndef __DIALOG_BOM_BASE_H__
#define __DIALOG_BOM_BASE_H__
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/intl.h>
class DIALOG_SHIM;
#include "dialog_shim.h"
#include <wx/string.h>
#include <wx/stattext.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/listbox.h>
#include <wx/textctrl.h>
#include <wx/sizer.h>
#include <wx/button.h>
#include <wx/statline.h>
#include <wx/dialog.h>
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/// Class DIALOG_BOM_BASE
///////////////////////////////////////////////////////////////////////////////
class DIALOG_BOM_BASE : public DIALOG_SHIM
{
DECLARE_EVENT_TABLE()
private:
// Private event handlers
void _wxFB_OnPluginSelected( wxCommandEvent& event ){ OnPluginSelected( event ); }
void _wxFB_OnCommandLineEdited( wxCommandEvent& event ){ OnCommandLineEdited( event ); }
void _wxFB_OnNameEdited( wxCommandEvent& event ){ OnNameEdited( event ); }
void _wxFB_OnRunPlugin( wxCommandEvent& event ){ OnRunPlugin( event ); }
void _wxFB_OnCancelClick( wxCommandEvent& event ){ OnCancelClick( event ); }
void _wxFB_OnHelp( wxCommandEvent& event ){ OnHelp( event ); }
void _wxFB_OnAddPlugin( wxCommandEvent& event ){ OnAddPlugin( event ); }
void _wxFB_OnChoosePlugin( wxCommandEvent& event ){ OnChoosePlugin( event ); }
void _wxFB_OnRemovePlugin( wxCommandEvent& event ){ OnRemovePlugin( event ); }
void _wxFB_OnEditPlugin( wxCommandEvent& event ){ OnEditPlugin( event ); }
protected:
enum
{
ID_CMDLINE = 1000,
IN_NAMELINE,
ID_CREATE_BOM,
ID_HELP,
ID_ADD_PLUGIN,
wxID_BROWSE_PLUGINS,
ID_REMOVEL_PLUGIN,
ID_FN
};
wxStaticText* m_staticTextPluginTitle;
wxListBox* m_lbPlugins;
wxStaticText* m_staticTextCmd;
wxTextCtrl* m_textCtrlCommand;
wxStaticText* m_staticTextName;
wxTextCtrl* m_textCtrlName;
wxButton* m_buttonNetlist;
wxButton* m_buttonCancel;
wxButton* m_buttonHelp;
wxStaticLine* m_staticline2;
wxButton* m_buttonAddPlugin;
wxButton* m_buttonBrowsePlugin;
wxButton* m_buttonDelPlugin;
wxButton* m_buttonEdit;
wxStaticText* m_staticTextDefaultFN;
wxTextCtrl* m_textCtrlDefaultFileName;
// Virtual event handlers, overide them in your derived class
virtual void OnPluginSelected( wxCommandEvent& event ) { event.Skip(); }
virtual void OnCommandLineEdited( wxCommandEvent& event ) { event.Skip(); }
virtual void OnNameEdited( wxCommandEvent& event ) { event.Skip(); }
virtual void OnRunPlugin( wxCommandEvent& event ) { event.Skip(); }
virtual void OnCancelClick( wxCommandEvent& event ) { event.Skip(); }
virtual void OnHelp( wxCommandEvent& event ) { event.Skip(); }
virtual void OnAddPlugin( wxCommandEvent& event ) { event.Skip(); }
virtual void OnChoosePlugin( wxCommandEvent& event ) { event.Skip(); }
virtual void OnRemovePlugin( wxCommandEvent& event ) { event.Skip(); }
virtual void OnEditPlugin( wxCommandEvent& event ) { event.Skip(); }
public:
DIALOG_BOM_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Bill of Material"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 404,334 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
~DIALOG_BOM_BASE();
};
#endif //__DIALOG_BOM_BASE_H__

View File

@ -0,0 +1,4 @@
plugins
plugin
cmd
opts

View File

@ -0,0 +1,210 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=windows-1252">
<TITLE>kicad help</TITLE>
<META NAME="GENERATOR" CONTENT="LibreOffice 4.0.2.2 (Windows)">
<META NAME="CREATED" CONTENT="0;0">
<META NAME="CHANGED" CONTENT="20130614;10225357">
<STYLE TYPE="text/css">
<!--
@page { margin: 2cm }
P { margin-bottom: 0.21cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto }
P.western { font-family: "Arial", sans-serif; font-size: 10pt; so-language: en-US }
A:link { color: #004586; text-decoration: none }
A.western:link { font-family: "Liberation Sans", sans-serif; so-language: zxx; font-style: italic }
A.sdfootnotesym-western { font-family: "DejaVu Serif", serif }
-->
</STYLE>
</HEAD>
<BODY LANG="en-AU" LINK="#004586" DIR="LTR">
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto"><A NAME="__RefHeading__2925_482973253"></A>
<FONT FACE="Times New Roman, serif"><FONT SIZE=3><B>1 - Full
documentation:</B></FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3><SPAN LANG="en-US"><B>The
</B></SPAN></FONT></FONT><FONT FACE="Times New Roman, serif"><FONT SIZE=3><SPAN LANG="en-US"><I><B>Eeschema
documentation, chapter 14</B></I></SPAN></FONT></FONT><FONT FACE="Times New Roman, serif"><FONT SIZE=3><SPAN LANG="en-US"><B>
describes this intermediate netlist and gives examples<BR>See also
</B></SPAN></FONT></FONT><FONT FACE="Times New Roman, serif"><FONT SIZE=3><SPAN LANG="en-US"><I><B>https://answers.launchpad.net/kicad/+faq/2265</B></I></SPAN></FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3><B><I>2 - </I>The
intermediate Netlist File</B></FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3>BOM files (and
netlist files) can be created from an Intermediate netlist file
created by Eeschema.</FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3>This file uses XML
syntax and is called the intermediate netlist. The intermediate
netlist includes a large amount of data about your board and because
of this, it can be used with post-processing to create a BOM or other
reports.</FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3>Depending on the
output (BOM or netlist), different subsets of the complete
Intermediate Netlist file will be used in the post-processing.</FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3><B>3 - Conversion to
a new format</B></FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3>By applying a
post-processing filter to the Intermediate netlist file you can
generate foreign netlist files as well as BOM files. Because this
conversion is a text to text transformation.</FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3>this post-processing
filter can be written using Python, XSLT, or any other tool capable
of taking XML as input.</FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3><SPAN STYLE="font-variant: normal"><SPAN STYLE="font-style: normal"><SPAN STYLE="font-weight: normal">XSLT
itself is a XML language very suitable for XML transformations. There
is a free program called </SPAN></SPAN></SPAN><I><SPAN STYLE="font-weight: normal">xsltproc</SPAN></I><SPAN STYLE="font-variant: normal">
</SPAN><SPAN STYLE="font-variant: normal"><SPAN STYLE="font-style: normal"><SPAN STYLE="font-weight: normal">that
you can download and install. The</SPAN></SPAN></SPAN><SPAN STYLE="font-variant: normal">
</SPAN><SPAN STYLE="font-variant: normal"><SPAN STYLE="font-style: normal"><SPAN STYLE="font-weight: normal">xsltproc
program can be used to read the Intermediate XML netlist input file,
apply</SPAN></SPAN></SPAN><SPAN STYLE="font-variant: normal"> </SPAN><SPAN STYLE="font-variant: normal"><SPAN STYLE="font-style: normal"><SPAN STYLE="font-weight: normal">a
style-sheet to transform the input, and save the results in an output
file. Use of xsltproc requires a style-sheet file using XSLT
conventions. The full conversion process is handled</SPAN></SPAN></SPAN><SPAN STYLE="font-variant: normal">
</SPAN><SPAN STYLE="font-variant: normal"><SPAN STYLE="font-style: normal"><SPAN STYLE="font-weight: normal">by
Eeschema, after it is configured once to run xsltproc in a specific
way.</SPAN></SPAN></SPAN></FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3><B>4 -
Initialization of the dialog window</B></FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3>You should add a new
pluging (a script) in plugin list by clicking on the Add Plugin
button.</FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3><B>4.1 - Plugin
Configuration Parameters</B></FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3>The Eeschema plug-in
configuration dialog requires the following information:</FONT></FONT></P>
<UL>
<LI><P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3>The title: for
instance, the name of the netlist format.</FONT></FONT></P>
<LI><P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3>The command line to
launch the converter (usually a script).</FONT></FONT></P>
</UL>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3>Once you click on
the generate button the following will happen:</FONT></FONT></P>
<OL>
<LI><P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3>Eeschema creates an
intermediate netlist file *.xml, for instance <I>test.xml.</I></FONT></FONT></P>
<LI><P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3>Eeschema runs the
script from the command line to create the final output file.</FONT></FONT></P>
</OL>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3><B>4.2 - Generate
netlist files with the command line</B></FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3>Assuming we are
using the program <I>xsltproc.exe</I><SPAN STYLE="font-variant: normal">
</SPAN><SPAN STYLE="font-variant: normal"><SPAN STYLE="font-style: normal">to
apply the sheet style to the intermediate file, </SPAN></SPAN><I>xsltproc.exe</I><SPAN STYLE="font-variant: normal">
</SPAN><SPAN STYLE="font-variant: normal"><SPAN STYLE="font-style: normal">is
executed with the following command.</SPAN></SPAN></FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3>xsltproc.exe -o &lt;
output filename &gt; &lt; style-sheet filename &gt; &lt; input XML
file to convert &gt;</FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3><FONT SIZE=2 STYLE="font-size: 11pt">On</FONT>
<FONT SIZE=2 STYLE="font-size: 11pt">Windows the command line is the
following.<BR></FONT><FONT SIZE=2 STYLE="font-size: 11pt"><I>f:/kicad/bin/xsltproc.exe
-o &ldquo;%O&rdquo; f:/kicad/bin/plugins/myconverter.xsl &ldquo;%I&rdquo;</I></FONT></FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3><FONT SIZE=2 STYLE="font-size: 11pt">On</FONT>
<FONT SIZE=2 STYLE="font-size: 11pt">Linux the command becomes as
following.<BR></FONT><FONT SIZE=2 STYLE="font-size: 11pt"><I>xsltproc
-o &ldquo;%O&rdquo; /usr/local/kicad/bin/plugins/myconverter .xsl
&ldquo;%I&rdquo;</I></FONT></FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3><SPAN STYLE="font-variant: normal"><FONT SIZE=2 STYLE="font-size: 11pt"><SPAN STYLE="font-style: normal"><SPAN STYLE="font-weight: normal">Where
</SPAN></SPAN></FONT></SPAN><SPAN STYLE="font-variant: normal"><FONT SIZE=2 STYLE="font-size: 11pt"><I><SPAN STYLE="font-weight: normal">myconverter</SPAN></I></FONT></SPAN><FONT SIZE=2 STYLE="font-size: 11pt"><I><SPAN STYLE="font-weight: normal">.xsl</SPAN></I></FONT><SPAN STYLE="font-variant: normal">
</SPAN><SPAN STYLE="font-variant: normal"><FONT SIZE=2 STYLE="font-size: 11pt"><SPAN STYLE="font-style: normal"><SPAN STYLE="font-weight: normal">is
the style-sheet that you are applying. Do not forget the double
quotes</SPAN></SPAN></FONT></SPAN><SPAN STYLE="font-variant: normal">
</SPAN><SPAN STYLE="font-variant: normal"><FONT SIZE=2 STYLE="font-size: 11pt"><SPAN STYLE="font-style: normal"><SPAN STYLE="font-weight: normal">around
the file names, this allows them to have spaces after the
substitution by Eeschema.</SPAN></SPAN></FONT></SPAN></FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3>The command line
format accepts parameters for filenames:</FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3>The supported
formatting parameters are.</FONT></FONT></P>
<UL>
<LI><P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3>%B =&gt; base
filename and path of selected output file, minus path and extension.</FONT></FONT></P>
<LI><P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3>%I =&gt; complete
filename and path of the temporary input file (the intermediate net
file).</FONT></FONT></P>
<LI><P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3>%O =&gt; complete
filename and path of the user chosen output file.</FONT></FONT></P>
</UL>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3>%I will be replaced
by the actual intermediate file name<BR><SPAN STYLE="font-variant: normal"><SPAN STYLE="font-style: normal"><SPAN STYLE="font-weight: normal">%O
will be replaced by the actual output file name.</SPAN></SPAN></SPAN></FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3><B>4.3 - Command
line format: example for <SPAN STYLE="font-variant: normal"><SPAN STYLE="font-style: normal">xsltproc</SPAN></SPAN></B></FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3><SPAN STYLE="font-variant: normal"><SPAN STYLE="font-style: normal">The
command line format for xsltproc is the following:<BR>&lt; path of
</SPAN></SPAN>xsltproc &gt; <SPAN STYLE="font-variant: normal"><SPAN STYLE="font-style: normal">xsltproc
&lt; </SPAN></SPAN>xsltproc parameters &gt;</FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3>On
Windows:<BR><I><B>f:/kicad/bin/xsltproc.exe -o &ldquo;%O&rdquo;
f:/kicad/bin/plugins/netlist_form_pads-pcb.xsl &ldquo;%I&rdquo;</B></I></FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3><FONT SIZE=2 STYLE="font-size: 11pt">On</FONT>
<FONT SIZE=2 STYLE="font-size: 11pt">Linux:<BR></FONT><FONT SIZE=2 STYLE="font-size: 11pt"><I><B>xsltproc
-o &ldquo;%O&rdquo;
/usr/local/kicad/bin/plugins/netlist_form_pads-pcb.xsl &ldquo;%I&rdquo;</B></I></FONT></FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3><SPAN STYLE="font-variant: normal"><FONT SIZE=2 STYLE="font-size: 11pt"><SPAN STYLE="font-style: normal"><SPAN STYLE="font-weight: normal">The
above examples assume</SPAN></SPAN></FONT></SPAN><SPAN STYLE="font-variant: normal">
</SPAN><SPAN STYLE="font-variant: normal"><FONT SIZE=2 STYLE="font-size: 11pt"><SPAN STYLE="font-style: normal"><SPAN STYLE="font-weight: normal">xsltproc
is installed on your PC under Windows and all files located in
kicad/bin.</SPAN></SPAN></FONT></SPAN></FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3><B>4.4 - Command
line format: example fo<SPAN STYLE="font-variant: normal"><SPAN STYLE="font-style: normal">r
python scripts</SPAN></SPAN></B></FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3>The command line
format for python is something like:<BR><SPAN STYLE="font-variant: normal"><SPAN STYLE="font-style: normal">python</SPAN></SPAN><SPAN STYLE="font-variant: normal">
</SPAN><SPAN STYLE="font-variant: normal"><SPAN STYLE="font-style: normal">&lt;
script file name </SPAN></SPAN>&gt; &lt; input filename &gt; &lt;
output filename &gt;</FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3>On
Windows:<BR><I><B>python.exe f:/kicad/python/my_python_script.py</B></I>
&ldquo;<I><B>%I&rdquo; &ldquo;%O&rdquo;</B></I></FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3>On Linux:<BR><I><B>python</B></I>
<I><B>/usr/local/kicad/python/my_python_script.py</B></I> &ldquo;<I><B>%I&rdquo;
&ldquo;%O&rdquo;</B></I></FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto">
<FONT FACE="Times New Roman, serif"><FONT SIZE=3>Assuming python is
installed on your PC.</FONT></FONT></P>
<P LANG="en-US" CLASS="western" STYLE="margin-bottom: 0cm; widows: 0; orphans: 0; page-break-before: auto; page-break-after: auto"><A NAME="__RefHeading__1787_435485510"></A>
<BR>
</P>
</BODY>
</HTML>

View File

@ -37,8 +37,8 @@
// DIALOG_<class>.cpp file. // DIALOG_<class>.cpp file.
#ifndef INVOKE_A_DIALOG_H_ #ifndef INVOKE_SCH_DIALOG_H_
#define INVOKE_A_DIALOG_H_ #define INVOKE_SCH_DIALOG_H_
class wxFrame; class wxFrame;
@ -61,6 +61,9 @@ wxDialog* InvokeDialogERC( SCH_EDIT_FRAME* aCaller );
/// DIALOG_PRINT_USING_PRINTER::ShowModal() returns. /// DIALOG_PRINT_USING_PRINTER::ShowModal() returns.
int InvokeDialogPrintUsingPrinter( SCH_EDIT_FRAME* aCaller ); int InvokeDialogPrintUsingPrinter( SCH_EDIT_FRAME* aCaller );
/// Create and show DIALOG_BOM and return whatever
/// DIALOG_BOM::ShowModal() returns.
int InvokeDialogCreateBOM( SCH_EDIT_FRAME* aCaller );
#endif // INVOKE_A_DIALOG_H_ #endif // INVOKE_SCH_DIALOG_H_

View File

@ -374,26 +374,6 @@ public:
sort( componentFlatList.begin(), componentFlatList.end(), sortByRefAndValue ); sort( componentFlatList.begin(), componentFlatList.end(), sortByRefAndValue );
} }
/**
* Function SortByValueAndRef
* sorts the list of references by value.
* <p>
* Components are sorted in the following order:
* <ul>
* <li>Value of component.</li>
* <li>Numeric value of reference designator.</li>
* <li>Unit number when component has multiple parts.</li>
* <li>Sheet number.</li>
* <li>X coordinate position.</li>
* <li>Y coordinate position.</li>
* </ul>
* </p>
*/
void SortByValueAndRef()
{
sort( componentFlatList.begin(), componentFlatList.end(), sortByValueAndRef );
}
/** /**
* Function SortByReferenceOnly * Function SortByReferenceOnly
* sorts the list of references by reference. * sorts the list of references by reference.
@ -410,25 +390,6 @@ public:
sort( componentFlatList.begin(), componentFlatList.end(), sortByReferenceOnly ); sort( componentFlatList.begin(), componentFlatList.end(), sortByReferenceOnly );
} }
/**
* Function SortByValueOnly
* sort the list of references by value.
* <p>
* Components are grouped by type and are sorted in the following order:
* <ul>
* <li>Value of component.</li>
* <li>Numeric value of reference designator.</li>
* <li>Unit number when component has multiple parts.</li>
* </ul>
* </p>
* groups are made by the first letter of reference
* or the 2 first letters when existing
*/
void SortByValueOnly()
{
sort( componentFlatList.begin(), componentFlatList.end(), sortByValueOnly );
}
/** /**
* Function GetUnit * Function GetUnit
* searches the sorted list of components for a another component with the same * searches the sorted list of components for a another component with the same
@ -474,16 +435,12 @@ private:
static bool sortByRefAndValue( const SCH_REFERENCE& item1, const SCH_REFERENCE& item2 ); static bool sortByRefAndValue( const SCH_REFERENCE& item1, const SCH_REFERENCE& item2 );
static bool sortByValueAndRef( const SCH_REFERENCE& item1, const SCH_REFERENCE& item2 );
static bool sortByXPosition( const SCH_REFERENCE& item1, const SCH_REFERENCE& item2 ); static bool sortByXPosition( const SCH_REFERENCE& item1, const SCH_REFERENCE& item2 );
static bool sortByYPosition( const SCH_REFERENCE& item1, const SCH_REFERENCE& item2 ); static bool sortByYPosition( const SCH_REFERENCE& item1, const SCH_REFERENCE& item2 );
static bool sortByTimeStamp( const SCH_REFERENCE& item1, const SCH_REFERENCE& item2 ); static bool sortByTimeStamp( const SCH_REFERENCE& item1, const SCH_REFERENCE& item2 );
static bool sortByValueOnly( const SCH_REFERENCE& item1, const SCH_REFERENCE& item2 );
static bool sortByReferenceOnly( const SCH_REFERENCE& item1, const SCH_REFERENCE& item2 ); static bool sortByReferenceOnly( const SCH_REFERENCE& item1, const SCH_REFERENCE& item2 );
/** /**

View File

@ -632,10 +632,7 @@ void SCH_EDIT_FRAME::OnCreateNetlist( wxCommandEvent& event )
void SCH_EDIT_FRAME::OnCreateBillOfMaterials( wxCommandEvent& ) void SCH_EDIT_FRAME::OnCreateBillOfMaterials( wxCommandEvent& )
{ {
wxMessageDialog dlg( this, InvokeDialogCreateBOM( this );
wxT( "https://answers.launchpad.net/kicad/+faq/2265" ),
_( "BOM Howto" ) );
dlg.ShowModal();
} }

View File

@ -0,0 +1,14 @@
bom_?.py are some python scripts which read a generic xml netlist from eeschema,
and create a bom.
All examples use ky_generic_netlist_reader.py, which is a python utility to read
and parse this generic xml netlist and create the corresponding data
used to build the bom.
You can modify them to build the bom you want.
to use them, you should install python, and run:
python bom_example?.py <netlist name> <bom list netname>
See Eeschema doc, chapter 14 for info about the generic xml netlist format,
and how to run a script from Eeschema to create a customized netlist or BOM.

View File

@ -5,7 +5,7 @@
# #
# Import the KiCad python helper module and the csv formatter # Import the KiCad python helper module and the csv formatter
import ky import ky_generic_netlist_reader
import sys import sys
# Start with a basic html template # Start with a basic html template
@ -30,13 +30,13 @@ html = """
""" """
def myEqu(self, other): def myEqu(self, other):
"""myEqu is a more advanced equivalence function for components which is """myEqu is a more advanced equivalence function for components which is
used by component grouping. Normal operation is to group components based used by component grouping. Normal operation is to group components based
on their Value, Library source, and Library part. on their Value, Library source, and Library part.
In this example of a more advanced equivalency operator we also compare the In this example of a more advanced equivalency operator we also compare the
custom fields Voltage, Tolerance and Manufacturer as well as the assigned custom fields Voltage, Tolerance and Manufacturer as well as the assigned
footprint. If these fields are not used in some parts they will simply be footprint. If these fields are not used in some parts they will simply be
ignored (they will match as both will be empty strings). ignored (they will match as both will be empty strings).
""" """
@ -54,18 +54,18 @@ def myEqu(self, other):
elif self.getField("Manufacturer") != other.getField("Manufacturer"): elif self.getField("Manufacturer") != other.getField("Manufacturer"):
result = False result = False
elif self.getField("Voltage") != other.getField("Voltage"): elif self.getField("Voltage") != other.getField("Voltage"):
result = False result = False
return result return result
# Override the component equivalence operator - it is important to do this # Override the component equivalence operator - it is important to do this
# before loading the netlist, otherwise all components will have the original # before loading the netlist, otherwise all components will have the original
# equivalency operator. # equivalency operator.
ky.component.__equ__ = myEqu ky_generic_netlist_reader.component.__equ__ = myEqu
# Generate an instance of a generic netlist, and load the netlist tree from # Generate an instance of a generic netlist, and load the netlist tree from
# video.tmp. If the file doesn't exist, execution will stop # video.tmp. If the file doesn't exist, execution will stop
net = ky.netlist(sys.argv[1]) net = ky_generic_netlist_reader.netlist(sys.argv[1])
# Open a file to write too, if the file cannot be opened output to stdout # Open a file to write too, if the file cannot be opened output to stdout
# instead # instead
@ -82,31 +82,33 @@ html = html.replace('<!--TOOL-->', net.getTool())
html = html.replace('<!--COMPCOUNT-->', "<b>Component Count:</b>" + \ html = html.replace('<!--COMPCOUNT-->', "<b>Component Count:</b>" + \
str(len(net.components))) str(len(net.components)))
row = "<tr><th style='width:640px'>Ref</th>" + "<th>Qnty</th>" row = "<tr><th style='width:640px'>Ref</th>" + "<th>Qnty</th>"
row += "<th>Value</th>" + "<th>Part</th>" + "<th>Datasheet</th>" row += "<th>Value</th>" + "<th>Part</th>" + "<th>Datasheet</th>"
row += "<th>Description</th>" + "<th>Vendor</th></tr>" row += "<th>Description</th>" + "<th>Vendor</th></tr>"
html = html.replace('<!--TABLEROW-->', row + "<!--TABLEROW-->") html = html.replace('<!--TABLEROW-->', row + "<!--TABLEROW-->")
# Get all of the components in groups of matching parts + values (see ky.py) # Get all of the components in groups of matching parts + values
# (see ky_generic_netlist_reader.py)
grouped = net.groupComponents() grouped = net.groupComponents()
# Output all of the component information # Output all of the component information
for group in grouped: for group in grouped:
refs = "" refs = ""
# Add the reference of every component in the group and keep a reference # Add the reference of every component in the group and keep a reference
# to the component so that the other data can be filled in once per group # to the component so that the other data can be filled in once per group
for component in group: for component in group:
refs += component.getRef() + ", " refs += component.getRef() + ", "
c = component c = component
row = "<tr><td>" + refs +"</td><td>" + str(len(group)) row = "\n "
row += "</td><td>" + c.getValue() + "</td><td>" + c.getLib() + "/" row += "<tr><td>" + refs +"</td><td>" + str(len(group))
row += c.getPart() + "</td><td>" + c.getDatasheet() + "</td><td>" row += "</td><td>" + c.getValue() + "</td><td>" + c.getLib() + "/"
row += c.getDescription() + "</td><td>" + c.getField("Vendor") row += c.getPart() + "</td><td>" + c.getDatasheet() + "</td><td>"
row += c.getDescription() + "</td><td>" + c.getField("Vendor")
row += "</td></tr>" row += "</td></tr>"
html = html.replace('<!--TABLEROW-->', row + "<!--TABLEROW-->") html = html.replace('<!--TABLEROW-->', row + "<!--TABLEROW-->")
# Print the formatted html to output file # Print the formatted html to output file

View File

@ -5,13 +5,13 @@
# #
# Import the KiCad python helper module and the csv formatter # Import the KiCad python helper module and the csv formatter
import ky import ky_generic_netlist_reader
import csv import csv
import sys import sys
# Generate an instance of a generic netlist, and load the netlist tree from # Generate an instance of a generic netlist, and load the netlist tree from
# the command line option. If the file doesn't exist, execution will stop # the command line option. If the file doesn't exist, execution will stop
net = ky.netlist(sys.argv[1]) net = ky_generic_netlist_reader.netlist(sys.argv[1])
# Open a file to write to, if the file cannot be opened output to stdout # Open a file to write to, if the file cannot be opened output to stdout
# instead # instead
@ -23,16 +23,16 @@ except IOError:
# Create a new csv writer object to use as the output formatter, although we # Create a new csv writer object to use as the output formatter, although we
# are created a tab delimited list instead! # are created a tab delimited list instead!
out = csv.writer(f, delimiter='\t', quoting=csv.QUOTE_NONE) out = csv.writer(f, lineterminator='\n', delimiter='\t', quoting=csv.QUOTE_NONE)
# Output a field delimited header line # Output a field delimited header line
out.writerow(['Source:', net.getSource()]) out.writerow(['Source:', net.getSource()])
out.writerow(['Date:', net.getDate()]) out.writerow(['Date:', net.getDate()])
out.writerow(['Tool:', net.getTool()]) out.writerow(['Tool:', net.getTool()])
out.writerow(['Component Count:', len(net.components)]) out.writerow(['Component Count:', len(net.components)])
out.writerow(['Ref', 'Value', 'Part', 'Documentation', 'Description', 'Vendor']) out.writerow(['Ref', 'Value', 'Part', 'Documentation', 'Description', 'Vendor'])
# Output all of the component information # Output all of the component information
for c in net.components: for c in net.components:
out.writerow([c.getRef(), c.getValue(), c.getLib() + "/" + c.getPart(), out.writerow([c.getRef(), c.getValue(), c.getLib() + "/" + c.getPart(),
c.getDatasheet(), c.getDescription(), c.getField("Vendor")]) c.getDatasheet(), c.getDescription(), c.getField("Vendor")])

View File

@ -5,16 +5,16 @@
# #
# Import the KiCad python helper module # Import the KiCad python helper module
import ky import ky_generic_netlist_reader
import csv import csv
import sys import sys
# Generate an instance of a generic netlist, and load the netlist tree from # Generate an instance of a generic netlist, and load the netlist tree from
# the command line option. If the file doesn't exist, execution will stop # the command line option. If the file doesn't exist, execution will stop
net = ky.netlist(sys.argv[1]) net = ky_generic_netlist_reader.netlist(sys.argv[1])
# Open a file to write to, if the file cannot be opened output to stdout # Open a file to write to, if the file cannot be opened output to stdout
# instead # instead
try: try:
f = open(sys.argv[2], 'w') f = open(sys.argv[2], 'w')
except IOError: except IOError:
@ -22,13 +22,13 @@ except IOError:
f = stdout f = stdout
# Create a new csv writer object to use as the output formatter # Create a new csv writer object to use as the output formatter
out = csv.writer(f, delimiter=',', quotechar="\"", quoting=csv.QUOTE_ALL) out = csv.writer(f, lineterminator='\n', delimiter=',', quotechar="\"", quoting=csv.QUOTE_ALL)
# Output a field delimited header line # Output a field delimited header line
out.writerow(['Source:', net.getSource()]) out.writerow(['Source:', net.getSource()])
out.writerow(['Date:', net.getDate()]) out.writerow(['Date:', net.getDate()])
out.writerow(['Tool:', net.getTool()]) out.writerow(['Tool:', net.getTool()])
out.writerow(['Component Count:', len(net.components)]) out.writerow(['Component Count:', len(net.components)])
out.writerow(['Ref', 'Value', 'Footprint', 'Datasheet', 'Manufacturer', 'Vendor']) out.writerow(['Ref', 'Value', 'Footprint', 'Datasheet', 'Manufacturer', 'Vendor'])
# Output all of the component information (One component per row) # Output all of the component information (One component per row)

View File

@ -5,13 +5,13 @@
# #
# Import the KiCad python helper module and the csv formatter # Import the KiCad python helper module and the csv formatter
import ky import ky_generic_netlist_reader
import csv import csv
import sys import sys
# Generate an instance of a generic netlist, and load the netlist tree from # Generate an instance of a generic netlist, and load the netlist tree from
# the command line option. If the file doesn't exist, execution will stop # the command line option. If the file doesn't exist, execution will stop
net = ky.netlist(sys.argv[1]) net = ky_generic_netlist_reader.netlist(sys.argv[1])
# Open a file to write to, if the file cannot be opened output to stdout # Open a file to write to, if the file cannot be opened output to stdout
# instead # instead
@ -22,23 +22,24 @@ except IOError:
f = stdout f = stdout
# Create a new csv writer object to use as the output formatter # Create a new csv writer object to use as the output formatter
out = csv.writer(f, delimiter=',', quotechar='\"', quoting=csv.QUOTE_ALL) out = csv.writer(f, lineterminator='\n', delimiter=',', quotechar='\"', quoting=csv.QUOTE_ALL)
# Output a set of rows for a header providing general information # Output a set of rows for a header providing general information
out.writerow(['Source:', net.getSource()]) out.writerow(['Source:', net.getSource()])
out.writerow(['Date:', net.getDate()]) out.writerow(['Date:', net.getDate()])
out.writerow(['Tool:', net.getTool()]) out.writerow(['Tool:', net.getTool()])
out.writerow(['Component Count:', len(net.components)]) out.writerow(['Component Count:', len(net.components)])
out.writerow(['Ref', 'Qnty', 'Value', 'Part', 'Datasheet', 'Description', 'Vendor']) out.writerow(['Ref', 'Qnty', 'Value', 'Part', 'Datasheet', 'Description', 'Vendor'])
# Get all of the components in groups of matching parts + values (see ky.py) # Get all of the components in groups of matching parts + values
# (see ky_generic_netlist_reader.py)
grouped = net.groupComponents() grouped = net.groupComponents()
# Output all of the component information # Output all of the component information
for group in grouped: for group in grouped:
refs = "" refs = ""
# Add the reference of every component in the group and keep a reference # Add the reference of every component in the group and keep a reference
# to the component so that the other data can be filled in once per group # to the component so that the other data can be filled in once per group
for component in group: for component in group:
refs += component.getRef() + ", " refs += component.getRef() + ", "

View File

@ -0,0 +1,119 @@
#
# Example python script to generate a BOM from a KiCad generic netlist
#
# Example: Sorted and Grouped HTML BOM with more advanced grouping
#
# Import the KiCad python helper module and the csv formatter
import ky_generic_netlist_reader
import sys
# Start with a basic html template
html = """
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>KiCad BOM Example 5</title>
</head>
<body>
<h1><!--SOURCE--></h1>
<p><!--DATE--></p>
<p><!--TOOL--></p>
<p><!--COMPCOUNT--></p>
<table>
<!--TABLEROW-->
</table>
</body>
</html>
"""
def myEqu(self, other):
"""myEqu is a more advanced equivalence function for components which is
used by component grouping. Normal operation is to group components based
on their Value, Library source, and Library part.
In this example of a more advanced equivalency operator we also compare the
custom fields Voltage, Tolerance and Manufacturer as well as the assigned
footprint. If these fields are not used in some parts they will simply be
ignored (they will match as both will be empty strings).
"""
result = True
if self.getValue() != other.getValue():
result = False
elif self.getLib() != other.getLib():
result = False
elif self.getPart() != other.getPart():
result = False
elif self.getFootprint() != other.getFootprint():
result = False
elif self.getField("Tolerance") != other.getField("Tolerance"):
result = False
elif self.getField("Manufacturer") != other.getField("Manufacturer"):
result = False
elif self.getField("Voltage") != other.getField("Voltage"):
result = False
return result
# Override the component equivalence operator - it is important to do this
# before loading the netlist, otherwise all components will have the original
# equivalency operator.
ky_generic_netlist_reader.component.__equ__ = myEqu
# Generate an instance of a generic netlist, and load the netlist tree from
# video.xml. If the file doesn't exist, execution will stop
net = ky_generic_netlist_reader.netlist(sys.argv[1])
# Open a file to write too, if the file cannot be opened output to stdout
# instead
try:
f = open(sys.argv[2], 'w')
except IOError:
print >> sys.stderr, __file__, ":", e
f = stdout
# Output a set of rows for a header providing general information
html = html.replace('<!--SOURCE-->', net.getSource())
html = html.replace('<!--DATE-->', net.getDate())
html = html.replace('<!--TOOL-->', net.getTool())
html = html.replace('<!--COMPCOUNT-->', "<b>Component Count:</b>" + \
str(len(net.components)))
row = "<tr><th style='width:640px'>Ref</th>" + "<th>Qnty</th>"
row += "<th>Value</th>" + "<th>Part</th>"
row += "<th>Description</th>"
#row += "<th>Datasheet</th>"
row += "<th>PartNumber</th>" + "<th>Vendor</th></tr>"
html = html.replace('<!--TABLEROW-->', row + "<!--TABLEROW-->")
# Get all of the components in groups of matching parts + values
# (see ky_generic_netlist_reader.py)
grouped = net.groupComponents()
# Output all of the component information
for group in grouped:
refs = ""
# Add the reference of every component in the group and keep a reference
# to the component so that the other data can be filled in once per group
for component in group:
refs += component.getRef() + ", "
c = component
row = "<tr><td>" + refs +"</td><td>" + str(len(group))
row += "</td><td>" + c.getValue() + "</td><td>"
row += c.getLib() + "/" + c.getPart() + "</td><td>"
#row += c.getDatasheet() + "</td><td>"
row += c.getDescription() + "</td><td>"
row += c.getField("PartNumber") + "</td><td>"
row += c.getField("Vendor")
row += "</td></tr>"
html = html.replace('<!--TABLEROW-->', row + "<!--TABLEROW-->")
# Print the formatted html to output file
print >> f, html

View File

@ -5,7 +5,7 @@
# #
# Import the KiCad python helper module and the csv formatter # Import the KiCad python helper module and the csv formatter
import ky import ky_generic_netlist_reader
import sys import sys
# Start with a basic html template # Start with a basic html template
@ -27,10 +27,10 @@ html = """
</body> </body>
</html> </html>
""" """
# Generate an instance of a generic netlist, and load the netlist tree from # Generate an instance of a generic netlist, and load the netlist tree from
# the command line option. If the file doesn't exist, execution will stop # the command line option. If the file doesn't exist, execution will stop
net = ky.netlist(sys.argv[1]) net = ky_generic_netlist_reader.netlist(sys.argv[1])
# Open a file to write to, if the file cannot be opened output to stdout # Open a file to write to, if the file cannot be opened output to stdout
# instead # instead
@ -47,31 +47,32 @@ html = html.replace('<!--TOOL-->', net.getTool())
html = html.replace('<!--COMPCOUNT-->', "<b>Component Count:</b>" + \ html = html.replace('<!--COMPCOUNT-->', "<b>Component Count:</b>" + \
str(len(net.components))) str(len(net.components)))
row = "<tr><th style='width:640px'>Ref</th>" + "<th>Qnty</th>" row = "<tr><th style='width:640px'>Ref</th>" + "<th>Qnty</th>"
row += "<th>Value</th>" + "<th>Part</th>" + "<th>Datasheet</th>" row += "<th>Value</th>" + "<th>Part</th>" + "<th>Datasheet</th>"
row += "<th>Description</th>" + "<th>Vendor</th></tr>" row += "<th>Description</th>" + "<th>Vendor</th></tr>"
html = html.replace('<!--TABLEROW-->', row + "<!--TABLEROW-->") html = html.replace('<!--TABLEROW-->', row + "<!--TABLEROW-->")
# Get all of the components in groups of matching parts + values (see ky.py) # Get all of the components in groups of matching parts + values
# (see ky_generic_netlist_reader.py)
grouped = net.groupComponents() grouped = net.groupComponents()
# Output all of the component information # Output all of the component information
for group in grouped: for group in grouped:
refs = "" refs = ""
# Add the reference of every component in the group and keep a reference # Add the reference of every component in the group and keep a reference
# to the component so that the other data can be filled in once per group # to the component so that the other data can be filled in once per group
for component in group: for component in group:
refs += component.getRef() + ", " refs += component.getRef() + ", "
c = component c = component
row = "<tr><td>" + refs +"</td><td>" + str(len(group)) row = "<tr><td>" + refs +"</td><td>" + str(len(group))
row += "</td><td>" + c.getValue() + "</td><td>" + c.getLib() + "/" row += "</td><td>" + c.getValue() + "</td><td>" + c.getLib() + "/"
row += c.getPart() + "</td><td>" + c.getDatasheet() + "</td><td>" row += c.getPart() + "</td><td>" + c.getDatasheet() + "</td><td>"
row += c.getDescription() + "</td><td>" + c.getField("Vendor") row += c.getDescription() + "</td><td>" + c.getField("Vendor")
row += "</td></tr>" row += "</td></tr>"
html = html.replace('<!--TABLEROW-->', row + "<!--TABLEROW-->") html = html.replace('<!--TABLEROW-->', row + "<!--TABLEROW-->")
# Print the formatted html to the file # Print the formatted html to the file

View File

@ -5,12 +5,12 @@
# #
# Import the KiCad python helper module and the csv formatter # Import the KiCad python helper module and the csv formatter
import ky import ky_generic_netlist_reader
import sys import sys
# Generate an instance of a generic netlist, and load the netlist tree from # Generate an instance of a generic netlist, and load the netlist tree from
# the command line option. If the file doesn't exist, execution will stop # the command line option. If the file doesn't exist, execution will stop
net = ky.netlist(sys.argv[1]) net = ky_generic_netlist_reader.netlist(sys.argv[1])
# Open a file to write to, if the file cannot be opened output to stdout # Open a file to write to, if the file cannot be opened output to stdout
# instead # instead

View File

@ -5,7 +5,7 @@
# #
# Import the KiCad python helper module and the csv formatter # Import the KiCad python helper module and the csv formatter
import ky import ky_generic_netlist_reader
import sys import sys
def checkvalue(self): def checkvalue(self):
@ -21,7 +21,7 @@ def checkvalue(self):
newval = dec[0] + "." + dec[1] newval = dec[0] + "." + dec[1]
self.setValue(newval) self.setValue(newval)
v = self.getValue() v = self.getValue()
if len(r) == 2 and r[1].isdigit(): if len(r) == 2 and r[1].isdigit():
# This is a resistor - make values consistent # This is a resistor - make values consistent
# If the value is a pure value, add R to the end of the value # If the value is a pure value, add R to the end of the value
@ -34,8 +34,8 @@ def checkvalue(self):
i = i / 1000 i = i / 1000
v = str(i) + "K" v = str(i) + "K"
else: else:
v = str(i) + "R" v = str(i) + "R"
self.setValue(v) self.setValue(v)
else: else:
# Get the multiplier character # Get the multiplier character
@ -45,17 +45,17 @@ def checkvalue(self):
if (len(v) == 2): if (len(v) == 2):
newval = v[0] + multiplier + v[1] newval = v[0] + multiplier + v[1]
self.setValue(newval) self.setValue(newval)
v = self.getValue() v = self.getValue()
# Give components a new method for checking the values (this could easily be a # Give components a new method for checking the values (this could easily be a
# Company Part Number generator method instead) # Company Part Number generator method instead)
ky.component.checkvalue = checkvalue ky_generic_netlist_reader.component.checkvalue = checkvalue
# Generate an instance of a generic netlist, and load the netlist tree from # Generate an instance of a generic netlist, and load the netlist tree from
# the command line option. If the file doesn't exist, execution will stop # the command line option. If the file doesn't exist, execution will stop
net = ky.netlist(sys.argv[1]) net = ky_generic_netlist_reader.netlist(sys.argv[1])
# Open a file to write to, if the file cannot be opened output to stdout # Open a file to write to, if the file cannot be opened output to stdout
# instead # instead
@ -67,5 +67,5 @@ except IOError:
for c in net.components: for c in net.components:
c.checkvalue() c.checkvalue()
print >> f, net.formatXML() print >> f, net.formatXML()