Performance enhancements in fp loading, string cmp, etc.

Knocks about 1/3 off the first footprint load, and more than 1/2
off subsequent loads.
This commit is contained in:
Jeff Young 2018-07-30 14:18:37 +01:00
parent 0a35c5c97e
commit f8a5e2c1c8
31 changed files with 370 additions and 214 deletions

View File

@ -250,6 +250,139 @@ wxString GetKicadConfigPath()
} }
enum Bracket
{
Bracket_None,
Bracket_Normal = ')',
Bracket_Curly = '}',
#ifdef __WINDOWS__
Bracket_Windows = '%', // yeah, Windows people are a bit strange ;-)
#endif
Bracket_Max
};
//
// Stolen from wxExpandEnvVars and then heavily optimized
//
wxString KIwxExpandEnvVars(const wxString& str)
{
size_t strlen = str.length();
wxString strResult;
strResult.Alloc(strlen);
for ( size_t n = 0; n < strlen; n++ ) {
wxUniChar str_n = str[n];
switch ( str_n.GetValue() ) {
#ifdef __WINDOWS__
case wxT('%'):
#endif // __WINDOWS__
case wxT('$'):
{
Bracket bracket;
#ifdef __WINDOWS__
if ( str_n == wxT('%') )
bracket = Bracket_Windows;
else
#endif // __WINDOWS__
if ( n == strlen - 1 ) {
bracket = Bracket_None;
}
else {
switch ( str[n + 1].GetValue() ) {
case wxT('('):
bracket = Bracket_Normal;
n++; // skip the bracket
break;
case wxT('{'):
bracket = Bracket_Curly;
n++; // skip the bracket
break;
default:
bracket = Bracket_None;
}
}
size_t m = n + 1;
wxUniChar str_m = str[m];
while ( m < strlen && (wxIsalnum(str_m) || str_m == wxT('_')) )
str_m = str[++m];
wxString strVarName(str.c_str() + n + 1, m - n - 1);
#ifdef __WXWINCE__
const bool expanded = false;
#else
// NB: use wxGetEnv instead of wxGetenv as otherwise variables
// set through wxSetEnv may not be read correctly!
bool expanded = false;
wxString tmp;
if (wxGetEnv(strVarName, &tmp))
{
strResult += tmp;
expanded = true;
}
else
#endif
{
// variable doesn't exist => don't change anything
#ifdef __WINDOWS__
if ( bracket != Bracket_Windows )
#endif
if ( bracket != Bracket_None )
strResult << str[n - 1];
strResult << str_n << strVarName;
}
// check the closing bracket
if ( bracket != Bracket_None ) {
if ( m == strlen || str_m != (wxChar)bracket ) {
// under MSW it's common to have '%' characters in the registry
// and it's annoying to have warnings about them each time, so
// ignroe them silently if they are not used for env vars
//
// under Unix, OTOH, this warning could be useful for the user to
// understand why isn't the variable expanded as intended
#ifndef __WINDOWS__
wxLogWarning(_("Environment variables expansion failed: missing '%c' at position %u in '%s'."),
(char)bracket, (unsigned int) (m + 1), str.c_str());
#endif // __WINDOWS__
}
else {
// skip closing bracket unless the variables wasn't expanded
if ( !expanded )
strResult << (wxChar)bracket;
str_m = str[++m];
}
}
n = m - 1; // skip variable name
}
break;
case wxT('\\'):
// backslash can be used to suppress special meaning of % and $
if ( n != strlen - 1 && (str[n + 1] == wxT('%') || str[n + 1] == wxT('$')) ) {
strResult += str[++n];
break;
}
//else: fall through
default:
strResult += str_n;
}
}
return strResult;
}
#include <ki_mutex.h> #include <ki_mutex.h>
const wxString ExpandEnvVarSubstitutions( const wxString& aString ) const wxString ExpandEnvVarSubstitutions( const wxString& aString )
{ {
@ -261,7 +394,7 @@ const wxString ExpandEnvVarSubstitutions( const wxString& aString )
// We reserve the right to do this another way, by providing our own member // We reserve the right to do this another way, by providing our own member
// function. // function.
return wxExpandEnvVars( aString ); return KIwxExpandEnvVars( aString );
} }

View File

@ -83,7 +83,7 @@ void FOOTPRINT_FILTER_IT::increment()
// include the library name in the search string // include the library name in the search string
// e.g. LibName:FootprintName // e.g. LibName:FootprintName
if( filter_pattern.Contains( ":" ) ) if( filter_pattern.Contains( ":" ) )
currname = list->GetItem( m_pos ).GetNickname().Lower() + ":"; currname = list->GetItem( m_pos ).GetLibNickname().Lower() + ":";
currname += list->GetItem( m_pos ).GetFootprintName().Lower(); currname += list->GetItem( m_pos ).GetFootprintName().Lower();
@ -135,7 +135,7 @@ bool FOOTPRINT_FILTER_IT::FootprintFilterMatch( FOOTPRINT_INFO& aItem )
// If the filter contains a ':' character, include the library name in the pattern // If the filter contains a ':' character, include the library name in the pattern
if( each_filter->GetPattern().Contains( ":" ) ) if( each_filter->GetPattern().Contains( ":" ) )
{ {
name = aItem.GetNickname().Lower() + ":"; name = aItem.GetLibNickname().Lower() + ":";
} }
name += aItem.GetFootprintName().Lower(); name += aItem.GetFootprintName().Lower();

View File

@ -59,7 +59,7 @@ FOOTPRINT_INFO* FOOTPRINT_LIST::GetModuleInfo( const wxString& aLibNickname,
for( auto& fp : m_list ) for( auto& fp : m_list )
{ {
if( aLibNickname == fp->GetNickname() && aFootprintName == fp->GetFootprintName() ) if( aLibNickname == fp->GetLibNickname() && aFootprintName == fp->GetFootprintName() )
return &*fp; return &*fp;
} }

View File

@ -323,18 +323,14 @@ static void setLibNickname( MODULE* aModule,
} }
MODULE* FP_LIB_TABLE::LoadEnumeratedFootprint( const wxString& aNickname, const MODULE* FP_LIB_TABLE::GetEnumeratedFootprint( const wxString& aNickname,
const wxString& aFootprintName ) const wxString& aFootprintName )
{ {
const FP_LIB_TABLE_ROW* row = FindRow( aNickname ); const FP_LIB_TABLE_ROW* row = FindRow( aNickname );
wxASSERT( (PLUGIN*) row->plugin ); wxASSERT( (PLUGIN*) row->plugin );
MODULE* ret = row->plugin->LoadEnumeratedFootprint( row->GetFullURI( true ), aFootprintName, return row->plugin->GetEnumeratedFootprint( row->GetFullURI( true ), aFootprintName,
row->GetProperties() ); row->GetProperties() );
setLibNickname( ret, row->GetNickName(), aFootprintName );
return ret;
} }

View File

@ -141,13 +141,24 @@ LIB_TREE_NODE_UNIT::LIB_TREE_NODE_UNIT( LIB_TREE_NODE* aParent, LIB_TREE_ITEM* a
} }
LIB_TREE_NODE_LIB_ID::LIB_TREE_NODE_LIB_ID( LIB_TREE_NODE* aParent, LIB_TREE_ITEM* aAlias ) LIB_TREE_NODE_LIB_ID::LIB_TREE_NODE_LIB_ID( LIB_TREE_NODE* aParent, LIB_TREE_ITEM* aItem )
{ {
wxASSERT( aParent && aAlias );
Type = LIBID; Type = LIBID;
Parent = aParent; Parent = aParent;
Update( aAlias );
LibId = aItem->GetLibId();
Name = aItem->GetName();
Desc = aItem->GetDescription();
MatchName = aItem->GetName().Lower();
SearchText = aItem->GetSearchText();
SearchTextNormalized = false;
IsRoot = aItem->IsRoot();
for( int u = 1; u <= aItem->GetUnitCount(); ++u )
AddUnit( aItem, u );
} }
@ -161,21 +172,19 @@ LIB_TREE_NODE_UNIT& LIB_TREE_NODE_LIB_ID::AddUnit( LIB_TREE_ITEM* aItem, int aUn
void LIB_TREE_NODE_LIB_ID::Update( LIB_TREE_ITEM* aItem ) void LIB_TREE_NODE_LIB_ID::Update( LIB_TREE_ITEM* aItem )
{ {
IsRoot = aItem->IsRoot(); // Update is called when the names match, so just update the other fields.
LibId = aItem->GetLibId();
LibId.SetLibNickname( aItem->GetLibNickname() );
Name = aItem->GetName();
Desc = aItem->GetDescription(); Desc = aItem->GetDescription();
MatchName = aItem->GetName().Lower();
SearchText = aItem->GetSearchText(); SearchText = aItem->GetSearchText();
SearchTextNormalized = false; SearchTextNormalized = false;
IsRoot = aItem->IsRoot();
Children.clear(); Children.clear();
int unitCount = aItem->GetUnitCount(); for( int u = 1; u <= aItem->GetUnitCount(); ++u )
for( int u = 1; u <= unitCount; ++u )
AddUnit( aItem, u ); AddUnit( aItem, u );
} }
@ -246,11 +255,11 @@ LIB_TREE_NODE_LIB::LIB_TREE_NODE_LIB( LIB_TREE_NODE* aParent, wxString const& aN
} }
LIB_TREE_NODE_LIB_ID& LIB_TREE_NODE_LIB::AddComp( LIB_TREE_ITEM* aAlias ) LIB_TREE_NODE_LIB_ID& LIB_TREE_NODE_LIB::AddItem( LIB_TREE_ITEM* aItem )
{ {
LIB_TREE_NODE_LIB_ID* alias = new LIB_TREE_NODE_LIB_ID( this, aAlias ); LIB_TREE_NODE_LIB_ID* item = new LIB_TREE_NODE_LIB_ID( this, aItem );
Children.push_back( std::unique_ptr<LIB_TREE_NODE>( alias ) ); Children.push_back( std::unique_ptr<LIB_TREE_NODE>( item ) );
return *alias; return *item;
} }

View File

@ -249,9 +249,9 @@ public:
/** /**
* Construct a new alias node, add it to this library, and return it. * Construct a new alias node, add it to this library, and return it.
* *
* @param aAlias LIB_COMPONENT to provide data * @param aItem LIB_COMPONENT to provide data
*/ */
LIB_TREE_NODE_LIB_ID& AddComp( LIB_TREE_ITEM* aAlias ); LIB_TREE_NODE_LIB_ID& AddItem( LIB_TREE_ITEM* aItem );
virtual void UpdateScore( EDA_COMBINED_MATCHER& aMatcher ) override; virtual void UpdateScore( EDA_COMBINED_MATCHER& aMatcher ) override;
}; };

View File

@ -107,12 +107,12 @@ void LIB_TREE_MODEL_ADAPTER::SetPreselectNode( LIB_ID const& aLibId, int aUnit )
void LIB_TREE_MODEL_ADAPTER::DoAddLibrary( wxString const& aNodeName, wxString const& aDesc, void LIB_TREE_MODEL_ADAPTER::DoAddLibrary( wxString const& aNodeName, wxString const& aDesc,
std::vector<LIB_TREE_ITEM*> const& aCompList ) std::vector<LIB_TREE_ITEM*> const& aItemList )
{ {
auto& lib_node = m_tree.AddLib( aNodeName, aDesc ); auto& lib_node = m_tree.AddLib( aNodeName, aDesc );
for( auto a: aCompList ) for( auto item: aItemList )
lib_node.AddComp( a ); lib_node.AddItem( item );
lib_node.AssignIntrinsicRanks(); lib_node.AssignIntrinsicRanks();
m_tree.AssignIntrinsicRanks(); m_tree.AssignIntrinsicRanks();

View File

@ -148,10 +148,10 @@ public:
* *
* @param aNodeName the parent node the components will appear under * @param aNodeName the parent node the components will appear under
* @param aDesc the description field of the parent node * @param aDesc the description field of the parent node
* @param aCompList list of components * @param aItemList list of components
*/ */
void DoAddLibrary( wxString const& aNodeName, wxString const& aDesc, void DoAddLibrary( wxString const& aNodeName, wxString const& aDesc,
std::vector<LIB_TREE_ITEM*> const& aCompList ); std::vector<LIB_TREE_ITEM*> const& aItemList );
/** /**
* Set the search string provided by the user. * Set the search string provided by the user.

View File

@ -242,55 +242,50 @@ int StrNumCmp( const wxString& aString1, const wxString& aString2, int aLength,
wxString::const_iterator str1 = aString1.begin(), str2 = aString2.begin(); wxString::const_iterator str1 = aString1.begin(), str2 = aString2.begin();
if( ( str1 == aString1.end() ) || ( str2 == aString2.end() ) )
return 0;
for( i = 0; i < aLength; i++ ) for( i = 0; i < aLength; i++ )
{ {
if( isdigit( *str1 ) && isdigit( *str2 ) ) /* digit found */ wxUniChar c1 = *str1;
wxUniChar c2 = *str2;
if( isdigit( c1 ) && isdigit( c2 ) ) /* digit found */
{ {
nb1 = 0; nb1 = 0;
nb2 = 0; nb2 = 0;
while( isdigit( *str1 ) ) while( isdigit( c1 ) )
{ {
nb1 = nb1 * 10 + (int) *str1 - '0'; nb1 = nb1 * 10 + (int) c1 - '0';
++str1; c1 = *(++str1);
} }
while( isdigit( *str2 ) ) while( isdigit( c2 ) )
{ {
nb2 = nb2 * 10 + (int) *str2 - '0'; nb2 = nb2 * 10 + (int) c2 - '0';
++str2; c2 = *(++str2);
} }
if( nb1 < nb2 ) if( nb1 < nb2 )
return -1; return -1;
else if( nb1 > nb2 )
if( nb1 > nb2 )
return 1; return 1;
} }
if( aIgnoreCase ) if( aIgnoreCase )
{ {
if( toupper( *str1 ) < toupper( *str2 ) ) if( toupper( c1 ) < toupper(c2 ) )
return -1; return -1;
else if( toupper( c1 ) > toupper( c2 ) )
if( toupper( *str1 ) > toupper( *str2 ) )
return 1; return 1;
else if( ( c1 == 0 ) && ( c2 == 0 ) )
if( ( *str1 == 0 ) && ( *str2 == 0 ) )
return 0; return 0;
} }
else else
{ {
if( *str1 < *str2 ) if( c1 < c2 )
return -1; return -1;
else if( c1 > c2 )
if( *str1 > *str2 )
return 1; return 1;
else if( ( c1 == 0 ) && ( c2 == 0 ) )
if( ( str1 == aString1.end() ) && ( str2 == aString2.end() ) )
return 0; return 0;
} }

View File

@ -242,7 +242,7 @@ bool FOOTPRINT_SELECT_WIDGET::UpdateList()
{ {
for( auto& fpinfo : m_fp_filter ) for( auto& fpinfo : m_fp_filter )
{ {
wxString display_name( fpinfo.GetNickname() + ":" + fpinfo.GetFootprintName() ); wxString display_name( fpinfo.GetLibNickname() + ":" + fpinfo.GetFootprintName() );
m_fp_sel_ctrl->Append( display_name, new wxStringClientData( display_name ) ); m_fp_sel_ctrl->Append( display_name, new wxStringClientData( display_name ) );
++n_items; ++n_items;

View File

@ -496,7 +496,7 @@ void DISPLAY_FOOTPRINTS_FRAME::InitDisplay()
GetBoard()->m_Modules.PushBack( module ); GetBoard()->m_Modules.PushBack( module );
if( module_info ) if( module_info )
SetStatusText( wxString::Format( _( "Lib: %s" ), module_info->GetNickname() ), 0 ); SetStatusText( wxString::Format( _( "Lib: %s" ), module_info->GetLibNickname() ), 0 );
else else
SetStatusText( wxEmptyString, 0 ); SetStatusText( wxEmptyString, 0 );

View File

@ -154,7 +154,7 @@ void FOOTPRINTS_LISTBOX::SetFootprints( FOOTPRINT_LIST& aList, const wxString& a
for( auto& i: filter ) for( auto& i: filter )
{ {
msg.Printf( "%3d %s:%s", int( newList.GetCount() + 1 ), msg.Printf( "%3d %s:%s", int( newList.GetCount() + 1 ),
GetChars( i.GetNickname() ), GetChars( i.GetLibNickname() ),
GetChars( i.GetFootprintName() ) ); GetChars( i.GetFootprintName() ) );
newList.Add( msg ); newList.Add( msg );
} }

View File

@ -94,7 +94,7 @@ LIB_ALIAS::~LIB_ALIAS()
} }
const wxString LIB_ALIAS::GetLibraryName() wxString LIB_ALIAS::GetLibNickname() const
{ {
wxASSERT_MSG( shared, wxT( "LIB_ALIAS without a LIB_PART" ) ); wxASSERT_MSG( shared, wxT( "LIB_ALIAS without a LIB_PART" ) );

View File

@ -109,14 +109,11 @@ public:
return shared; return shared;
} }
const wxString GetLibraryName(); PART_LIB* GetLib();
bool IsRoot() const override;
LIB_ID GetLibId() const override; LIB_ID GetLibId() const override;
PART_LIB* GetLib(); wxString GetLibNickname() const override;
const wxString& GetName() const override { return name; } const wxString& GetName() const override { return name; }
void SetName( const wxString& aName ); void SetName( const wxString& aName );
@ -144,8 +141,19 @@ public:
wxString GetSearchText() override; wxString GetSearchText() override;
/**
* For symbols having aliases, IsRoot() indicates the principal item.
*/
bool IsRoot() const override;
/**
* For symbols with units, return the number of units.
*/
int GetUnitCount() override; int GetUnitCount() override;
/**
* For symbols with units, return an identifier for unit x.
*/
wxString GetUnitReference( int aUnit ) override; wxString GetUnitReference( int aUnit ) override;
/** /**

View File

@ -1409,7 +1409,7 @@ void SCH_COMPONENT::GetMsgPanelInfo( EDA_UNITS_T aUnits, MSG_PANEL_ITEMS& aList
aList.push_back( MSG_PANEL_ITEM( _( "Alias of" ), part->GetName(), BROWN ) ); aList.push_back( MSG_PANEL_ITEM( _( "Alias of" ), part->GetName(), BROWN ) );
if( alias->GetLib() && alias->GetLib()->IsCache() ) if( alias->GetLib() && alias->GetLib()->IsCache() )
aList.push_back( MSG_PANEL_ITEM( _( "Library" ), alias->GetLibraryName(), RED ) ); aList.push_back( MSG_PANEL_ITEM( _( "Library" ), alias->GetLibNickname(), RED ) );
else if( !m_lib_id.GetLibNickname().empty() ) else if( !m_lib_id.GetLibNickname().empty() )
aList.push_back( MSG_PANEL_ITEM( _( "Library" ), m_lib_id.GetLibNickname(), aList.push_back( MSG_PANEL_ITEM( _( "Library" ), m_lib_id.GetLibNickname(),
BROWN ) ); BROWN ) );

View File

@ -130,7 +130,7 @@ void SYMBOL_TREE_SYNCHRONIZING_ADAPTER::updateLibrary( LIB_TREE_NODE_LIB& aLibNo
{ {
// add a new library // add a new library
for( auto alias : m_libMgr->GetAliases( aLibNode.Name ) ) for( auto alias : m_libMgr->GetAliases( aLibNode.Name ) )
aLibNode.AddComp( alias ); aLibNode.AddItem( alias );
} }
else if( hashIt->second != m_libMgr->GetLibraryHash( aLibNode.Name ) ) else if( hashIt->second != m_libMgr->GetLibraryHash( aLibNode.Name ) )
{ {
@ -162,7 +162,7 @@ void SYMBOL_TREE_SYNCHRONIZING_ADAPTER::updateLibrary( LIB_TREE_NODE_LIB& aLibNo
// now the aliases list contains only new aliases that need to be added to the tree // now the aliases list contains only new aliases that need to be added to the tree
for( auto alias : aliases ) for( auto alias : aliases )
aLibNode.AddComp( alias ); aLibNode.AddItem( alias );
} }
aLibNode.AssignIntrinsicRanks(); aLibNode.AssignIntrinsicRanks();

View File

@ -44,9 +44,6 @@
#include <memory> #include <memory>
#define USE_FPI_LAZY 0 // 1:yes lazy, 0:no early
class FP_LIB_TABLE; class FP_LIB_TABLE;
class FOOTPRINT_LIST; class FOOTPRINT_LIST;
class FOOTPRINT_LIST_IMPL; class FOOTPRINT_LIST_IMPL;
@ -80,7 +77,7 @@ public:
return m_fpname; return m_fpname;
} }
const wxString& GetNickname() const wxString GetLibNickname() const override
{ {
return m_nickname; return m_nickname;
} }

View File

@ -187,12 +187,14 @@ public:
MODULE* FootprintLoad( const wxString& aNickname, const wxString& aFootprintName ); MODULE* FootprintLoad( const wxString& aNickname, const wxString& aFootprintName );
/** /**
* Function LoadEnumeratedFootprint * Function GetEnumeratedFootprint
* *
* a version of FootprintLoad() for use after FootprintEnumerate() for more efficient * a version of FootprintLoad() for use after FootprintEnumerate() for more efficient
* cache management. * cache management. Return value is const to allow it to return a reference to a cached
* item.
*/ */
MODULE* LoadEnumeratedFootprint( const wxString& aNickname, const wxString& aFootprintName ); const MODULE* GetEnumeratedFootprint( const wxString& aNickname,
const wxString& aFootprintName );
/** /**
* Enum SAVE_T * Enum SAVE_T
* is the set of return values from FootprintSave() below. * is the set of return values from FootprintSave() below.

View File

@ -39,19 +39,20 @@
class LIB_TREE_ITEM class LIB_TREE_ITEM
{ {
public: public:
/**
* For items having aliases, IsRoot() indicates the principal item.
*/
virtual bool IsRoot() const { return true; }
virtual LIB_ID GetLibId() const = 0; virtual LIB_ID GetLibId() const = 0;
virtual const wxString& GetName() const = 0; virtual const wxString& GetName() const = 0;
virtual wxString GetLibNickname() const = 0;
virtual wxString GetDescription() { return wxEmptyString; } virtual wxString GetDescription() { return wxEmptyString; }
virtual wxString GetSearchText() { return wxEmptyString; } virtual wxString GetSearchText() { return wxEmptyString; }
/**
* For items having aliases, IsRoot() indicates the principal item.
*/
virtual bool IsRoot() const { return true; }
/** /**
* For items with units, return the number of units. * For items with units, return the number of units.
*/ */

View File

@ -463,18 +463,6 @@ public:
*/ */
bool OpenProjectFiles( const std::vector<wxString>& aFileSet, int aCtl = 0 ) override; bool OpenProjectFiles( const std::vector<wxString>& aFileSet, int aCtl = 0 ) override;
/**
* Build the footprint library tree. Displays a progress dialog.
*/
void initLibraryTree();
/**
* Synchronize the footprint library tree to the current state of the footprint library
* table.
* @param aProgress
*/
void syncLibraryTree( bool aProgress );
/** /**
* Allows Modedit to install its preferences panel into the preferences dialog. * Allows Modedit to install its preferences panel into the preferences dialog.
*/ */
@ -506,6 +494,19 @@ protected:
/// List of footprint editor configuration parameters. /// List of footprint editor configuration parameters.
PARAM_CFG_ARRAY m_configParams; PARAM_CFG_ARRAY m_configParams;
/**
* Make sure the footprint info list is loaded (with a progress dialog) and then initialize
* the footprint library tree.
*/
void initLibraryTree();
/**
* Synchronize the footprint library tree to the current state of the footprint library
* table.
* @param aProgress
*/
void syncLibraryTree( bool aProgress );
/** /**
* Function UpdateTitle * Function UpdateTitle
* updates window title according to getLibNickName(). * updates window title according to getLibNickName().

View File

@ -48,8 +48,9 @@ void FOOTPRINT_INFO_IMPL::load()
wxASSERT( fptable ); wxASSERT( fptable );
std::unique_ptr<MODULE> footprint( fptable->LoadEnumeratedFootprint( m_nickname, m_fpname ) ); const MODULE* footprint = fptable->GetEnumeratedFootprint( m_nickname, m_fpname );
if( footprint.get() == NULL ) // Should happen only with malformed/broken libraries
if( footprint == NULL ) // Should happen only with malformed/broken libraries
{ {
m_pad_count = 0; m_pad_count = 0;
m_unique_pad_count = 0; m_unique_pad_count = 0;
@ -60,10 +61,9 @@ void FOOTPRINT_INFO_IMPL::load()
m_unique_pad_count = footprint->GetUniquePadCount( DO_NOT_INCLUDE_NPTH ); m_unique_pad_count = footprint->GetUniquePadCount( DO_NOT_INCLUDE_NPTH );
m_keywords = footprint->GetKeywords(); m_keywords = footprint->GetKeywords();
m_doc = footprint->GetDescription(); m_doc = footprint->GetDescription();
// tell ensure_loaded() I'm loaded.
m_loaded = true;
} }
m_loaded = true;
} }
@ -119,7 +119,9 @@ void FOOTPRINT_LIST_IMPL::loader_job()
bool FOOTPRINT_LIST_IMPL::ReadFootprintFiles( FP_LIB_TABLE* aTable, const wxString* aNickname, bool FOOTPRINT_LIST_IMPL::ReadFootprintFiles( FP_LIB_TABLE* aTable, const wxString* aNickname,
PROGRESS_REPORTER* aProgressReporter ) PROGRESS_REPORTER* aProgressReporter )
{ {
if( m_list_timestamp == aTable->GenerateTimestamp( aNickname ) ) long long int generatedTimestamp = aTable->GenerateTimestamp( aNickname );
if( generatedTimestamp == m_list_timestamp )
return true; return true;
m_progress_reporter = aProgressReporter; m_progress_reporter = aProgressReporter;
@ -163,6 +165,11 @@ bool FOOTPRINT_LIST_IMPL::ReadFootprintFiles( FP_LIB_TABLE* aTable, const wxStri
m_progress_reporter->AdvancePhase(); m_progress_reporter->AdvancePhase();
} }
if( m_cancelled )
m_list_timestamp = 0; // God knows what we got before we were cancelled
else
m_list_timestamp = generatedTimestamp;
return m_errors.empty(); return m_errors.empty();
} }
@ -296,7 +303,7 @@ bool FOOTPRINT_LIST_IMPL::JoinWorkers()
if( m_progress_reporter && !m_progress_reporter->KeepRefreshing() ) if( m_progress_reporter && !m_progress_reporter->KeepRefreshing() )
m_cancelled = true; m_cancelled = true;
wxMilliSleep( 20 ); wxMilliSleep( 30 );
} }
for( auto& thr : threads ) for( auto& thr : threads )
@ -307,14 +314,11 @@ bool FOOTPRINT_LIST_IMPL::JoinWorkers()
while( queue_parsed.pop( fpi ) ) while( queue_parsed.pop( fpi ) )
m_list.push_back( std::move( fpi ) ); m_list.push_back( std::move( fpi ) );
std::sort( m_list.begin(), m_list.end(), std::sort( m_list.begin(), m_list.end(), []( std::unique_ptr<FOOTPRINT_INFO> const& lhs,
[]( std::unique_ptr<FOOTPRINT_INFO> const& lhs, std::unique_ptr<FOOTPRINT_INFO> const& rhs ) -> bool
std::unique_ptr<FOOTPRINT_INFO> const& rhs ) -> bool { return *lhs < *rhs; } ); {
return *lhs < *rhs;
if( m_cancelled ) } );
m_list_timestamp = 0; // God knows what we got before we were cancelled
else
m_list_timestamp = m_lib_table->GenerateTimestamp( m_library );
return m_errors.empty(); return m_errors.empty();
} }

View File

@ -44,9 +44,14 @@ public:
m_num = 0; m_num = 0;
m_pad_count = 0; m_pad_count = 0;
m_unique_pad_count = 0; m_unique_pad_count = 0;
#if !USE_FPI_LAZY
load(); load();
#endif }
// A dummy constructor for use as a target in a binary search
FOOTPRINT_INFO_IMPL( const wxString& aFootprintName )
{
m_fpname = aFootprintName;
} }
protected: protected:

View File

@ -61,7 +61,7 @@ std::vector<LIB_TREE_ITEM*> FP_TREE_MODEL_ADAPTER::getFootprints( const wxString
for( auto& footprint : GFootprintList.GetList() ) for( auto& footprint : GFootprintList.GetList() )
{ {
if( footprint->GetNickname() != aLibName ) if( footprint->GetLibNickname() != aLibName )
{ {
if( found ) if( found )
return list; return list;

View File

@ -95,16 +95,19 @@ void FP_TREE_SYNCHRONIZING_ADAPTER::updateLibrary( LIB_TREE_NODE_LIB& aLibNode )
// remove the common part from the aliases list // remove the common part from the aliases list
for( auto nodeIt = aLibNode.Children.begin(); nodeIt != aLibNode.Children.end(); ) for( auto nodeIt = aLibNode.Children.begin(); nodeIt != aLibNode.Children.end(); )
{ {
auto footprintIt = std::find_if( footprints.begin(), footprints.end(), // Since the list is sorted we can use a binary search to speed up searches within
[&] ( const LIB_TREE_ITEM* a ) // libraries with lots of footprints.
{ FOOTPRINT_INFO_IMPL dummy( (*nodeIt)->Name );
return a->GetName() == (*nodeIt)->Name; auto footprintIt = std::lower_bound( footprints.begin(), footprints.end(), &dummy,
} ); []( LIB_TREE_ITEM* a, LIB_TREE_ITEM* b )
{
return a->GetName() < b->GetName();
} );
if( footprintIt != footprints.end() ) if( footprintIt != footprints.end() && dummy.GetName() == (*footprintIt)->GetName() )
{ {
// alias exists both in the component tree and the library manager, // footprint exists both in the lib tree and the footprint info list; just
// update only the node data // update the node data
static_cast<LIB_TREE_NODE_LIB_ID*>( nodeIt->get() )->Update( *footprintIt ); static_cast<LIB_TREE_NODE_LIB_ID*>( nodeIt->get() )->Update( *footprintIt );
footprints.erase( footprintIt ); footprints.erase( footprintIt );
++nodeIt; ++nodeIt;
@ -118,7 +121,7 @@ void FP_TREE_SYNCHRONIZING_ADAPTER::updateLibrary( LIB_TREE_NODE_LIB& aLibNode )
// now the aliases list contains only new aliases that need to be added to the tree // now the aliases list contains only new aliases that need to be added to the tree
for( auto footprint : footprints ) for( auto footprint : footprints )
aLibNode.AddComp( footprint ); aLibNode.AddItem( footprint );
aLibNode.AssignIntrinsicRanks(); aLibNode.AssignIntrinsicRanks();
m_libMap.insert( aLibNode.Name ); m_libMap.insert( aLibNode.Name );

View File

@ -954,10 +954,10 @@ void GPCB_PLUGIN::FootprintEnumerate( wxArrayString& aFootprintNames,
} }
MODULE* GPCB_PLUGIN::doLoadFootprint( const wxString& aLibraryPath, const MODULE* GPCB_PLUGIN::getFootprint( const wxString& aLibraryPath,
const wxString& aFootprintName, const wxString& aFootprintName,
const PROPERTIES* aProperties, const PROPERTIES* aProperties,
bool checkModified ) bool checkModified )
{ {
LOCALE_IO toggle; // toggles on, then off, the C locale. LOCALE_IO toggle; // toggles on, then off, the C locale.
@ -974,23 +974,23 @@ MODULE* GPCB_PLUGIN::doLoadFootprint( const wxString& aLibraryPath,
return NULL; return NULL;
} }
// copy constructor to clone the already loaded MODULE return it->second->GetModule();
return new MODULE( *it->second->GetModule() );
} }
MODULE* GPCB_PLUGIN::LoadEnumeratedFootprint( const wxString& aLibraryPath, const MODULE* GPCB_PLUGIN::GetEnumeratedFootprint( const wxString& aLibraryPath,
const wxString& aFootprintName, const wxString& aFootprintName,
const PROPERTIES* aProperties ) const PROPERTIES* aProperties )
{ {
return doLoadFootprint( aLibraryPath, aFootprintName, aProperties, false ); return getFootprint( aLibraryPath, aFootprintName, aProperties, false );
} }
MODULE* GPCB_PLUGIN::FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName, MODULE* GPCB_PLUGIN::FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName,
const PROPERTIES* aProperties ) const PROPERTIES* aProperties )
{ {
return doLoadFootprint( aLibraryPath, aFootprintName, aProperties, true ); const MODULE* footprint = getFootprint( aLibraryPath, aFootprintName, aProperties, true );
return footprint ? new MODULE( *footprint ) : nullptr;
} }

View File

@ -65,14 +65,15 @@ public:
void FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aLibraryPath, void FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aLibraryPath,
const PROPERTIES* aProperties = NULL) override; const PROPERTIES* aProperties = NULL) override;
MODULE* LoadEnumeratedFootprint( const wxString& aLibraryPath, const wxString& aFootprintName, const MODULE* GetEnumeratedFootprint( const wxString& aLibraryPath,
const PROPERTIES* aProperties = NULL ) override; const wxString& aFootprintName,
const PROPERTIES* aProperties = NULL ) override;
MODULE* FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName, MODULE* FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName,
const PROPERTIES* aProperties = NULL ) override; const PROPERTIES* aProperties = NULL ) override;
void FootprintDelete( const wxString& aLibraryPath, const wxString& aFootprintName, void FootprintDelete( const wxString& aLibraryPath, const wxString& aFootprintName,
const PROPERTIES* aProperties = NULL ) override; const PROPERTIES* aProperties = NULL ) override;
bool FootprintLibDelete( const wxString& aLibraryPath, bool FootprintLibDelete( const wxString& aLibraryPath,
const PROPERTIES* aProperties = NULL ) override; const PROPERTIES* aProperties = NULL ) override;
@ -101,8 +102,8 @@ protected:
private: private:
void validateCache( const wxString& aLibraryPath, bool checkModified = true ); void validateCache( const wxString& aLibraryPath, bool checkModified = true );
MODULE* doLoadFootprint( const wxString& aLibraryPath, const wxString& aFootprintName, const MODULE* getFootprint( const wxString& aLibraryPath, const wxString& aFootprintName,
const PROPERTIES* aProperties, bool checkModified ); const PROPERTIES* aProperties, bool checkModified );
void init( const PROPERTIES* aProperties ); void init( const PROPERTIES* aProperties );
}; };

View File

@ -407,13 +407,13 @@ public:
const PROPERTIES* aProperties = NULL ); const PROPERTIES* aProperties = NULL );
/** /**
* Function LoadEnumeratedFootprint * Function GetEnumeratedFootprint
* a version of FootprintLoad() for use after FootprintEnumerate() for more * a version of FootprintLoad() for use after FootprintEnumerate() for more efficient
* efficient cache management. * cache management.
*/ */
virtual MODULE* LoadEnumeratedFootprint( const wxString& aLibraryPath, virtual const MODULE* GetEnumeratedFootprint( const wxString& aLibraryPath,
const wxString& aFootprintName, const wxString& aFootprintName,
const PROPERTIES* aProperties = NULL ); const PROPERTIES* aProperties = NULL );
/** /**
* Function FootprintSave * Function FootprintSave

View File

@ -91,10 +91,10 @@ class FP_CACHE_ITEM
public: public:
FP_CACHE_ITEM( MODULE* aModule, const wxFileName& aFileName ); FP_CACHE_ITEM( MODULE* aModule, const wxFileName& aFileName );
wxString GetName() const { return m_file_name.GetDirs().Last(); } const wxString& GetName() const { return m_file_name.GetDirs().Last(); }
wxFileName GetFileName() const { return m_file_name; } const wxFileName& GetFileName() const { return m_file_name; }
MODULE* GetModule() const { return m_module.get(); } const MODULE* GetModule() const { return m_module.get(); }
}; };
@ -112,9 +112,10 @@ typedef MODULE_MAP::const_iterator MODULE_CITER;
class FP_CACHE class FP_CACHE
{ {
PCB_IO* m_owner; /// Plugin object that owns the cache. PCB_IO* m_owner; // Plugin object that owns the cache.
wxFileName m_lib_path; /// The path of the library. wxFileName m_lib_path; // The path of the library.
MODULE_MAP m_modules; /// Map of footprint file name per MODULE*. wxString m_lib_raw_path; // For quick comparisons.
MODULE_MAP m_modules; // Map of footprint file name per MODULE*.
bool m_cache_dirty; // Stored separately because it's expensive to check bool m_cache_dirty; // Stored separately because it's expensive to check
// m_cache_timestamp against all the files. // m_cache_timestamp against all the files.
@ -124,7 +125,7 @@ class FP_CACHE
public: public:
FP_CACHE( PCB_IO* aOwner, const wxString& aLibraryPath ); FP_CACHE( PCB_IO* aOwner, const wxString& aLibraryPath );
wxString GetPath() const { return m_lib_path.GetPath(); } wxString GetPath() const { return m_lib_raw_path; }
bool IsWritable() const { return m_lib_path.IsOk() && m_lib_path.IsDirWritable(); } bool IsWritable() const { return m_lib_path.IsOk() && m_lib_path.IsDirWritable(); }
bool Exists() const { return m_lib_path.IsOk() && m_lib_path.DirExists(); } bool Exists() const { return m_lib_path.IsOk() && m_lib_path.DirExists(); }
MODULE_MAP& GetModules() { return m_modules; } MODULE_MAP& GetModules() { return m_modules; }
@ -178,6 +179,7 @@ public:
FP_CACHE::FP_CACHE( PCB_IO* aOwner, const wxString& aLibraryPath ) FP_CACHE::FP_CACHE( PCB_IO* aOwner, const wxString& aLibraryPath )
{ {
m_owner = aOwner; m_owner = aOwner;
m_lib_raw_path = aLibraryPath;
m_lib_path.SetPath( aLibraryPath ); m_lib_path.SetPath( aLibraryPath );
m_cache_timestamp = 0; m_cache_timestamp = 0;
m_cache_dirty = true; m_cache_dirty = true;
@ -191,13 +193,13 @@ void FP_CACHE::Save( MODULE* aModule )
if( !m_lib_path.DirExists() && !m_lib_path.Mkdir() ) if( !m_lib_path.DirExists() && !m_lib_path.Mkdir() )
{ {
THROW_IO_ERROR( wxString::Format( _( "Cannot create footprint library path \"%s\"" ), THROW_IO_ERROR( wxString::Format( _( "Cannot create footprint library path \"%s\"" ),
m_lib_path.GetPath().GetData() ) ); m_lib_raw_path ) );
} }
if( !m_lib_path.IsDirWritable() ) if( !m_lib_path.IsDirWritable() )
{ {
THROW_IO_ERROR( wxString::Format( _( "Footprint library path \"%s\" is read only" ), THROW_IO_ERROR( wxString::Format( _( "Footprint library path \"%s\" is read only" ),
GetChars( m_lib_path.GetPath() ) ) ); m_lib_raw_path ) );
} }
for( MODULE_ITER it = m_modules.begin(); it != m_modules.end(); ++it ) for( MODULE_ITER it = m_modules.begin(); it != m_modules.end(); ++it )
@ -255,18 +257,15 @@ void FP_CACHE::Save( MODULE* aModule )
void FP_CACHE::Load() void FP_CACHE::Load()
{ {
wxDir dir( m_lib_path.GetPath() ); wxDir dir( m_lib_raw_path );
if( !dir.IsOpened() ) if( !dir.IsOpened() )
{ {
m_cache_timestamp = 0; m_cache_timestamp = 0;
m_cache_dirty = false; m_cache_dirty = false;
wxString msg = wxString::Format( wxString msg = wxString::Format( _( "Footprint library path \"%s\" does not exist" ),
_( "Footprint library path \"%s\" does not exist" ), m_lib_raw_path );
GetChars( m_lib_path.GetPath() )
);
THROW_IO_ERROR( msg ); THROW_IO_ERROR( msg );
} }
else else
@ -285,7 +284,7 @@ void FP_CACHE::Load()
do do
{ {
// prepend the libpath into fullPath // prepend the libpath into fullPath
wxFileName fullPath( m_lib_path.GetPath(), fpFileName ); wxFileName fullPath( m_lib_raw_path, fpFileName );
// Queue I/O errors so only files that fail to parse don't get loaded. // Queue I/O errors so only files that fail to parse don't get loaded.
try try
@ -325,11 +324,9 @@ void FP_CACHE::Remove( const wxString& aFootprintName )
if( it == m_modules.end() ) if( it == m_modules.end() )
{ {
wxString msg = wxString::Format( wxString msg = wxString::Format( _( "library \"%s\" has no footprint \"%s\" to delete" ),
_( "library \"%s\" has no footprint \"%s\" to delete" ), m_lib_raw_path,
GetChars( m_lib_path.GetPath() ), aFootprintName );
GetChars( aFootprintName )
);
THROW_IO_ERROR( msg ); THROW_IO_ERROR( msg );
} }
@ -342,11 +339,7 @@ void FP_CACHE::Remove( const wxString& aFootprintName )
bool FP_CACHE::IsPath( const wxString& aPath ) const bool FP_CACHE::IsPath( const wxString& aPath ) const
{ {
// Converts path separators to native path separators return aPath == m_lib_raw_path;
wxFileName newPath;
newPath.AssignDir( aPath );
return m_lib_path == newPath;
} }
@ -373,10 +366,18 @@ long long FP_CACHE::GetTimestamp()
for( MODULE_CITER it = m_modules.begin(); it != m_modules.end(); ++it ) for( MODULE_CITER it = m_modules.begin(); it != m_modules.end(); ++it )
{ {
wxFileName fn = it->second->GetFileName(); const wxFileName& fn = it->second->GetFileName();
#ifndef __WINDOWS__ #ifdef __WINDOWS__
if( fn.FileExists() )
files_timestamp += fn.GetModificationTime().GetValue().GetValue();
#else
// By stat-ing the file ourselves we save wxWidgets from doing it three times:
// fn.Exists( wxFILE_EXISTS_SYMLINK ), fn.FileExists() & fn.GetModificationTime()
struct stat fn_stat;
wxLstat( fn.GetFullPath(), &fn_stat );
// Timestamp the source file, not the symlink // Timestamp the source file, not the symlink
if( fn.Exists( wxFILE_EXISTS_SYMLINK ) ) if( S_ISLNK( fn_stat.st_mode ) ) // wxFILE_EXISTS_SYMLINK
{ {
char buffer[ PATH_MAX + 1 ]; char buffer[ PATH_MAX + 1 ];
ssize_t pathLen = readlink( TO_UTF8( fn.GetFullPath() ), buffer, PATH_MAX ); ssize_t pathLen = readlink( TO_UTF8( fn.GetFullPath() ), buffer, PATH_MAX );
@ -384,13 +385,16 @@ long long FP_CACHE::GetTimestamp()
if( pathLen > 0 ) if( pathLen > 0 )
{ {
buffer[ pathLen ] = '\0'; buffer[ pathLen ] = '\0';
fn.Assign( fn.GetPath() + wxT( "/" ) + wxString::FromUTF8( buffer ) ); wxFileName srcFn;
fn.Normalize(); srcFn.Assign( fn.GetPath() + wxT( "/" ) + wxString::FromUTF8( buffer ) );
srcFn.Normalize();
wxLstat( srcFn.GetFullPath(), &fn_stat );
} }
} }
if( S_ISREG( fn_stat.st_mode ) ) // wxFileExists()
files_timestamp += fn_stat.st_mtime * 1000;
#endif #endif
if( fn.FileExists() )
files_timestamp += fn.GetModificationTime().GetValue().GetValue();
} }
} }
@ -2028,10 +2032,10 @@ void PCB_IO::FootprintEnumerate( wxArrayString& aFootprintNames,
} }
MODULE* PCB_IO::doLoadFootprint( const wxString& aLibraryPath, const MODULE* PCB_IO::getFootprint( const wxString& aLibraryPath,
const wxString& aFootprintName, const wxString& aFootprintName,
const PROPERTIES* aProperties, const PROPERTIES* aProperties,
bool checkModified ) bool checkModified )
{ {
LOCALE_IO toggle; // toggles on, then off, the C locale. LOCALE_IO toggle; // toggles on, then off, the C locale.
@ -2055,23 +2059,23 @@ MODULE* PCB_IO::doLoadFootprint( const wxString& aLibraryPath,
return NULL; return NULL;
} }
// copy constructor to clone the already loaded MODULE return it->second->GetModule();
return new MODULE( *it->second->GetModule() );
} }
MODULE* PCB_IO::LoadEnumeratedFootprint( const wxString& aLibraryPath, const MODULE* PCB_IO::GetEnumeratedFootprint( const wxString& aLibraryPath,
const wxString& aFootprintName, const wxString& aFootprintName,
const PROPERTIES* aProperties ) const PROPERTIES* aProperties )
{ {
return doLoadFootprint( aLibraryPath, aFootprintName, aProperties, false ); return getFootprint( aLibraryPath, aFootprintName, aProperties, false );
} }
MODULE* PCB_IO::FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName, MODULE* PCB_IO::FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName,
const PROPERTIES* aProperties ) const PROPERTIES* aProperties )
{ {
return doLoadFootprint( aLibraryPath, aFootprintName, aProperties, true ); const MODULE* footprint = getFootprint( aLibraryPath, aFootprintName, aProperties, true );
return footprint ? new MODULE( *footprint ) : nullptr;
} }
@ -2093,12 +2097,10 @@ void PCB_IO::FootprintSave( const wxString& aLibraryPath, const MODULE* aFootpri
if( !m_cache->Exists() ) if( !m_cache->Exists() )
{ {
const wxString msg = wxString::Format( _( "Library \"%s\" does not exist.\n" const wxString msg = wxString::Format( _( "Library \"%s\" does not exist.\n"
"Would you like to create it?"), "Would you like to create it?"),
GetChars( aLibraryPath ) ); GetChars( aLibraryPath ) );
const wxString title = wxString::Format( _( "Create new library \"%s\"?"),
GetChars( aLibraryPath ) );
if( wxMessageBox( msg, title, wxYES_NO | wxICON_QUESTION ) != wxYES ) if( wxMessageBox( msg, _( "Library Not Found"), wxYES_NO | wxICON_QUESTION ) != wxYES )
return; return;
// Save throws its own IO_ERROR on failure, so no need to recreate here // Save throws its own IO_ERROR on failure, so no need to recreate here
@ -2106,12 +2108,9 @@ void PCB_IO::FootprintSave( const wxString& aLibraryPath, const MODULE* aFootpri
} }
else else
{ {
wxString msg = wxString::Format( _( "Library \"%s\" is read only" ), wxString msg = wxString::Format( _( "Library \"%s\" is read only" ), aLibraryPath );
GetChars( aLibraryPath ) );
THROW_IO_ERROR( msg ); THROW_IO_ERROR( msg );
} }
} }
wxString footprintName = aFootprint->GetFPID().GetLibItemName(); wxString footprintName = aFootprint->GetFPID().GetLibItemName();
@ -2141,13 +2140,13 @@ void PCB_IO::FootprintSave( const wxString& aLibraryPath, const MODULE* aFootpri
if( !fn.IsOk() ) if( !fn.IsOk() )
{ {
THROW_IO_ERROR( wxString::Format( _( "Footprint file name \"%s\" is not valid." ), THROW_IO_ERROR( wxString::Format( _( "Footprint file name \"%s\" is not valid." ),
GetChars( fn.GetFullPath() ) ) ); fn.GetFullPath() ) );
} }
if( fn.FileExists() && !fn.IsFileWritable() ) if( fn.FileExists() && !fn.IsFileWritable() )
{ {
THROW_IO_ERROR( wxString::Format( _( "user does not have write permission to delete file \"%s\" " ), THROW_IO_ERROR( wxString::Format( _( "No write permissions to delete file \"%s\" " ),
GetChars( fn.GetFullPath() ) ) ); fn.GetFullPath() ) );
} }
MODULE_CITER it = mods.find( footprintName ); MODULE_CITER it = mods.find( footprintName );

View File

@ -119,13 +119,14 @@ public:
const PROPERTIES* aProperties = NULL ) override; const PROPERTIES* aProperties = NULL ) override;
void FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aLibraryPath, void FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aLibraryPath,
const PROPERTIES* aProperties = NULL ) override; const PROPERTIES* aProperties = NULL ) override;
MODULE* LoadEnumeratedFootprint( const wxString& aLibraryPath, const wxString& aFootprintName, const MODULE* GetEnumeratedFootprint( const wxString& aLibraryPath,
const PROPERTIES* aProperties = NULL ) override; const wxString& aFootprintName,
const PROPERTIES* aProperties = NULL ) override;
MODULE* FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName, MODULE* FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName,
const PROPERTIES* aProperties = NULL ) override; const PROPERTIES* aProperties = NULL ) override;
void FootprintSave( const wxString& aLibraryPath, const MODULE* aFootprint, void FootprintSave( const wxString& aLibraryPath, const MODULE* aFootprint,
const PROPERTIES* aProperties = NULL ) override; const PROPERTIES* aProperties = NULL ) override;
@ -193,8 +194,8 @@ protected:
void validateCache( const wxString& aLibraryPath, bool checkModified = true ); void validateCache( const wxString& aLibraryPath, bool checkModified = true );
MODULE* doLoadFootprint( const wxString& aLibraryPath, const wxString& aFootprintName, const MODULE* getFootprint( const wxString& aLibraryPath, const wxString& aFootprintName,
const PROPERTIES* aProperties, bool checkModified ); const PROPERTIES* aProperties, bool checkModified );
void init( const PROPERTIES* aProperties ); void init( const PROPERTIES* aProperties );

View File

@ -421,7 +421,7 @@ bool FOOTPRINT_EDIT_FRAME::SaveLibraryAs( const wxString& aLibraryPath )
for( unsigned i = 0; i < footprints.size(); ++i ) for( unsigned i = 0; i < footprints.size(); ++i )
{ {
const MODULE* footprint = cur->LoadEnumeratedFootprint( curLibPath, footprints[i] ); const MODULE* footprint = cur->GetEnumeratedFootprint( curLibPath, footprints[i] );
dst->FootprintSave( dstLibPath, footprint ); dst->FootprintSave( dstLibPath, footprint );
msg = wxString::Format( _( "Footprint \"%s\" saved" ), footprints[i] ); msg = wxString::Format( _( "Footprint \"%s\" saved" ), footprints[i] );

View File

@ -38,9 +38,8 @@
static void not_implemented( PLUGIN* aPlugin, const char* aCaller ) static void not_implemented( PLUGIN* aPlugin, const char* aCaller )
{ {
THROW_IO_ERROR( wxString::Format( FMT_UNIMPLEMENTED, THROW_IO_ERROR( wxString::Format( FMT_UNIMPLEMENTED,
aPlugin->PluginName().GetData(), aPlugin->PluginName().GetData(),
wxString::FromUTF8( aCaller ).GetData() ) wxString::FromUTF8( aCaller ).GetData() ) );
);
} }
@ -73,9 +72,9 @@ void PLUGIN::PrefetchLib( const wxString& aLibraryPath, const PROPERTIES* aPrope
} }
MODULE* PLUGIN::LoadEnumeratedFootprint( const wxString& aLibraryPath, const MODULE* PLUGIN::GetEnumeratedFootprint( const wxString& aLibraryPath,
const wxString& aFootprintName, const wxString& aFootprintName,
const PROPERTIES* aProperties ) const PROPERTIES* aProperties )
{ {
// default implementation // default implementation
return FootprintLoad( aLibraryPath, aFootprintName, aProperties ); return FootprintLoad( aLibraryPath, aFootprintName, aProperties );
@ -83,7 +82,7 @@ MODULE* PLUGIN::LoadEnumeratedFootprint( const wxString& aLibraryPath,
MODULE* PLUGIN::FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName, MODULE* PLUGIN::FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName,
const PROPERTIES* aProperties ) const PROPERTIES* aProperties )
{ {
// not pure virtual so that plugins only have to implement subset of the PLUGIN interface. // not pure virtual so that plugins only have to implement subset of the PLUGIN interface.
not_implemented( this, __FUNCTION__ ); not_implemented( this, __FUNCTION__ );
@ -91,14 +90,16 @@ MODULE* PLUGIN::FootprintLoad( const wxString& aLibraryPath, const wxString& aFo
} }
void PLUGIN::FootprintSave( const wxString& aLibraryPath, const MODULE* aFootprint, const PROPERTIES* aProperties ) void PLUGIN::FootprintSave( const wxString& aLibraryPath, const MODULE* aFootprint,
const PROPERTIES* aProperties )
{ {
// not pure virtual so that plugins only have to implement subset of the PLUGIN interface. // not pure virtual so that plugins only have to implement subset of the PLUGIN interface.
not_implemented( this, __FUNCTION__ ); not_implemented( this, __FUNCTION__ );
} }
void PLUGIN::FootprintDelete( const wxString& aLibraryPath, const wxString& aFootprintName, const PROPERTIES* aProperties ) void PLUGIN::FootprintDelete( const wxString& aLibraryPath, const wxString& aFootprintName,
const PROPERTIES* aProperties )
{ {
// not pure virtual so that plugins only have to implement subset of the PLUGIN interface. // not pure virtual so that plugins only have to implement subset of the PLUGIN interface.
not_implemented( this, __FUNCTION__ ); not_implemented( this, __FUNCTION__ );