Eeschema: fix potential symbol cache library name collisions.

If a schematic contains two symbols with the same name from different
libraries, the cache will contain the last symbol saved with that name.
Prepend the library nickname with the original schematic symbol library
nickname when saving the cache library to prevent name collisions.
This commit is contained in:
Wayne Stambaugh 2017-12-07 18:01:03 -05:00
parent f7072cc7c6
commit 7ca7d9078e
9 changed files with 77 additions and 68 deletions

View File

@ -200,6 +200,12 @@ LIB_ALIAS* PART_LIB::FindAlias( const wxString& aName ) const
}
LIB_ALIAS* PART_LIB::FindAlias( const LIB_ID& aLibId ) const
{
return FindAlias( aLibId.Format().wx_str() );
}
LIB_PART* PART_LIB::FindPart( const wxString& aName ) const
{
LIB_ALIAS* alias = FindAlias( aName );
@ -211,6 +217,12 @@ LIB_PART* PART_LIB::FindPart( const wxString& aName ) const
}
LIB_PART* PART_LIB::FindPart( const LIB_ID& aLibId ) const
{
return FindPart( aLibId.Format().wx_str() );
}
bool PART_LIB::HasPowerParts() const
{
// return true if at least one power part is found in lib
@ -415,7 +427,7 @@ LIB_PART* PART_LIBS::FindLibPart( const LIB_ID& aLibId, const wxString& aLibrary
if( !aLibraryName.IsEmpty() && lib.GetName() != aLibraryName )
continue;
part = lib.FindPart( aLibId.GetLibItemName() );
part = lib.FindPart( aLibId.GetLibItemName().wx_str() );
if( part )
break;
@ -434,7 +446,7 @@ LIB_ALIAS* PART_LIBS::FindLibraryAlias( const LIB_ID& aLibId, const wxString& aL
if( !aLibraryName.IsEmpty() && lib.GetName() != aLibraryName )
continue;
entry = lib.FindAlias( aLibId.GetLibItemName() );
entry = lib.FindAlias( aLibId.GetLibItemName().wx_str() );
if( entry )
break;

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2008-2017 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2008 Wayne Stambaugh <stambaughw@gmail.com>
* Copyright (C) 2004-2017 KiCad Developers, see change_log.txt for contributors.
*
* This program is free software; you can redistribute it and/or
@ -132,20 +132,17 @@ public:
// Accessors
/**
* Function GetFilterPowerParts
* @return true if the filtering of power parts is on
*/
bool GetFilterPowerParts() const { return m_filterPowerParts; }
/**
* Function GetAllowedLibList
* @return am wxArrayString of the names of allowed libs
*/
const wxArrayString& GetAllowedLibList() const { return m_allowedLibs; }
/**
* Function GetLibSource
* @return the name of the lib to use to load a part, or an a empty string
* Useful to load (in lib editor or lib viewer) a part from a given library
*/
@ -184,10 +181,10 @@ typedef boost::ptr_vector< PART_LIB > PART_LIBS_BASE;
/**
* Class PART_LIBS
* is a collection of PART_LIBs. It extends from PROJECT::_ELEM so it can be
* hung in the PROJECT. It does not use any UI calls, but rather simply throws
* an IO_ERROR when there is a problem.
* A collection of #PART_LIB objects.
*
* It extends from PROJECT::_ELEM so it can be hung in the PROJECT. It does not use any
* UI calls, but rather simply throws an IO_ERROR when there is a problem.
*/
class PART_LIBS : public PART_LIBS_BASE, public PROJECT::_ELEM
{
@ -205,8 +202,7 @@ public:
int GetModifyHash();
/**
* Function AddLibrary
* allocates and adds a part library to the library list.
* Allocate and adds a part library to the library list.
*
* @param aFileName - File name object of part library.
* @throw IO_ERROR if there's any problem loading.
@ -214,8 +210,7 @@ public:
PART_LIB* AddLibrary( const wxString& aFileName );
/**
* Function AddLibrary
* inserts a part library into the library list.
* Insert a part library into the library list.
*
* @param aFileName - File name object of part library.
* @param aIterator - Iterator to insert library in front of.
@ -225,31 +220,30 @@ public:
PART_LIB* AddLibrary( const wxString& aFileName, PART_LIBS::iterator& aIterator );
/**
* Function LoadAllLibraries
* loads all of the project's libraries into this container, which should
* Load all of the project's libraries into this container, which should
* be cleared before calling it.
*
* @note This method is only to be used when loading legacy projects. All further symbol
* library access should be done via the symbol library table.
*/
void LoadAllLibraries( PROJECT* aProject, bool aShowProgress=true );
/**
* Function LibNamesAndPaths
* either saves or loads the names of the currently configured part libraries
* (without paths).
* Save or load the names of the currently configured part libraries (without paths).
*/
static void LibNamesAndPaths( PROJECT* aProject, bool doSave,
wxString* aPaths, wxArrayString* aNames=NULL );
/**
* Function cacheName
* returns the name of the cache library after potentially fixing it from
* Return the name of the cache library after potentially fixing it from
* an older naming scheme. That is, the old file is renamed if needed.
*
* @param aFullProjectFilename - the *.pro filename with absolute path.
*/
static const wxString CacheName( const wxString& aFullProjectFilename );
/**
* Function FindLibrary
* finds a part library by \a aName.
* Find a part library by \a aName.
*
* @param aName - Library file name without path or extension to find.
* @return Part library if found, otherwise NULL.
@ -261,18 +255,15 @@ public:
PART_LIB* GetCacheLibrary();
/**
* Function GetLibraryNames
* returns the list of part library file names without path and extension.
* Return the list of part library file names without path and extension.
*
* @param aSorted - Sort the list of name if true. Otherwise use the
* library load order.
* @param aSorted - Sort the list of name if true. Otherwise use the library load order.
* @return The list of library names.
*/
wxArrayString GetLibraryNames( bool aSorted = true );
/**
* Function FindLibPart
* searches all libraries in the list for a part.
* Search all libraries in the list for a part.
*
* A part object will always be returned. If the entry found
* is an alias. The root part will be found and returned.
@ -317,9 +308,7 @@ public:
/**
* Class PART_LIB
* is used to load, save, search, and otherwise manipulate
* part library files.
* Object used to load, save, search, and otherwise manipulate symbol library files.
*/
class PART_LIB
{
@ -365,8 +354,7 @@ public:
}
/**
* Function GetCount
* returns the number of entries in the library.
* Return the number of entries in the library.
*
* @return The number of part and alias entries.
*/
@ -391,7 +379,6 @@ public:
void Save( bool aSaveDocFile = true );
/**
* Function IsReadOnly
* @return true if current user does not have write access to the library file.
*/
bool IsReadOnly() const { return !fileName.IsFileWritable(); }
@ -425,6 +412,8 @@ public:
*/
LIB_ALIAS* FindAlias( const wxString& aName ) const;
LIB_ALIAS* FindAlias( const LIB_ID& aLibId ) const;
/**
* Find part by \a aName.
*
@ -436,6 +425,8 @@ public:
*/
LIB_PART* FindPart( const wxString& aName ) const;
LIB_PART* FindPart( const LIB_ID& aLibId ) const;
/**
* Add \a aPart entry to library.
*
@ -476,16 +467,15 @@ public:
const wxString GetName() const { return fileName.GetName(); }
/**
* Function GetFullFileName
* returns the full file library name with path and extension.
* Return the full file library name with path and extension.
*
* @return wxString - Full library file name with path and extension.
*/
wxString GetFullFileName() const { return fileName.GetFullPath(); }
/**
* Function GetLogicalName
* returns the logical name of the library.
* Return the logical name of the library.
*
* @return wxString - The logical name of this library.
*/
const wxString GetLogicalName() const
@ -503,18 +493,15 @@ public:
/**
* Function LoadLibrary
* allocates and loads a part library file.
* Allocate and load a symbol library file.
*
* @param aFileName - File name of the part library to load.
* @return PART_LIB* - the allocated and loaded PART_LIB, which is owned by
* the caller.
* @return PART_LIB* - the allocated and loaded PART_LIB, which is owned by the caller.
* @throw IO_ERROR if there's any problem loading the library.
*/
static PART_LIB* LoadLibrary( const wxString& aFileName );
/**
* Function HasPowerParts
* @return true if at least one power part is found in lib
* Useful to select or list only libs containing power parts
*/

View File

@ -741,7 +741,7 @@ void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::InitBuffers( SCH_COMPONENT* aComponent
which came from the component.
*/
m_part = GetParent()->GetLibPart( m_cmp->GetLibId() );
m_part = GetParent()->GetLibPart( m_cmp->GetLibId(), true );
#if 0 && defined(DEBUG)
for( int i = 0; i<aComponent->GetFieldCount(); ++i )

View File

@ -277,9 +277,9 @@ DIALOG_SCH_EDIT_ONE_FIELD::DIALOG_SCH_EDIT_ONE_FIELD( SCH_BASE_FRAME* aParent,
wxASSERT_MSG( component != NULL && component->Type() == SCH_COMPONENT_T,
wxT( "Invalid schematic field parent item." ) );
const LIB_PART* part = GetParent()->GetLibPart( component->GetLibId() );
const LIB_PART* part = GetParent()->GetLibPart( component->GetLibId(), true );
wxASSERT_MSG( part, wxT( "Library part for component <" ) +
wxASSERT_MSG( part, wxT( "Library symbol for schematic symbol <" ) +
component->GetLibId().Format() + wxT( "> could not be found." ) );
m_isPower = part->IsPower();

View File

@ -250,7 +250,7 @@ bool DIALOG_SYMBOL_REMAP::remapSymbolToLibTable( SCH_COMPONENT* aSymbol )
if( it->IsCache() )
continue;
LIB_ALIAS* alias = it->FindAlias( aSymbol->GetLibId().GetLibItemName() );
LIB_ALIAS* alias = it->FindAlias( aSymbol->GetLibId().GetLibItemName().wx_str() );
// Found in the same library as the old look up method assuming the user didn't
// change the libraries or library ordering since the last time the schematic was

View File

@ -53,22 +53,22 @@ void SCH_EDIT_FRAME::EditComponentFieldText( SCH_FIELD* aField )
wxCHECK_RET( component != NULL && component->Type() == SCH_COMPONENT_T,
wxT( "Invalid schematic field parent item." ) );
LIB_ID id = component->GetLibId();
LIB_ALIAS* alias = NULL;
// LIB_ID id = component->GetLibId();
// LIB_ALIAS* alias = NULL;
try
{
alias = Prj().SchSymbolLibTable()->LoadSymbol( id );
}
catch( ... )
{
}
// try
// {
// alias = Prj().SchSymbolLibTable()->LoadSymbol( id );
// }
// catch( ... )
// {
// }
LIB_PART* part = ( alias ) ? alias->GetPart() : NULL;
// LIB_PART* part = ( alias ) ? alias->GetPart() : NULL;
wxCHECK_RET( part, wxString::Format( "Symbol '%s' not found in library '%s'",
id.GetLibItemName().wx_str(),
id.GetLibNickname().wx_str() ) );
// wxCHECK_RET( part, wxString::Format( "Symbol '%s' not found in library '%s'",
// id.GetLibItemName().wx_str(),
// id.GetLibNickname().wx_str() ) );
// Save old component in undo list if not already in edit, or moving.
if( aField->GetFlags() == 0 )

View File

@ -93,7 +93,7 @@ bool SCH_EDIT_FRAME::CreateArchiveLibrary( const wxString& aFileName )
try
{
if( archLib->FindAlias( component->GetLibId().GetLibItemName() ) )
if( archLib->FindAlias( component->GetLibId() ) )
continue;
part = GetLibPart( component->GetLibId(), true );
@ -114,8 +114,13 @@ bool SCH_EDIT_FRAME::CreateArchiveLibrary( const wxString& aFileName )
if( part )
{
// Use the full LIB_ID as the symbol name to prevent symbol name collisions.
wxString oldName = part->GetName();
part->SetName( component->GetLibId().Format() );
// AddPart() does first clone the part before adding.
archLib->AddPart( part );
part->SetName( oldName );
}
else
{

View File

@ -50,7 +50,7 @@ LIB_ALIAS* SchGetLibAlias( const LIB_ID& aLibId, SYMBOL_LIB_TABLE* aLibTable, PA
alias = aLibTable->LoadSymbol( aLibId );
if( !alias && aCacheLib )
alias = aCacheLib->FindAlias( aLibId.GetLibItemName() );
alias = aCacheLib->FindAlias( aLibId );
}
catch( const IO_ERROR& ioe )
{

View File

@ -256,7 +256,7 @@ void SCH_COMPONENT::SetLibId( const LIB_ID& aLibId, SYMBOL_LIB_TABLE* aSymLibTab
alias = aSymLibTable->LoadSymbol( m_lib_id.GetLibNickname(), m_lib_id.GetLibItemName() );
if( !alias && aCacheLib )
alias = aCacheLib->FindAlias( m_lib_id.GetLibItemName() );
alias = aCacheLib->FindAlias( m_lib_id.Format().wx_str() );
if( alias && alias->GetPart() )
m_part = alias->GetPart()->SharedPtr();
@ -323,7 +323,7 @@ bool SCH_COMPONENT::Resolve( SYMBOL_LIB_TABLE& aLibTable, PART_LIB* aCacheLib )
// Fall back to cache library. This is temporary until the new schematic file
// format is implemented.
if( !alias && aCacheLib )
alias = aCacheLib->FindAlias( m_lib_id.GetLibItemName() );
alias = aCacheLib->FindAlias( m_lib_id.Format().wx_str() );
if( alias && alias->GetPart() )
{
@ -1322,7 +1322,12 @@ void SCH_COMPONENT::GetMsgPanelInfo( MSG_PANEL_ITEMS& aList )
{
if( part.get() != dummy() )
{
LIB_ALIAS* alias = part->GetAlias( GetLibId().GetLibItemName() );
LIB_ALIAS* alias = nullptr;
if( part->GetLib() && part->GetLib()->IsCache() )
alias = part->GetAlias( GetLibId().Format() );
else
alias = part->GetAlias( GetLibId().GetLibItemName() );
if( !alias )
return;
@ -1343,7 +1348,7 @@ void SCH_COMPONENT::GetMsgPanelInfo( MSG_PANEL_ITEMS& aList )
if( alias->GetName() != part->GetName() )
aList.push_back( MSG_PANEL_ITEM( _( "Alias of" ), part->GetName(), BROWN ) );
if( m_lib_id.GetLibNickname().empty() && alias->GetLib() && alias->GetLib()->IsCache() )
if( alias->GetLib() && alias->GetLib()->IsCache() )
aList.push_back( MSG_PANEL_ITEM( _( "Library" ), alias->GetLibraryName(), RED ) );
else if( !m_lib_id.GetLibNickname().empty() )
aList.push_back( MSG_PANEL_ITEM( _( "Library" ), m_lib_id.GetLibNickname(),