Eeschema: add dialog and utilities to create BOMs from generic netlist
This commit is contained in:
parent
2810f5a5fe
commit
26b7bdc35c
|
@ -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} )
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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] );
|
||||||
|
}
|
|
@ -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
|
@ -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__
|
|
@ -0,0 +1,4 @@
|
||||||
|
plugins
|
||||||
|
plugin
|
||||||
|
cmd
|
||||||
|
opts
|
|
@ -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 <
|
||||||
|
output filename > < style-sheet filename > < input XML
|
||||||
|
file to convert ></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 “%O” f:/kicad/bin/plugins/myconverter.xsl “%I”</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 “%O” /usr/local/kicad/bin/plugins/myconverter .xsl
|
||||||
|
“%I”</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 => 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 => 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 => 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>< path of
|
||||||
|
</SPAN></SPAN>xsltproc > <SPAN STYLE="font-variant: normal"><SPAN STYLE="font-style: normal">xsltproc
|
||||||
|
< </SPAN></SPAN>xsltproc parameters ></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 “%O”
|
||||||
|
f:/kicad/bin/plugins/netlist_form_pads-pcb.xsl “%I”</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 “%O”
|
||||||
|
/usr/local/kicad/bin/plugins/netlist_form_pads-pcb.xsl “%I”</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"><
|
||||||
|
script file name </SPAN></SPAN>> < input filename > <
|
||||||
|
output filename ></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>
|
||||||
|
“<I><B>%I” “%O”</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> “<I><B>%I”
|
||||||
|
“%O”</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>
|
|
@ -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_
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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.
|
|
@ -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
|
|
@ -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")])
|
|
@ -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)
|
|
@ -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() + ", "
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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()
|
Loading…
Reference in New Issue