From f559e94b009269b9f31cc3792e1cfd40fa64177b Mon Sep 17 00:00:00 2001 From: Roberto Fernandez Bautista Date: Sun, 31 Jan 2021 21:55:51 +0000 Subject: [PATCH] Non-Kicad Project Importers: Fix the creation of project fp libraries Adds a new function to PLUGIN GetImportedCachedLibraryFootprints() that loads the library footprints of the board design that was imported Fixes https://gitlab.com/kicad/code/kicad/-/issues/7449 --- include/kiway_player.h | 1 + pcbnew/files.cpp | 156 ++++++++++-------- pcbnew/io_mgr.h | 10 ++ pcbnew/plugin.cpp | 6 + .../cadstar/cadstar_pcb_archive_loader.cpp | 12 ++ .../cadstar/cadstar_pcb_archive_loader.h | 5 + .../cadstar/cadstar_pcb_archive_plugin.cpp | 28 ++++ .../cadstar/cadstar_pcb_archive_plugin.h | 11 +- pcbnew/plugins/eagle/eagle_plugin.cpp | 13 ++ pcbnew/plugins/eagle/eagle_plugin.h | 2 + 10 files changed, 171 insertions(+), 73 deletions(-) diff --git a/include/kiway_player.h b/include/kiway_player.h index 640aeeaf58..bd3b1c3c6c 100644 --- a/include/kiway_player.h +++ b/include/kiway_player.h @@ -77,6 +77,7 @@ public: // For the aCtl argument of OpenProjectFiles() #define KICTL_EAGLE_BRD (1<<0) ///< chosen *.brd file is Eagle according to user. #define KICTL_CREATE (1<<1) ///< caller thinks requested project files may not exist. +#define KICTL_IMPORT_LIB (1<<2) ///< import all footprints into a project library. /** * Open a project or set of files given by @a aFileList. diff --git a/pcbnew/files.cpp b/pcbnew/files.cpp index 8469059882..991fe95376 100644 --- a/pcbnew/files.cpp +++ b/pcbnew/files.cpp @@ -761,6 +761,90 @@ bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector& aFileSet, in "It will be converted to the new format when saved." ), wxICON_WARNING ); } + + // Import footprints into a project-specific library + //================================================== + // TODO: This should be refactored out of here into somewhere specific to the Project Import + // E.g. KICAD_MANAGER_FRAME::ImportNonKiCadProject + if( aCtl & KICTL_IMPORT_LIB ) + { + wxFileName loadedBoardFn( fullFileName ); + wxString libNickName = loadedBoardFn.GetName(); + + // Extract a footprint library from the design and add it to the fp-lib-table + // The footprints are saved in a new .pretty library. + // If this library already exists, all previous footprints will be deleted + std::vector loadedFootprints = pi->GetImportedCachedLibraryFootprints(); + wxString newLibPath = CreateNewLibrary( libNickName ); + + // Only create the new library if CreateNewLibrary succeeded (note that this fails if + // the library already exists and the user aborts after seeing the warning message + // which prompts the user to continue with overwrite or abort) + if( newLibPath.Length() > 0 ) + { + PLUGIN::RELEASER piSexpr( IO_MGR::PluginFind( IO_MGR::KICAD_SEXP ) ); + + for( FOOTPRINT* footprint : loadedFootprints ) + { + try + { + if( !footprint->GetFPID().GetLibItemName().empty() ) // Handle old boards. + { + footprint->SetReference( "REF**" ); + piSexpr->FootprintSave( newLibPath, footprint ); + delete footprint; + } + } + catch( const IO_ERROR& ioe ) + { + wxLogError( wxString::Format( _( "Error occurred when saving footprint " + "'%s' to the project specific footprint " + "library: %s" ), + footprint->GetFPID().GetUniStringLibItemName(), + ioe.What() ) ); + } + } + + FP_LIB_TABLE* prjlibtable = Prj().PcbFootprintLibs(); + const wxString& project_env = PROJECT_VAR_NAME; + wxString rel_path, env_path; + + wxASSERT_MSG( wxGetEnv( project_env, &env_path ), "There is no project variable?" ); + + wxString result( newLibPath ); + rel_path = result.Replace( env_path, wxString( "$(" + project_env + ")" ) ) ? result + : ""; + + FP_LIB_TABLE_ROW* row = new FP_LIB_TABLE_ROW( libNickName, rel_path, + wxT( "KiCad" ), wxEmptyString ); + prjlibtable->InsertRow( row ); + + wxString tblName = Prj().FootprintLibTblName(); + + try + { + Prj().PcbFootprintLibs()->Save( tblName ); + } + catch( const IO_ERROR& ioe ) + { + wxLogError( wxString::Format( _( "Error occurred saving the project specific " + "footprint library table: %s" ), + ioe.What() ) ); + } + + // Update footprint LIB_IDs to point to the just imported library + for( FOOTPRINT* footprint : GetBoard()->Footprints() ) + { + LIB_ID libId = footprint->GetFPID(); + + if( libId.GetLibItemName().empty() ) + continue; + + libId.SetLibNickname( libNickName ); + footprint->SetFPID( libId ); + } + } + } } { @@ -1101,76 +1185,8 @@ bool PCB_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType ) { case IO_MGR::CADSTAR_PCB_ARCHIVE: case IO_MGR::EAGLE: - if( OpenProjectFiles( std::vector( 1, aFileName ), KICTL_EAGLE_BRD ) ) - { - wxString projectpath = Kiway().Prj().GetProjectPath(); - wxFileName newfilename; - - newfilename.SetPath( Prj().GetProjectPath() ); - newfilename.SetName( Prj().GetProjectName() ); - newfilename.SetExt( KiCadPcbFileExtension ); - - GetBoard()->SetFileName( newfilename.GetFullPath() ); - UpdateTitle(); - OnModify(); - - // Extract a footprint library from the design and add it to the fp-lib-table - wxString newLibPath; - ExportFootprintsToLibrary( true, newfilename.GetName(), &newLibPath ); - - if( newLibPath.Length() > 0 ) - { - FP_LIB_TABLE* prjlibtable = Prj().PcbFootprintLibs(); - const wxString& project_env = PROJECT_VAR_NAME; - wxString rel_path, env_path; - - wxGetEnv( project_env, &env_path ); - - wxString result( newLibPath ); - rel_path = result.Replace( env_path, - wxString( "$(" + project_env + ")" ) ) ? result : "" ; - - if( !rel_path.IsEmpty() ) - newLibPath = rel_path; - - FP_LIB_TABLE_ROW* row = new FP_LIB_TABLE_ROW( newfilename.GetName(), - newLibPath, wxT( "KiCad" ), wxEmptyString ); - prjlibtable->InsertRow( row ); - } - - if( !GetBoard()->GetFileName().IsEmpty() ) - { - wxString tblName = Prj().FootprintLibTblName(); - - try - { - Prj().PcbFootprintLibs()->Save( tblName ); - } - catch( const IO_ERROR& ioe ) - { - wxString msg = wxString::Format( _( - "Error occurred saving project specific footprint library " - "table:\n\n%s" ), ioe.What() ); - wxMessageBox( msg, _( "File Save Error" ), wxOK | wxICON_ERROR ); - } - } - - // Update footprint LIB_IDs to point to the just imported library - for( FOOTPRINT* footprint : GetBoard()->Footprints() ) - { - LIB_ID libId = footprint->GetFPID(); - - if( libId.GetLibItemName().empty() ) - continue; - - libId.SetLibNickname( newfilename.GetName() ); - footprint->SetFPID( libId ); - } - - return true; - } - - return false; + return OpenProjectFiles( std::vector( 1, aFileName ), + KICTL_EAGLE_BRD | KICTL_IMPORT_LIB ); default: return false; diff --git a/pcbnew/io_mgr.h b/pcbnew/io_mgr.h index d2418f3a4e..f063949d1b 100644 --- a/pcbnew/io_mgr.h +++ b/pcbnew/io_mgr.h @@ -306,6 +306,16 @@ public: virtual BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties = nullptr, PROJECT* aProject = nullptr ); + /** + * Return a container with the cached library footprints generated in the last call to + * #Load. This function is intended to be used ONLY by the non-KiCad board importers for the + * purpose of obtaining the footprint library of the design and creating a project-specific + * library. + * + * @return Footprints (caller owns the objects) + */ + virtual std::vector GetImportedCachedLibraryFootprints(); + /** * Write @a aBoard to a storage file in a format that this PLUGIN implementation knows * about or it can be used to write a portion of \a aBoard to a special kind of export diff --git a/pcbnew/plugin.cpp b/pcbnew/plugin.cpp index 80e72c7ee5..6ad947a4da 100644 --- a/pcbnew/plugin.cpp +++ b/pcbnew/plugin.cpp @@ -51,6 +51,12 @@ BOARD* PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPER } +std::vector PLUGIN::GetImportedCachedLibraryFootprints() +{ + not_implemented( this, __FUNCTION__ ); + return std::vector(); +} + void PLUGIN::Save( const wxString& aFileName, BOARD* aBoard, const PROPERTIES* aProperties ) { // not pure virtual so that plugins only have to implement subset of the PLUGIN interface. diff --git a/pcbnew/plugins/cadstar/cadstar_pcb_archive_loader.cpp b/pcbnew/plugins/cadstar/cadstar_pcb_archive_loader.cpp index f0378dd0d7..5030db08b4 100644 --- a/pcbnew/plugins/cadstar/cadstar_pcb_archive_loader.cpp +++ b/pcbnew/plugins/cadstar/cadstar_pcb_archive_loader.cpp @@ -128,6 +128,18 @@ void CADSTAR_PCB_ARCHIVE_LOADER::Load( ::BOARD* aBoard, ::PROJECT* aProject ) "Please review the import errors and warnings (if any)." ) ); } +std::vector CADSTAR_PCB_ARCHIVE_LOADER::GetLoadedLibraryFootpints() const +{ + std::vector retval; + + for( std::pair fpPair : mLibraryMap ) + { + retval.push_back( static_cast( fpPair.second->Clone() ) ); + } + + return retval; +} + void CADSTAR_PCB_ARCHIVE_LOADER::logBoardStackupWarning( const wxString& aCadstarLayerName, diff --git a/pcbnew/plugins/cadstar/cadstar_pcb_archive_loader.h b/pcbnew/plugins/cadstar/cadstar_pcb_archive_loader.h index ca81ef137b..27686dd3c2 100644 --- a/pcbnew/plugins/cadstar/cadstar_pcb_archive_loader.h +++ b/pcbnew/plugins/cadstar/cadstar_pcb_archive_loader.h @@ -71,6 +71,11 @@ public: */ void Load( ::BOARD* aBoard, ::PROJECT* aProject ); + /** + * @brief Return a copy of the loaded library footprints (caller owns the objects) + * @return Container with all the footprint definitions that were loaded + */ + std::vector GetLoadedLibraryFootpints() const; private: LAYER_MAPPING_HANDLER mLayerMappingHandler; ///< Callback to get layer mapping diff --git a/pcbnew/plugins/cadstar/cadstar_pcb_archive_plugin.cpp b/pcbnew/plugins/cadstar/cadstar_pcb_archive_plugin.cpp index 06967f02e9..57f0b871df 100644 --- a/pcbnew/plugins/cadstar/cadstar_pcb_archive_plugin.cpp +++ b/pcbnew/plugins/cadstar/cadstar_pcb_archive_plugin.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -68,6 +69,17 @@ CADSTAR_PCB_ARCHIVE_PLUGIN::~CADSTAR_PCB_ARCHIVE_PLUGIN() } +void CADSTAR_PCB_ARCHIVE_PLUGIN::clearLoadedFootprints() +{ + for( FOOTPRINT* fp : m_loaded_footprints ) + { + delete fp; + } + + m_loaded_footprints.clear(); +} + + const wxString CADSTAR_PCB_ARCHIVE_PLUGIN::PluginName() const { return wxT( "CADSTAR PCB Archive" ); @@ -80,11 +92,25 @@ const wxString CADSTAR_PCB_ARCHIVE_PLUGIN::GetFileExtension() const } +std::vector CADSTAR_PCB_ARCHIVE_PLUGIN::GetImportedCachedLibraryFootprints() +{ + std::vector retval; + + for( FOOTPRINT* fp : m_loaded_footprints ) + { + retval.push_back( static_cast( fp->Clone() ) ); + } + + return retval; +} + + BOARD* CADSTAR_PCB_ARCHIVE_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties, PROJECT* aProject ) { m_props = aProperties; m_board = aAppendToMe ? aAppendToMe : new BOARD(); + clearLoadedFootprints(); CADSTAR_PCB_ARCHIVE_LOADER tempPCB( aFileName, m_layer_mapping_handler, m_show_layer_mapping_warnings ); @@ -111,5 +137,7 @@ BOARD* CADSTAR_PCB_ARCHIVE_PLUGIN::Load( const wxString& aFileName, BOARD* aAppe } } + m_loaded_footprints = tempPCB.GetLoadedLibraryFootpints(); + return m_board; } diff --git a/pcbnew/plugins/cadstar/cadstar_pcb_archive_plugin.h b/pcbnew/plugins/cadstar/cadstar_pcb_archive_plugin.h index 7dde2efac3..7a908f1b87 100644 --- a/pcbnew/plugins/cadstar/cadstar_pcb_archive_plugin.h +++ b/pcbnew/plugins/cadstar/cadstar_pcb_archive_plugin.h @@ -49,6 +49,8 @@ public: return 0; } + std::vector GetImportedCachedLibraryFootprints() override; + /** * Return the automapped layers. * @@ -69,9 +71,12 @@ public: ~CADSTAR_PCB_ARCHIVE_PLUGIN(); private: - const PROPERTIES* m_props; - BOARD* m_board; - bool m_show_layer_mapping_warnings; + void clearLoadedFootprints(); + + const PROPERTIES* m_props; + BOARD* m_board; + std::vector m_loaded_footprints; + bool m_show_layer_mapping_warnings; }; #endif // CADSTAR_ARCHIVE_PLUGIN_H_ diff --git a/pcbnew/plugins/eagle/eagle_plugin.cpp b/pcbnew/plugins/eagle/eagle_plugin.cpp index 5ffe821c0b..ef6f47798c 100644 --- a/pcbnew/plugins/eagle/eagle_plugin.cpp +++ b/pcbnew/plugins/eagle/eagle_plugin.cpp @@ -402,6 +402,19 @@ BOARD* EAGLE_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, } +std::vector EAGLE_PLUGIN::GetImportedCachedLibraryFootprints() +{ + std::vector retval; + + for( std::pair fp : m_templates ) + { + retval.push_back( static_cast( fp.second->Clone() ) ); + } + + return retval; +} + + void EAGLE_PLUGIN::init( const PROPERTIES* aProperties ) { m_hole_count = 0; diff --git a/pcbnew/plugins/eagle/eagle_plugin.h b/pcbnew/plugins/eagle/eagle_plugin.h index 906d0e1517..36a02de1da 100644 --- a/pcbnew/plugins/eagle/eagle_plugin.h +++ b/pcbnew/plugins/eagle/eagle_plugin.h @@ -132,6 +132,8 @@ public: BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties = nullptr, PROJECT* aProject = nullptr ) override; + std::vector GetImportedCachedLibraryFootprints() override; + const wxString GetFileExtension() const override; void FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aLibraryPath,