kicad-source/eeschema/class_library.cpp
Wayne Stambaugh 1e752ba164 Eeschema: symbol library viewer improvements.
Select the first library in the list and the first symbol in the first
library if they exist the first time the symbol viewer is opened.

Prevent clicking on the next or previous toolbar buttons from wrapping
past the end of the symbol list to mimic the behavior of the up and down
arrow key strokes.opens a select
library dialog.

Use incriminating or decrementing the current symbol selection when using
the next and previous symbol toolbar buttons rather looking up the next
symbol in the library.  Just use the next or previous symbol name in the
list.

Replace the select library and select symbol from library list dialogs
which where redundant with the symbol search dialog used in place symbol
tool in the schematic editor.  This gives the user type ahead search and
selects the library and symbol in one dialog.

Move updating toolbar buttons from the ReCreateHToolbar() function into
dedicated wxUpdateUIEvents.

Break Process_Special_Functions() into individual event handlers.

Remove PART_LIB::GetNextEntry() and PART_LIB::GetPreviousEntry() as they
are no longer required due to the changes to the symbol library viewer.

Purge wxT() macros from all modified source files.
2016-10-21 08:39:18 -04:00

1059 lines
27 KiB
C++

/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2004-2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2008-2015 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2004-2016 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file class_library.cpp
*/
#include <fctsys.h>
#include <kiface_i.h>
#include <gr_basic.h>
#include <macros.h>
#include <kicad_string.h>
#include <gestfich.h>
#include <eda_doc.h>
#include <wxstruct.h>
#include <richio.h>
#include <config_params.h>
#include <wildcards_and_files_ext.h>
#include <project_rescue.h>
#include <general.h>
#include <class_library.h>
#include <sch_legacy_plugin.h>
#include <wx/tokenzr.h>
#include <wx/regex.h>
#define DUPLICATE_NAME_MSG \
_( "Library '%s' has duplicate entry name '%s'.\n" \
"This may cause some unexpected behavior when loading components into a schematic." )
PART_LIB::PART_LIB( int aType, const wxString& aFileName ) :
// start @ != 0 so each additional library added
// is immediately detectable, zero would not be.
m_mod_hash( PART_LIBS::s_modify_generation )
{
type = aType;
isModified = false;
timeStamp = 0;
isCache = false;
timeStamp = wxDateTime::Now();
versionMajor = 0; // Will be updated after reading the lib file
versionMinor = 0; // Will be updated after reading the lib file
fileName = aFileName;
if( !fileName.IsOk() )
fileName = wxT( "unnamed.lib" );
}
PART_LIB::~PART_LIB()
{
// When the library is destroyed, all of the alias objects on the heap should be deleted.
for( LIB_ALIAS_MAP::iterator it = m_amap.begin(); it != m_amap.end(); ++it )
{
wxLogTrace( traceSchLibMem, wxT( "Removing alias %s from library %s." ),
GetChars( it->second->GetName() ), GetChars( GetLogicalName() ) );
LIB_PART* part = it->second->GetPart();
LIB_ALIAS* alias = it->second;
delete alias;
// When the last alias of a part is destroyed, the part is no longer required and it
// too is destroyed.
if( part && part->GetAliasCount() == 0 )
delete part;
}
m_amap.clear();
}
void PART_LIB::GetAliasNames( wxArrayString& aNames )
{
for( LIB_ALIAS_MAP::iterator it = m_amap.begin(); it!=m_amap.end(); it++ )
{
aNames.Add( (*it).first );
}
aNames.Sort();
}
void PART_LIB::GetEntryTypePowerNames( wxArrayString& aNames )
{
for( LIB_ALIAS_MAP::iterator it = m_amap.begin(); it!=m_amap.end(); it++ )
{
LIB_ALIAS* alias = it->second;
LIB_PART* root = alias->GetPart();
if( !root || !root->IsPower() )
continue;
aNames.Add( (*it).first );
}
aNames.Sort();
}
bool PART_LIB::Conflicts( LIB_PART* aPart )
{
wxCHECK_MSG( aPart != NULL, false,
wxT( "Cannot test NULL component for conflicts in library " ) + GetName() );
for( size_t i=0; i<aPart->m_aliases.size(); i++ )
{
LIB_ALIAS_MAP::iterator it = m_amap.find( aPart->m_aliases[i]->GetName() );
if( it != m_amap.end() )
return true;
}
return false;
}
LIB_ALIAS* PART_LIB::FindAlias( const wxString& aName )
{
LIB_ALIAS_MAP::iterator it = m_amap.find( aName );
if( it != m_amap.end() )
return it->second;
return NULL;
}
LIB_PART* PART_LIB::FindPart( const wxString& aName )
{
#if 0 && defined(DEBUG)
if( !aName.Cmp( wxT( "TI_STELLARIS_BOOSTERPACK" ) ) )
{
int breakhere = 1;
(void) breakhere;
}
#endif
if( LIB_ALIAS* alias = FindAlias( aName ) )
{
return alias->GetPart();
}
return NULL;
}
bool PART_LIB::HasPowerParts()
{
// return true if at least one power part is found in lib
for( LIB_ALIAS_MAP::iterator it = m_amap.begin(); it!=m_amap.end(); it++ )
{
LIB_ALIAS* alias = it->second;
LIB_PART* root = alias->GetPart();
if( root && root->IsPower() )
return true;
}
return false;
}
bool PART_LIB::AddAlias( LIB_ALIAS* aAlias )
{
wxASSERT( aAlias );
#if defined(DEBUG) && 0
if( !aAlias->GetName().Cmp( wxT( "TI_STELLARIS_BOOSTERPACK" ) ) )
{
int breakhere = 1;
(void) breakhere;
}
#endif
LIB_ALIAS_MAP::iterator it = m_amap.find( aAlias->GetName() );
if( it != m_amap.end() )
{
wxString msg;
msg.Printf( _( "Cannot add duplicate alias '%s' to library '%s'." ),
GetChars( aAlias->GetName() ),
GetChars( fileName.GetName() ) );
return false;
}
wxString name = aAlias->GetName();
m_amap[ name ] = aAlias;
isModified = true;
++m_mod_hash;
return true;
}
bool PART_LIB::AddPart( LIB_PART* aPart )
{
// Conflict detection: See if already existing aliases exist,
// and if yes, ask user for continue or abort
// Special case: if the library is the library cache of the project,
// old aliases are always removed to avoid conflict,
// and user is not prompted )
if( Conflicts( aPart ) && !IsCache() )
{
wxFAIL_MSG( wxT( "Cannot add component <" ) + aPart->GetName() +
wxT( "> to library <" ) + GetName() + wxT( "> due to name conflict." ) );
return false;
}
// add a clone, not the caller's copy
LIB_PART* my_part = new LIB_PART( *aPart );
for( size_t i = 0; i < my_part->m_aliases.size(); i++ )
{
wxString aliasname = my_part->m_aliases[i]->GetName();
if( LIB_ALIAS* alias = FindAlias( aliasname ) )
RemoveAlias( alias );
m_amap[ aliasname ] = my_part->m_aliases[i];
}
isModified = true;
++m_mod_hash;
return true;
}
LIB_ALIAS* PART_LIB::RemoveAlias( LIB_ALIAS* aEntry )
{
wxCHECK_MSG( aEntry != NULL, NULL, wxT( "NULL pointer cannot be removed from library." ) );
LIB_ALIAS_MAP::iterator it = m_amap.find( aEntry->GetName() );
if( it == m_amap.end() )
return NULL;
// If the entry pointer doesn't match the name it is mapped to in the library, we
// have done something terribly wrong.
wxCHECK_MSG( *it->second == aEntry, NULL,
wxT( "Pointer mismatch while attempting to remove entry <" ) +
aEntry->GetName() + wxT( "> from library <" ) + GetName() + wxT( ">." ) );
LIB_ALIAS* alias = aEntry;
LIB_PART* part = alias->GetPart();
alias = part->RemoveAlias( alias );
if( !alias )
{
delete part;
if( m_amap.size() > 1 )
{
LIB_ALIAS_MAP::iterator next = it;
next++;
if( next == m_amap.end() )
next = m_amap.begin();
alias = next->second;
}
}
m_amap.erase( it );
isModified = true;
++m_mod_hash;
return alias;
}
LIB_PART* PART_LIB::ReplacePart( LIB_PART* aOldPart, LIB_PART* aNewPart )
{
wxASSERT( aOldPart != NULL );
wxASSERT( aNewPart != NULL );
/* Remove the old root component. The component will automatically be deleted
* when all it's aliases are deleted. Do not place any code that accesses
* aOldPart inside this loop that gets evaluated after the last alias is
* removed in RemoveAlias(). Failure to heed this warning will result in a
* segfault.
*/
size_t i = aOldPart->m_aliases.size();
while( i > 0 )
{
i -= 1;
RemoveAlias( aOldPart->m_aliases[ i ] );
}
LIB_PART* my_part = new LIB_PART( *aNewPart, this );
// Add new aliases to library alias map.
for( i = 0; i < my_part->m_aliases.size(); i++ )
{
wxString aname = my_part->m_aliases[ i ]->GetName();
m_amap[ aname ] = my_part->m_aliases[ i ];
}
isModified = true;
++m_mod_hash;
return my_part;
}
bool PART_LIB::Load( wxString& aErrorMsg )
{
if( fileName.GetFullPath().IsEmpty() )
{
aErrorMsg = _( "The component library file name is not set." );
return false;
}
FILE* file = wxFopen( fileName.GetFullPath(), wxT( "rt" ) );
if( file == NULL )
{
aErrorMsg = _( "The file could not be opened." );
return false;
}
FILE_LINE_READER reader( file, fileName.GetFullPath() );
if( !reader.ReadLine() )
{
aErrorMsg = _( "The file is empty!" );
return false;
}
// There is no header if this is a symbol library.
if( type == LIBRARY_TYPE_EESCHEMA )
{
char* line = reader.Line();
header = FROM_UTF8( line );
wxStringTokenizer tkn( header );
/*
* The file header (first line) in library versions 2.0 and lower
* apparently started with EESchema-LIB. Sometime after 2.0, it
* was changed to EESchema-LIBRARY. Therefore, the test for
* EESchema-LIB will work in both cases. Don't change this unless
* backwards compatibility is no longer required.
*/
if( !tkn.HasMoreTokens()
|| !tkn.GetNextToken().Upper().StartsWith(wxT( "EESCHEMA-LIB" ) ) )
{
aErrorMsg = _( "The file is NOT an Eeschema library!" );
return false;
}
if( !tkn.HasMoreTokens() )
{
aErrorMsg = _( "The file header is missing version and time stamp information." );
return false;
}
if( tkn.GetNextToken() != wxT( "Version" ) || !tkn.HasMoreTokens() )
{
aErrorMsg = wxT( "The file header version information is invalid." );
return false;
}
long major, minor;
wxStringTokenizer vers( tkn.GetNextToken(), wxT( "." ) );
if( !vers.HasMoreTokens() || !vers.GetNextToken().ToLong( &major )
|| major < 1L || !vers.HasMoreTokens()
|| !vers.GetNextToken().ToLong( & minor ) || minor < 0L
|| minor > 99 )
{
#if 0 // Note for developers:
// Not sure this warning is very useful: old designs *must* be always loadable
wxLogWarning( wxT(
"The component library '%s' header version "
"number is invalid.\n\nIn future versions of Eeschema this library may not "
"load correctly. To resolve this problem open the library in the library "
"editor and save it. If this library is the project cache library, save "
"the current schematic." ),
GetChars( GetName() ) );
#endif
}
else
{
versionMajor = (int) major;
versionMinor = (int) minor;
}
}
while( reader.ReadLine() )
{
char * line = reader.Line();
if( type == LIBRARY_TYPE_EESCHEMA && strncasecmp( line, "$HEADER", 7 ) == 0 )
{
if( !LoadHeader( reader ) )
{
aErrorMsg = _( "An error occurred attempting to read the header." );
return false;
}
continue;
}
wxString msg;
if( strncasecmp( line, "DEF", 3 ) == 0 )
{
// Read one DEF/ENDDEF part entry from library:
LIB_PART* part = new LIB_PART( wxEmptyString, this );
if( part->Load( reader, msg ) )
{
// Check for duplicate entry names and warn the user about
// the potential conflict.
if( FindAlias( part->GetName() ) != NULL )
{
wxLogWarning( DUPLICATE_NAME_MSG,
GetChars( fileName.GetName() ),
GetChars( part->GetName() ) );
}
LoadAliases( part );
}
else
{
wxLogWarning( _( "Library '%s' component load error %s." ),
GetChars( fileName.GetName() ),
GetChars( msg ) );
msg.Clear();
delete part;
}
}
}
++m_mod_hash;
return true;
}
void PART_LIB::LoadAliases( LIB_PART* aPart )
{
wxCHECK_RET( aPart, wxT( "Cannot load aliases of NULL part. Bad programmer!" ) );
for( size_t i = 0; i < aPart->m_aliases.size(); i++ )
{
if( FindAlias( aPart->m_aliases[i]->GetName() ) != NULL )
{
wxLogError( DUPLICATE_NAME_MSG,
GetChars( fileName.GetName() ),
GetChars( aPart->m_aliases[i]->GetName() ) );
}
wxString aname = aPart->m_aliases[i]->GetName();
m_amap[ aname ] = aPart->m_aliases[i];
}
}
bool PART_LIB::LoadHeader( LINE_READER& aLineReader )
{
char* line, * text, * data;
while( aLineReader.ReadLine() )
{
line = (char*) aLineReader;
text = strtok( line, " \t\r\n" );
data = strtok( NULL, " \t\r\n" );
if( strcasecmp( text, "TimeStamp" ) == 0 )
timeStamp = atol( data );
if( strcasecmp( text, "$ENDHEADER" ) == 0 )
return true;
}
return false;
}
bool PART_LIB::LoadDocs( wxString& aErrorMsg )
{
int lineNumber = 0;
char line[8000], * name, * text;
LIB_ALIAS* entry;
FILE* file;
wxFileName fn = fileName;
fn.SetExt( DOC_EXT );
file = wxFopen( fn.GetFullPath(), wxT( "rt" ) );
if( file == NULL )
{
aErrorMsg.Printf( _( "Could not open component document library file '%s'." ),
GetChars( fn.GetFullPath() ) );
return false;
}
if( GetLine( file, line, &lineNumber, sizeof(line) ) == NULL )
{
aErrorMsg.Printf( _( "Part document library file '%s' is empty." ),
GetChars( fn.GetFullPath() ) );
fclose( file );
return false;
}
if( strncasecmp( line, DOCFILE_IDENT, 10 ) != 0 )
{
aErrorMsg.Printf( _( "File '%s' is not a valid component library document file." ),
GetChars( fn.GetFullPath() ) );
fclose( file );
return false;
}
while( GetLine( file, line, &lineNumber, sizeof(line) ) )
{
if( strncmp( line, "$CMP", 4 ) != 0 )
{
aErrorMsg.Printf( wxT( "$CMP command expected in line %d, aborted." ), lineNumber );
fclose( file );
return false;
}
// Read one $CMP/$ENDCMP part entry from library:
name = strtok( line + 5, "\n\r" );
wxString cmpname = FROM_UTF8( name );
entry = FindAlias( cmpname );
while( GetLine( file, line, &lineNumber, sizeof(line) ) )
{
if( strncmp( line, "$ENDCMP", 7 ) == 0 )
break;
text = strtok( line + 2, "\n\r" );
if( entry )
{
switch( line[0] )
{
case 'D':
entry->SetDescription( FROM_UTF8( text ) );
break;
case 'K':
entry->SetKeyWords( FROM_UTF8( text ) );
break;
case 'F':
entry->SetDocFileName( FROM_UTF8( text ) );
break;
}
}
}
}
fclose( file );
return true;
}
bool PART_LIB::Save( OUTPUTFORMATTER& aFormatter )
{
if( isModified )
{
timeStamp = GetNewTimeStamp();
isModified = false;
}
bool success = true;
try
{
SaveHeader( aFormatter );
for( LIB_ALIAS_MAP::iterator it=m_amap.begin(); it!=m_amap.end(); it++ )
{
if( !it->second->IsRoot() )
continue;
it->second->GetPart()->Save( aFormatter );
}
aFormatter.Print( 0, "#\n#End Library\n" );
}
catch( const IO_ERROR& )
{
success = false;
}
return success;
}
bool PART_LIB::SaveDocs( OUTPUTFORMATTER& aFormatter )
{
bool success = true;
try
{
aFormatter.Print( 0, "%s\n", DOCFILE_IDENT );
for( LIB_ALIAS_MAP::iterator it=m_amap.begin(); it!=m_amap.end(); it++ )
{
if( !it->second->SaveDoc( aFormatter ) )
success = false;
}
aFormatter.Print( 0, "#\n#End Doc Library\n" );
}
catch( const IO_ERROR& )
{
success = false;
}
return success;
}
bool PART_LIB::SaveHeader( OUTPUTFORMATTER& aFormatter )
{
aFormatter.Print( 0, "%s %d.%d\n", LIBFILE_IDENT,
LIB_VERSION_MAJOR, LIB_VERSION_MINOR );
aFormatter.Print( 0, "#encoding utf-8\n");
#if 0
aFormatter.Print( 0, "$HEADER\n" );
aFormatter.Print( 0, "TimeStamp %8.8lX\n", m_TimeStamp );
aFormatter.Print( 0, "Parts %d\n", m_amap.size() );
aFormatter.Print( 0, "$ENDHEADER\n" ) != 1 );
#endif
return true;
}
PART_LIB* PART_LIB::LoadLibrary( const wxString& aFileName ) throw( IO_ERROR, boost::bad_pointer )
{
std::unique_ptr<PART_LIB> lib( new PART_LIB( LIBRARY_TYPE_EESCHEMA, aFileName ) );
wxBusyCursor ShowWait; // Do we want UI elements in PART_LIB?
wxString errorMsg;
#ifdef KICAD_USE_SCH_IO_MANAGER
SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_LEGACY ) );
wxArrayString tmp;
pi->EnumerateSymbolLib( tmp, aFileName );
pi->TransferCache( *lib.get() );
#else
if( !lib->Load( errorMsg ) )
THROW_IO_ERROR( errorMsg );
if( USE_OLD_DOC_FILE_FORMAT( lib->versionMajor, lib->versionMinor ) )
{
#if 1
// not fatal if error here.
lib->LoadDocs( errorMsg );
#else
if( !lib->LoadDocs( errorMsg ) )
THROW_IO_ERROR( errorMsg );
#endif
}
#endif
PART_LIB* ret = lib.release();
return ret;
}
PART_LIB* PART_LIBS::AddLibrary( const wxString& aFileName ) throw( IO_ERROR, boost::bad_pointer )
{
PART_LIB* lib;
#if 1
wxFileName fn = aFileName;
// Don't reload the library if it is already loaded.
lib = FindLibrary( fn.GetName() );
if( lib )
return lib;
#endif
lib = PART_LIB::LoadLibrary( aFileName );
push_back( lib );
return lib;
}
PART_LIB* PART_LIBS::AddLibrary( const wxString& aFileName, PART_LIBS::iterator& aIterator )
throw( IO_ERROR, boost::bad_pointer )
{
#if 1
// Don't reload the library if it is already loaded.
wxFileName fn( aFileName );
PART_LIB* lib = FindLibrary( fn.GetName() );
if( lib )
return lib;
#endif
lib = PART_LIB::LoadLibrary( aFileName );
if( aIterator >= begin() && aIterator < end() )
insert( aIterator, lib );
else
push_back( lib );
return lib;
}
void PART_LIBS::RemoveLibrary( const wxString& aName )
{
if( aName.IsEmpty() )
return;
for( PART_LIBS::iterator it = begin(); it < end(); ++it )
{
if( it->GetName().CmpNoCase( aName ) == 0 )
{
erase( it );
return;
}
}
}
PART_LIB* PART_LIBS::FindLibrary( const wxString& aName )
{
for( PART_LIBS::iterator it = begin(); it!=end(); ++it )
{
if( it->GetName() == aName )
return &*it;
}
return NULL;
}
wxArrayString PART_LIBS::GetLibraryNames( bool aSorted )
{
wxArrayString cacheNames;
wxArrayString names;
for( PART_LIB& lib : *this )
{
if( lib.IsCache() && aSorted )
cacheNames.Add( lib.GetName() );
else
names.Add( lib.GetName() );
}
// Even sorted, the cache library is always at the end of the list.
if( aSorted )
names.Sort();
for( unsigned int i = 0; i<cacheNames.Count(); i++ )
names.Add( cacheNames.Item( i ) );
return names;
}
LIB_PART* PART_LIBS::FindLibPart( const wxString& aPartName, const wxString& aLibraryName )
{
LIB_PART* part = NULL;
for( PART_LIB& lib : *this )
{
if( !aLibraryName.IsEmpty() && lib.GetName() != aLibraryName )
continue;
part = lib.FindPart( aPartName );
if( part )
break;
}
return part;
}
LIB_ALIAS* PART_LIBS::FindLibraryAlias( const wxString& aEntryName, const wxString& aLibraryName )
{
LIB_ALIAS* entry = NULL;
for( PART_LIB& lib : *this )
{
if( !!aLibraryName && lib.GetName() != aLibraryName )
continue;
entry = lib.FindAlias( aEntryName );
if( entry )
break;
}
return entry;
}
/* searches all libraries in the list for an entry, using a case insensitive comparison.
* Used to find an entry, when the normal (case sensitive) search fails.
*/
void PART_LIBS::FindLibraryNearEntries( std::vector<LIB_ALIAS*>& aCandidates,
const wxString& aEntryName,
const wxString& aLibraryName )
{
for( PART_LIB& lib : *this )
{
if( !!aLibraryName && lib.GetName() != aLibraryName )
continue;
wxArrayString aliasNames;
lib.GetAliasNames( aliasNames );
if( aliasNames.IsEmpty() )
continue;
for( size_t i = 0; i < aliasNames.size(); i++ )
{
if( aliasNames[i].CmpNoCase( aEntryName ) == 0 )
aCandidates.push_back( lib.FindAlias( aliasNames[i] ) );
}
}
}
int PART_LIBS::s_modify_generation = 1; // starts at 1 and goes up
int PART_LIBS::GetModifyHash()
{
int hash = 0;
for( PART_LIBS::const_iterator it = begin(); it != end(); ++it )
{
hash += it->m_mod_hash;
}
return hash;
}
void PART_LIBS::LibNamesAndPaths( PROJECT* aProject, bool doSave,
wxString* aPaths, wxArrayString* aNames )
throw( IO_ERROR, boost::bad_pointer )
{
wxString pro = aProject->GetProjectFullName();
PARAM_CFG_ARRAY ca;
if( aPaths )
ca.push_back( new PARAM_CFG_FILENAME( wxT( "LibDir" ), aPaths ) );
if( aNames )
ca.push_back( new PARAM_CFG_LIBNAME_LIST( wxT( "LibName" ), aNames, GROUP_SCH_LIBS ) );
if( doSave )
{
aProject->ConfigSave( Kiface().KifaceSearch(), GROUP_SCH, ca );
/*
{
wxString msg = wxString::Format( _(
"Unable save project's '%s' file" ),
GetChars( pro )
);
THROW_IO_ERROR( msg );
}
*/
}
else
{
if( !aProject->ConfigLoad( Kiface().KifaceSearch(), GROUP_SCH, ca ) )
{
wxString msg = wxString::Format( _(
"Unable to load project's '%s' file" ),
GetChars( pro )
);
THROW_IO_ERROR( msg );
}
}
}
const wxString PART_LIBS::CacheName( const wxString& aFullProjectFilename )
{
/* until apr 2009 the project cache lib was named: <root_name>.cache.lib,
* and after: <root_name>-cache.lib. So if the <name>-cache.lib is not found,
* the old file will be renamed and returned.
*/
wxFileName new_name = aFullProjectFilename;
new_name.SetName( new_name.GetName() + wxT( "-cache" ) );
new_name.SetExt( SchematicLibraryFileExtension );
if( new_name.FileExists() )
return new_name.GetFullPath();
else
{
wxFileName old_name = aFullProjectFilename;
old_name.SetExt( wxT( "cache.lib" ) );
if( old_name.FileExists() )
{
wxRenameFile( old_name.GetFullPath(), new_name.GetFullPath() );
return new_name.GetFullPath();
}
}
return wxEmptyString;
}
void PART_LIBS::LoadAllLibraries( PROJECT* aProject ) throw( IO_ERROR, boost::bad_pointer )
{
wxFileName fn;
wxString filename;
wxString libs_not_found;
SEARCH_STACK* lib_search = aProject->SchSearchS();
#if defined(DEBUG) && 1
lib_search->Show( __func__ );
#endif
wxArrayString lib_names;
LibNamesAndPaths( aProject, false, NULL, &lib_names );
// If the list is empty, force loading the standard power symbol library.
if( !lib_names.GetCount() )
lib_names.Add( wxT( "power" ) );
wxASSERT( !size() ); // expect to load into "this" empty container.
for( unsigned i = 0; i < lib_names.GetCount(); ++i )
{
fn.Clear();
fn.SetName( lib_names[i] );
fn.SetExt( SchematicLibraryFileExtension );
// Skip if the file name is not valid..
if( !fn.IsOk() )
continue;
if( !fn.FileExists() )
{
filename = lib_search->FindValidPath( fn.GetFullPath() );
if( !filename )
{
libs_not_found += fn.GetName();
libs_not_found += wxT( '\n' );
continue;
}
}
else
{
filename = fn.GetFullPath();
}
try
{
AddLibrary( filename );
}
catch( const IO_ERROR& ioe )
{
wxString msg = wxString::Format( _(
"Part library '%s' failed to load. Error:\n"
"%s" ),
GetChars( filename ),
GetChars( ioe.What() )
);
wxLogError( msg );
}
}
// add the special cache library.
wxString cache_name = CacheName( aProject->GetProjectFullName() );
PART_LIB* cache_lib;
if( !!cache_name )
{
try
{
cache_lib = AddLibrary( cache_name );
if( cache_lib )
cache_lib->SetCache();
}
catch( const IO_ERROR& ioe )
{
wxString msg = wxString::Format( _(
"Part library '%s' failed to load.\nError: %s" ),
GetChars( cache_name ),
GetChars( ioe.What() )
);
THROW_IO_ERROR( msg );
}
}
// Print the libraries not found
if( !!libs_not_found )
{
// Use a different exception type so catch()er can route to proper use
// of the HTML_MESSAGE_BOX.
THROW_PARSE_ERROR( wxEmptyString, UTF8( __func__ ),
UTF8( libs_not_found ), 0, 0 );
}
#if defined(DEBUG) && 1
printf( "%s: lib_names:\n", __func__ );
for( PART_LIBS::const_iterator it = begin(); it < end(); ++it )
printf( " %s\n", TO_UTF8( it->GetName() ) );
#endif
}