ADDED: Support EAGLE libraries directly in Symbol Library Table.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/2214
This commit is contained in:
parent
9ed19192de
commit
a16bdb7288
|
@ -30,6 +30,7 @@
|
|||
#include <string_utils.h>
|
||||
#include <richio.h>
|
||||
#include <wx/log.h>
|
||||
#include <wx/regex.h>
|
||||
|
||||
#include <functional>
|
||||
#include <cstdio>
|
||||
|
@ -145,6 +146,36 @@ bool substituteVariable( wxString* aText )
|
|||
}
|
||||
|
||||
|
||||
wxString convertDescription( wxString aDescr )
|
||||
{
|
||||
aDescr.Replace( wxS( "\n" ), wxS( " " ) );
|
||||
aDescr.Replace( wxS( "\r" ), wxEmptyString );
|
||||
|
||||
wxRegEx( wxS( "<a\\s+(?:[^>]*?\\s+)?href=\"([^\"]*)\"[^>]*>" ) )
|
||||
.ReplaceAll( &aDescr, wxS( "\\1 " ) );
|
||||
|
||||
aDescr.Replace( wxS( "<p>" ), wxS( "\n\n" ) );
|
||||
aDescr.Replace( wxS( "</p>" ), wxS( "\n\n" ) );
|
||||
|
||||
aDescr.Replace( wxS( "<br>" ), wxS( "\n" ) );
|
||||
aDescr.Replace( wxS( "<ul>" ), wxS( "\n" ) );
|
||||
aDescr.Replace( wxS( "</ul>" ), wxS( "\n\n" ) );
|
||||
aDescr.Replace( wxS( "<li></li>" ), wxS( "\n" ) );
|
||||
aDescr.Replace( wxS( "<li>" ), wxS( "\n \u2022 " ) ); // Bullet point
|
||||
|
||||
aDescr = RemoveHTMLTags( aDescr );
|
||||
|
||||
wxRegEx( wxS( "\n +" ) ).ReplaceAll( &aDescr, wxS( "\n" ) );
|
||||
wxRegEx( wxS( " +\n" ) ).ReplaceAll( &aDescr, wxS( "\n" ) );
|
||||
|
||||
wxRegEx( wxS( "\n{3,}" ) ).ReplaceAll( &aDescr, wxS( "\n\n" ) );
|
||||
wxRegEx( wxS( "^\n+" ) ).ReplaceAll( &aDescr, wxEmptyString );
|
||||
wxRegEx( wxS( "\n+$" ) ).ReplaceAll( &aDescr, wxEmptyString );
|
||||
|
||||
return aDescr;
|
||||
}
|
||||
|
||||
|
||||
template<> template<>
|
||||
OPTIONAL_XML_ATTRIBUTE<wxString>::OPTIONAL_XML_ATTRIBUTE( wxString aData )
|
||||
{
|
||||
|
|
|
@ -59,6 +59,9 @@ wxString interpretText( const wxString& aText );
|
|||
///< Translates Eagle special text reference to a KiCad variable reference
|
||||
bool substituteVariable( wxString* aText );
|
||||
|
||||
///< Converts Eagle's HTML description into KiCad description format
|
||||
wxString convertDescription( wxString aDescr );
|
||||
|
||||
static inline wxXmlNode* getChildrenNodes( NODE_MAP& aMap, const wxString& aName )
|
||||
{
|
||||
auto it = aMap.find( aName );
|
||||
|
|
|
@ -421,24 +421,7 @@ SCH_SHEET* SCH_EAGLE_PLUGIN::LoadSchematicFile( const wxString& aFileName, SCHEM
|
|||
}
|
||||
|
||||
// Load the document
|
||||
wxXmlDocument xmlDocument;
|
||||
wxFFileInputStream stream( m_filename.GetFullPath() );
|
||||
|
||||
// read first line to check for Eagle XML format file
|
||||
wxTextInputStream text( stream );
|
||||
wxString line = text.ReadLine();
|
||||
if( !line.StartsWith( wxT( "<?xml" ) ) )
|
||||
{
|
||||
THROW_IO_ERROR( wxString::Format( _( "'%s' is an Eagle binary-format schematic file; "
|
||||
"only Eagle XML-format schematics can be imported." ),
|
||||
m_filename.GetFullPath() ) );
|
||||
}
|
||||
|
||||
if( !stream.IsOk() || !xmlDocument.Load( stream ) )
|
||||
{
|
||||
THROW_IO_ERROR( wxString::Format( _( "Unable to read file '%s'." ),
|
||||
m_filename.GetFullPath() ) );
|
||||
}
|
||||
wxXmlDocument xmlDocument = loadXmlDocument( m_filename.GetFullPath() );
|
||||
|
||||
// Delete on exception, if I own m_rootSheet, according to aAppendToMe
|
||||
unique_ptr<SCH_SHEET> deleter( aAppendToMe ? nullptr : m_rootSheet );
|
||||
|
@ -527,6 +510,144 @@ SCH_SHEET* SCH_EAGLE_PLUGIN::LoadSchematicFile( const wxString& aFileName, SCHEM
|
|||
}
|
||||
|
||||
|
||||
void SCH_EAGLE_PLUGIN::EnumerateSymbolLib( wxArrayString& aSymbolNameList,
|
||||
const wxString& aLibraryPath,
|
||||
const STRING_UTF8_MAP* aProperties )
|
||||
{
|
||||
m_filename = aLibraryPath;
|
||||
m_libName = m_filename.GetName();
|
||||
|
||||
ensureLoadedLibrary( aLibraryPath );
|
||||
|
||||
auto it = m_eagleLibs.find( m_libName );
|
||||
|
||||
if( it != m_eagleLibs.end() )
|
||||
{
|
||||
for( const auto& [symName, libSymbol] : it->second.KiCadSymbols )
|
||||
aSymbolNameList.push_back( symName );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SCH_EAGLE_PLUGIN::EnumerateSymbolLib( std::vector<LIB_SYMBOL*>& aSymbolList,
|
||||
const wxString& aLibraryPath,
|
||||
const STRING_UTF8_MAP* aProperties )
|
||||
{
|
||||
m_filename = aLibraryPath;
|
||||
m_libName = m_filename.GetName();
|
||||
|
||||
ensureLoadedLibrary( aLibraryPath );
|
||||
|
||||
auto it = m_eagleLibs.find( m_libName );
|
||||
|
||||
if( it != m_eagleLibs.end() )
|
||||
{
|
||||
for( const auto& [symName, libSymbol] : it->second.KiCadSymbols )
|
||||
aSymbolList.push_back( libSymbol );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LIB_SYMBOL* SCH_EAGLE_PLUGIN::LoadSymbol( const wxString& aLibraryPath, const wxString& aAliasName,
|
||||
const STRING_UTF8_MAP* aProperties )
|
||||
{
|
||||
m_filename = aLibraryPath;
|
||||
m_libName = m_filename.GetName();
|
||||
|
||||
ensureLoadedLibrary( aLibraryPath );
|
||||
|
||||
auto it = m_eagleLibs.find( m_libName );
|
||||
|
||||
if( it != m_eagleLibs.end() )
|
||||
{
|
||||
auto it2 = it->second.KiCadSymbols.find( aAliasName );
|
||||
|
||||
if( it2 != it->second.KiCadSymbols.end() )
|
||||
return it2->second;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
long long SCH_EAGLE_PLUGIN::getLibraryTimestamp( const wxString& aLibraryPath ) const
|
||||
{
|
||||
wxFileName fn( aLibraryPath );
|
||||
|
||||
if( fn.IsFileReadable() && fn.GetModificationTime().IsValid() )
|
||||
return fn.GetModificationTime().GetValue().GetValue();
|
||||
else
|
||||
return wxDateTime( 0.0 ).GetValue().GetValue();
|
||||
}
|
||||
|
||||
|
||||
void SCH_EAGLE_PLUGIN::ensureLoadedLibrary( const wxString& aLibraryPath )
|
||||
{
|
||||
if( m_eagleLibs.find( m_libName ) != m_eagleLibs.end() )
|
||||
{
|
||||
wxCHECK( m_timestamps.count( m_libName ), /*void*/ );
|
||||
|
||||
if( m_timestamps.at( m_libName ) == getLibraryTimestamp( aLibraryPath ) )
|
||||
return;
|
||||
}
|
||||
|
||||
LOCALE_IO toggle; // toggles on, then off, the C locale.
|
||||
|
||||
if( m_progressReporter )
|
||||
{
|
||||
m_progressReporter->Report( wxString::Format( _( "Loading %s..." ), aLibraryPath ) );
|
||||
|
||||
if( !m_progressReporter->KeepRefreshing() )
|
||||
THROW_IO_ERROR( ( "Open canceled by user." ) );
|
||||
}
|
||||
|
||||
// Load the document
|
||||
wxXmlDocument xmlDocument = loadXmlDocument( m_filename.GetFullPath() );
|
||||
|
||||
// Retrieve the root as current node
|
||||
wxXmlNode* currentNode = xmlDocument.GetRoot();
|
||||
|
||||
// If the attribute is found, store the Eagle version;
|
||||
// otherwise, store the dummy "0.0" version.
|
||||
m_version = currentNode->GetAttribute( wxT( "version" ), wxT( "0.0" ) );
|
||||
|
||||
// Map all children into a readable dictionary
|
||||
NODE_MAP children = MapChildren( currentNode );
|
||||
|
||||
// Load drawing
|
||||
loadDrawing( children["drawing"] );
|
||||
|
||||
// Remember timestamp
|
||||
m_timestamps[m_libName] = getLibraryTimestamp( aLibraryPath );
|
||||
}
|
||||
|
||||
|
||||
wxXmlDocument SCH_EAGLE_PLUGIN::loadXmlDocument( const wxString& aFileName )
|
||||
{
|
||||
wxXmlDocument xmlDocument;
|
||||
wxFFileInputStream stream( m_filename.GetFullPath() );
|
||||
|
||||
// read first line to check for Eagle XML format file
|
||||
wxTextInputStream text( stream );
|
||||
wxString line = text.ReadLine();
|
||||
|
||||
if( !line.StartsWith( wxT( "<?xml" ) ) && !line.StartsWith( wxT( "<!--" ) ) )
|
||||
{
|
||||
THROW_IO_ERROR( wxString::Format( _( "'%s' is an Eagle binary-format file; "
|
||||
"only Eagle XML-format files can be imported." ),
|
||||
m_filename.GetFullPath() ) );
|
||||
}
|
||||
|
||||
if( !stream.IsOk() || !xmlDocument.Load( stream ) )
|
||||
{
|
||||
THROW_IO_ERROR(
|
||||
wxString::Format( _( "Unable to read file '%s'." ), m_filename.GetFullPath() ) );
|
||||
}
|
||||
|
||||
return xmlDocument;
|
||||
}
|
||||
|
||||
|
||||
void SCH_EAGLE_PLUGIN::loadDrawing( wxXmlNode* aDrawingNode )
|
||||
{
|
||||
// Map all children into a readable dictionary
|
||||
|
@ -542,7 +663,15 @@ void SCH_EAGLE_PLUGIN::loadDrawing( wxXmlNode* aDrawingNode )
|
|||
if( layers )
|
||||
loadLayerDefs( layers );
|
||||
|
||||
// wxXmlNode* library = drawingChildren["library"]
|
||||
wxXmlNode* libraryNode = drawingChildren["library"];
|
||||
|
||||
if( libraryNode )
|
||||
{
|
||||
EAGLE_LIBRARY& elib = m_eagleLibs[m_libName];
|
||||
elib.name = m_libName;
|
||||
|
||||
loadLibrary( libraryNode, &elib );
|
||||
}
|
||||
|
||||
// wxXmlNode* settings = drawingChildren["settings"]
|
||||
|
||||
|
@ -1873,9 +2002,14 @@ EAGLE_LIBRARY* SCH_EAGLE_PLUGIN::loadLibrary( wxXmlNode* aLibraryNode,
|
|||
EDEVICE_SET edeviceset = EDEVICE_SET( devicesetNode );
|
||||
|
||||
wxString prefix = edeviceset.prefix ? edeviceset.prefix.Get() : wxString( wxT( "" ) );
|
||||
wxString deviceSetDescr;
|
||||
|
||||
NODE_MAP deviceSetChildren = MapChildren( devicesetNode );
|
||||
wxXmlNode* deviceNode = getChildrenNodes( deviceSetChildren, wxT( "devices" ) );
|
||||
wxXmlNode* deviceNode = getChildrenNodes( deviceSetChildren, wxT( "devices" ) );
|
||||
wxXmlNode* deviceSetDescrNode = getChildrenNodes( deviceSetChildren, wxT( "description" ) );
|
||||
|
||||
if( deviceSetDescrNode )
|
||||
deviceSetDescr = convertDescription( UnescapeHTML( deviceSetDescrNode->GetContent() ) );
|
||||
|
||||
// For each device in the device set:
|
||||
while( deviceNode )
|
||||
|
@ -1939,26 +2073,42 @@ EAGLE_LIBRARY* SCH_EAGLE_PLUGIN::loadLibrary( wxXmlNode* aLibraryNode,
|
|||
// Don't set the footprint field if no package is defined in the Eagle schematic.
|
||||
if( edevice.package )
|
||||
{
|
||||
// assume that footprint library is identical to project name
|
||||
wxString packageString = m_schematic->Prj().GetProjectName() + wxT( ":" ) +
|
||||
aEagleLibrary->package[symbolName];
|
||||
wxString libName;
|
||||
|
||||
if( m_schematic )
|
||||
{
|
||||
// assume that footprint library is identical to project name
|
||||
libName = m_schematic->Prj().GetProjectName();
|
||||
}
|
||||
else
|
||||
{
|
||||
libName = m_libName;
|
||||
}
|
||||
|
||||
wxString packageString = libName + wxT( ":" ) + aEagleLibrary->package[symbolName];
|
||||
|
||||
libSymbol->GetFootprintField().SetText( packageString );
|
||||
}
|
||||
|
||||
wxString libName = libSymbol->GetName();
|
||||
libSymbol->SetName( libName );
|
||||
libSymbol->SetDescription( deviceSetDescr );
|
||||
|
||||
// If duplicate symbol names exist in multiple Eagle symbol libraries, prefix the
|
||||
// Eagle symbol library name to the symbol which should ensure that it is unique.
|
||||
if( m_pi->LoadSymbol( getLibFileName().GetFullPath(), libName ) )
|
||||
if( m_pi )
|
||||
{
|
||||
libName = aEagleLibrary->name + wxT( "_" ) + libName;
|
||||
libName = EscapeString( libName, CTX_LIBID );
|
||||
libSymbol->SetName( libName );
|
||||
// If duplicate symbol names exist in multiple Eagle symbol libraries, prefix the
|
||||
// Eagle symbol library name to the symbol which should ensure that it is unique.
|
||||
if( m_pi->LoadSymbol( getLibFileName().GetFullPath(), libName ) )
|
||||
{
|
||||
libName = aEagleLibrary->name + wxT( "_" ) + libName;
|
||||
libName = EscapeString( libName, CTX_LIBID );
|
||||
libSymbol->SetName( libName );
|
||||
}
|
||||
|
||||
m_pi->SaveSymbol( getLibFileName().GetFullPath(),
|
||||
new LIB_SYMBOL( *libSymbol.get() ), m_properties.get() );
|
||||
}
|
||||
|
||||
m_pi->SaveSymbol( getLibFileName().GetFullPath(), new LIB_SYMBOL( *libSymbol.get() ),
|
||||
m_properties.get() );
|
||||
aEagleLibrary->KiCadSymbols.insert( libName, libSymbol.release() );
|
||||
|
||||
// Store information on whether the value of VALUE_FIELD for a part should be
|
||||
|
|
|
@ -100,10 +100,10 @@ public:
|
|||
return PLUGIN_FILE_DESC( _HKI( "Eagle XML schematic files" ), { "sch" } );
|
||||
}
|
||||
|
||||
/*const PLUGIN_FILE_DESC GetLibraryFileDesc() const override
|
||||
const PLUGIN_FILE_DESC GetLibraryFileDesc() const override
|
||||
{
|
||||
return PLUGIN_FILE_DESC( _HKI( "Eagle XML library files" ), { "lbr" } );
|
||||
}*/
|
||||
}
|
||||
|
||||
bool CanReadSchematicFile( const wxString& aFileName ) const override;
|
||||
bool CanReadLibrary( const wxString& aFileName ) const override;
|
||||
|
@ -114,10 +114,24 @@ public:
|
|||
SCH_SHEET* aAppendToMe = nullptr,
|
||||
const STRING_UTF8_MAP* aProperties = nullptr ) override;
|
||||
|
||||
void EnumerateSymbolLib( wxArrayString& aSymbolNameList, const wxString& aLibraryPath,
|
||||
const STRING_UTF8_MAP* aProperties ) override;
|
||||
|
||||
void EnumerateSymbolLib( std::vector<LIB_SYMBOL*>& aSymbolList, const wxString& aLibraryPath,
|
||||
const STRING_UTF8_MAP* aProperties ) override;
|
||||
|
||||
LIB_SYMBOL* LoadSymbol( const wxString& aLibraryPath, const wxString& aAliasName,
|
||||
const STRING_UTF8_MAP* aProperties ) override;
|
||||
|
||||
bool IsSymbolLibWritable( const wxString& aLibraryPath ) override { return false; }
|
||||
|
||||
private:
|
||||
void checkpoint();
|
||||
|
||||
bool checkHeader( const wxString& aFileName ) const;
|
||||
bool checkHeader( const wxString& aFileName ) const;
|
||||
wxXmlDocument loadXmlDocument( const wxString& aFileName );
|
||||
long long getLibraryTimestamp( const wxString& aLibraryPath ) const;
|
||||
void ensureLoadedLibrary( const wxString& aLibraryPath );
|
||||
|
||||
void loadDrawing( wxXmlNode* aDrawingNode );
|
||||
void loadLayerDefs( wxXmlNode* aLayers );
|
||||
|
@ -239,9 +253,10 @@ private:
|
|||
wxString m_libName; ///< Library name to save symbols
|
||||
SCHEMATIC* m_schematic; ///< Passed to Load(), the schematic object being loaded
|
||||
|
||||
EPART_MAP m_partlist;
|
||||
std::map<wxString, EAGLE_LIBRARY> m_eagleLibs;
|
||||
std::unordered_map<wxString, bool> m_userValue; ///< deviceset/@uservalue for device.
|
||||
EPART_MAP m_partlist;
|
||||
std::map<wxString, long long> m_timestamps;
|
||||
std::map<wxString, EAGLE_LIBRARY> m_eagleLibs;
|
||||
std::unordered_map<wxString, bool> m_userValue; ///< deviceset/@uservalue for device.
|
||||
|
||||
SCH_PLUGIN::SCH_PLUGIN_RELEASER m_pi; ///< PI to create KiCad symbol library.
|
||||
std::unique_ptr<STRING_UTF8_MAP> m_properties; ///< Library plugin properties.
|
||||
|
|
|
@ -1786,7 +1786,10 @@ FOOTPRINT* EAGLE_PLUGIN::makeFootprint( wxXmlNode* aPackage, const wxString& aPk
|
|||
const wxString& itemName = packageItem->GetName();
|
||||
|
||||
if( itemName == wxT( "description" ) )
|
||||
m->SetLibDescription( packageItem->GetNodeContent() );
|
||||
{
|
||||
wxString descr = convertDescription( UnescapeHTML( packageItem->GetNodeContent() ) );
|
||||
m->SetLibDescription( descr );
|
||||
}
|
||||
else if( itemName == wxT( "wire" ) )
|
||||
packageWire( m.get(), packageItem );
|
||||
else if( itemName == wxT( "pad" ) )
|
||||
|
|
Loading…
Reference in New Issue