Commit b4d0cd74 authored by jean-pierre charras's avatar jean-pierre charras

Eeschema: Add dialog and utilities (help files ...) to create BOMs from...

Eeschema: Add dialog and utilities (help files ...) to create BOMs from generic netlist, using python scripts or xsltproc+style sheet.
Remove dead code relative to old BOM generation.
Rename witha  more explicit name bom-example?.py , fix some issues and move them from script/bom-in-python/ky to script/bom-in-python
Rename ki.py utility to more explicit  ky_generic_netlist_reader.py
parents 60eb4b00 26b7bdc3
......@@ -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" )
foreach( line ${lines} )
file( APPEND ${outputFile} "\"" ${line} "\"\n" )
STRING(REGEX REPLACE "\"" "\\\\\"" linem ${line})
file( APPEND ${outputFile} "\"" ${linem} "\\n\"\n" )
endforeach( line ${lines} )
......@@ -14,6 +14,9 @@ set(EESCHEMA_DLGS
dialogs/dialog_color_config.cpp
dialogs/dialog_annotate.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_base.cpp
dialogs/dialog_edit_component_in_lib.cpp
......@@ -203,6 +206,33 @@ make_lexer(
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
${EESCHEMA_SRCS}
${EESCHEMA_COMMON_SRCS}
......
......@@ -67,7 +67,6 @@ bool SCH_REFERENCE_LIST::sortByXPosition( const SCH_REFERENCE& item1,
return ii < 0;
}
bool SCH_REFERENCE_LIST::sortByYPosition( const SCH_REFERENCE& item1,
const SCH_REFERENCE& item2 )
{
......@@ -106,252 +105,6 @@ bool SCH_REFERENCE_LIST::sortByRefAndValue( const SCH_REFERENCE& item1,
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,
const SCH_REFERENCE& item2 )
......@@ -385,7 +138,6 @@ bool SCH_REFERENCE_LIST::sortByTimeStamp( const SCH_REFERENCE& item1,
return ii < 0;
}
int SCH_REFERENCE_LIST::FindUnit( size_t aIndex, int aUnit )
{
int NumRef;
......
This diff is collapsed.
///////////////////////////////////////////////////////////////////////////
// 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( 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 )
EVT_TEXT( ID_CMDLINE, DIALOG_BOM_BASE::_wxFB_OnCommandLineEdited )
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_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, wxALIGN_CENTER_HORIZONTAL|wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 );
m_buttonCancel = new wxButton( this, wxID_CANCEL, _("Close"), wxDefaultPosition, wxDefaultSize, 0 );
bRightSizer->Add( m_buttonCancel, 0, wxALIGN_CENTER_HORIZONTAL|wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 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|wxRIGHT|wxLEFT, 5 );
m_buttonAddPlugin = new wxButton( this, ID_ADD_PLUGIN, _("Add Plugin"), wxDefaultPosition, wxDefaultSize, 0 );
bRightSizer->Add( m_buttonAddPlugin, 0, wxALIGN_CENTER_HORIZONTAL|wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 );
m_buttonBrowsePlugin = new wxButton( this, wxID_BROWSE_PLUGINS, _("Set Plugin Cmd"), wxDefaultPosition, wxDefaultSize, 0 );
bRightSizer->Add( m_buttonBrowsePlugin, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 );
m_buttonDelPlugin = new wxButton( this, ID_REMOVEL_PLUGIN, _("Remove Plugin"), wxDefaultPosition, wxDefaultSize, 0 );
bRightSizer->Add( m_buttonDelPlugin, 0, wxALIGN_CENTER_HORIZONTAL|wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 );
m_buttonEdit = new wxButton( this, wxID_ANY, _("Edit Plugin File"), 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 );
wxBoxSizer* bbottomSizer;
bbottomSizer = new wxBoxSizer( wxVERTICAL );
m_staticTextCmd = new wxStaticText( this, wxID_ANY, _("Command line:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextCmd->Wrap( -1 );
bbottomSizer->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( 380,-1 ) );
bbottomSizer->Add( m_textCtrlCommand, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
bMainSizer->Add( bbottomSizer, 0, wxEXPAND, 5 );
this->SetSizer( bMainSizer );
this->Layout();
this->Centre( wxBOTH );
}
DIALOG_BOM_BASE::~DIALOG_BOM_BASE()
{
}
This source diff could not be displayed because it is too large. You can view the blob instead.
///////////////////////////////////////////////////////////////////////////
// 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_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 ); }
void _wxFB_OnCommandLineEdited( wxCommandEvent& event ){ OnCommandLineEdited( event ); }
protected:
enum
{
IN_NAMELINE = 1000,
ID_CREATE_BOM,
ID_HELP,
ID_ADD_PLUGIN,
wxID_BROWSE_PLUGINS,
ID_REMOVEL_PLUGIN,
ID_CMDLINE
};
wxStaticText* m_staticTextPluginTitle;
wxListBox* m_lbPlugins;
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_staticTextCmd;
wxTextCtrl* m_textCtrlCommand;
// Virtual event handlers, overide them in your derived class
virtual void OnPluginSelected( 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(); }
virtual void OnCommandLineEdited( 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,315 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
~DIALOG_BOM_BASE();
};
#endif //__DIALOG_BOM_BASE_H__
This diff is collapsed.
......@@ -37,8 +37,8 @@
// DIALOG_<class>.cpp file.
#ifndef INVOKE_A_DIALOG_H_
#define INVOKE_A_DIALOG_H_
#ifndef INVOKE_SCH_DIALOG_H_
#define INVOKE_SCH_DIALOG_H_
class wxFrame;
......@@ -61,6 +61,9 @@ wxDialog* InvokeDialogERC( SCH_EDIT_FRAME* aCaller );
/// DIALOG_PRINT_USING_PRINTER::ShowModal() returns.
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_
......@@ -374,26 +374,6 @@ public:
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
* sorts the list of references by reference.
......@@ -410,25 +390,6 @@ public:
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
* 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 sortByValueAndRef( 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 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 );
/**
......
......@@ -632,10 +632,7 @@ void SCH_EDIT_FRAME::OnCreateNetlist( wxCommandEvent& event )
void SCH_EDIT_FRAME::OnCreateBillOfMaterials( wxCommandEvent& )
{
wxMessageDialog dlg( this,
wxT( "https://answers.launchpad.net/kicad/+faq/2265" ),
_( "BOM Howto" ) );
dlg.ShowModal();
InvokeDialogCreateBOM( this );
}
......
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.
......@@ -5,7 +5,7 @@
#
# Import the KiCad python helper module and the csv formatter
import ky
import ky_generic_netlist_reader
import sys
# Start with a basic html template
......@@ -61,11 +61,11 @@ def myEqu(self, other):
# 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.component.__equ__ = myEqu
ky_generic_netlist_reader.component.__equ__ = myEqu
# Generate an instance of a generic netlist, and load the netlist tree from
# 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
# instead
......@@ -88,7 +88,8 @@ row += "<th>Description</th>" + "<th>Vendor</th></tr>"
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()
# Output all of the component information
......@@ -101,7 +102,8 @@ for group in grouped:
refs += component.getRef() + ", "
c = component
row = "<tr><td>" + refs +"</td><td>" + str(len(group))
row = "\n "
row += "<tr><td>" + refs +"</td><td>" + str(len(group))
row += "</td><td>" + c.getValue() + "</td><td>" + c.getLib() + "/"
row += c.getPart() + "</td><td>" + c.getDatasheet() + "</td><td>"
row += c.getDescription() + "</td><td>" + c.getField("Vendor")
......
......@@ -5,13 +5,13 @@
#
# Import the KiCad python helper module and the csv formatter
import ky
import ky_generic_netlist_reader
import csv
import sys
# 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
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
# instead
......@@ -23,7 +23,7 @@ except IOError:
# Create a new csv writer object to use as the output formatter, although we
# 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
out.writerow(['Source:', net.getSource()])
......
......@@ -5,13 +5,13 @@
#
# Import the KiCad python helper module
import ky
import ky_generic_netlist_reader
import csv
import sys
# 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
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
# instead
......@@ -22,7 +22,7 @@ except IOError:
f = stdout
# 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
out.writerow(['Source:', net.getSource()])
......
......@@ -5,13 +5,13 @@
#
# Import the KiCad python helper module and the csv formatter
import ky
import ky_generic_netlist_reader
import csv
import sys
# 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
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
# instead
......@@ -22,7 +22,7 @@ except IOError:
f = stdout
# 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
out.writerow(['Source:', net.getSource()])
......@@ -31,7 +31,8 @@ out.writerow(['Tool:', net.getTool()])
out.writerow(['Component Count:', len(net.components)])
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()
# Output all of the component information
......
#
# 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
......@@ -5,7 +5,7 @@
#
# Import the KiCad python helper module and the csv formatter
import ky
import ky_generic_netlist_reader
import sys
# Start with a basic html template
......@@ -30,7 +30,7 @@ html = """
# 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
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
# instead
......@@ -53,7 +53,8 @@ row += "<th>Description</th>" + "<th>Vendor</th></tr>"
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()
# Output all of the component information
......
......@@ -5,12 +5,12 @@
#
# Import the KiCad python helper module and the csv formatter
import ky
import ky_generic_netlist_reader
import sys
# 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
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
# instead
......
......@@ -5,7 +5,7 @@
#
# Import the KiCad python helper module and the csv formatter
import ky
import ky_generic_netlist_reader
import sys
def checkvalue(self):
......@@ -51,11 +51,11 @@ def checkvalue(self):
# Give components a new method for checking the values (this could easily be a
# 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
# 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
# instead
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment