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>
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
// 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
// e.g. LibName:FootprintName
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();
@ -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( each_filter->GetPattern().Contains( ":" ) )
{
name = aItem.GetNickname().Lower() + ":";
name = aItem.GetLibNickname().Lower() + ":";
}
name += aItem.GetFootprintName().Lower();

View File

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

View File

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

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;
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 )
{
IsRoot = aItem->IsRoot();
LibId = aItem->GetLibId();
// Update is called when the names match, so just update the other fields.
LibId.SetLibNickname( aItem->GetLibNickname() );
Name = aItem->GetName();
Desc = aItem->GetDescription();
MatchName = aItem->GetName().Lower();
SearchText = aItem->GetSearchText();
SearchTextNormalized = false;
IsRoot = aItem->IsRoot();
Children.clear();
int unitCount = aItem->GetUnitCount();
for( int u = 1; u <= unitCount; ++u )
for( int u = 1; u <= aItem->GetUnitCount(); ++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 );
Children.push_back( std::unique_ptr<LIB_TREE_NODE>( alias ) );
return *alias;
LIB_TREE_NODE_LIB_ID* item = new LIB_TREE_NODE_LIB_ID( this, aItem );
Children.push_back( std::unique_ptr<LIB_TREE_NODE>( item ) );
return *item;
}

View File

@ -249,9 +249,9 @@ public:
/**
* 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;
};

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,
std::vector<LIB_TREE_ITEM*> const& aCompList )
std::vector<LIB_TREE_ITEM*> const& aItemList )
{
auto& lib_node = m_tree.AddLib( aNodeName, aDesc );
for( auto a: aCompList )
lib_node.AddComp( a );
for( auto item: aItemList )
lib_node.AddItem( item );
lib_node.AssignIntrinsicRanks();
m_tree.AssignIntrinsicRanks();

View File

@ -148,10 +148,10 @@ public:
*
* @param aNodeName the parent node the components will appear under
* @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,
std::vector<LIB_TREE_ITEM*> const& aCompList );
std::vector<LIB_TREE_ITEM*> const& aItemList );
/**
* 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();
if( ( str1 == aString1.end() ) || ( str2 == aString2.end() ) )
return 0;
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;
nb2 = 0;
while( isdigit( *str1 ) )
while( isdigit( c1 ) )
{
nb1 = nb1 * 10 + (int) *str1 - '0';
++str1;
nb1 = nb1 * 10 + (int) c1 - '0';
c1 = *(++str1);
}
while( isdigit( *str2 ) )
while( isdigit( c2 ) )
{
nb2 = nb2 * 10 + (int) *str2 - '0';
++str2;
nb2 = nb2 * 10 + (int) c2 - '0';
c2 = *(++str2);
}
if( nb1 < nb2 )
return -1;
if( nb1 > nb2 )
else if( nb1 > nb2 )
return 1;
}
if( aIgnoreCase )
{
if( toupper( *str1 ) < toupper( *str2 ) )
if( toupper( c1 ) < toupper(c2 ) )
return -1;
if( toupper( *str1 ) > toupper( *str2 ) )
else if( toupper( c1 ) > toupper( c2 ) )
return 1;
if( ( *str1 == 0 ) && ( *str2 == 0 ) )
else if( ( c1 == 0 ) && ( c2 == 0 ) )
return 0;
}
else
{
if( *str1 < *str2 )
if( c1 < c2 )
return -1;
if( *str1 > *str2 )
else if( c1 > c2 )
return 1;
if( ( str1 == aString1.end() ) && ( str2 == aString2.end() ) )
else if( ( c1 == 0 ) && ( c2 == 0 ) )
return 0;
}

View File

@ -242,7 +242,7 @@ bool FOOTPRINT_SELECT_WIDGET::UpdateList()
{
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 ) );
++n_items;

View File

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

View File

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

View File

@ -109,14 +109,11 @@ public:
return shared;
}
const wxString GetLibraryName();
bool IsRoot() const override;
PART_LIB* GetLib();
LIB_ID GetLibId() const override;
PART_LIB* GetLib();
wxString GetLibNickname() const override;
const wxString& GetName() const override { return name; }
void SetName( const wxString& aName );
@ -144,8 +141,19 @@ public:
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;
/**
* For symbols with units, return an identifier for unit x.
*/
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 ) );
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() )
aList.push_back( MSG_PANEL_ITEM( _( "Library" ), m_lib_id.GetLibNickname(),
BROWN ) );

View File

@ -130,7 +130,7 @@ void SYMBOL_TREE_SYNCHRONIZING_ADAPTER::updateLibrary( LIB_TREE_NODE_LIB& aLibNo
{
// add a new library
for( auto alias : m_libMgr->GetAliases( aLibNode.Name ) )
aLibNode.AddComp( alias );
aLibNode.AddItem( alias );
}
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
for( auto alias : aliases )
aLibNode.AddComp( alias );
aLibNode.AddItem( alias );
}
aLibNode.AssignIntrinsicRanks();

View File

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

View File

@ -187,12 +187,14 @@ public:
MODULE* FootprintLoad( const wxString& aNickname, const wxString& aFootprintName );
/**
* Function LoadEnumeratedFootprint
* Function GetEnumeratedFootprint
*
* 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
* is the set of return values from FootprintSave() below.

View File

@ -39,19 +39,20 @@
class LIB_TREE_ITEM
{
public:
/**
* For items having aliases, IsRoot() indicates the principal item.
*/
virtual bool IsRoot() const { return true; }
virtual LIB_ID GetLibId() const = 0;
virtual const wxString& GetName() const = 0;
virtual wxString GetLibNickname() const = 0;
virtual wxString GetDescription() { 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.
*/

View File

@ -463,18 +463,6 @@ public:
*/
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.
*/
@ -506,6 +494,19 @@ protected:
/// List of footprint editor configuration parameters.
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
* updates window title according to getLibNickName().

View File

@ -48,8 +48,9 @@ void FOOTPRINT_INFO_IMPL::load()
wxASSERT( fptable );
std::unique_ptr<MODULE> footprint( fptable->LoadEnumeratedFootprint( m_nickname, m_fpname ) );
if( footprint.get() == NULL ) // Should happen only with malformed/broken libraries
const MODULE* footprint = fptable->GetEnumeratedFootprint( m_nickname, m_fpname );
if( footprint == NULL ) // Should happen only with malformed/broken libraries
{
m_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_keywords = footprint->GetKeywords();
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,
PROGRESS_REPORTER* aProgressReporter )
{
if( m_list_timestamp == aTable->GenerateTimestamp( aNickname ) )
long long int generatedTimestamp = aTable->GenerateTimestamp( aNickname );
if( generatedTimestamp == m_list_timestamp )
return true;
m_progress_reporter = aProgressReporter;
@ -163,6 +165,11 @@ bool FOOTPRINT_LIST_IMPL::ReadFootprintFiles( FP_LIB_TABLE* aTable, const wxStri
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();
}
@ -296,7 +303,7 @@ bool FOOTPRINT_LIST_IMPL::JoinWorkers()
if( m_progress_reporter && !m_progress_reporter->KeepRefreshing() )
m_cancelled = true;
wxMilliSleep( 20 );
wxMilliSleep( 30 );
}
for( auto& thr : threads )
@ -307,14 +314,11 @@ bool FOOTPRINT_LIST_IMPL::JoinWorkers()
while( queue_parsed.pop( fpi ) )
m_list.push_back( std::move( fpi ) );
std::sort( m_list.begin(), m_list.end(),
[]( std::unique_ptr<FOOTPRINT_INFO> const& lhs,
std::unique_ptr<FOOTPRINT_INFO> const& rhs ) -> bool { 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 );
std::sort( m_list.begin(), m_list.end(), []( std::unique_ptr<FOOTPRINT_INFO> const& lhs,
std::unique_ptr<FOOTPRINT_INFO> const& rhs ) -> bool
{
return *lhs < *rhs;
} );
return m_errors.empty();
}

View File

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

View File

@ -61,7 +61,7 @@ std::vector<LIB_TREE_ITEM*> FP_TREE_MODEL_ADAPTER::getFootprints( const wxString
for( auto& footprint : GFootprintList.GetList() )
{
if( footprint->GetNickname() != aLibName )
if( footprint->GetLibNickname() != aLibName )
{
if( found )
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
for( auto nodeIt = aLibNode.Children.begin(); nodeIt != aLibNode.Children.end(); )
{
auto footprintIt = std::find_if( footprints.begin(), footprints.end(),
[&] ( const LIB_TREE_ITEM* a )
{
return a->GetName() == (*nodeIt)->Name;
} );
// Since the list is sorted we can use a binary search to speed up searches within
// libraries with lots of footprints.
FOOTPRINT_INFO_IMPL dummy( (*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,
// update only the node data
// footprint exists both in the lib tree and the footprint info list; just
// update the node data
static_cast<LIB_TREE_NODE_LIB_ID*>( nodeIt->get() )->Update( *footprintIt );
footprints.erase( footprintIt );
++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
for( auto footprint : footprints )
aLibNode.AddComp( footprint );
aLibNode.AddItem( footprint );
aLibNode.AssignIntrinsicRanks();
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 wxString& aFootprintName,
const PROPERTIES* aProperties,
bool checkModified )
const MODULE* GPCB_PLUGIN::getFootprint( const wxString& aLibraryPath,
const wxString& aFootprintName,
const PROPERTIES* aProperties,
bool checkModified )
{
LOCALE_IO toggle; // toggles on, then off, the C locale.
@ -974,23 +974,23 @@ MODULE* GPCB_PLUGIN::doLoadFootprint( const wxString& aLibraryPath,
return NULL;
}
// copy constructor to clone the already loaded MODULE
return new MODULE( *it->second->GetModule() );
return it->second->GetModule();
}
MODULE* GPCB_PLUGIN::LoadEnumeratedFootprint( const wxString& aLibraryPath,
const wxString& aFootprintName,
const PROPERTIES* aProperties )
const MODULE* GPCB_PLUGIN::GetEnumeratedFootprint( const wxString& aLibraryPath,
const wxString& aFootprintName,
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,
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,
const PROPERTIES* aProperties = NULL) override;
MODULE* LoadEnumeratedFootprint( const wxString& aLibraryPath, const wxString& aFootprintName,
const PROPERTIES* aProperties = NULL ) override;
const MODULE* GetEnumeratedFootprint( const wxString& aLibraryPath,
const wxString& aFootprintName,
const PROPERTIES* aProperties = NULL ) override;
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,
const PROPERTIES* aProperties = NULL ) override;
const PROPERTIES* aProperties = NULL ) override;
bool FootprintLibDelete( const wxString& aLibraryPath,
const PROPERTIES* aProperties = NULL ) override;
@ -101,8 +102,8 @@ protected:
private:
void validateCache( const wxString& aLibraryPath, bool checkModified = true );
MODULE* doLoadFootprint( const wxString& aLibraryPath, const wxString& aFootprintName,
const PROPERTIES* aProperties, bool checkModified );
const MODULE* getFootprint( const wxString& aLibraryPath, const wxString& aFootprintName,
const PROPERTIES* aProperties, bool checkModified );
void init( const PROPERTIES* aProperties );
};

View File

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

View File

@ -91,10 +91,10 @@ class FP_CACHE_ITEM
public:
FP_CACHE_ITEM( MODULE* aModule, const wxFileName& aFileName );
wxString GetName() const { return m_file_name.GetDirs().Last(); }
wxFileName GetFileName() const { return m_file_name; }
const wxString& GetName() const { return m_file_name.GetDirs().Last(); }
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
{
PCB_IO* m_owner; /// Plugin object that owns the cache.
wxFileName m_lib_path; /// The path of the library.
MODULE_MAP m_modules; /// Map of footprint file name per MODULE*.
PCB_IO* m_owner; // Plugin object that owns the cache.
wxFileName m_lib_path; // The path of the library.
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
// m_cache_timestamp against all the files.
@ -124,7 +125,7 @@ class FP_CACHE
public:
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 Exists() const { return m_lib_path.IsOk() && m_lib_path.DirExists(); }
MODULE_MAP& GetModules() { return m_modules; }
@ -178,6 +179,7 @@ public:
FP_CACHE::FP_CACHE( PCB_IO* aOwner, const wxString& aLibraryPath )
{
m_owner = aOwner;
m_lib_raw_path = aLibraryPath;
m_lib_path.SetPath( aLibraryPath );
m_cache_timestamp = 0;
m_cache_dirty = true;
@ -191,13 +193,13 @@ void FP_CACHE::Save( MODULE* aModule )
if( !m_lib_path.DirExists() && !m_lib_path.Mkdir() )
{
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() )
{
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 )
@ -255,18 +257,15 @@ void FP_CACHE::Save( MODULE* aModule )
void FP_CACHE::Load()
{
wxDir dir( m_lib_path.GetPath() );
wxDir dir( m_lib_raw_path );
if( !dir.IsOpened() )
{
m_cache_timestamp = 0;
m_cache_dirty = false;
wxString msg = wxString::Format(
_( "Footprint library path \"%s\" does not exist" ),
GetChars( m_lib_path.GetPath() )
);
wxString msg = wxString::Format( _( "Footprint library path \"%s\" does not exist" ),
m_lib_raw_path );
THROW_IO_ERROR( msg );
}
else
@ -285,7 +284,7 @@ void FP_CACHE::Load()
do
{
// 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.
try
@ -325,11 +324,9 @@ void FP_CACHE::Remove( const wxString& aFootprintName )
if( it == m_modules.end() )
{
wxString msg = wxString::Format(
_( "library \"%s\" has no footprint \"%s\" to delete" ),
GetChars( m_lib_path.GetPath() ),
GetChars( aFootprintName )
);
wxString msg = wxString::Format( _( "library \"%s\" has no footprint \"%s\" to delete" ),
m_lib_raw_path,
aFootprintName );
THROW_IO_ERROR( msg );
}
@ -342,11 +339,7 @@ void FP_CACHE::Remove( const wxString& aFootprintName )
bool FP_CACHE::IsPath( const wxString& aPath ) const
{
// Converts path separators to native path separators
wxFileName newPath;
newPath.AssignDir( aPath );
return m_lib_path == newPath;
return aPath == m_lib_raw_path;
}
@ -373,10 +366,18 @@ long long FP_CACHE::GetTimestamp()
for( MODULE_CITER it = m_modules.begin(); it != m_modules.end(); ++it )
{
wxFileName fn = it->second->GetFileName();
#ifndef __WINDOWS__
const wxFileName& fn = it->second->GetFileName();
#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
if( fn.Exists( wxFILE_EXISTS_SYMLINK ) )
if( S_ISLNK( fn_stat.st_mode ) ) // wxFILE_EXISTS_SYMLINK
{
char buffer[ PATH_MAX + 1 ];
ssize_t pathLen = readlink( TO_UTF8( fn.GetFullPath() ), buffer, PATH_MAX );
@ -384,13 +385,16 @@ long long FP_CACHE::GetTimestamp()
if( pathLen > 0 )
{
buffer[ pathLen ] = '\0';
fn.Assign( fn.GetPath() + wxT( "/" ) + wxString::FromUTF8( buffer ) );
fn.Normalize();
wxFileName srcFn;
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
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 wxString& aFootprintName,
const PROPERTIES* aProperties,
bool checkModified )
const MODULE* PCB_IO::getFootprint( const wxString& aLibraryPath,
const wxString& aFootprintName,
const PROPERTIES* aProperties,
bool checkModified )
{
LOCALE_IO toggle; // toggles on, then off, the C locale.
@ -2055,23 +2059,23 @@ MODULE* PCB_IO::doLoadFootprint( const wxString& aLibraryPath,
return NULL;
}
// copy constructor to clone the already loaded MODULE
return new MODULE( *it->second->GetModule() );
return it->second->GetModule();
}
MODULE* PCB_IO::LoadEnumeratedFootprint( const wxString& aLibraryPath,
const wxString& aFootprintName,
const PROPERTIES* aProperties )
const MODULE* PCB_IO::GetEnumeratedFootprint( const wxString& aLibraryPath,
const wxString& aFootprintName,
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,
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() )
{
const wxString msg = wxString::Format( _( "Library \"%s\" does not exist.\n"
"Would you like to create it?"),
GetChars( aLibraryPath ) );
const wxString title = wxString::Format( _( "Create new library \"%s\"?"),
GetChars( aLibraryPath ) );
"Would you like to create it?"),
GetChars( aLibraryPath ) );
if( wxMessageBox( msg, title, wxYES_NO | wxICON_QUESTION ) != wxYES )
if( wxMessageBox( msg, _( "Library Not Found"), wxYES_NO | wxICON_QUESTION ) != wxYES )
return;
// 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
{
wxString msg = wxString::Format( _( "Library \"%s\" is read only" ),
GetChars( aLibraryPath ) );
wxString msg = wxString::Format( _( "Library \"%s\" is read only" ), aLibraryPath );
THROW_IO_ERROR( msg );
}
}
wxString footprintName = aFootprint->GetFPID().GetLibItemName();
@ -2141,13 +2140,13 @@ void PCB_IO::FootprintSave( const wxString& aLibraryPath, const MODULE* aFootpri
if( !fn.IsOk() )
{
THROW_IO_ERROR( wxString::Format( _( "Footprint file name \"%s\" is not valid." ),
GetChars( fn.GetFullPath() ) ) );
fn.GetFullPath() ) );
}
if( fn.FileExists() && !fn.IsFileWritable() )
{
THROW_IO_ERROR( wxString::Format( _( "user does not have write permission to delete file \"%s\" " ),
GetChars( fn.GetFullPath() ) ) );
THROW_IO_ERROR( wxString::Format( _( "No write permissions to delete file \"%s\" " ),
fn.GetFullPath() ) );
}
MODULE_CITER it = mods.find( footprintName );

View File

@ -119,13 +119,14 @@ public:
const PROPERTIES* aProperties = NULL ) override;
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 PROPERTIES* aProperties = NULL ) override;
const MODULE* GetEnumeratedFootprint( const wxString& aLibraryPath,
const wxString& aFootprintName,
const PROPERTIES* aProperties = NULL ) override;
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,
const PROPERTIES* aProperties = NULL ) override;
@ -193,8 +194,8 @@ protected:
void validateCache( const wxString& aLibraryPath, bool checkModified = true );
MODULE* doLoadFootprint( const wxString& aLibraryPath, const wxString& aFootprintName,
const PROPERTIES* aProperties, bool checkModified );
const MODULE* getFootprint( const wxString& aLibraryPath, const wxString& aFootprintName,
const PROPERTIES* aProperties, bool checkModified );
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 )
{
const MODULE* footprint = cur->LoadEnumeratedFootprint( curLibPath, footprints[i] );
const MODULE* footprint = cur->GetEnumeratedFootprint( curLibPath, footprints[i] );
dst->FootprintSave( dstLibPath, footprint );
msg = wxString::Format( _( "Footprint \"%s\" saved" ), footprints[i] );

View File

@ -38,9 +38,8 @@
static void not_implemented( PLUGIN* aPlugin, const char* aCaller )
{
THROW_IO_ERROR( wxString::Format( FMT_UNIMPLEMENTED,
aPlugin->PluginName().GetData(),
wxString::FromUTF8( aCaller ).GetData() )
);
aPlugin->PluginName().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 wxString& aFootprintName,
const PROPERTIES* aProperties )
const MODULE* PLUGIN::GetEnumeratedFootprint( const wxString& aLibraryPath,
const wxString& aFootprintName,
const PROPERTIES* aProperties )
{
// default implementation
return FootprintLoad( aLibraryPath, aFootprintName, aProperties );
@ -83,7 +82,7 @@ MODULE* PLUGIN::LoadEnumeratedFootprint( const wxString& aLibraryPath,
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_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_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_implemented( this, __FUNCTION__ );