Commit 45bd4431 authored by Dick Hollenbeck's avatar Dick Hollenbeck

1) Implement EAGLE_PLUGIN::FootprintLoad(), FootprintEnumerate(), and IsFootprintWritable().

2) Add PCAD_PLUGIN to _pcbnew.so for scripting, fixing a linking bug.
parent dd3b684c
......@@ -322,12 +322,14 @@ if (KICAD_SCRIPTING_MODULES)
3d-viewer
pcbcommon
common
bitmaps
pcad2kicadpcb
polygon
bitmaps
${wxWidgets_LIBRARIES}
${OPENGL_LIBRARIES}
${GDI_PLUS_LIBRARIES}
${PYTHON_LIBRARIES})
${PYTHON_LIBRARIES}
)
endif (KICAD_SCRIPTING_MODULES)
......@@ -414,9 +416,9 @@ target_link_libraries(pcbnew
3d-viewer
pcbcommon
common
bitmaps
polygon
pcad2kicadpcb
polygon
bitmaps
${wxWidgets_LIBRARIES}
${OPENGL_LIBRARIES}
${GDI_PLUS_LIBRARIES}
......
......@@ -67,6 +67,7 @@ Load() TODO's
#include <macros.h>
#include <fctsys.h>
#include <trigo.h>
#include <wx/filename.h>
#include <class_board.h>
#include <class_module.h>
......@@ -1053,6 +1054,7 @@ static inline unsigned long timeStamp( CPTREE& aTree )
EAGLE_PLUGIN::EAGLE_PLUGIN() :
m_rules( new ERULES() ),
m_xpath( new XPATH() )
// m_mod_time( wxDateTime::Now() )
{
init( NULL );
}
......@@ -1158,7 +1160,8 @@ void EAGLE_PLUGIN::init( PROPERTIES* aProperties )
m_xpath->clear();
m_pads_to_nets.clear();
m_templates.clear();
// m_templates.clear(); this is the FOOTPRINT cache too
m_board = NULL;
m_props = aProperties;
......@@ -1494,65 +1497,69 @@ void EAGLE_PLUGIN::loadPlain( CPTREE& aGraphics )
}
void EAGLE_PLUGIN::loadLibraries( CPTREE& aLibs )
void EAGLE_PLUGIN::loadLibrary( CPTREE& aLib, const std::string* aLibName )
{
m_xpath->push( "libraries.library", "name" );
m_xpath->push( "packages" );
for( CITER library = aLibs.begin(); library != aLibs.end(); ++library )
{
const std::string& lib_name = library->second.get<std::string>( "<xmlattr>.name" );
// library will have <xmlattr> node, skip that and get the single packages node
CPTREE& packages = aLib.get_child( "packages" );
m_xpath->Value( lib_name.c_str() );
// Create a MODULE for all the eagle packages, for use later via a copy constructor
// to instantiate needed MODULES in our BOARD. Save the MODULE templates in
// a MODULE_MAP using a single lookup key consisting of libname+pkgname.
for( CITER package = packages.begin(); package != packages.end(); ++package )
{
m_xpath->push( "package", "name" );
const std::string& pack_name = package->second.get<std::string>( "<xmlattr>.name" );
#if defined(DEBUG)
if( pack_name == "TO220H" )
{
m_xpath->push( "packages" );
int breakhere = 1;
(void) breakhere;
}
#endif
m_xpath->Value( pack_name.c_str() );
// library will have <xmlattr> node, skip that and get the single packages node
CPTREE& packages = library->second.get_child( "packages" );
std::string key = aLibName ? makeKey( *aLibName, pack_name ) : pack_name;
// Create a MODULE for all the eagle packages, for use later via a copy constructor
// to instantiate needed MODULES in our BOARD. Save the MODULE templates in
// a MODULE_MAP using a single lookup key consisting of libname+pkgname.
MODULE* m = makeModule( package->second, pack_name );
for( CITER package = packages.begin(); package != packages.end(); ++package )
{
m_xpath->push( "package", "name" );
const std::string& pack_name = package->second.get<std::string>( "<xmlattr>.name" );
// add the templating MODULE to the MODULE template factory "m_templates"
std::pair<MODULE_ITER, bool> r = m_templates.insert( key, m );
#if defined(DEBUG)
if( pack_name == "TO220H" )
{
int breakhere = 1;
(void) breakhere;
}
#endif
m_xpath->Value( pack_name.c_str() );
if( !r.second )
{
wxString lib = aLibName ? FROM_UTF8( aLibName->c_str() ) : m_lib_path;
wxString pkg = FROM_UTF8( pack_name.c_str() );
wxString emsg = wxString::Format(
_( "<package> name:'%s' duplicated in eagle <library>:'%s'" ),
GetChars( pkg ),
GetChars( lib )
);
THROW_IO_ERROR( emsg );
}
std::string key = makeKey( lib_name, pack_name );
m_xpath->pop();
}
MODULE* m = makeModule( package->second, pack_name );
m_xpath->pop(); // "packages"
}
// add the templating MODULE to the MODULE template factory "m_templates"
std::pair<MODULE_ITER, bool> r = m_templates.insert( key, m );
if( !r.second )
{
wxString lib = FROM_UTF8( lib_name.c_str() );
wxString pkg = FROM_UTF8( pack_name.c_str() );
wxString emsg = wxString::Format(
_( "<package> name:'%s' duplicated in eagle <library>:'%s'" ),
GetChars( pkg ),
GetChars( lib )
);
THROW_IO_ERROR( emsg );
}
void EAGLE_PLUGIN::loadLibraries( CPTREE& aLibs )
{
m_xpath->push( "libraries.library", "name" );
m_xpath->pop();
}
for( CITER library = aLibs.begin(); library != aLibs.end(); ++library )
{
const std::string& lib_name = library->second.get<std::string>( "<xmlattr>.name" );
m_xpath->pop(); // "packages"
}
m_xpath->Value( lib_name.c_str() );
loadLibrary( library->second, &lib_name );
}
m_xpath->pop();
......@@ -1573,7 +1580,7 @@ void EAGLE_PLUGIN::loadElements( CPTREE& aElements )
EELEMENT e( it->second );
// use "NULL-ness" as an indiation of presence of the attribute:
// use "NULL-ness" as an indication of presence of the attribute:
EATTR* nameAttr = 0;
EATTR* valueAttr = 0;
......@@ -2591,56 +2598,119 @@ void EAGLE_PLUGIN::centerBoard()
}
/*
void EAGLE_PLUGIN::Save( const wxString& aFileName, BOARD* aBoard, PROPERTIES* aProperties )
wxDateTime EAGLE_PLUGIN::getModificationTime( const wxString& aPath )
{
// Eagle lovers apply here.
wxFileName fn( aPath );
/*
// update the writable flag while we have a wxFileName, in a network this
// is possibly quite dynamic anyway.
m_writable = fn.IsFileWritable();
*/
return fn.GetModificationTime();
}
int EAGLE_PLUGIN::biuSprintf( char* buf, BIU aValue ) const
void EAGLE_PLUGIN::cacheLib( const wxString& aLibPath )
{
double engUnits = mm_per_biu * aValue;
int len;
if( engUnits != 0.0 && fabs( engUnits ) <= 0.0001 )
try
{
// printf( "f: " );
len = sprintf( buf, "%.10f", engUnits );
wxDateTime modtime;
if( aLibPath != m_lib_path ||
m_mod_time != ( modtime = getModificationTime( aLibPath ) ) )
{
//D(printf("Loading '%s'\n", TO_UTF8( aLibPath ) );)
while( --len > 0 && buf[len] == '0' )
buf[len] = '\0';
PTREE doc;
LOCALE_IO toggle; // toggles on, then off, the C locale.
++len;
m_templates.clear();
// Set this before completion of loading, since we rely on it for
// text of an exception. Delay setting m_mod_time until after successful load
// however.
m_lib_path = aLibPath;
// 8 bit "filename" should be encoded according to disk filename encoding,
// (maybe this is current locale, maybe not, its a filesystem issue),
// and is not necessarily utf8.
std::string filename = (const char*) aLibPath.char_str( wxConvFile );
read_xml( filename, doc, xml_parser::trim_whitespace | xml_parser::no_comments );
CPTREE& library = doc.get_child( "eagle.drawing.library" );
m_xpath->push( "eagle.drawing.library" );
loadLibrary( library, NULL );
m_xpath->pop();
m_mod_time = modtime;
}
}
else
catch( file_parser_error fpe )
{
// printf( "g: " );
len = sprintf( buf, "%.10g", engUnits );
// for xml_parser_error, what() has the line number in it,
// but no byte offset. That should be an adequate error message.
THROW_IO_ERROR( fpe.what() );
}
// Class ptree_error is a base class for xml_parser_error & file_parser_error,
// so one catch should be OK for all errors.
catch( ptree_error pte )
{
std::string errmsg = pte.what();
errmsg += " @\n";
errmsg += m_xpath->Contents();
THROW_IO_ERROR( errmsg );
}
return len;
}
std::string EAGLE_PLUGIN::fmtBIU( BIU aValue ) const
wxArrayString EAGLE_PLUGIN::FootprintEnumerate( const wxString& aLibraryPath, PROPERTIES* aProperties )
{
char temp[50];
init( aProperties );
int len = biuSprintf( temp, aValue );
cacheLib( aLibraryPath );
return std::string( temp, len );
wxArrayString ret;
for( MODULE_CITER it = m_templates.begin(); it != m_templates.end(); ++it )
ret.Add( FROM_UTF8( it->first.c_str() ) );
return ret;
}
wxArrayString EAGLE_PLUGIN::FootprintEnumerate( const wxString& aLibraryPath, PROPERTIES* aProperties )
MODULE* EAGLE_PLUGIN::FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName, PROPERTIES* aProperties )
{
return wxArrayString();
init( aProperties );
cacheLib( aLibraryPath );
std::string key = TO_UTF8( aFootprintName );
MODULE_CITER mi = m_templates.find( key );
if( mi == m_templates.end() )
return NULL;
// copy constructor to clone the template
MODULE* ret = new MODULE( *mi->second );
return ret;
}
MODULE* EAGLE_PLUGIN::FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName, PROPERTIES* aProperties )
/*
void EAGLE_PLUGIN::Save( const wxString& aFileName, BOARD* aBoard, PROPERTIES* aProperties )
{
return NULL;
// Eagle lovers apply here.
}
......
......@@ -85,13 +85,18 @@ public:
const wxString& GetFileExtension() const;
/*
void Save( const wxString& aFileName, BOARD* aBoard, PROPERTIES* aProperties = NULL );
wxArrayString FootprintEnumerate( const wxString& aLibraryPath, PROPERTIES* aProperties = NULL);
MODULE* FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName, PROPERTIES* aProperties = NULL );
bool IsFootprintLibWritable( const wxString& aLibraryPath )
{
return false; // until someone writes others like FootprintSave(), etc.
}
/*
void Save( const wxString& aFileName, BOARD* aBoard, PROPERTIES* aProperties = NULL );
void FootprintSave( const wxString& aLibraryPath, const MODULE* aFootprint, PROPERTIES* aProperties = NULL );
void FootprintDelete( const wxString& aLibraryPath, const wxString& aFootprintName );
......@@ -100,7 +105,6 @@ public:
bool FootprintLibDelete( const wxString& aLibraryPath, PROPERTIES* aProperties = NULL );
bool IsFootprintLibWritable( const wxString& aLibraryPath );
*/
//-----</PUBLIC PLUGIN API>-------------------------------------------------
......@@ -116,21 +120,23 @@ private:
XPATH* m_xpath; ///< keeps track of what we are working on within
///< XML document during a Load().
std::string m_err_path; ///< snapshot m_xpath contentx into here on exception
int m_hole_count; ///< generates unique module names from eagle "hole"s.
NET_MAP m_pads_to_nets; ///< net list
MODULE_MAP m_templates; ///< is part of a MODULE factory that operates
///< using copy construction.
///< lookup key is libname.packagename
///< lookup key is either libname.packagename or simply
///< packagename if FootprintLoad() or FootprintEnumberate()
PROPERTIES* m_props; ///< passed via Save() or Load(), no ownership, may be NULL.
BOARD* m_board; ///< which BOARD is being worked on, no ownership here
double mm_per_biu; ///< how many mm in each BIU
double biu_per_mm; ///< how many bius in a mm
wxString m_lib_path;
wxDateTime m_mod_time;
/// initialize PLUGIN like a constructor would, and futz with fresh BOARD if needed.
void init( PROPERTIES* aProperties );
......@@ -150,31 +156,11 @@ private:
double eagle_x( BIU x ) const { return eagle( x ); }
double eagle_y( BIU y ) const { return eagle( y ); }
/// This PLUGIN only caches one footprint library, this determines which one.
void cacheLib( const wxString& aLibraryPath );
#if 0
/// encapsulate the BIU formatting tricks in one place.
int biuSprintf( char* buf, BIU aValue ) const;
/**
* Function fmtBIU
* converts a BIU to engineering units by scaling and formatting to ASCII.
* This function is the complement of biuParse(). One has to know what the
* other is doing.
*/
std::string fmtBIU( BIU aValue ) const;
std::string fmtBIUPair( BIU first, BIU second ) const;
std::string fmtBIUPoint( const wxPoint& aPoint ) const
{
return fmtBIUPair( aPoint.x, aPoint.y );
}
std::string fmtBIUSize( const wxSize& aSize ) const
{
return fmtBIUPair( aSize.x, aSize.y );
}
#endif
/// get a file's or dir's modification time.
static wxDateTime getModificationTime( const wxString& aPath );
// all these loadXXX() throw IO_ERROR or ptree_error exceptions:
......@@ -183,6 +169,20 @@ private:
void loadLayerDefs( CPTREE& aLayers );
void loadPlain( CPTREE& aPlain );
void loadSignals( CPTREE& aSignals );
/**
* Function loadLibrary
* loads the Eagle "library" XML element, which can occur either under
* a "libraries" element (if a *.brd file) or under a "drawing" element if a
* *.lbr file.
* @param aLib is the portion of the loaded XML document tree that is the "library"
* element.
* @param aLibName is a pointer to the library name or NULL. If NULL this means
* we are loading a *.lbr not a *.brd file and the key used in m_templates is to exclude
* the library name.
*/
void loadLibrary( CPTREE& aLib, const std::string* aLibName );
void loadLibraries( CPTREE& aLibs );
void loadElements( CPTREE& aElements );
......
......@@ -3866,7 +3866,7 @@ typedef MODULE_MAP::const_iterator MODULE_CITER;
struct FPL_CACHE
{
LEGACY_PLUGIN* m_owner; // my owner, I need its LEGACY_PLUGIN::LoadMODULE()
wxString m_lib_name;
wxString m_lib_path;
wxDateTime m_mod_time;
MODULE_MAP m_modules; // map or tuple of footprint_name vs. MODULE*
bool m_writable;
......@@ -3877,7 +3877,7 @@ struct FPL_CACHE
// error codes nor user interface calls from here, nor in any PLUGIN.
// Catch these exceptions higher up please.
/// save the entire legacy library to m_lib_name;
/// save the entire legacy library to m_lib_path;
void Save();
void SaveHeader( FILE* aFile );
......@@ -3905,7 +3905,7 @@ struct FPL_CACHE
FPL_CACHE::FPL_CACHE( LEGACY_PLUGIN* aOwner, const wxString& aLibraryPath ) :
m_owner( aOwner ),
m_lib_name( aLibraryPath ),
m_lib_path( aLibraryPath ),
m_writable( true )
{
}
......@@ -3913,7 +3913,7 @@ FPL_CACHE::FPL_CACHE( LEGACY_PLUGIN* aOwner, const wxString& aLibraryPath ) :
wxDateTime FPL_CACHE::GetLibModificationTime()
{
wxFileName fn( m_lib_name );
wxFileName fn( m_lib_path );
// update the writable flag while we have a wxFileName, in a network this
// is possibly quite dynamic anyway.
......@@ -3925,7 +3925,7 @@ wxDateTime FPL_CACHE::GetLibModificationTime()
void FPL_CACHE::Load()
{
FILE_LINE_READER reader( m_lib_name );
FILE_LINE_READER reader( m_lib_path );
ReadAndVerifyHeader( &reader );
SkipIndex( &reader );
......@@ -3970,7 +3970,7 @@ void FPL_CACHE::ReadAndVerifyHeader( LINE_READER* aReader )
L_bad_library:
THROW_IO_ERROR( wxString::Format( _( "File '%s' is empty or is not a legacy library" ),
m_lib_name.GetData() ) );
m_lib_path.GetData() ) );
}
......@@ -4082,7 +4082,7 @@ void FPL_CACHE::Save()
if( !m_writable )
{
THROW_IO_ERROR( wxString::Format(
_( "Legacy library file '%s' is read only" ), m_lib_name.GetData() ) );
_( "Legacy library file '%s' is read only" ), m_lib_path.GetData() ) );
}
wxString tempFileName;
......@@ -4090,20 +4090,20 @@ void FPL_CACHE::Save()
// a block {} scope to fire wxFFile wxf()'s destructor
{
// CreateTempFileName works better with an absolute path
wxFileName abs_lib_name( m_lib_name );
wxFileName abs_lib_name( m_lib_path );
abs_lib_name.MakeAbsolute();
tempFileName = wxFileName::CreateTempFileName( abs_lib_name.GetFullPath() );
wxLogDebug( wxT( "tempFileName:'%s' m_lib_name:'%s'\n" ),
TO_UTF8( tempFileName ), TO_UTF8( m_lib_name ) );
wxLogDebug( wxT( "tempFileName:'%s' m_lib_path:'%s'\n" ),
TO_UTF8( tempFileName ), TO_UTF8( m_lib_path ) );
FILE* fp = wxFopen( tempFileName, wxT( "w" ) );
if( !fp )
{
THROW_IO_ERROR( wxString::Format(
_( "Unable to open or create legacy library file '%s'" ),
m_lib_name.GetData() ) );
m_lib_path.GetData() ) );
}
// wxf now owns fp, will close on exception or exit from
......@@ -4117,20 +4117,20 @@ void FPL_CACHE::Save()
}
// fp is now closed here, and that seems proper before trying to rename
// the temporary file to m_lib_name.
// the temporary file to m_lib_path.
wxRemove( m_lib_name ); // it is not an error if this does not exist
wxRemove( m_lib_path ); // it is not an error if this does not exist
// Even on linux you can see an _intermittent_ error when calling wxRename(),
// and it is fully inexplicable. See if this dodges the error.
wxMilliSleep( 250L );
if( wxRename( tempFileName, m_lib_name ) )
if( wxRename( tempFileName, m_lib_path ) )
{
THROW_IO_ERROR( wxString::Format(
_( "Unable to rename tempfile '%s' to library file '%s'" ),
tempFileName.GetData(),
m_lib_name.GetData() ) );
m_lib_path.GetData() ) );
}
}
......@@ -4173,7 +4173,7 @@ void FPL_CACHE::SaveModules( FILE* aFile )
void LEGACY_PLUGIN::cacheLib( const wxString& aLibraryPath )
{
if( !m_cache || m_cache->m_lib_name != aLibraryPath ||
if( !m_cache || m_cache->m_lib_path != aLibraryPath ||
// somebody else on a network touched the library:
m_cache->m_mod_time != m_cache->GetLibModificationTime() )
{
......@@ -4342,7 +4342,7 @@ bool LEGACY_PLUGIN::FootprintLibDelete( const wxString& aLibraryPath, PROPERTIES
aLibraryPath.GetData() ) );
}
if( m_cache && m_cache->m_lib_name == aLibraryPath )
if( m_cache && m_cache->m_lib_path == aLibraryPath )
{
delete m_cache;
m_cache = 0;
......
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