Commit 6c4518b0 authored by Wayne Stambaugh's avatar Wayne Stambaugh

Pcbnew: Geda plugin fixes.

* Prevent cache from being reloaded on every footprint file read.
* Fix a bug forming wxFileName in GPCB_FP_CACHE::Load().
* Fix invalid file name time stamp debug assertion.
* Use FPID to set loaded footprint name.
* Remove file name <> from exception strings per UIPolicy.
parent 7ba078b6
...@@ -135,12 +135,19 @@ GPCB_FPL_CACHE_ITEM::GPCB_FPL_CACHE_ITEM( MODULE* aModule, const wxFileName& aFi ...@@ -135,12 +135,19 @@ GPCB_FPL_CACHE_ITEM::GPCB_FPL_CACHE_ITEM( MODULE* aModule, const wxFileName& aFi
m_module( aModule ) m_module( aModule )
{ {
m_file_name = aFileName; m_file_name = aFileName;
m_mod_time.Now();
if( m_file_name.FileExists() )
m_mod_time = m_file_name.GetModificationTime();
else
m_mod_time.Now();
} }
bool GPCB_FPL_CACHE_ITEM::IsModified() const bool GPCB_FPL_CACHE_ITEM::IsModified() const
{ {
if( !m_file_name.FileExists() )
return false;
return m_file_name.GetModificationTime() != m_mod_time; return m_file_name.GetModificationTime() != m_mod_time;
} }
...@@ -207,9 +214,35 @@ public: ...@@ -207,9 +214,35 @@ public:
void Remove( const wxString& aFootprintName ); void Remove( const wxString& aFootprintName );
wxDateTime GetLibModificationTime(); wxDateTime GetLibModificationTime() const;
/**
* Function IsModified
* check if the footprint cache has been modified relative to \a aLibPath
* and \a aFootprintName.
*
* @param aLibPath is a path to test the current cache library path against.
* @param aFootprintName is the footprint name in the cache to test. If the footprint
* name is empty, the all the footprint files in the library are
* checked to see if they have been modified.
* @return true if the cache has been modified.
*/
bool IsModified( const wxString& aLibPath,
const wxString& aFootprintName = wxEmptyString ) const;
bool IsModified(); /**
* Function IsPath
* checks if \a aPath is the same as the current cache path.
*
* This tests paths by converting \a aPath using the native separators. Internally
* #FP_CACHE stores the current path using native separators. This prevents path
* miscompares on Windows due to the fact that paths can be stored with / instead of \\
* in the footprint library table.
*
* @param aPath is the library path to test against.
* @return true if \a aPath is the same as the cache path.
*/
bool IsPath( const wxString& aPath ) const;
}; };
...@@ -220,8 +253,11 @@ GPCB_FPL_CACHE::GPCB_FPL_CACHE( GPCB_PLUGIN* aOwner, const wxString& aLibraryPat ...@@ -220,8 +253,11 @@ GPCB_FPL_CACHE::GPCB_FPL_CACHE( GPCB_PLUGIN* aOwner, const wxString& aLibraryPat
} }
wxDateTime GPCB_FPL_CACHE::GetLibModificationTime() wxDateTime GPCB_FPL_CACHE::GetLibModificationTime() const
{ {
if( !m_lib_path.DirExists() )
return wxDateTime::Now();
return m_lib_path.GetModificationTime(); return m_lib_path.GetModificationTime();
} }
...@@ -232,7 +268,7 @@ void GPCB_FPL_CACHE::Load() ...@@ -232,7 +268,7 @@ void GPCB_FPL_CACHE::Load()
if( !dir.IsOpened() ) if( !dir.IsOpened() )
{ {
THROW_IO_ERROR( wxString::Format( _( "footprint library path <%s> does not exist" ), THROW_IO_ERROR( wxString::Format( _( "footprint library path '%s' does not exist" ),
m_lib_path.GetPath().GetData() ) ); m_lib_path.GetPath().GetData() ) );
} }
...@@ -244,21 +280,16 @@ void GPCB_FPL_CACHE::Load() ...@@ -244,21 +280,16 @@ void GPCB_FPL_CACHE::Load()
do do
{ {
wxFileName fn = fpFileName; wxFileName fn( m_lib_path.GetPath(), fpFileName );
fn.SetPath( m_lib_path.GetPath() );
// reader now owns fp, will close on exception or return // reader now owns fp, will close on exception or return
FILE_LINE_READER reader( fn.GetFullPath() ); FILE_LINE_READER reader( fn.GetFullPath() );
std::string name = TO_UTF8( fn.GetName() ); std::string name = TO_UTF8( fn.GetName() );
MODULE* module = parseMODULE( &reader ); MODULE* footprint = parseMODULE( &reader );
// Set the module name to the file name sans path and extension. // The footprint name is the file name without the extension.
if( module->Reference().GetText().IsEmpty() ) footprint->SetFPID( fn.GetName() );
{ m_modules.insert( name, new GPCB_FPL_CACHE_ITEM( footprint, fn.GetName() ) );
module->Reference().SetText( fn.GetName() );
}
m_modules.insert( name, new GPCB_FPL_CACHE_ITEM( module, fn.GetName() ) );
} while( dir.GetNext( &fpFileName ) ); } while( dir.GetNext( &fpFileName ) );
...@@ -290,29 +321,56 @@ void GPCB_FPL_CACHE::Remove( const wxString& aFootprintName ) ...@@ -290,29 +321,56 @@ void GPCB_FPL_CACHE::Remove( const wxString& aFootprintName )
} }
bool GPCB_FPL_CACHE::IsModified() bool GPCB_FPL_CACHE::IsPath( const wxString& aPath ) const
{ {
if( !m_lib_path.DirExists() ) // Converts path separators to native path separators
wxFileName newPath;
newPath.AssignDir( aPath );
return m_lib_path == newPath;
}
bool GPCB_FPL_CACHE::IsModified( const wxString& aLibPath, const wxString& aFootprintName ) const
{
// The library is modified if the library path got deleted or changed.
if( !m_lib_path.DirExists() || !IsPath( aLibPath ) )
return true; return true;
for( MODULE_ITER it = m_modules.begin(); it != m_modules.end(); ++it ) // If no footprint was specified, check every file modification time against the time
// it was loaded.
if( aFootprintName.IsEmpty() )
{ {
wxFileName fn = it->second->GetFileName(); for( MODULE_CITER it = m_modules.begin(); it != m_modules.end(); ++it )
if( !fn.FileExists() )
{ {
wxLogTrace( traceFootprintLibrary, wxT( "Footprint cache file '%s' does not exist." ), wxFileName fn = m_lib_path;
fn.GetFullPath().GetData() );
return true; fn.SetName( it->second->GetFileName().GetName() );
fn.SetExt( KiCadFootprintFileExtension );
if( !fn.FileExists() )
{
wxLogTrace( traceFootprintLibrary,
wxT( "Footprint cache file '%s' does not exist." ),
fn.GetFullPath().GetData() );
return true;
}
if( it->second->IsModified() )
{
wxLogTrace( traceFootprintLibrary,
wxT( "Footprint cache file '%s' has been modified." ),
fn.GetFullPath().GetData() );
return true;
}
} }
}
else
{
MODULE_CITER it = m_modules.find( TO_UTF8( aFootprintName ) );
if( it->second->IsModified() ) if( it == m_modules.end() || it->second->IsModified() )
{
wxLogTrace( traceFootprintLibrary,
wxT( "Footprint cache file '%s' has been modified." ),
fn.GetFullPath().GetData() );
return true; return true;
}
} }
return false; return false;
...@@ -811,9 +869,9 @@ void GPCB_PLUGIN::init( const PROPERTIES* aProperties ) ...@@ -811,9 +869,9 @@ void GPCB_PLUGIN::init( const PROPERTIES* aProperties )
} }
void GPCB_PLUGIN::cacheLib( const wxString& aLibraryPath ) void GPCB_PLUGIN::cacheLib( const wxString& aLibraryPath, const wxString& aFootprintName )
{ {
if( !m_cache || m_cache->GetPath() != aLibraryPath || m_cache->IsModified() ) if( !m_cache || m_cache->IsModified( aLibraryPath, aFootprintName ) )
{ {
// a spectacular episode in memory management: // a spectacular episode in memory management:
delete m_cache; delete m_cache;
...@@ -823,8 +881,8 @@ void GPCB_PLUGIN::cacheLib( const wxString& aLibraryPath ) ...@@ -823,8 +881,8 @@ void GPCB_PLUGIN::cacheLib( const wxString& aLibraryPath )
} }
wxArrayString GPCB_PLUGIN::FootprintEnumerate( const wxString& aLibraryPath, wxArrayString GPCB_PLUGIN::FootprintEnumerate( const wxString& aLibraryPath,
const PROPERTIES* aProperties ) const PROPERTIES* aProperties )
{ {
LOCALE_IO toggle; // toggles on, then off, the C locale. LOCALE_IO toggle; // toggles on, then off, the C locale.
...@@ -852,7 +910,7 @@ MODULE* GPCB_PLUGIN::FootprintLoad( const wxString& aLibraryPath, const wxString ...@@ -852,7 +910,7 @@ MODULE* GPCB_PLUGIN::FootprintLoad( const wxString& aLibraryPath, const wxString
init( aProperties ); init( aProperties );
cacheLib( aLibraryPath ); cacheLib( aLibraryPath, aFootprintName );
const MODULE_MAP& mods = m_cache->GetModules(); const MODULE_MAP& mods = m_cache->GetModules();
...@@ -868,7 +926,8 @@ MODULE* GPCB_PLUGIN::FootprintLoad( const wxString& aLibraryPath, const wxString ...@@ -868,7 +926,8 @@ MODULE* GPCB_PLUGIN::FootprintLoad( const wxString& aLibraryPath, const wxString
} }
void GPCB_PLUGIN::FootprintDelete( const wxString& aLibraryPath, const wxString& aFootprintName, const PROPERTIES* aProperties ) void GPCB_PLUGIN::FootprintDelete( const wxString& aLibraryPath, const wxString& aFootprintName,
const PROPERTIES* aProperties )
{ {
LOCALE_IO toggle; // toggles on, then off, the C locale. LOCALE_IO toggle; // toggles on, then off, the C locale.
...@@ -878,7 +937,7 @@ void GPCB_PLUGIN::FootprintDelete( const wxString& aLibraryPath, const wxString& ...@@ -878,7 +937,7 @@ void GPCB_PLUGIN::FootprintDelete( const wxString& aLibraryPath, const wxString&
if( !m_cache->IsWritable() ) if( !m_cache->IsWritable() )
{ {
THROW_IO_ERROR( wxString::Format( _( "Library <%s> is read only" ), THROW_IO_ERROR( wxString::Format( _( "Library '%s' is read only" ),
aLibraryPath.GetData() ) ); aLibraryPath.GetData() ) );
} }
...@@ -897,7 +956,7 @@ bool GPCB_PLUGIN::FootprintLibDelete( const wxString& aLibraryPath, const PROPER ...@@ -897,7 +956,7 @@ bool GPCB_PLUGIN::FootprintLibDelete( const wxString& aLibraryPath, const PROPER
if( !fn.IsDirWritable() ) if( !fn.IsDirWritable() )
{ {
THROW_IO_ERROR( wxString::Format( _( "user does not have permission to delete directory <%s>" ), THROW_IO_ERROR( wxString::Format( _( "user does not have permission to delete directory '%s'" ),
aLibraryPath.GetData() ) ); aLibraryPath.GetData() ) );
} }
...@@ -905,7 +964,7 @@ bool GPCB_PLUGIN::FootprintLibDelete( const wxString& aLibraryPath, const PROPER ...@@ -905,7 +964,7 @@ bool GPCB_PLUGIN::FootprintLibDelete( const wxString& aLibraryPath, const PROPER
if( dir.HasSubDirs() ) if( dir.HasSubDirs() )
{ {
THROW_IO_ERROR( wxString::Format( _( "library directory <%s> has unexpected sub-directories" ), THROW_IO_ERROR( wxString::Format( _( "library directory '%s' has unexpected sub-directories" ),
aLibraryPath.GetData() ) ); aLibraryPath.GetData() ) );
} }
...@@ -924,7 +983,7 @@ bool GPCB_PLUGIN::FootprintLibDelete( const wxString& aLibraryPath, const PROPER ...@@ -924,7 +983,7 @@ bool GPCB_PLUGIN::FootprintLibDelete( const wxString& aLibraryPath, const PROPER
if( tmp.GetExt() != KiCadFootprintFileExtension ) if( tmp.GetExt() != KiCadFootprintFileExtension )
{ {
THROW_IO_ERROR( wxString::Format( _( "unexpected file <%s> was found in library path '%s'" ), THROW_IO_ERROR( wxString::Format( _( "unexpected file '%s' was found in library path '%s'" ),
files[i].GetData(), aLibraryPath.GetData() ) ); files[i].GetData(), aLibraryPath.GetData() ) );
} }
} }
...@@ -942,7 +1001,7 @@ bool GPCB_PLUGIN::FootprintLibDelete( const wxString& aLibraryPath, const PROPER ...@@ -942,7 +1001,7 @@ bool GPCB_PLUGIN::FootprintLibDelete( const wxString& aLibraryPath, const PROPER
// we don't want that. we want bare metal portability with no UI here. // we don't want that. we want bare metal portability with no UI here.
if( !wxRmdir( aLibraryPath ) ) if( !wxRmdir( aLibraryPath ) )
{ {
THROW_IO_ERROR( wxString::Format( _( "footprint library <%s> cannot be deleted" ), THROW_IO_ERROR( wxString::Format( _( "footprint library '%s' cannot be deleted" ),
aLibraryPath.GetData() ) ); aLibraryPath.GetData() ) );
} }
......
...@@ -62,12 +62,14 @@ public: ...@@ -62,12 +62,14 @@ public:
return wxT( "fp" ); return wxT( "fp" );
} }
wxArrayString FootprintEnumerate( const wxString& aLibraryPath, const PROPERTIES* aProperties = NULL); wxArrayString FootprintEnumerate( const wxString& aLibraryPath,
const PROPERTIES* aProperties = NULL);
MODULE* FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName, MODULE* FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName,
const PROPERTIES* aProperties = NULL ); const PROPERTIES* aProperties = NULL );
void FootprintDelete( const wxString& aLibraryPath, const wxString& aFootprintName, const PROPERTIES* aProperties = NULL ); void FootprintDelete( const wxString& aLibraryPath, const wxString& aFootprintName,
const PROPERTIES* aProperties = NULL );
bool FootprintLibDelete( const wxString& aLibraryPath, const PROPERTIES* aProperties = NULL ); bool FootprintLibDelete( const wxString& aLibraryPath, const PROPERTIES* aProperties = NULL );
...@@ -83,17 +85,16 @@ public: ...@@ -83,17 +85,16 @@ public:
protected: protected:
wxString m_error; ///< for throwing exceptions wxString m_error; ///< for throwing exceptions
const PROPERTIES* m_props; ///< passed via Save() or Load(), no ownership, may be NULL. const PROPERTIES* m_props; ///< passed via Save() or Load(), no ownership, may be NULL.
GPCB_FPL_CACHE* m_cache; ///< Footprint library cache. GPCB_FPL_CACHE* m_cache; ///< Footprint library cache.
int m_ctl; int m_ctl;
LINE_READER* m_reader; ///< no ownership here.
LINE_READER* m_reader; ///< no ownership here. wxString m_filename; ///< for saves only, name is in m_reader for loads
wxString m_filename; ///< for saves only, name is in m_reader for loads
private: private:
/// we only cache one footprint library for now, this determines which one. /// we only cache one footprint library for now, this determines which one.
void cacheLib( const wxString& aLibraryPath ); void cacheLib( const wxString& aLibraryPath, const wxString& aFootprintName = wxEmptyString );
void init( const PROPERTIES* aProperties ); void init( const PROPERTIES* aProperties );
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment