diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a1139ad1e..6195bbd65a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 ) diff --git a/CMakeModules/download_boost.cmake b/CMakeModules/download_boost.cmake index e97973175b..d16fed7bc7 100644 --- a/CMakeModules/download_boost.cmake +++ b/CMakeModules/download_boost.cmake @@ -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 diff --git a/common/footprint_info.cpp b/common/footprint_info.cpp index c789119a9c..516b484d6d 100644 --- a/common/footprint_info.cpp +++ b/common/footprint_info.cpp @@ -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 ); diff --git a/common/fp_lib_table.cpp b/common/fp_lib_table.cpp index 558dcc888a..186505514b 100644 --- a/common/fp_lib_table.cpp +++ b/common/fp_lib_table.cpp @@ -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 ); } diff --git a/cvpcb/cfg.cpp b/cvpcb/cfg.cpp index 6d1bb55596..bd043b986f 100644 --- a/cvpcb/cfg.cpp +++ b/cvpcb/cfg.cpp @@ -38,6 +38,7 @@ #include #include +#include #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 ) { diff --git a/cvpcb/readwrite_dlgs.cpp b/cvpcb/readwrite_dlgs.cpp index 43d94bbdb5..1a153fbe98 100644 --- a/cvpcb/readwrite_dlgs.cpp +++ b/cvpcb/readwrite_dlgs.cpp @@ -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() ) ) diff --git a/include/fp_lib_table.h b/include/fp_lib_table.h index 6430b7f009..3e7c54a290 100644 --- a/include/fp_lib_table.h +++ b/include/fp_lib_table.h @@ -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 diff --git a/pcbnew/files.cpp b/pcbnew/files.cpp index 0da4e45233..751180a20a 100644 --- a/pcbnew/files.cpp +++ b/pcbnew/files.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -49,6 +50,9 @@ #include #include // LEGACY_BOARD_FILE_VERSION +#include +#include + //#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: diff --git a/pcbnew/module_editor_frame.h b/pcbnew/module_editor_frame.h index e8c4fc0493..442da70151 100644 --- a/pcbnew/module_editor_frame.h +++ b/pcbnew/module_editor_frame.h @@ -150,6 +150,7 @@ public: void OnUpdateLoadModuleFromBoard( wxUpdateUIEvent& aEvent ); void OnUpdateInsertModuleInBoard( wxUpdateUIEvent& aEvent ); void OnUpdateReplaceModuleInBoard( wxUpdateUIEvent& aEvent ); + void OnUpdateSelectCurrentLib( wxUpdateUIEvent& aEvent ); /** * Function LoadModuleFromBoard diff --git a/pcbnew/moduleframe.cpp b/pcbnew/moduleframe.cpp index fed5c049e1..d98c93a821 100644 --- a/pcbnew/moduleframe.cpp +++ b/pcbnew/moduleframe.cpp @@ -38,6 +38,7 @@ #include <3d_viewer.h> #include #include +#include #include #include @@ -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 ) diff --git a/pcbnew/pcbnew_config.cpp b/pcbnew/pcbnew_config.cpp index 1e6cd47581..9585b67cdc 100644 --- a/pcbnew/pcbnew_config.cpp +++ b/pcbnew/pcbnew_config.cpp @@ -51,6 +51,8 @@ #include #include #include +#include +#include #include #include @@ -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