Footprint library table improvements.

* Add save table and set project path environment variable code to
  FP_LIB_TABLE object.
* Add code to Pcbnew and CvPcb to set project path environment variable.
* Create empty footprint table in Pcbnew when new board created.
* Save current project specific footprint library table to path on file save
  as or empty project path.
* Fix a bug in Pcbnew in file save function that would silently overwrite
  an existing board file.
* Disable selecting the current library in the module editor when there are
  no libraries defined.
* Catch exceptions and report errors when writing footprint library tables.
* Fix Boost build CMakeFile to fix bug when bootstrapping a Boost build in
  MSys.
This commit is contained in:
Wayne Stambaugh 2013-10-13 12:29:20 -04:00
parent a8e57e10e8
commit 8580d87ef7
11 changed files with 299 additions and 33 deletions

View File

@ -49,6 +49,11 @@ option( KICAD_SCRIPTING_WXPYTHON
option( USE_FP_LIB_TABLE "Use the new footprint library table implementation. ( default OFF)" )
# BUILD_GITHUB_PLUGIN for MINGW is pretty demanding due to download_openssl.cmake and openssl's
# use of perl to drive its configure step. You might find it works in a cross builder say on linux.
# Dick is not personally supporting Windows any more with this exotic stuff. Some other windows
# developer will have to smooth out the build issues. So enable this for MINGW without my help but
# with my best wishes.
option( BUILD_GITHUB_PLUGIN "Build the GITHUB_PLUGIN for pcbnew." OFF )

View File

@ -93,7 +93,14 @@ if( BUILD_GITHUB_PLUGIN )
#message( STATUS "REPLACE libs_csv:${boost_libs_list}" )
if( MINGW )
set( bootstrap bootstrap.bat mingw )
if( MSYS )
# The Boost system does not build properly on MSYS using bootstrap.sh. Running
# bootstrap.bat with cmd.exe does. It's ugly but it works. At least for Boost
# version 1.54.
set( bootstrap cmd.exe /c "bootstrap.bat mingw" )
else()
set( bootstrap ./bootstrap.bat mingw )
endif()
foreach( lib ${boost_libs_list} )
set( b2_libs ${b2_libs} --with-${lib} )
@ -103,7 +110,7 @@ if( BUILD_GITHUB_PLUGIN )
string( REGEX REPLACE "\\;" "," libs_csv "${boost_libs_list}" )
#message( STATUS "libs_csv:${libs_csv}" )
set( bootstrap bootstrap.sh --with-libraries=${libs_csv} )
set( bootstrap ./bootstrap.sh --with-libraries=${libs_csv} )
# pass to *both* C and C++ compilers
set( PIC_STUFF "cflags=${PIC_FLAG}" )
set( BOOST_INCLUDE "${BOOST_ROOT}/include" )
@ -125,7 +132,7 @@ if( BUILD_GITHUB_PLUGIN )
UPDATE_COMMAND ${CMAKE_COMMAND} -E remove_directory "${BOOST_ROOT}"
BINARY_DIR "${PREFIX}/src/boost/"
CONFIGURE_COMMAND ./${bootstrap}
CONFIGURE_COMMAND ${bootstrap}
BUILD_COMMAND ./b2
variant=release

View File

@ -148,12 +148,22 @@ bool FOOTPRINT_LIST::ReadFootprintFiles( FP_LIB_TABLE& aTable )
{
const FP_LIB_TABLE::ROW* row = aTable.FindRow( libNickNames[ii] );
wxCHECK2_MSG( row != NULL, continue,
wxCHECK2_MSG( row != NULL, retv = false; continue,
wxString::Format( wxT( "No library name <%s> found in footprint library "
"table." ), GetChars( libNickNames[ii] ) ) );
try
{
PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::EnumFromStr( row->GetType() ) ) );
PLUGIN* plugin = IO_MGR::PluginFind( IO_MGR::EnumFromStr( row->GetType() ) );
if( plugin == NULL )
{
m_filesNotFound << wxString::Format( _( "Cannot find plugin type '%s'." ),
GetChars( row->GetType() ) );
retv = false;
continue;
}
PLUGIN::RELEASER pi( plugin );
wxString path = FP_LIB_TABLE::ExpandSubstitutions( row->GetFullURI() );
wxArrayString fpnames = pi->FootprintEnumerate( path );

View File

@ -42,6 +42,25 @@
using namespace FP_LIB_TABLE_T;
/**
* Definition for enabling and disabling footprint library trace output. See the
* wxWidgets documentation on using the WXTRACE environment variable.
*/
static const wxString traceFpLibTable( wxT( "KicadFpLibTable" ) );
/// The evinronment variable name for the current project path. This is used interanally
/// at run time and is not exposed outside of the current process.
static wxString projectPathEnvVariableName( wxT( "KICAD_PRJ_PATH" ) );
/// The footprint library table name used when no project file is passed to Pcbnew or CvPcb.
/// This is used temporarily to store the project specific library table until the project
/// file being edited is save. It is then moved to the file fp-lib-table in the folder where
/// the project file is saved.
static wxString defaultProjectFileName( wxT( "prj-fp-lib-table" ) );
static wxString defaultFileName( wxT( "fp-lib-table" ) );
void FP_LIB_TABLE::ROW::SetType( const wxString& aType )
{
type = IO_MGR::EnumFromStr( aType );
@ -261,6 +280,18 @@ void FP_LIB_TABLE::ROW::Format( OUTPUTFORMATTER* out, int nestLevel ) const
}
void FP_LIB_TABLE::Save( const wxFileName& aPath ) const throw( IO_ERROR )
{
wxFileName fn = GetProjectFileName( aPath );
wxLogTrace( traceFpLibTable, wxT( "Saving footprint libary table <%s>." ),
GetChars( fn.GetFullPath() ) );
FILE_OUTPUTFORMATTER sf( fn.GetFullPath() );
Format( &sf, 0 );
}
#define OPT_SEP '|' ///< options separator character
PROPERTIES* FP_LIB_TABLE::ParseOptions( const std::string& aOptionsList )
@ -486,9 +517,9 @@ const wxString FP_LIB_TABLE::ExpandSubstitutions( const wxString& aString )
}
bool FP_LIB_TABLE::IsEmpty() const
bool FP_LIB_TABLE::IsEmpty( bool aIncludeFallback )
{
if( fallBack == NULL )
if( !aIncludeFallback || (fallBack == NULL) )
return rows.empty();
return fallBack->IsEmpty() && rows.empty();
@ -667,6 +698,55 @@ bool FP_LIB_TABLE::ConvertFromLegacy( NETLIST& aNetList, const wxArrayString& aL
}
void FP_LIB_TABLE::SetProjectPathEnvVariable( const wxFileName& aPath )
{
wxString path;
if( !aPath.IsOk() || !aPath.DirExists() )
path = wxEmptyString;
else
path = aPath.GetPath();
wxLogTrace( traceFpLibTable, wxT( "Setting env %s to <%s>." ),
GetChars( projectPathEnvVariableName ), GetChars( path ) );
wxSetEnv( projectPathEnvVariableName, path );
}
const wxString& FP_LIB_TABLE::GetProjectPathEnvVariableName() const
{
return projectPathEnvVariableName;
}
wxString FP_LIB_TABLE::GetProjectFileName( const wxFileName& aPath )
{
wxFileName fn = aPath;
// Set $KICAD_PRJ_PATH to user's configuration path if aPath is not set or does not exist.
if( !aPath.IsOk() || !aPath.DirExists() )
{
fn.AssignDir( wxStandardPaths::Get().GetUserConfigDir() );
#if defined( __WINDOWS__ )
fn.AppendDir( wxT( "kicad" ) );
#endif
fn.SetName( defaultProjectFileName );
}
else
{
fn.AssignDir( aPath.GetPath() );
fn.SetName( defaultFileName );
}
wxLogTrace( traceFpLibTable, wxT( "Project specific footprint library table file <%s>." ),
GetChars( fn.GetFullPath() ) );
return fn.GetFullPath();
}
bool FP_LIB_TABLE::LoadGlobalTable( FP_LIB_TABLE& aTable ) throw (IO_ERROR, PARSE_ERROR )
{
bool tableExists = true;
@ -710,29 +790,28 @@ wxString FP_LIB_TABLE::GetGlobalTableFileName()
fn.SetName( GetFileName() );
wxLogTrace( traceFpLibTable, wxT( "Global footprint library table file <%s>." ),
GetChars( fn.GetFullPath() ) );
return fn.GetFullPath();
}
wxString FP_LIB_TABLE::GetFileName()
const wxString& FP_LIB_TABLE::GetFileName()
{
return wxString( wxT( "fp-lib-table" ) );
return defaultFileName;
}
void FP_LIB_TABLE::Load( const wxFileName& aFileName, FP_LIB_TABLE* aFallBackTable )
throw( IO_ERROR )
{
wxFileName fn = aFileName;
fallBack = aFallBackTable;
fn.SetName( FP_LIB_TABLE::GetFileName() );
fn.SetExt( wxEmptyString );
if( fn.FileExists() )
// Empty footprint library tables are valid.
if( aFileName.IsOk() && aFileName.FileExists() )
{
FILE_LINE_READER reader( fn.GetFullPath() );
FILE_LINE_READER reader( aFileName.GetFullPath() );
FP_LIB_TABLE_LEXER lexer( &reader );
Parse( &lexer );
}

View File

@ -38,6 +38,7 @@
#include <cvpcb.h>
#include <cvpcb_mainframe.h>
#include <class_DisplayFootprintsFrame.h>
#define GROUP wxT("/cvpcb")
@ -94,9 +95,17 @@ void CVPCB_MAINFRAME::LoadProjectFile( const wxString& aFileName )
// Attempt to load the project footprint library table if it exists.
m_footprintLibTable = new FP_LIB_TABLE();
if( m_DisplayFootprintFrame )
m_DisplayFootprintFrame->SetFootprintLibTable( m_footprintLibTable );
wxFileName projectFpLibTableFileName;
projectFpLibTableFileName = FP_LIB_TABLE::GetProjectFileName( fn );
try
{
m_footprintLibTable->Load( fn, m_globalFootprintTable );
m_footprintLibTable->Load( projectFpLibTableFileName, m_globalFootprintTable );
FP_LIB_TABLE::SetProjectPathEnvVariable( projectFpLibTableFileName );
}
catch( IO_ERROR ioe )
{

View File

@ -271,6 +271,35 @@ int CVPCB_MAINFRAME::SaveCmpLinkFile( const wxString& aFullFileName )
if( !fn.HasExt() )
fn.SetExt( ComponentFileExtension );
#if defined( USE_FP_LIB_TABLE )
// Save the project specific footprint library table.
if( !m_footprintLibTable->IsEmpty( false ) )
{
wxFileName fpLibFileName = fn;
fpLibFileName.ClearExt();
fpLibFileName.SetName( FP_LIB_TABLE::GetFileName() );
if( fpLibFileName.FileExists()
&& IsOK( this, _( "A footprint library table already exsist in this path.\n\nDo "
"you want to overwrite it?" ) ) )
{
try
{
m_footprintLibTable->Save( fpLibFileName );
}
catch( IO_ERROR& ioe )
{
DisplayError( this,
wxString::Format( _( "An error occurred attempting to save the "
"footpirnt library table <%s>\n\n%s" ),
GetChars( fpLibFileName.GetFullPath() ),
GetChars( ioe.errorText ) ) );
}
}
}
#endif
}
if( !IsWritable( fn.GetFullPath() ) )

View File

@ -375,6 +375,8 @@ public:
*/
void Format( OUTPUTFORMATTER* out, int nestLevel ) const throw( IO_ERROR );
void Save( const wxFileName& aPath ) const throw( IO_ERROR );
/**
* Function GetLogicalLibs
* returns the logical library names, all of them that are pertinent to
@ -486,9 +488,11 @@ public:
/**
* Function IsEmpty
* @param aIncludeFallback is used to determine if the fallback table should be
* included in the test.
* @return true if the footprint library table is empty.
*/
bool IsEmpty() const;
bool IsEmpty( bool aIncludeFallback = true );
/**
* Function MissingLegacyLibs
@ -552,10 +556,16 @@ public:
static wxString GetGlobalTableFileName();
/**
* Function GetFootprintTableFileName
* Function GetFileName
* @return the footprint library file name.
*/
static wxString GetFileName();
static const wxString& GetFileName();
static void SetProjectPathEnvVariable( const wxFileName& aPath );
const wxString& GetProjectPathEnvVariableName() const;
static wxString GetProjectFileName( const wxFileName& aPath );
/**
* Function Load

View File

@ -41,6 +41,7 @@
#include <filter_reader.h>
#include <appl_wxstruct.h>
#include <msgpanel.h>
#include <fp_lib_table.h>
#include <pcbnew.h>
#include <pcbnew_id.h>
@ -49,6 +50,9 @@
#include <class_board.h>
#include <build_version.h> // LEGACY_BOARD_FILE_VERSION
#include <module_editor_frame.h>
#include <modview_frame.h>
//#define USE_INSTRUMENTATION true
#define USE_INSTRUMENTATION false
@ -136,8 +140,29 @@ void PCB_EDIT_FRAME::Files_io( wxCommandEvent& event )
case ID_NEW_BOARD:
{
Clear_Pcb( true );
wxFileName fn( wxT( "noname" ) );
#if defined( USE_FP_LIB_TABLE )
// Create a new empty footprint library table for the new board.
delete m_footprintLibTable;
m_footprintLibTable = new FP_LIB_TABLE( m_globalFootprintTable );
FOOTPRINT_EDIT_FRAME* editFrame = FOOTPRINT_EDIT_FRAME::GetActiveFootprintEditor();
if( editFrame )
editFrame->SetFootprintLibTable( m_footprintLibTable );
FOOTPRINT_VIEWER_FRAME* viewFrame = FOOTPRINT_VIEWER_FRAME::GetActiveFootprintViewer();
if( viewFrame )
viewFrame->SetFootprintLibTable( m_footprintLibTable );
wxFileName emptyFileName;
FP_LIB_TABLE::SetProjectPathEnvVariable( emptyFileName );
#endif
wxFileName fn;
fn.AssignCwd();
fn.SetName( wxT( "noname" ) );
fn.SetExt( PcbFileExtension );
GetBoard()->SetFileName( fn.GetFullPath() );
UpdateTitle();
@ -451,6 +476,7 @@ bool PCB_EDIT_FRAME::SavePcbFile( const wxString& aFileName, bool aCreateBackupF
wxString lowerTxt;
wxString msg;
bool saveok = true;
bool isSaveAs = false;
IO_MGR::PCB_FILE_T pluginType;
@ -460,6 +486,7 @@ bool PCB_EDIT_FRAME::SavePcbFile( const wxString& aFileName, bool aCreateBackupF
wildcard << wxGetTranslation( PcbFileWildcard ) << wxChar( '|' ) <<
wxGetTranslation( LegacyPcbFileWildcard );
isSaveAs = true;
pcbFileName = GetBoard()->GetFileName();
if( pcbFileName.GetName() == wxEmptyString )
@ -489,11 +516,48 @@ bool PCB_EDIT_FRAME::SavePcbFile( const wxString& aFileName, bool aCreateBackupF
// Note: on Linux wxFileDialog is not reliable for noticing a changed filename.
// We probably need to file a bug report or implement our own derivation.
pcbFileName = dlg.GetPath();
// enforce file extension, must match plugin's policy.
pcbFileName.SetExt( IO_MGR::GetFileExtension( pluginType ) );
// Since the file overwrite test was removed from wxFileDialog because it doesn't work
// when multiple wildcards are defined, we have to check it ourselves to prevent an
// existing board file from silently being over written.
if( pcbFileName.FileExists()
&& !IsOK( this, wxString::Format( _( "The file <%s> already exists.\n\nDo you want "
"to overwrite it?" ),
GetChars( pcbFileName.GetFullPath() ) )) )
return false;
#if defined( USE_FP_LIB_TABLE )
// Save the project specific footprint library table.
if( !m_footprintLibTable->IsEmpty( false ) )
{
wxFileName fn = pcbFileName;
fn.ClearExt();
fn.SetName( FP_LIB_TABLE::GetFileName() );
if( fn.FileExists()
&& IsOK( this, _( "A footprint library table already exsist in this path.\n\nDo "
"you want to overwrite it?" ) ) )
{
try
{
m_footprintLibTable->Save( fn );
}
catch( IO_ERROR& ioe )
{
DisplayError( this,
wxString::Format( _( "An error occurred attempting to save the "
"footpirnt library table <%s>\n\n%s" ),
GetChars( fn.GetFullPath() ),
GetChars( ioe.errorText ) ) );
}
}
}
#endif
}
else
{
@ -578,6 +642,11 @@ bool PCB_EDIT_FRAME::SavePcbFile( const wxString& aFileName, bool aCreateBackupF
// and not need to have an autosave file in file history
if( aCreateBackupFile )
UpdateFileHistory( GetBoard()->GetFileName() );
// It's possible that the save as wrote over an existing board file that was part of a
// project so attempt reload the projects settings.
if( isSaveAs )
LoadProjectSettings( pcbFileName.GetFullPath() );
}
// Display the file names:

View File

@ -150,6 +150,7 @@ public:
void OnUpdateLoadModuleFromBoard( wxUpdateUIEvent& aEvent );
void OnUpdateInsertModuleInBoard( wxUpdateUIEvent& aEvent );
void OnUpdateReplaceModuleInBoard( wxUpdateUIEvent& aEvent );
void OnUpdateSelectCurrentLib( wxUpdateUIEvent& aEvent );
/**
* Function LoadModuleFromBoard

View File

@ -38,6 +38,7 @@
#include <3d_viewer.h>
#include <pcbcommon.h>
#include <msgpanel.h>
#include <fp_lib_table.h>
#include <class_board.h>
#include <class_module.h>
@ -133,7 +134,7 @@ BEGIN_EVENT_TABLE( FOOTPRINT_EDIT_FRAME, PCB_BASE_FRAME )
EVT_MENU( ID_MENU_PCB_SHOW_3D_FRAME, FOOTPRINT_EDIT_FRAME::Show3D_Frame )
EVT_UPDATE_UI( ID_MODEDIT_DELETE_PART, FOOTPRINT_EDIT_FRAME::OnUpdateLibSelected )
EVT_UPDATE_UI( ID_MODEDIT_SELECT_CURRENT_LIB, FOOTPRINT_EDIT_FRAME::OnUpdateSelectCurrentLib )
EVT_UPDATE_UI( ID_MODEDIT_EXPORT_PART, FOOTPRINT_EDIT_FRAME::OnUpdateModuleSelected )
EVT_UPDATE_UI( ID_MODEDIT_CREATE_NEW_LIB_AND_SAVE_CURRENT_PART,
FOOTPRINT_EDIT_FRAME::OnUpdateModuleSelected )
@ -455,6 +456,16 @@ void FOOTPRINT_EDIT_FRAME::OnUpdateReplaceModuleInBoard( wxUpdateUIEvent& aEvent
}
void FOOTPRINT_EDIT_FRAME::OnUpdateSelectCurrentLib( wxUpdateUIEvent& aEvent )
{
#if defined( USE_FP_LIB_TABLE )
aEvent.Enable( m_footprintLibTable && !m_footprintLibTable->IsEmpty() );
#else
aEvent.Enable( !g_LibraryNames.IsEmpty() );
#endif
}
void FOOTPRINT_EDIT_FRAME::Show3D_Frame( wxCommandEvent& event )
{
if( m_Draw3DFrame )

View File

@ -51,6 +51,8 @@
#include <pcbnew_id.h>
#include <hotkeys.h>
#include <pcbnew_config.h>
#include <module_editor_frame.h>
#include <modview_frame.h>
#include <dialog_mask_clearance.h>
#include <dialog_general_options.h>
@ -88,20 +90,37 @@ void PCB_EDIT_FRAME::Process_Config( wxCommandEvent& event )
if( r & 1 )
{
FILE_OUTPUTFORMATTER sf( FP_LIB_TABLE::GetGlobalTableFileName() );
m_globalFootprintTable->Format( &sf, 0 );
try
{
FILE_OUTPUTFORMATTER sf( FP_LIB_TABLE::GetGlobalTableFileName() );
m_globalFootprintTable->Format( &sf, 0 );
}
catch( IO_ERROR& ioe )
{
wxString msg;
msg.Printf( _( "Error occurred saving the global footprint library "
"table:\n\n%s" ), ioe.errorText.GetData() );
wxMessageBox( msg, _( "File Seave Error" ), wxOK | wxICON_ERROR );
}
}
if( r & 2 )
// If no board file is defined, do not save the project specific library table. It
// is kept in memory and created in the path when the new board is saved.
if( (r & 2) && !GetBoard()->GetFileName().IsEmpty() )
{
wxFileName fn = GetBoard()->GetFileName();
fn.SetName( FP_LIB_TABLE::GetFileName() );
fn.SetExt( wxEmptyString );
FILE_OUTPUTFORMATTER sf( fn.GetFullPath() );
m_footprintLibTable->Format( &sf, 0 );
try
{
m_footprintLibTable->Save( fn );
}
catch( IO_ERROR& ioe )
{
wxString msg;
msg.Printf( _( "Error occurred saving project specific footprint library "
"table:\n\n%s" ), ioe.errorText.GetData() );
wxMessageBox( msg, _( "File Seave Error" ), wxOK | wxICON_ERROR );
}
}
}
@ -188,6 +207,8 @@ void PCB_EDIT_FRAME::Process_Config( wxCommandEvent& event )
bool PCB_EDIT_FRAME::LoadProjectSettings( const wxString& aProjectFileName )
{
wxLogDebug( wxT( "Loading project <%s> settings." ), GetChars( aProjectFileName ) );
wxFileName fn = aProjectFileName;
if( fn.GetExt() != ProjectFileExtension )
@ -229,16 +250,31 @@ bool PCB_EDIT_FRAME::LoadProjectSettings( const wxString& aProjectFileName )
#if defined( USE_FP_LIB_TABLE )
delete m_footprintLibTable;
wxFileName projectFpLibTableFileName;
projectFpLibTableFileName = FP_LIB_TABLE::GetProjectFileName( fn );
m_footprintLibTable = new FP_LIB_TABLE();
try
{
m_footprintLibTable->Load( fn, m_globalFootprintTable );
m_footprintLibTable->Load( projectFpLibTableFileName, m_globalFootprintTable );
}
catch( IO_ERROR ioe )
{
DisplayError( this, ioe.errorText );
}
FOOTPRINT_EDIT_FRAME* editFrame = FOOTPRINT_EDIT_FRAME::GetActiveFootprintEditor();
if( editFrame )
editFrame->SetFootprintLibTable( m_footprintLibTable );
FOOTPRINT_VIEWER_FRAME* viewFrame = FOOTPRINT_VIEWER_FRAME::GetActiveFootprintViewer();
if( viewFrame )
viewFrame->SetFootprintLibTable( m_footprintLibTable );
FP_LIB_TABLE::SetProjectPathEnvVariable( fn );
#endif
// Load the page layout decr file, from the filename stored in