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:
parent
0a35c5c97e
commit
f8a5e2c1c8
|
@ -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 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
||||||
|
|
|
@ -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 );
|
||||||
}
|
}
|
||||||
|
|
|
@ -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" ) );
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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 ) );
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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().
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 );
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
||||||
|
|
|
@ -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] );
|
||||||
|
|
|
@ -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__ );
|
||||||
|
|
Loading…
Reference in New Issue