Recursively add KiCad and GEDA libraries inside a folder
CHANGED: KiCad and GEDA libraries can now be added recursively by selecting a parent folder.
This commit is contained in:
parent
a91ca785e5
commit
10a862c458
|
@ -61,16 +61,21 @@
|
||||||
#include <pcbnew_id.h> // For ID_PCBNEW_END_LIST
|
#include <pcbnew_id.h> // For ID_PCBNEW_END_LIST
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Container that describes file type info for the add a library options
|
||||||
|
*/
|
||||||
struct supportedFileType
|
struct supportedFileType
|
||||||
{
|
{
|
||||||
wxString m_Description; ///< Description shown in the file picker dialog
|
wxString m_Description; ///< Description shown in the file picker dialog
|
||||||
wxString m_FileFilter; ///< In case of folders it stands for extensions of files stored inside
|
wxString m_FileFilter; ///< Filter used for file pickers if m_IsFile is true
|
||||||
bool m_IsFile; ///< Whether the library is a folder or a file
|
wxString m_FolderSearchExtension; ///< In case of folders it stands for extensions of files stored inside
|
||||||
|
bool m_IsFile; ///< Whether the library is a folder or a file
|
||||||
IO_MGR::PCB_FILE_T m_Plugin;
|
IO_MGR::PCB_FILE_T m_Plugin;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Event IDs for the menu items in the split button menu
|
* Event IDs for the menu items in the split button menu for add a library
|
||||||
*/
|
*/
|
||||||
enum {
|
enum {
|
||||||
ID_PANEL_FPLIB_ADD_KICADMOD = ID_PCBNEW_END_LIST,
|
ID_PANEL_FPLIB_ADD_KICADMOD = ID_PCBNEW_END_LIST,
|
||||||
|
@ -79,18 +84,99 @@ enum {
|
||||||
ID_PANEL_FPLIB_ADD_GEDA,
|
ID_PANEL_FPLIB_ADD_GEDA,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Map of event id as key to the file type struct
|
* Map with event id as the key to supported file types that will be listed for the add a library option.
|
||||||
*/
|
*
|
||||||
static const std::map<int, supportedFileType> fileTypes =
|
*/
|
||||||
|
static const std::map<int, supportedFileType>& fileTypes()
|
||||||
{
|
{
|
||||||
{ ID_PANEL_FPLIB_ADD_KICADMOD, { "KiCad (folder with .kicad_mod files)", "", false, IO_MGR::KICAD_SEXP } },
|
/*
|
||||||
{ ID_PANEL_FPLIB_ADD_EAGLE6, { "Eagle 6.x (*.lbr)", EagleFootprintLibPathWildcard(), true, IO_MGR::EAGLE } },
|
* This is wrapped inside a function to prevent a static initialization order fiasco with the file extension
|
||||||
{ ID_PANEL_FPLIB_ADD_KICADLEGACY, { "KiCad legacy (*.mod)", LegacyFootprintLibPathWildcard(), true, IO_MGR::LEGACY } },
|
* variables. Once C++20 is allowed in KiCad code, those file extensions can be made constexpr and this can
|
||||||
{ ID_PANEL_FPLIB_ADD_GEDA, { "Geda (folder with *.fp files)", "", false, IO_MGR::GEDA_PCB } },
|
* be removed from a function call and placed in the file normally.
|
||||||
};
|
*/
|
||||||
|
static const std::map<int, supportedFileType> fileTypes =
|
||||||
|
{
|
||||||
|
{ ID_PANEL_FPLIB_ADD_KICADMOD, { "KiCad (folder with .kicad_mod files)", "", KiCadFootprintFileExtension, false, IO_MGR::KICAD_SEXP } },
|
||||||
|
{ ID_PANEL_FPLIB_ADD_EAGLE6, { "Eagle 6.x (*.lbr)", EagleFootprintLibPathWildcard(), "", true, IO_MGR::EAGLE } },
|
||||||
|
{ ID_PANEL_FPLIB_ADD_KICADLEGACY, { "KiCad legacy (*.mod)", LegacyFootprintLibPathWildcard(), "", true, IO_MGR::LEGACY } },
|
||||||
|
{ ID_PANEL_FPLIB_ADD_GEDA, { "Geda (folder with *.fp files)", "", GedaPcbFootprintLibFileExtension, false, IO_MGR::GEDA_PCB } },
|
||||||
|
};
|
||||||
|
|
||||||
|
return fileTypes;
|
||||||
|
}
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Traverser implementation that looks to find any and all "folder" libraries by looking for files
|
||||||
|
* with a specific extension inside folders
|
||||||
|
*/
|
||||||
|
class LIBRARY_TRAVERSER : public wxDirTraverser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LIBRARY_TRAVERSER( wxString aSearchExtension ) : m_searchExtension( aSearchExtension )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
virtual wxDirTraverseResult OnFile( const wxString& aFileName )
|
||||||
|
{
|
||||||
|
wxFileName file( aFileName );
|
||||||
|
if( m_searchExtension.IsSameAs( file.GetExt(), false ) )
|
||||||
|
{
|
||||||
|
m_foundDirs.insert( { m_currentDir, 1 } );
|
||||||
|
}
|
||||||
|
|
||||||
|
return wxDIR_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
virtual wxDirTraverseResult OnOpenError( const wxString& aOpenErrorName )
|
||||||
|
{
|
||||||
|
m_failedDirs.insert( { aOpenErrorName, 1 } );
|
||||||
|
return wxDIR_IGNORE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool HasDirectoryOpenFailures()
|
||||||
|
{
|
||||||
|
return m_failedDirs.size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
virtual wxDirTraverseResult OnDir( const wxString& aDirName )
|
||||||
|
{
|
||||||
|
m_currentDir = aDirName;
|
||||||
|
return wxDIR_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GetPaths( wxArrayString& aPathArray )
|
||||||
|
{
|
||||||
|
for( auto foundDirsPair : m_foundDirs )
|
||||||
|
{
|
||||||
|
aPathArray.Add( foundDirsPair.first );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GetFailedPaths( wxArrayString& aPathArray )
|
||||||
|
{
|
||||||
|
for( auto failedDirsPair : m_failedDirs )
|
||||||
|
{
|
||||||
|
aPathArray.Add( failedDirsPair.first );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
wxString m_searchExtension;
|
||||||
|
wxString m_currentDir;
|
||||||
|
std::unordered_map<wxString, int> m_foundDirs;
|
||||||
|
std::unordered_map<wxString, int> m_failedDirs;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class builds a wxGridTableBase by wrapping an #FP_LIB_TABLE object.
|
* This class builds a wxGridTableBase by wrapping an #FP_LIB_TABLE object.
|
||||||
*/
|
*/
|
||||||
|
@ -353,7 +439,7 @@ PANEL_FP_LIB_TABLE::PANEL_FP_LIB_TABLE( DIALOG_EDIT_LIBRARY_TABLES* aParent,
|
||||||
|
|
||||||
// Populate the browse library options
|
// Populate the browse library options
|
||||||
wxMenu* browseMenu = m_browseButton->GetSplitButtonMenu();
|
wxMenu* browseMenu = m_browseButton->GetSplitButtonMenu();
|
||||||
for( auto& fileType : fileTypes )
|
for( auto& fileType : fileTypes() )
|
||||||
{
|
{
|
||||||
browseMenu->Append( fileType.first, fileType.second.m_Description );
|
browseMenu->Append( fileType.first, fileType.second.m_Description );
|
||||||
|
|
||||||
|
@ -618,14 +704,14 @@ void PANEL_FP_LIB_TABLE::browseLibrariesHandler( wxCommandEvent& event )
|
||||||
if( event.GetEventType() == wxEVT_BUTTON )
|
if( event.GetEventType() == wxEVT_BUTTON )
|
||||||
{
|
{
|
||||||
// Let's default to adding a kicad module for just the module
|
// Let's default to adding a kicad module for just the module
|
||||||
fileTypeIt = fileTypes.find( ID_PANEL_FPLIB_ADD_KICADMOD );
|
fileTypeIt = fileTypes().find( ID_PANEL_FPLIB_ADD_KICADMOD );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fileTypeIt = fileTypes.find( event.GetId() );
|
fileTypeIt = fileTypes().find( event.GetId() );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( fileTypeIt == fileTypes.end() )
|
if( fileTypeIt == fileTypes().end() )
|
||||||
{
|
{
|
||||||
wxLogWarning( "File type selection event received but could not find the file type in the table" );
|
wxLogWarning( "File type selection event received but could not find the file type in the table" );
|
||||||
return;
|
return;
|
||||||
|
@ -666,7 +752,33 @@ void PANEL_FP_LIB_TABLE::browseLibrariesHandler( wxCommandEvent& event )
|
||||||
if( result == wxID_CANCEL )
|
if( result == wxID_CANCEL )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
files.Add( dlg.GetPath() );
|
// is there a file extension configured to hunt out their containing folders?
|
||||||
|
if( fileType.m_FolderSearchExtension != "" )
|
||||||
|
{
|
||||||
|
wxDir rootDir( dlg.GetPath() );
|
||||||
|
|
||||||
|
LIBRARY_TRAVERSER traverser( fileType.m_FolderSearchExtension );
|
||||||
|
rootDir.Traverse( traverser );
|
||||||
|
|
||||||
|
traverser.GetPaths( files );
|
||||||
|
|
||||||
|
if( traverser.HasDirectoryOpenFailures() )
|
||||||
|
{
|
||||||
|
wxArrayString failedDirs;
|
||||||
|
traverser.GetPaths( failedDirs );
|
||||||
|
wxString detailedMsg = _( "The following directories could not be opened: \n" );
|
||||||
|
|
||||||
|
for( auto& path : failedDirs )
|
||||||
|
detailedMsg << path << "\n";
|
||||||
|
|
||||||
|
DisplayErrorMessage( this, _( "Failed to open directories to look for libraries" ),
|
||||||
|
detailedMsg );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
files.Add( dlg.GetPath() );
|
||||||
|
}
|
||||||
|
|
||||||
m_lastBrowseDir = dlg.GetPath();
|
m_lastBrowseDir = dlg.GetPath();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue