Make the schematic I/O plugin the only option.

Add SCH_PLUGIN object to PART_LIB object.

Convert all PART_LIB I/O to use SCH_PLUGIN.

Remove library caching from PART_LIB and use caching provided by SCH_PLUGIN.

Add support to use PROPERTIES for buffering and document file write control
instead of adding code the SCH_PLUGIN object in the SCH_LEGACY_PLUGIN that
will not be required when the new file formats are implemented.

Add buffering to SCH_LEGACY_PLUGIN to prevent cache from writing file on
every change to library.  This is to prevent the cache library from being
written every time a new symbol is added.

Add option to not save library document file when saving library.  This is
primarily used by the cache library write code.

Move symbol library write code out of LIB_PART and into SCH_LEGACY_PLUGIN.

Add exception handling where LIB_PART caught the exception and returned
an error status.

Remove KICAD_SCH_IO_MANAGER build option as it is no longer optional.
This commit is contained in:
Wayne Stambaugh 2017-01-27 10:56:36 -05:00
parent 283ba553ba
commit 73bbc35c3e
17 changed files with 478 additions and 851 deletions

View File

@ -2,8 +2,8 @@
* This program source code file is part of KiCad, a free EDA CAD application. * 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) 2004-2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2008-2015 Wayne Stambaugh <stambaughw@verizon.net> * Copyright (C) 2008-2017 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2004-2016 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2004-2017 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License

View File

@ -2,8 +2,8 @@
* This program source code file is part of KiCad, a free EDA CAD application. * 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) 2004-2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2008-2016 Wayne Stambaugh <stambaughw@verizon.net> * Copyright (C) 2008-2017 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2004-2016 KiCad Developers, see change_log.txt for contributors. * Copyright (C) 2004-2017 KiCad Developers, see change_log.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -189,7 +189,7 @@ class LIB_PART : public EDA_ITEM
PART_SPTR m_me; ///< http://www.boost.org/doc/libs/1_55_0/libs/smart_ptr/sp_techniques.html#weak_without_shared PART_SPTR m_me; ///< http://www.boost.org/doc/libs/1_55_0/libs/smart_ptr/sp_techniques.html#weak_without_shared
wxString m_name; wxString m_name;
LIB_ID m_libId; LIB_ID m_libId;
int m_pinNameOffset; ///< The offset in mils to draw the pin name. Set to 0 int m_pinNameOffset; ///< The offset in mils to draw the pin name. Set to 0
///< to draw the pin name above the pin. ///< to draw the pin name above the pin.
bool m_unitsLocked; ///< True if part has multiple units and changing bool m_unitsLocked; ///< True if part has multiple units and changing
@ -237,7 +237,7 @@ public:
virtual void SetName( const wxString& aName ); virtual void SetName( const wxString& aName );
const wxString& GetName() { return m_name; } const wxString& GetName() const { return m_name; }
const LIB_ID& GetLibId() const { return m_libId; } const LIB_ID& GetLibId() const { return m_libId; }
void SetLibId( const LIB_ID& aLibId ) { m_libId = aLibId; } void SetLibId( const LIB_ID& aLibId ) { m_libId = aLibId; }

View File

@ -2,8 +2,8 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2004-2016 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2004-2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2008-2016 Wayne Stambaugh <stambaughw@verizon.net> * Copyright (C) 2008-2017 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2004-2016 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2004-2017 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -39,6 +39,7 @@
#include <config_params.h> #include <config_params.h>
#include <wildcards_and_files_ext.h> #include <wildcards_and_files_ext.h>
#include <project_rescue.h> #include <project_rescue.h>
#include <properties.h>
#include <general.h> #include <general.h>
#include <class_library.h> #include <class_library.h>
@ -53,10 +54,11 @@
"This may cause some unexpected behavior when loading components into a schematic." ) "This may cause some unexpected behavior when loading components into a schematic." )
PART_LIB::PART_LIB( int aType, const wxString& aFileName ) : PART_LIB::PART_LIB( int aType, const wxString& aFileName, SCH_IO_MGR::SCH_FILE_T aPluginType ) :
// start @ != 0 so each additional library added // start @ != 0 so each additional library added
// is immediately detectable, zero would not be. // is immediately detectable, zero would not be.
m_mod_hash( PART_LIBS::s_modify_generation ) m_mod_hash( PART_LIBS::s_modify_generation ),
m_pluginType( aPluginType )
{ {
type = aType; type = aType;
isModified = false; isModified = false;
@ -65,41 +67,71 @@ PART_LIB::PART_LIB( int aType, const wxString& aFileName ) :
timeStamp = wxDateTime::Now(); timeStamp = wxDateTime::Now();
versionMajor = 0; // Will be updated after reading the lib file versionMajor = 0; // Will be updated after reading the lib file
versionMinor = 0; // Will be updated after reading the lib file versionMinor = 0; // Will be updated after reading the lib file
m_buffering = false;
fileName = aFileName; fileName = aFileName;
if( !fileName.IsOk() ) if( !fileName.IsOk() )
fileName = "unnamed.lib"; fileName = "unnamed.lib";
m_plugin.reset( SCH_IO_MGR::FindPlugin( m_pluginType ) );
} }
PART_LIB::~PART_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, "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. void PART_LIB::Save( bool aSaveDocFile )
if( part && part->GetAliasCount() == 0 ) {
delete part; wxCHECK_RET( m_plugin != NULL, wxString::Format( "no plugin defined for library `%s`.",
fileName.GetFullPath() ) );
std::unique_ptr< PROPERTIES > props;
if( !aSaveDocFile )
{
props.reset( new PROPERTIES );
(*props.get())[ SCH_LEGACY_PLUGIN::PropNoDocFile ] = "";
} }
m_amap.clear(); m_plugin->SaveLibrary( fileName.GetFullPath(), props.get() );
}
void PART_LIB::Create( const wxString& aFileName )
{
std::unique_ptr< PROPERTIES > props;
if( isCache )
{
props.reset( new PROPERTIES );
(*props.get())[ SCH_LEGACY_PLUGIN::PropNoDocFile ] = "";
}
wxString tmpFileName = fileName.GetFullPath();
if( !aFileName.IsEmpty() )
tmpFileName = aFileName;
m_plugin->CreateSymbolLib( tmpFileName, props.get() );
}
void PART_LIB::SetPluginType( SCH_IO_MGR::SCH_FILE_T aPluginType )
{
if( m_pluginType != aPluginType )
{
m_pluginType = aPluginType;
m_plugin.reset( SCH_IO_MGR::FindPlugin( m_pluginType ) );
}
} }
void PART_LIB::GetAliasNames( wxArrayString& aNames ) void PART_LIB::GetAliasNames( wxArrayString& aNames )
{ {
for( LIB_ALIAS_MAP::iterator it = m_amap.begin(); it!=m_amap.end(); it++ ) m_plugin->EnumerateSymbolLib( aNames, fileName.GetFullPath() );
{
aNames.Add( (*it).first );
}
aNames.Sort(); aNames.Sort();
} }
@ -107,15 +139,24 @@ void PART_LIB::GetAliasNames( wxArrayString& aNames )
void PART_LIB::GetEntryTypePowerNames( wxArrayString& aNames ) void PART_LIB::GetEntryTypePowerNames( wxArrayString& aNames )
{ {
for( LIB_ALIAS_MAP::iterator it = m_amap.begin(); it!=m_amap.end(); it++ ) wxArrayString aliases;
m_plugin->EnumerateSymbolLib( aliases, fileName.GetFullPath() );
for( size_t i = 0; i < aliases.GetCount(); i++ )
{ {
LIB_ALIAS* alias = it->second; LIB_ALIAS* alias = m_plugin->LoadSymbol( fileName.GetFullPath(), aliases[i] );
wxCHECK2_MSG( alias != NULL, continue,
wxString::Format( "alias '%s' not found in symbol library '%s'",
aliases[i], fileName.GetFullPath() ) );
LIB_PART* root = alias->GetPart(); LIB_PART* root = alias->GetPart();
if( !root || !root->IsPower() ) if( !root || !root->IsPower() )
continue; continue;
aNames.Add( (*it).first ); aNames.Add( aliases[i] );
} }
aNames.Sort(); aNames.Sort();
@ -124,29 +165,16 @@ void PART_LIB::GetEntryTypePowerNames( wxArrayString& aNames )
LIB_ALIAS* PART_LIB::FindAlias( const wxString& aName ) LIB_ALIAS* PART_LIB::FindAlias( const wxString& aName )
{ {
LIB_ALIAS_MAP::iterator it = m_amap.find( aName ); return m_plugin->LoadSymbol( fileName.GetFullPath(), aName );
if( it != m_amap.end() )
return it->second;
return NULL;
} }
LIB_PART* PART_LIB::FindPart( const wxString& aName ) LIB_PART* PART_LIB::FindPart( const wxString& aName )
{ {
#if 0 && defined(DEBUG) LIB_ALIAS* alias = FindAlias( aName );
if( !aName.Cmp( "TI_STELLARIS_BOOSTERPACK" ) )
{
int breakhere = 1;
(void) breakhere;
}
#endif
if( LIB_ALIAS* alias = FindAlias( aName ) ) if( alias != NULL )
{
return alias->GetPart(); return alias->GetPart();
}
return NULL; return NULL;
} }
@ -155,12 +183,21 @@ LIB_PART* PART_LIB::FindPart( const wxString& aName )
bool PART_LIB::HasPowerParts() bool PART_LIB::HasPowerParts()
{ {
// return true if at least one power part is found in lib // 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++ ) wxArrayString aliases;
m_plugin->EnumerateSymbolLib( aliases, fileName.GetFullPath() );
for( size_t i = 0; i < aliases.GetCount(); i++ )
{ {
LIB_ALIAS* alias = it->second; LIB_ALIAS* alias = m_plugin->LoadSymbol( fileName.GetFullPath(), aliases[i] );
wxCHECK2_MSG( alias != NULL, continue,
wxString::Format( "alias '%s' not found in symbol library '%s'",
aliases[i], fileName.GetFullPath() ) );
LIB_PART* root = alias->GetPart(); LIB_PART* root = alias->GetPart();
if( root && root->IsPower() ) if( !root || root->IsPower() )
return true; return true;
} }
@ -168,56 +205,29 @@ bool PART_LIB::HasPowerParts()
} }
bool PART_LIB::AddAlias( LIB_ALIAS* aAlias )
{
wxASSERT( aAlias );
#if defined(DEBUG) && 0
if( !aAlias->GetName().Cmp( "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;
}
void PART_LIB::AddPart( LIB_PART* aPart ) void PART_LIB::AddPart( LIB_PART* aPart )
{ {
// add a clone, not the caller's copy std::unique_ptr< PROPERTIES > props;
LIB_PART* my_part = new LIB_PART( *aPart );
for( size_t i = 0; i < my_part->m_aliases.size(); i++ ) if( isCache || m_buffering )
{ {
wxString aliasname = my_part->m_aliases[i]->GetName(); props.reset( new PROPERTIES );
if( LIB_ALIAS* alias = FindAlias( aliasname ) ) if( isCache )
RemoveAlias( alias ); (*props.get())[ SCH_LEGACY_PLUGIN::PropNoDocFile ] = "";
m_amap[ aliasname ] = my_part->m_aliases[i]; if( m_buffering )
(*props.get())[ SCH_LEGACY_PLUGIN::PropBuffering ] = "";
} }
isModified = true; // add a clone, not the caller's copy, the plugin take ownership of the new symbol.
m_plugin->SaveSymbol( fileName.GetFullPath(), new LIB_PART( *aPart, this ), props.get() );
// If we are not buffering, the library file is updated immediately when the plugin
// SaveSymbol() function is called.
if( m_buffering )
isModified = true;
++m_mod_hash; ++m_mod_hash;
} }
@ -226,42 +236,28 @@ LIB_ALIAS* PART_LIB::RemoveAlias( LIB_ALIAS* aEntry )
{ {
wxCHECK_MSG( aEntry != NULL, NULL, "NULL pointer cannot be removed from library." ); wxCHECK_MSG( aEntry != NULL, NULL, "NULL pointer cannot be removed from library." );
LIB_ALIAS_MAP::iterator it = m_amap.find( aEntry->GetName() ); std::unique_ptr< PROPERTIES > props;
if( it == m_amap.end() ) if( isCache || m_buffering )
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,
"Pointer mismatch while attempting to remove entry <" +
aEntry->GetName() + "> from library <" + GetName() + ">." );
LIB_ALIAS* alias = aEntry;
LIB_PART* part = alias->GetPart();
alias = part->RemoveAlias( alias );
if( !alias )
{ {
delete part; props.reset( new PROPERTIES );
if( m_amap.size() > 1 ) if( isCache )
{ (*props.get())[ SCH_LEGACY_PLUGIN::PropNoDocFile ] = "";
LIB_ALIAS_MAP::iterator next = it;
next++;
if( next == m_amap.end() ) if( m_buffering )
next = m_amap.begin(); (*props.get())[ SCH_LEGACY_PLUGIN::PropBuffering ] = "";
alias = next->second;
}
} }
m_amap.erase( it ); m_plugin->DeleteAlias( fileName.GetFullPath(), aEntry->GetName(), props.get() );
isModified = true;
// If we are not buffering, the library file is updated immediately when the plugin
// SaveSymbol() function is called.
if( m_buffering )
isModified = true;
++m_mod_hash; ++m_mod_hash;
return alias; return NULL;
} }
@ -270,402 +266,43 @@ LIB_PART* PART_LIB::ReplacePart( LIB_PART* aOldPart, LIB_PART* aNewPart )
wxASSERT( aOldPart != NULL ); wxASSERT( aOldPart != NULL );
wxASSERT( aNewPart != NULL ); wxASSERT( aNewPart != NULL );
/* Remove the old root component. The component will automatically be deleted std::unique_ptr< PROPERTIES > props;
* 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 ) if( isCache || m_buffering )
{ {
i -= 1; props.reset( new PROPERTIES );
RemoveAlias( aOldPart->m_aliases[ i ] );
if( isCache )
(*props.get())[ SCH_LEGACY_PLUGIN::PropNoDocFile ] = "";
if( m_buffering )
(*props.get())[ SCH_LEGACY_PLUGIN::PropBuffering ] = "";
} }
m_plugin->DeleteSymbol( fileName.GetFullPath(), aOldPart->GetName(), props.get() );
LIB_PART* my_part = new LIB_PART( *aNewPart, this ); LIB_PART* my_part = new LIB_PART( *aNewPart, this );
// Add new aliases to library alias map. m_plugin->SaveSymbol( fileName.GetFullPath(), my_part, props.get() );
for( i = 0; i < my_part->m_aliases.size(); i++ )
{ // If we are not buffering, the library file is updated immediately when the plugin
wxString aname = my_part->m_aliases[ i ]->GetName(); // SaveSymbol() function is called.
m_amap[ aname ] = my_part->m_aliases[ i ]; if( m_buffering )
} isModified = true;
isModified = true;
++m_mod_hash; ++m_mod_hash;
return my_part; 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(), "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( "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() != "Version" || !tkn.HasMoreTokens() )
{
aErrorMsg = "The file header version information is invalid.";
return false;
}
long major, minor;
wxStringTokenizer vers( tkn.GetNextToken(), "." );
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(
"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, "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(), "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( "$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 ) 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 ) ); 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; wxArrayString tmp;
pi->EnumerateSymbolLib( tmp, aFileName ); // This loads the library although we could probably do lazy loading.
pi->TransferCache( *lib.get() ); lib->GetCount();
#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(); PART_LIB* ret = lib.release();
@ -774,7 +411,7 @@ LIB_ALIAS* PART_LIBS::FindLibraryAlias( const wxString& aEntryName, const wxStri
for( PART_LIB& lib : *this ) for( PART_LIB& lib : *this )
{ {
if( !!aLibraryName && lib.GetName() != aLibraryName ) if( !aLibraryName.IsEmpty() && lib.GetName() != aLibraryName )
continue; continue;
entry = lib.FindAlias( aEntryName ); entry = lib.FindAlias( aEntryName );
@ -796,7 +433,7 @@ void PART_LIBS::FindLibraryNearEntries( std::vector<LIB_ALIAS*>& aCandidates,
{ {
for( PART_LIB& lib : *this ) for( PART_LIB& lib : *this )
{ {
if( !!aLibraryName && lib.GetName() != aLibraryName ) if( !aLibraryName.IsEmpty() && lib.GetName() != aLibraryName )
continue; continue;
wxArrayString aliasNames; wxArrayString aliasNames;
@ -824,7 +461,7 @@ int PART_LIBS::GetModifyHash()
for( PART_LIBS::const_iterator it = begin(); it != end(); ++it ) for( PART_LIBS::const_iterator it = begin(); it != end(); ++it )
{ {
hash += it->m_mod_hash; hash += it->GetModHash();
} }
return hash; return hash;
@ -907,7 +544,7 @@ void PART_LIBS::LoadAllLibraries( PROJECT* aProject, bool aShowProgress ) throw(
wxString libs_not_found; wxString libs_not_found;
SEARCH_STACK* lib_search = aProject->SchSearchS(); SEARCH_STACK* lib_search = aProject->SchSearchS();
#if defined(DEBUG) && 1 #if defined(DEBUG) && 0
lib_search->Show( __func__ ); lib_search->Show( __func__ );
#endif #endif
@ -977,9 +614,9 @@ void PART_LIBS::LoadAllLibraries( PROJECT* aProject, bool aShowProgress ) throw(
} }
catch( const IO_ERROR& ioe ) catch( const IO_ERROR& ioe )
{ {
wxString msg = wxString::Format( _( wxString msg;
"Part library '%s' failed to load. Error:\n %s" ), msg.Printf( _( "Part library '%s' failed to load. Error:\n %s" ),
GetChars( filename ), GetChars( ioe.What() ) ); GetChars( filename ), GetChars( ioe.What() ) );
wxLogError( msg ); wxLogError( msg );
} }
@ -994,7 +631,7 @@ void PART_LIBS::LoadAllLibraries( PROJECT* aProject, bool aShowProgress ) throw(
wxString cache_name = CacheName( aProject->GetProjectFullName() ); wxString cache_name = CacheName( aProject->GetProjectFullName() );
PART_LIB* cache_lib; PART_LIB* cache_lib;
if( !!cache_name ) if( !cache_name.IsEmpty() )
{ {
try try
{ {
@ -1016,15 +653,14 @@ void PART_LIBS::LoadAllLibraries( PROJECT* aProject, bool aShowProgress ) throw(
} }
// Print the libraries not found // Print the libraries not found
if( !!libs_not_found ) if( !libs_not_found.IsEmpty() )
{ {
// Use a different exception type so catch()er can route to proper use // Use a different exception type so catch()er can route to proper use
// of the HTML_MESSAGE_BOX. // of the HTML_MESSAGE_BOX.
THROW_PARSE_ERROR( wxEmptyString, UTF8( __func__ ), THROW_PARSE_ERROR( wxEmptyString, UTF8( __func__ ), UTF8( libs_not_found ), 0, 0 );
UTF8( libs_not_found ), 0, 0 );
} }
#if defined(DEBUG) && 1 #if defined(DEBUG) && 0
printf( "%s: lib_names:\n", __func__ ); printf( "%s: lib_names:\n", __func__ );
for( PART_LIBS::const_iterator it = begin(); it < end(); ++it ) for( PART_LIBS::const_iterator it = begin(); it < end(); ++it )

View File

@ -2,8 +2,8 @@
* This program source code file is part of KiCad, a free EDA CAD application. * 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) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2008-2016 Wayne Stambaugh <stambaughw@verizon.net> * Copyright (C) 2008-2017 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2004-2016 KiCad Developers, see change_log.txt for contributors. * Copyright (C) 2004-2017 KiCad Developers, see change_log.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -34,6 +34,7 @@
#include <wx/filename.h> #include <wx/filename.h>
#include <class_libentry.h> #include <class_libentry.h>
#include <sch_io_mgr.h>
#include <project.h> #include <project.h>
@ -42,8 +43,11 @@
class LINE_READER; class LINE_READER;
class OUTPUTFORMATTER; class OUTPUTFORMATTER;
class SCH_LEGACY_PLUGIN; class SCH_LEGACY_PLUGIN;
class SCH_PLUGIN;
#define DOC_EXT "dcm"
/* /*
* Part Library version and file header macros. * Part Library version and file header macros.
*/ */
@ -70,11 +74,6 @@ class SCH_LEGACY_PLUGIN;
#define USE_OLD_DOC_FILE_FORMAT( major, minor ) \ #define USE_OLD_DOC_FILE_FORMAT( major, minor ) \
( LIB_VERSION( major, minor ) <= LIB_VERSION( 2, 3 ) ) ( LIB_VERSION( major, minor ) <= LIB_VERSION( 2, 3 ) )
/* Must be the first line of part library document (.dcm) files. */
#define DOCFILE_IDENT "EESchema-DOCLIB Version 2.0"
#define DOC_EXT "dcm"
// Helper class to filter a list of libraries, and/or a list of PART_LIB // Helper class to filter a list of libraries, and/or a list of PART_LIB
// in dialogs // in dialogs
class SCHLIB_FILTER class SCHLIB_FILTER
@ -331,52 +330,27 @@ class PART_LIB
True for the library cache */ True for the library cache */
wxString header; ///< first line of loaded library. wxString header; ///< first line of loaded library.
bool isModified; ///< Library modification status. bool isModified; ///< Library modification status.
LIB_ALIAS_MAP m_amap; ///< Map of alias objects associated with the library.
int m_mod_hash; ///< incremented each time library is changed. int m_mod_hash; ///< incremented each time library is changed.
bool m_buffering; ///< Set to true to prevent file write on every change.
friend class LIB_PART; SCH_IO_MGR::SCH_FILE_T m_pluginType;
friend class PART_LIBS; std::unique_ptr< SCH_PLUGIN > m_plugin;
friend class SCH_LEGACY_PLUGIN;
public: public:
PART_LIB( int aType, const wxString& aFileName ); PART_LIB( int aType, const wxString& aFileName,
SCH_IO_MGR::SCH_FILE_T aPluginType = SCH_IO_MGR::SCH_LEGACY );
~PART_LIB(); ~PART_LIB();
/** int GetModHash() const { return m_mod_hash; }
* Function Save
* writes library to \a aFormatter.
*
* @param aFormatter An #OUTPUTFORMATTER object to write the library to.
* @return True if success writing to \a aFormatter.
*/
bool Save( OUTPUTFORMATTER& aFormatter );
/** SCH_IO_MGR::SCH_FILE_T GetPluginType() const { return m_pluginType; }
* Function SaveDocs
* write the library document information to \a aFormatter.
*
* @param aFormatter An #OUTPUTFORMATTER object to write the library documentation to.
* @return True if success writing to \a aFormatter.
*/
bool SaveDocs( OUTPUTFORMATTER& aFormatter );
/** void SetPluginType( SCH_IO_MGR::SCH_FILE_T aPluginType );
* Load library from file.
*
* @param aErrorMsg - Error message if load fails.
* @return True if load was successful otherwise false.
*/
bool Load( wxString& aErrorMsg );
bool LoadDocs( wxString& aErrorMsg ); void Create( const wxString& aFileName = wxEmptyString );
private: void SetFileName( const wxString& aFileName ) { fileName = aFileName; }
bool SaveHeader( OUTPUTFORMATTER& aFormatter );
bool LoadHeader( LINE_READER& aLineReader );
void LoadAliases( LIB_PART* aPart );
public:
/** /**
* Get library entry status. * Get library entry status.
* *
@ -384,7 +358,7 @@ public:
*/ */
bool IsEmpty() const bool IsEmpty() const
{ {
return m_amap.empty(); return m_plugin->GetSymbolLibCount( fileName.GetFullPath() ) == 0;
} }
/** /**
@ -395,7 +369,7 @@ public:
*/ */
int GetCount() const int GetCount() const
{ {
return m_amap.size(); return (int) m_plugin->GetSymbolLibCount( fileName.GetFullPath() );
} }
bool IsModified() const bool IsModified() const
@ -407,6 +381,10 @@ public:
void SetCache( void ) { isCache = true; } void SetCache( void ) { isCache = true; }
void EnableBuffering( bool aEnable = true ) { m_buffering = aEnable; }
void Save( bool aSaveDocFile = true );
/** /**
* Function IsReadOnly * Function IsReadOnly
* @return true if current user does not have write access to the library file. * @return true if current user does not have write access to the library file.
@ -446,20 +424,6 @@ public:
*/ */
LIB_PART* FindPart( const wxString& aName ); LIB_PART* FindPart( const wxString& aName );
/**
* Add a new \a aAlias entry to the library.
*
* First check if a part or alias with the same name already exists
* in the library and add alias if no conflict occurs. Once the alias
* is added to the library it is owned by the library. Deleting the
* alias pointer will render the library unstable. Use RemoveEntry to
* remove the alias from the library.
*
* @param aAlias - Alias to add to library.
* @return True if alias added to library. False if a conflict exists.
*/
bool AddAlias( LIB_ALIAS* aAlias );
/** /**
* Add \a aPart entry to library. * Add \a aPart entry to library.
* *

View File

@ -2,9 +2,9 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2013-2016 Wayne Stambaugh <stambaughw@verizon.net> * Copyright (C) 2013-2017 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2013 CERN (www.cern.ch) * Copyright (C) 2013 CERN (www.cern.ch)
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -110,39 +110,24 @@ bool SCH_EDIT_FRAME::SaveEEFile( SCH_SCREEN* aScreen, bool aSaveUnderNewName,
wxLogTrace( traceAutoSave, wxLogTrace( traceAutoSave,
wxT( "Saving file <" ) + schematicFileName.GetFullPath() + wxT( ">" ) ); wxT( "Saving file <" ) + schematicFileName.GetFullPath() + wxT( ">" ) );
#ifdef KICAD_USE_SCH_IO_MANAGER SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_LEGACY ) );
SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_LEGACY ) );
try try
{
pi->Save( schematicFileName.GetFullPath(), aScreen, &Kiway() );
success = true;
}
catch( const IO_ERROR& ioe )
{
msg.Printf( _( "Error saving schematic file '%s'.\n%s" ),
GetChars( schematicFileName.GetFullPath() ), GetChars( ioe.What() ) );
DisplayError( this, msg );
msg.Printf( _( "Failed to save '%s'" ), GetChars( schematicFileName.GetFullPath() ) );
AppendMsgPanel( wxEmptyString, msg, CYAN );
success = false;
}
#else
FILE* f = wxFopen( schematicFileName.GetFullPath(), wxT( "wt" ) );
if( !f )
{ {
msg.Printf( _( "Failed to create file '%s'" ), pi->Save( schematicFileName.GetFullPath(), aScreen, &Kiway() );
GetChars( schematicFileName.GetFullPath() ) ); success = true;
DisplayError( this, msg );
return false;
} }
catch( const IO_ERROR& ioe )
{
msg.Printf( _( "Error saving schematic file '%s'.\n%s" ),
GetChars( schematicFileName.GetFullPath() ), GetChars( ioe.What() ) );
DisplayError( this, msg );
success = aScreen->Save( f ); msg.Printf( _( "Failed to save '%s'" ), GetChars( schematicFileName.GetFullPath() ) );
fclose( f ); AppendMsgPanel( wxEmptyString, msg, CYAN );
#endif
success = false;
}
if( success ) if( success )
{ {
@ -315,7 +300,6 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
} }
else else
{ {
#ifdef KICAD_USE_SCH_IO_MANAGER
delete g_RootSheet; // Delete the current project. delete g_RootSheet; // Delete the current project.
g_RootSheet = NULL; // Force CreateScreens() to build new empty project on load failure. g_RootSheet = NULL; // Force CreateScreens() to build new empty project on load failure.
@ -343,14 +327,7 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
return false; return false;
} }
#else
g_RootSheet->SetScreen( NULL );
DBG( printf( "%s: loading schematic %s\n", __func__, TO_UTF8( fullFileName ) );)
bool diag = g_RootSheet->Load( this );
(void) diag;
#endif
SetScreen( m_CurrentSheet->LastScreen() ); SetScreen( m_CurrentSheet->LastScreen() );
GetScreen()->ClrModify(); GetScreen()->ClrModify();

View File

@ -130,64 +130,28 @@ void LIB_EDIT_FRAME::OnExportPart( wxCommandEvent& event )
std::unique_ptr<PART_LIB> temp_lib( new PART_LIB( LIBRARY_TYPE_EESCHEMA, fn.GetFullPath() ) ); std::unique_ptr<PART_LIB> temp_lib( new PART_LIB( LIBRARY_TYPE_EESCHEMA, fn.GetFullPath() ) );
SaveOnePart( temp_lib.get() );
bool result = false;
try try
{ {
FILE_OUTPUTFORMATTER formatter( fn.GetFullPath() ); SaveOnePart( temp_lib.get() );
result = temp_lib.get()->Save( formatter );
} }
catch( ... /* IO_ERROR ioe */ ) catch( ... /* IO_ERROR ioe */ )
{ {
fn.MakeAbsolute(); fn.MakeAbsolute();
msg = wxT( "Failed to create component library file " ) + fn.GetFullPath(); msg = wxT( "Failed to create symbol library file " ) + fn.GetFullPath();
DisplayError( this, msg ); DisplayError( this, msg );
msg.Printf( _( "Error creating symbol library '%s'" ), fn.GetFullName() );
SetStatusText( msg );
return; return;
} }
try m_mruPath = fn.GetPath();
{
wxFileName docFileName = fn;
docFileName.SetExt( DOC_EXT ); msg.Printf( _( "'%s' - OK" ), GetChars( fn.GetFullPath() ) );
DisplayInfoMessage( this, _( "This library will not be available until it is loaded by "
FILE_OUTPUTFORMATTER formatter( docFileName.GetFullPath() ); "Eeschema.\n\n"
"Modify the Eeschema library configuration if you want to "
result = temp_lib.get()->SaveDocs( formatter ); "include it as part of this project." ) );
}
catch( ... /* IO_ERROR ioe */ )
{
fn.MakeAbsolute();
msg = wxT( "Failed to create component library document file " ) + fn.GetFullPath();
DisplayError( this, msg );
return;
}
if( result )
m_mruPath = fn.GetPath();
if( result )
{
if( createLib )
{
msg.Printf( _( "'%s' - OK" ), GetChars( fn.GetFullPath() ) );
DisplayInfoMessage( this, _(
"This library will not be available until it is loaded by Eeschema.\n\n"
"Modify the Eeschema library configuration if you want to include it"
" as part of this project." ) );
}
else
{
msg.Printf( _( "'%s' - Export OK" ), GetChars( fn.GetFullPath() ) );
}
}
else // Error
{
msg.Printf( _( "Error creating '%s'" ), GetChars( fn.GetFullName() ) );
}
msg.Printf( _( "'%s' - Export OK" ), GetChars( fn.GetFullPath() ) );
SetStatusText( msg ); SetStatusText( msg );
} }

View File

@ -2,8 +2,8 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2004 Jean-Pierre Charras, jp.charras ar wanadoo.fr * Copyright (C) 2004 Jean-Pierre Charras, jp.charras ar wanadoo.fr
* Copyright (C) 2008-2011 Wayne Stambaugh <stambaughw@verizon.net> * Copyright (C) 2008-2017 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2004-2016 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2004-2017 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -49,7 +49,7 @@ bool SCH_EDIT_FRAME::CreateArchiveLibraryCacheFile( bool aUseCurrentSheetFilenam
else else
fn = g_RootSheet->GetScreen()->GetFileName(); fn = g_RootSheet->GetScreen()->GetFileName();
fn.SetName( fn.GetName() + wxT( "-cache" ) ); fn.SetName( fn.GetName() + "-cache" );
fn.SetExt( SchematicLibraryFileExtension ); fn.SetExt( SchematicLibraryFileExtension );
return CreateArchiveLibrary( fn.GetFullPath() ); return CreateArchiveLibrary( fn.GetFullPath() );
@ -58,17 +58,18 @@ bool SCH_EDIT_FRAME::CreateArchiveLibraryCacheFile( bool aUseCurrentSheetFilenam
bool SCH_EDIT_FRAME::CreateArchiveLibrary( const wxString& aFileName ) bool SCH_EDIT_FRAME::CreateArchiveLibrary( const wxString& aFileName )
{ {
wxString msg;
SCH_SCREENS screens; SCH_SCREENS screens;
PART_LIBS* libs = Prj().SchLibs(); PART_LIBS* libs = Prj().SchLibs();
std::unique_ptr<PART_LIB> libCache( new PART_LIB( LIBRARY_TYPE_EESCHEMA, aFileName ) ); std::unique_ptr<PART_LIB> libCache( new PART_LIB( LIBRARY_TYPE_EESCHEMA, aFileName ) );
libCache->SetCache(); libCache->SetCache();
libCache->EnableBuffering();
/* examine all screens (not sheets) used and build the list of components /* Examine all screens (not hierarchical sheets) used in the schematic and build a
* found in lib. * library of unique symbols found in all screens. Complex hierarchies are not a
* Complex hierarchies are not a problem because we just want * problem because we just want to know the library symbols used in the schematic.
* to know used components in libraries
*/ */
for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() ) for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
{ {
@ -79,13 +80,27 @@ bool SCH_EDIT_FRAME::CreateArchiveLibrary( const wxString& aFileName )
SCH_COMPONENT* component = (SCH_COMPONENT*) item; SCH_COMPONENT* component = (SCH_COMPONENT*) item;
// If not already saved in the new cache, put it: // If not already saved in the new cache, add it.
if( !libCache->FindAlias( component->GetPartName() ) ) if( !libCache->FindAlias( component->GetPartName() ) )
{ {
if( LIB_PART* part = libs->FindLibPart( component->GetPartName() ) ) LIB_PART* part = NULL;
try
{ {
// AddPart() does first clone the part before adding. part = libs->FindLibPart( component->GetPartName() );
libCache->AddPart( part );
if( part )
{
// AddPart() does first clone the part before adding.
libCache->AddPart( part );
}
}
catch( ... /* IO_ERROR ioe */ )
{
msg.Printf( _( "Failed to add symbol %s to library file '%s'" ),
component->GetPartName(), aFileName );
DisplayError( this, msg );
return false;
} }
} }
} }
@ -93,24 +108,11 @@ bool SCH_EDIT_FRAME::CreateArchiveLibrary( const wxString& aFileName )
try try
{ {
FILE_OUTPUTFORMATTER formatter( aFileName ); libCache->Save( false );
if( !libCache->Save( formatter ) )
{
wxString msg = wxString::Format( _(
"An error occurred attempting to save component library '%s'." ),
GetChars( aFileName )
);
DisplayError( this, msg );
return false;
}
} }
catch( ... /* IO_ERROR ioe */ ) catch( ... /* IO_ERROR ioe */ )
{ {
wxString msg = wxString::Format( _( msg.Printf( _( "Failed to save symbol library file '%s'" ), aFileName );
"Failed to create component library file '%s'" ),
GetChars( aFileName )
);
DisplayError( this, msg ); DisplayError( this, msg );
return false; return false;
} }

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application. * 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) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2008-2013 Wayne Stambaugh <stambaughw@verizon.net> * Copyright (C) 2008-2017 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2004-2017 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2004-2017 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@ -163,7 +163,7 @@ void LIB_EDIT_FRAME::LoadOneLibraryPart( wxCommandEvent& event )
// The entry to load is not in the active lib // The entry to load is not in the active lib
// Ask for a new active lib // Ask for a new active lib
wxString msg = _( "The selected component is not in the active library." ); wxString msg = _( "The selected component is not in the active library." );
msg += wxT("\n\n"); msg += "\n\n";
msg += _( "Do you want to change the active library?" ); msg += _( "Do you want to change the active library?" );
if( IsOK( this, msg ) ) if( IsOK( this, msg ) )
@ -173,11 +173,9 @@ void LIB_EDIT_FRAME::LoadOneLibraryPart( wxCommandEvent& event )
if( !libEntry ) if( !libEntry )
{ {
wxString msg = wxString::Format( _( wxString msg = wxString::Format( _( "Part name '%s' not found in library '%s'" ),
"Part name '%s' not found in library '%s'" ), GetChars( cmp_name ),
GetChars( cmp_name ), GetChars( searchLib->GetName() ) );
GetChars( searchLib->GetName() )
);
DisplayError( this, msg ); DisplayError( this, msg );
return; return;
} }
@ -201,7 +199,7 @@ bool LIB_EDIT_FRAME::LoadOneLibraryPartAux( LIB_ALIAS* aEntry, PART_LIB* aLibrar
if( aEntry->GetName().IsEmpty() ) if( aEntry->GetName().IsEmpty() )
{ {
wxLogWarning( wxT( "Entry in library <%s> has empty name field." ), wxLogWarning( "Entry in library <%s> has empty name field.",
GetChars( aLibrary->GetName() ) ); GetChars( aLibrary->GetName() ) );
return false; return false;
} }
@ -212,7 +210,7 @@ bool LIB_EDIT_FRAME::LoadOneLibraryPartAux( LIB_ALIAS* aEntry, PART_LIB* aLibrar
wxASSERT( lib_part ); wxASSERT( lib_part );
wxLogDebug( wxT( "\"<%s>\" is alias of \"<%s>\"" ), wxLogDebug( "\"<%s>\" is alias of \"<%s>\"",
GetChars( cmpName ), GetChars( cmpName ),
GetChars( lib_part->GetName() ) ); GetChars( lib_part->GetName() ) );
@ -309,12 +307,17 @@ bool LIB_EDIT_FRAME::SaveActiveLibrary( bool newFile )
PART_LIB* lib = GetCurLib(); PART_LIB* lib = GetCurLib();
// Just in case the library hasn't been cached yet.
lib->GetCount();
if( !lib ) if( !lib )
{ {
DisplayError( this, _( "No library specified." ) ); DisplayError( this, _( "No library specified." ) );
return false; return false;
} }
wxString oldFileName = lib->GetFullFileName();
if( GetScreen()->IsModify() ) if( GetScreen()->IsModify() )
{ {
if( IsOK( this, _( "Include last component changes?" ) ) ) if( IsOK( this, _( "Include last component changes?" ) ) )
@ -352,15 +355,13 @@ bool LIB_EDIT_FRAME::SaveActiveLibrary( bool newFile )
{ {
fn = wxFileName( lib->GetFullFileName() ); fn = wxFileName( lib->GetFullFileName() );
msg.Printf( _( "Modify library file '%s' ?" ), msg.Printf( _( "Modify library file '%s' ?" ), GetChars( fn.GetFullPath() ) );
GetChars( fn.GetFullPath() ) );
if( !IsOK( this, msg ) ) if( !IsOK( this, msg ) )
return false; return false;
} }
// Verify the user has write privileges before attempting to // Verify the user has write privileges before attempting to save the library file.
// save the library file.
if( !IsWritable( fn ) ) if( !IsWritable( fn ) )
return false; return false;
@ -372,7 +373,7 @@ bool LIB_EDIT_FRAME::SaveActiveLibrary( bool newFile )
// Rename the old .lib file to .bak. // Rename the old .lib file to .bak.
if( libFileName.FileExists() ) if( libFileName.FileExists() )
{ {
backupFileName.SetExt( wxT( "bak" ) ); backupFileName.SetExt( "bak" );
if( backupFileName.FileExists() ) if( backupFileName.FileExists() )
wxRemoveFile( backupFileName.GetFullPath() ); wxRemoveFile( backupFileName.GetFullPath() );
@ -380,34 +381,11 @@ bool LIB_EDIT_FRAME::SaveActiveLibrary( bool newFile )
if( !wxRenameFile( libFileName.GetFullPath(), backupFileName.GetFullPath() ) ) if( !wxRenameFile( libFileName.GetFullPath(), backupFileName.GetFullPath() ) )
{ {
libFileName.MakeAbsolute(); libFileName.MakeAbsolute();
msg = wxT( "Failed to rename old component library file " ) + msg = _( "Failed to rename old component library file " ) + backupFileName.GetFullPath();
backupFileName.GetFullPath();
DisplayError( this, msg ); DisplayError( this, msg );
} }
} }
try
{
FILE_OUTPUTFORMATTER libFormatter( libFileName.GetFullPath() );
if( !lib->Save( libFormatter ) )
{
msg.Printf( _( "Error occurred while saving library file '%s'" ),
GetChars( fn.GetFullPath() ) );
AppendMsgPanel( _( "*** ERROR: ***" ), msg, RED );
DisplayError( this, msg );
return false;
}
}
catch( ... /* IO_ERROR ioe */ )
{
libFileName.MakeAbsolute();
msg.Printf( _( "Failed to create component library file '%s'" ),
GetChars( libFileName.GetFullPath() ) );
DisplayError( this, msg );
return false;
}
wxFileName docFileName = libFileName; wxFileName docFileName = libFileName;
docFileName.SetExt( DOC_EXT ); docFileName.SetExt( DOC_EXT );
@ -415,45 +393,37 @@ bool LIB_EDIT_FRAME::SaveActiveLibrary( bool newFile )
// Rename .doc file to .bck. // Rename .doc file to .bck.
if( docFileName.FileExists() ) if( docFileName.FileExists() )
{ {
backupFileName.SetExt( wxT( "bck" ) ); backupFileName.SetExt( "bck" );
if( backupFileName.FileExists() ) if( backupFileName.FileExists() )
wxRemoveFile( backupFileName.GetFullPath() ); wxRemoveFile( backupFileName.GetFullPath() );
if( !wxRenameFile( docFileName.GetFullPath(), backupFileName.GetFullPath() ) ) if( !wxRenameFile( docFileName.GetFullPath(), backupFileName.GetFullPath() ) )
{ {
msg = wxT( "Failed to save old library document file " ) + msg = _( "Failed to save old library document file " ) + backupFileName.GetFullPath();
backupFileName.GetFullPath();
DisplayError( this, msg ); DisplayError( this, msg );
} }
} }
try try
{ {
FILE_OUTPUTFORMATTER docFormatter( docFileName.GetFullPath() ); lib->SetFileName( fn.GetFullPath() );
lib->Save();
if( !lib->SaveDocs( docFormatter ) )
{
msg.Printf( _( "Error occurred while saving library documentation file <%s>" ),
GetChars( docFileName.GetFullPath() ) );
AppendMsgPanel( _( "*** ERROR: ***" ), msg, RED );
DisplayError( this, msg );
return false;
}
} }
catch( ... /* IO_ERROR ioe */ ) catch( ... /* IO_ERROR ioe */ )
{ {
docFileName.MakeAbsolute(); lib->SetFileName( oldFileName );
msg.Printf( _( "Failed to create component document library file <%s>" ), msg.Printf( _( "Failed to create symbol library file '%s'" ),
GetChars( docFileName.GetFullPath() ) ); GetChars( docFileName.GetFullPath() ) );
DisplayError( this, msg ); DisplayError( this, msg );
return false; return false;
} }
msg.Printf( _( "Library file '%s' OK" ), GetChars( fn.GetFullName() ) ); lib->SetFileName( oldFileName );
msg.Printf( _( "Library file '%s' saved" ), GetChars( fn.GetFullPath() ) );
fn.SetExt( DOC_EXT ); fn.SetExt( DOC_EXT );
wxString msg1; wxString msg1;
msg1.Printf( _( "Documentation file '%s' OK" ), GetChars( fn.GetFullPath() ) ); msg1.Printf( _( "Documentation file '%s' saved" ), GetChars( fn.GetFullPath() ) );
AppendMsgPanel( msg, msg1, BLUE ); AppendMsgPanel( msg, msg1, BLUE );
return true; return true;
@ -482,7 +452,7 @@ void LIB_EDIT_FRAME::DisplayCmpDoc()
alias = part->GetAlias( m_aliasName ); alias = part->GetAlias( m_aliasName );
wxCHECK_RET( alias != NULL, wxT( "Alias not found in component." ) ); wxCHECK_RET( alias != NULL, "Alias not found in component." );
AppendMsgPanel( _( "Alias" ), msg, RED, 8 ); AppendMsgPanel( _( "Alias" ), msg, RED, 8 );
@ -638,7 +608,7 @@ void LIB_EDIT_FRAME::CreateNewLibraryPart( wxCommandEvent& event )
} }
name = dlg.GetName(); name = dlg.GetName();
name.Replace( wxT( " " ), wxT( "_" ) ); name.Replace( " ", "_" );
PART_LIB* lib = GetCurLib(); PART_LIB* lib = GetCurLib();
@ -711,18 +681,26 @@ bool LIB_EDIT_FRAME::SaveOnePart( PART_LIB* aLib, bool aPromptUser )
{ {
wxString msg; wxString msg;
LIB_PART* part = GetCurPart(); LIB_PART* part = GetCurPart();
LIB_PART* old_part = NULL;
GetScreen()->ClrModify(); GetScreen()->ClrModify();
LIB_PART* old_part = aLib->FindPart( part->GetName() ); if( !wxFileName::FileExists( aLib->GetFullFileName() ) )
if( old_part && aPromptUser )
{ {
msg.Printf( _( "Part '%s' already exists. Change it?" ), aLib->Create();
GetChars( part->GetName() ) ); }
else
{
old_part = aLib->FindPart( part->GetName() );
if( !IsOK( this, msg ) ) if( old_part && aPromptUser )
return false; {
msg.Printf( _( "Part '%s' already exists. Change it?" ),
GetChars( part->GetName() ) );
if( !IsOK( this, msg ) )
return false;
}
} }
m_drawItem = m_lastDrawItem = NULL; m_drawItem = m_lastDrawItem = NULL;

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2015 Chris Pavlina <pavlina.chris@gmail.com> * Copyright (C) 2015 Chris Pavlina <pavlina.chris@gmail.com>
* Copyright (C) 2015-2016 KiCad Developers, see change_log.txt for contributors. * Copyright (C) 2015-2017 KiCad Developers, see change_log.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -44,31 +44,19 @@ typedef std::pair<SCH_COMPONENT*, wxString> COMPONENT_NAME_PAIR;
* Function save_library * Function save_library
* writes the library out to disk. Returns true on success. * writes the library out to disk. Returns true on success.
* *
* @param aFileName - Filename to receive the library
* @param aLibrary - Library to write * @param aLibrary - Library to write
* @param aEditFrame - the calling SCH_EDIT_FRAME * @param aEditFrame - the calling SCH_EDIT_FRAME
*/ */
static bool save_library( const wxString& aFileName, PART_LIB* aLibrary, SCH_EDIT_FRAME* aEditFrame ) static bool save_library( PART_LIB* aLibrary, SCH_EDIT_FRAME* aEditFrame )
{ {
try try
{ {
FILE_OUTPUTFORMATTER formatter( aFileName ); aLibrary->Save( false );
if( !aLibrary->Save( formatter ) )
{
wxString msg = wxString::Format( _(
"An error occurred attempting to save component library '%s'." ),
GetChars( aFileName )
);
DisplayError( aEditFrame, msg );
return false;
}
} }
catch( ... /* IO_ERROR ioe */ ) catch( ... /* IO_ERROR ioe */ )
{ {
wxString msg = wxString::Format( _( wxString msg = wxString::Format( _( "Failed to create component library file '%s'" ),
"Failed to create component library file '%s'" ), GetChars( aLibrary->GetFullFileName() )
GetChars( aFileName )
); );
DisplayError( aEditFrame, msg ); DisplayError( aEditFrame, msg );
return false; return false;
@ -162,7 +150,8 @@ static void get_components( std::vector<SCH_COMPONENT*>& aComponents )
{ {
for( SCH_ITEM* item = screen->GetDrawItems(); item; item = item->Next() ) for( SCH_ITEM* item = screen->GetDrawItems(); item; item = item->Next() )
{ {
if( item->Type() != SCH_COMPONENT_T ) continue; if( item->Type() != SCH_COMPONENT_T )
continue;
SCH_COMPONENT* component = dynamic_cast<SCH_COMPONENT*>( item ); SCH_COMPONENT* component = dynamic_cast<SCH_COMPONENT*>( item );
aComponents.push_back( component ); aComponents.push_back( component );
} }
@ -299,7 +288,8 @@ public:
{ {
for( SCH_COMPONENT* each_component : *aRescuer->GetComponents() ) for( SCH_COMPONENT* each_component : *aRescuer->GetComponents() )
{ {
if( each_component->GetPartName() != m_requested_name ) continue; if( each_component->GetPartName() != m_requested_name )
continue;
each_component->SetPartName( m_new_name ); each_component->SetPartName( m_new_name );
each_component->ClearFlags(); each_component->ClearFlags();
aRescuer->LogRescue( each_component, m_requested_name, m_new_name ); aRescuer->LogRescue( each_component, m_requested_name, m_new_name );
@ -317,7 +307,6 @@ class RESCUE_CACHE_CANDIDATE: public RESCUE_CANDIDATE
LIB_PART* m_lib_candidate; LIB_PART* m_lib_candidate;
static std::unique_ptr<PART_LIB> m_rescue_lib; static std::unique_ptr<PART_LIB> m_rescue_lib;
static wxFileName m_library_fn;
public: public:
/** /**
@ -398,14 +387,12 @@ public:
wxFileName fn( g_RootSheet->GetScreen()->GetFileName() ); wxFileName fn( g_RootSheet->GetScreen()->GetFileName() );
fn.SetName( fn.GetName() + wxT( "-rescue" ) ); fn.SetName( fn.GetName() + wxT( "-rescue" ) );
fn.SetExt( SchematicLibraryFileExtension ); fn.SetExt( SchematicLibraryFileExtension );
m_library_fn.SetPath( fn.GetPath() );
m_library_fn.SetName( fn.GetName() );
m_library_fn.SetExt( wxT( "lib" ) );
std::unique_ptr<PART_LIB> rescue_lib( new PART_LIB( LIBRARY_TYPE_EESCHEMA, std::unique_ptr<PART_LIB> rescue_lib( new PART_LIB( LIBRARY_TYPE_EESCHEMA,
fn.GetFullPath() ) ); fn.GetFullPath() ) );
m_rescue_lib = std::move( rescue_lib ); m_rescue_lib = std::move( rescue_lib );
m_rescue_lib->EnableBuffering();
} }
virtual bool PerformAction( RESCUER* aRescuer ) override virtual bool PerformAction( RESCUER* aRescuer ) override
@ -417,7 +404,8 @@ public:
for( SCH_COMPONENT* each_component : *aRescuer->GetComponents() ) for( SCH_COMPONENT* each_component : *aRescuer->GetComponents() )
{ {
if( each_component->GetPartName() != m_requested_name ) continue; if( each_component->GetPartName() != m_requested_name )
continue;
each_component->SetPartName( m_new_name ); each_component->SetPartName( m_new_name );
each_component->ClearFlags(); each_component->ClearFlags();
aRescuer->LogRescue( each_component, m_requested_name, m_new_name ); aRescuer->LogRescue( each_component, m_requested_name, m_new_name );
@ -433,15 +421,15 @@ public:
*/ */
static bool WriteRescueLibrary( SCH_EDIT_FRAME *aEditFrame, PROJECT* aProject ) static bool WriteRescueLibrary( SCH_EDIT_FRAME *aEditFrame, PROJECT* aProject )
{ {
if( !save_library( m_rescue_lib.get(), aEditFrame ) )
if( !save_library( m_library_fn.GetFullPath(), m_rescue_lib.get(), aEditFrame ) )
return false; return false;
return insert_library( aProject, m_rescue_lib.get(), 0 ); return insert_library( aProject, m_rescue_lib.get(), 0 );
} }
}; };
std::unique_ptr<PART_LIB> RESCUE_CACHE_CANDIDATE::m_rescue_lib; std::unique_ptr<PART_LIB> RESCUE_CACHE_CANDIDATE::m_rescue_lib;
wxFileName RESCUE_CACHE_CANDIDATE::m_library_fn;
RESCUER::RESCUER( SCH_EDIT_FRAME& aEditFrame, PROJECT& aProject ) RESCUER::RESCUER( SCH_EDIT_FRAME& aEditFrame, PROJECT& aProject )
{ {

View File

@ -5,7 +5,7 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2016 CERN * Copyright (C) 2016 CERN
* Copyright (C) 2016 KiCad Developers, see CHANGELOG.TXT for contributors. * Copyright (C) 2016-2017 KiCad Developers, see CHANGELOG.TXT for contributors.
* *
* @author Wayne Stambaugh <stambaughw@gmail.com> * @author Wayne Stambaugh <stambaughw@gmail.com>
* *
@ -216,6 +216,8 @@ public:
*/ */
virtual int GetModifyHash() const = 0; virtual int GetModifyHash() const = 0;
virtual void SaveLibrary( const wxString& aFileName, const PROPERTIES* aProperties = NULL );
/** /**
* Function Load * Function Load
* *
@ -271,6 +273,9 @@ public:
virtual void Save( const wxString& aFileName, SCH_SCREEN* aSchematic, KIWAY* aKiway, virtual void Save( const wxString& aFileName, SCH_SCREEN* aSchematic, KIWAY* aKiway,
const PROPERTIES* aProperties = NULL ); const PROPERTIES* aProperties = NULL );
virtual size_t GetSymbolLibCount( const wxString& aLibraryPath,
const PROPERTIES* aProperties = NULL );
/** /**
* Function EnumerateSymbolLib * Function EnumerateSymbolLib
* *
@ -291,9 +296,6 @@ public:
const wxString& aLibraryPath, const wxString& aLibraryPath,
const PROPERTIES* aProperties = NULL ); const PROPERTIES* aProperties = NULL );
// Temporary for testing using PART_LIB instead of SCH_PLUGIN.
virtual void TransferCache( PART_LIB& aTarget );
/** /**
* Function LoadSymbol * Function LoadSymbol
* *

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2016 CERN * Copyright (C) 2016 CERN
* Copyright (C) 2016 KiCad Developers, see change_log.txt for contributors. * Copyright (C) 2016-2017 KiCad Developers, see change_log.txt for contributors.
* *
* @author Wayne Stambaugh <stambaughw@gmail.com> * @author Wayne Stambaugh <stambaughw@gmail.com>
* *
@ -32,6 +32,7 @@
#include <kicad_string.h> #include <kicad_string.h>
#include <richio.h> #include <richio.h>
#include <core/typeinfo.h> #include <core/typeinfo.h>
#include <properties.h>
#include <general.h> #include <general.h>
#include <lib_field.h> #include <lib_field.h>
@ -58,6 +59,9 @@
#include <lib_text.h> #include <lib_text.h>
// Must be the first line of part library document (.dcm) files.
#define DOCFILE_IDENT "EESchema-DOCLIB Version 2.0"
#define SCH_PARSE_ERROR( text, reader, pos ) \ #define SCH_PARSE_ERROR( text, reader, pos ) \
THROW_PARSE_ERROR( text, reader.GetSource(), reader.Line(), \ THROW_PARSE_ERROR( text, reader.GetSource(), reader.Line(), \
reader.LineNumber(), pos - reader.Line() ) reader.LineNumber(), pos - reader.Line() )
@ -1955,6 +1959,8 @@ class SCH_LEGACY_PLUGIN_CACHE
bool checkForDuplicates( wxString& aAliasName ); bool checkForDuplicates( wxString& aAliasName );
LIB_ALIAS* removeAlias( LIB_ALIAS* aAlias ); LIB_ALIAS* removeAlias( LIB_ALIAS* aAlias );
void saveDocFile();
friend SCH_LEGACY_PLUGIN; friend SCH_LEGACY_PLUGIN;
public: public:
@ -1968,7 +1974,7 @@ public:
// Catch these exceptions higher up please. // Catch these exceptions higher up please.
/// Save the entire library to file m_libFileName; /// Save the entire library to file m_libFileName;
void Save(); void Save( bool aSaveDocFile = true );
void Load(); void Load();
@ -1984,7 +1990,13 @@ public:
bool IsFileChanged() const; bool IsFileChanged() const;
void SetModified( bool aModified = true ) { m_isModified = aModified; }
wxString GetLogicalName() const { return m_libFileName.GetName(); } wxString GetLogicalName() const { return m_libFileName.GetName(); }
void SetFileName( const wxString& aFileName ) { m_libFileName = aFileName; }
wxString GetFileName() const { return m_libFileName.GetFullPath(); }
}; };
@ -2088,11 +2100,7 @@ LIB_ALIAS* SCH_LEGACY_PLUGIN_CACHE::removeAlias( LIB_ALIAS* aAlias )
void SCH_LEGACY_PLUGIN_CACHE::AddSymbol( const LIB_PART* aPart ) void SCH_LEGACY_PLUGIN_CACHE::AddSymbol( const LIB_PART* aPart )
{ {
// Ugly hack to fix the fact that the LIB_PART copy constructor doesn't take a const // aPart is cloned in PART_LIB::AddPart(). The cache takes ownership of aPart.
// reference. I feel all dirty inside doing this.
// @todo: fix LIB_PART copy ctor so it can take a const reference.
LIB_PART* part = new LIB_PART( *const_cast< LIB_PART* >( aPart ) );
wxArrayString aliasNames = aPart->GetAliasNames(); wxArrayString aliasNames = aPart->GetAliasNames();
for( size_t i = 0; i < aliasNames.size(); i++ ) for( size_t i = 0; i < aliasNames.size(); i++ )
@ -2102,10 +2110,10 @@ void SCH_LEGACY_PLUGIN_CACHE::AddSymbol( const LIB_PART* aPart )
if( it != m_aliases.end() ) if( it != m_aliases.end() )
removeAlias( it->second ); removeAlias( it->second );
LIB_ALIAS* alias = part->GetAlias( aliasNames[i] ); LIB_ALIAS* alias = const_cast< LIB_PART* >( aPart )->GetAlias( aliasNames[i] );
wxASSERT_MSG( alias != NULL, "No alias <" + aliasNames[i] + "> found in symbol <" + wxASSERT_MSG( alias != NULL, "No alias <" + aliasNames[i] + "> found in symbol <" +
part->GetName() +">." ); aPart->GetName() +">." );
m_aliases[ aliasNames[i] ] = alias; m_aliases[ aliasNames[i] ] = alias;
} }
@ -2117,9 +2125,11 @@ void SCH_LEGACY_PLUGIN_CACHE::AddSymbol( const LIB_PART* aPart )
void SCH_LEGACY_PLUGIN_CACHE::Load() void SCH_LEGACY_PLUGIN_CACHE::Load()
{ {
FILE_LINE_READER reader( m_libFileName.GetFullPath() ); wxCHECK_RET( m_libFileName.IsAbsolute(),
wxString::Format( "Cannot use relative file paths in legacy plugin to "
"open library '%s'.", m_libFileName.GetFullPath() ) );
wxCHECK_RET( m_libFileName.IsAbsolute(), "Cannot use relative file paths in legacy plugin." ); FILE_LINE_READER reader( m_libFileName.GetFullPath() );
if( !reader.ReadLine() ) if( !reader.ReadLine() )
THROW_IO_ERROR( _( "unexpected end of file" ) ); THROW_IO_ERROR( _( "unexpected end of file" ) );
@ -3222,7 +3232,7 @@ void SCH_LEGACY_PLUGIN_CACHE::loadFootprintFilters( std::unique_ptr< LIB_PART >&
} }
void SCH_LEGACY_PLUGIN_CACHE::Save() void SCH_LEGACY_PLUGIN_CACHE::Save( bool aSaveDocFile )
{ {
if( !m_isModified ) if( !m_isModified )
return; return;
@ -3242,6 +3252,27 @@ void SCH_LEGACY_PLUGIN_CACHE::Save()
formatter.Print( 0, "#\n#End Library\n" ); formatter.Print( 0, "#\n#End Library\n" );
m_fileModTime = m_libFileName.GetModificationTime(); m_fileModTime = m_libFileName.GetModificationTime();
m_isModified = false; m_isModified = false;
if( aSaveDocFile )
saveDocFile();
}
void SCH_LEGACY_PLUGIN_CACHE::saveDocFile()
{
wxFileName docFileName = m_libFileName;
docFileName.SetExt( DOC_EXT );
FILE_OUTPUTFORMATTER formatter( docFileName.GetFullPath() );
formatter.Print( 0, "%s\n", DOCFILE_IDENT );
for( LIB_ALIAS_MAP::iterator it = m_aliases.begin(); it != m_aliases.end(); it++ )
{
it->second->SaveDoc( formatter );
}
formatter.Print( 0, "#\n#End Doc Library\n" );
} }
@ -3306,11 +3337,35 @@ void SCH_LEGACY_PLUGIN::cacheLib( const wxString& aLibraryFileName )
// a spectacular episode in memory management: // a spectacular episode in memory management:
delete m_cache; delete m_cache;
m_cache = new SCH_LEGACY_PLUGIN_CACHE( aLibraryFileName ); m_cache = new SCH_LEGACY_PLUGIN_CACHE( aLibraryFileName );
m_cache->Load();
if( !isBuffering( m_props ) )
m_cache->Load();
} }
} }
bool SCH_LEGACY_PLUGIN::writeDocFile( const PROPERTIES* aProperties )
{
std::string propName( SCH_LEGACY_PLUGIN::PropNoDocFile );
if( aProperties && aProperties->find( propName ) != aProperties->end() )
return false;
return true;
}
bool SCH_LEGACY_PLUGIN::isBuffering( const PROPERTIES* aProperties )
{
std::string propName( SCH_LEGACY_PLUGIN::PropBuffering );
if( aProperties && aProperties->find( propName ) != aProperties->end() )
return true;
return false;
}
int SCH_LEGACY_PLUGIN::GetModifyHash() const int SCH_LEGACY_PLUGIN::GetModifyHash() const
{ {
if( m_cache ) if( m_cache )
@ -3321,6 +3376,19 @@ int SCH_LEGACY_PLUGIN::GetModifyHash() const
} }
size_t SCH_LEGACY_PLUGIN::GetSymbolLibCount( const wxString& aLibraryPath,
const PROPERTIES* aProperties )
{
LOCALE_IO toggle;
init( NULL, aProperties );
cacheLib( aLibraryPath );
return m_cache->m_aliases.size();
}
void SCH_LEGACY_PLUGIN::EnumerateSymbolLib( wxArrayString& aAliasNameList, void SCH_LEGACY_PLUGIN::EnumerateSymbolLib( wxArrayString& aAliasNameList,
const wxString& aLibraryPath, const wxString& aLibraryPath,
const PROPERTIES* aProperties ) const PROPERTIES* aProperties )
@ -3338,24 +3406,6 @@ void SCH_LEGACY_PLUGIN::EnumerateSymbolLib( wxArrayString& aAliasNameList,
} }
void SCH_LEGACY_PLUGIN::TransferCache( PART_LIB& aTarget )
{
aTarget.m_amap = m_cache->m_aliases;
for( LIB_ALIAS_MAP::iterator it = aTarget.m_amap.begin(); it != aTarget.m_amap.end(); ++it )
it->second->GetPart()->SetLib( &aTarget );
aTarget.type = m_cache->m_libType;
aTarget.fileName = m_cache->m_libFileName;
aTarget.versionMajor = m_cache->m_versionMajor;
aTarget.versionMinor = m_cache->m_versionMinor;
m_cache->m_aliases.clear();
delete m_cache;
m_cache = NULL;
}
LIB_ALIAS* SCH_LEGACY_PLUGIN::LoadSymbol( const wxString& aLibraryPath, const wxString& aAliasName, LIB_ALIAS* SCH_LEGACY_PLUGIN::LoadSymbol( const wxString& aLibraryPath, const wxString& aAliasName,
const PROPERTIES* aProperties ) const PROPERTIES* aProperties )
{ {
@ -3382,7 +3432,9 @@ void SCH_LEGACY_PLUGIN::SaveSymbol( const wxString& aLibraryPath, const LIB_PART
cacheLib( aLibraryPath ); cacheLib( aLibraryPath );
m_cache->AddSymbol( aSymbol ); m_cache->AddSymbol( aSymbol );
m_cache->Save();
if( !isBuffering( aProperties ) )
m_cache->Save( writeDocFile( aProperties ) );
} }
@ -3394,6 +3446,9 @@ void SCH_LEGACY_PLUGIN::DeleteAlias( const wxString& aLibraryPath, const wxStrin
cacheLib( aLibraryPath ); cacheLib( aLibraryPath );
m_cache->DeleteAlias( aAliasName ); m_cache->DeleteAlias( aAliasName );
if( !isBuffering( aProperties ) )
m_cache->Save( writeDocFile( aProperties ) );
} }
@ -3405,6 +3460,9 @@ void SCH_LEGACY_PLUGIN::DeleteSymbol( const wxString& aLibraryPath, const wxStri
cacheLib( aLibraryPath ); cacheLib( aLibraryPath );
m_cache->DeleteSymbol( aAliasName ); m_cache->DeleteSymbol( aAliasName );
if( !isBuffering( aProperties ) )
m_cache->Save( writeDocFile( aProperties ) );
} }
@ -3424,7 +3482,8 @@ void SCH_LEGACY_PLUGIN::CreateSymbolLib( const wxString& aLibraryPath,
delete m_cache; delete m_cache;
m_cache = new SCH_LEGACY_PLUGIN_CACHE( aLibraryPath ); m_cache = new SCH_LEGACY_PLUGIN_CACHE( aLibraryPath );
m_cache->Save(); m_cache->SetModified();
m_cache->Save( writeDocFile( aProperties ) );
m_cache->Load(); // update m_writable and m_mod_time m_cache->Load(); // update m_writable and m_mod_time
} }
@ -3453,3 +3512,26 @@ bool SCH_LEGACY_PLUGIN::DeleteSymbolLib( const wxString& aLibraryPath,
return true; return true;
} }
void SCH_LEGACY_PLUGIN::SaveLibrary( const wxString& aLibraryPath, const PROPERTIES* aProperties )
{
if( m_cache )
{
wxString oldFileName = m_cache->GetFileName();
if( !m_cache->IsFile( aLibraryPath ) )
{
m_cache->SetFileName( aLibraryPath );
}
// This is a forced save.
m_cache->SetModified();
m_cache->Save( writeDocFile( aProperties ) );
m_cache->SetFileName( oldFileName );
}
}
const char* SCH_LEGACY_PLUGIN::PropBuffering = "buffering";
const char* SCH_LEGACY_PLUGIN::PropNoDocFile = "no_doc_file";

View File

@ -5,7 +5,7 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2016 CERN * Copyright (C) 2016 CERN
* Copyright (C) 2016 KiCad Developers, see change_log.txt for contributors. * Copyright (C) 2016-2017 KiCad Developers, see change_log.txt for contributors.
* *
* @author Wayne Stambaugh <stambaughw@gmail.com> * @author Wayne Stambaugh <stambaughw@gmail.com>
* *
@ -75,6 +75,23 @@ public:
return wxT( "sch" ); return wxT( "sch" );
} }
/**
* const char* PropBuffering
*
* is a property used internally by the plugin to enable cache buffering which prevents
* the library file from being written every time the cache is changed. This is useful
* when writing the schematic cache library file or saving a library to a new file name.
*/
static const char* PropBuffering;
/**
* const char* PropBuffering
*
* is a property used internally by the plugin to disable writing the library
* documentation (.dcm) file when saving the library cache.
*/
static const char* PropNoDocFile;
int GetModifyHash() const override; int GetModifyHash() const override;
SCH_SHEET* Load( const wxString& aFileName, KIWAY* aKiway, SCH_SHEET* Load( const wxString& aFileName, KIWAY* aKiway,
@ -85,6 +102,8 @@ public:
void Format( SCH_SCREEN* aScreen ); void Format( SCH_SCREEN* aScreen );
size_t GetSymbolLibCount( const wxString& aLibraryPath,
const PROPERTIES* aProperties = NULL ) override;
void EnumerateSymbolLib( wxArrayString& aAliasNameList, void EnumerateSymbolLib( wxArrayString& aAliasNameList,
const wxString& aLibraryPath, const wxString& aLibraryPath,
const PROPERTIES* aProperties = NULL ) override; const PROPERTIES* aProperties = NULL ) override;
@ -100,9 +119,7 @@ public:
const PROPERTIES* aProperties = NULL ) override; const PROPERTIES* aProperties = NULL ) override;
bool DeleteSymbolLib( const wxString& aLibraryPath, bool DeleteSymbolLib( const wxString& aLibraryPath,
const PROPERTIES* aProperties = NULL ) override; const PROPERTIES* aProperties = NULL ) override;
void SaveLibrary( const wxString& aLibraryPath, const PROPERTIES* aProperties = NULL ) override;
// Temporary for testing using PART_LIB instead of SCH_PLUGIN.
void TransferCache( PART_LIB& aTarget ) override;
private: private:
void loadHierarchy( SCH_SHEET* aSheet ); void loadHierarchy( SCH_SHEET* aSheet );
@ -129,6 +146,8 @@ private:
void saveText( SCH_TEXT* aText ); void saveText( SCH_TEXT* aText );
void cacheLib( const wxString& aLibraryFileName ); void cacheLib( const wxString& aLibraryFileName );
bool writeDocFile( const PROPERTIES* aProperties );
bool isBuffering( const PROPERTIES* aProperties );
protected: protected:
int m_version; ///< Version of file being loaded. int m_version; ///< Version of file being loaded.

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2016 CERN * Copyright (C) 2016 CERN
* Copyright (C) 2016 KiCad Developers, see change_log.txt for contributors. * Copyright (C) 2016-2017 KiCad Developers, see change_log.txt for contributors.
* *
* @author Wayne Stambaugh <stambaughw@gmail.com> * @author Wayne Stambaugh <stambaughw@gmail.com>
* *
@ -41,6 +41,20 @@ static void not_implemented( SCH_PLUGIN* aPlugin, const char* aCaller )
} }
static void not_implemented( const SCH_PLUGIN* aPlugin, const char* aCaller )
{
THROW_IO_ERROR( wxString::Format( FMT_UNIMPLEMENTED,
aPlugin->GetName().GetData(),
wxString::FromUTF8( aCaller ).GetData() ) );
}
void SCH_PLUGIN::SaveLibrary( const wxString& aFileName, const PROPERTIES* aProperties )
{
not_implemented( this, __FUNCTION__ );
}
SCH_SHEET* SCH_PLUGIN::Load( const wxString& aFileName, KIWAY* aKiway, SCH_SHEET* aAppendToMe, SCH_SHEET* SCH_PLUGIN::Load( const wxString& aFileName, KIWAY* aKiway, SCH_SHEET* aAppendToMe,
const PROPERTIES* aProperties ) const PROPERTIES* aProperties )
{ {
@ -57,16 +71,18 @@ void SCH_PLUGIN::Save( const wxString& aFileName, SCH_SCREEN* aSchematic, KIWAY*
} }
void SCH_PLUGIN::EnumerateSymbolLib( wxArrayString& aAliasNameList, size_t SCH_PLUGIN::GetSymbolLibCount( const wxString& aLibraryPath,
const wxString& aLibraryPath, const PROPERTIES* aProperties )
const PROPERTIES* aProperties )
{ {
// not pure virtual so that plugins only have to implement subset of the SCH_PLUGIN interface. // not pure virtual so that plugins only have to implement subset of the SCH_PLUGIN interface.
not_implemented( this, __FUNCTION__ ); not_implemented( this, __FUNCTION__ );
return 0;
} }
void SCH_PLUGIN::TransferCache( PART_LIB& aTarget ) void SCH_PLUGIN::EnumerateSymbolLib( wxArrayString& aAliasNameList,
const wxString& aLibraryPath,
const PROPERTIES* aProperties )
{ {
// not pure virtual so that plugins only have to implement subset of the SCH_PLUGIN interface. // not pure virtual so that plugins only have to implement subset of the SCH_PLUGIN interface.
not_implemented( this, __FUNCTION__ ); not_implemented( this, __FUNCTION__ );

View File

@ -2,8 +2,8 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2004 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2004 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2008-2011 Wayne Stambaugh <stambaughw@verizon.net> * Copyright (C) 2008-2017 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2004-2016 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2004-2017 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -57,6 +57,7 @@ void LIB_EDIT_FRAME::LoadOneSymbol()
m_canvas->SetIgnoreMouseEvents( true ); m_canvas->SetIgnoreMouseEvents( true );
wxString default_path = prj.GetRString( PROJECT::SCH_LIB_PATH ); wxString default_path = prj.GetRString( PROJECT::SCH_LIB_PATH );
if( !default_path ) if( !default_path )
default_path = search->LastVisitedPath(); default_path = search->LastVisitedPath();
@ -77,35 +78,28 @@ void LIB_EDIT_FRAME::LoadOneSymbol()
std::unique_ptr<PART_LIB> lib( new PART_LIB( LIBRARY_TYPE_SYMBOL, filename ) ); std::unique_ptr<PART_LIB> lib( new PART_LIB( LIBRARY_TYPE_SYMBOL, filename ) );
wxString err; wxString msg;
if( !lib->Load( err ) ) try
{ {
wxString msg = wxString::Format( _( if( lib->IsEmpty() )
"Error '%s' occurred loading part file '%s'." ), {
GetChars( err ), msg.Printf( _( "No parts found in part file '%s'." ), GetChars( filename ) );
GetChars( filename ) DisplayError( this, msg );
); return;
DisplayError( this, msg ); }
return;
} }
catch( const IO_ERROR& exc )
if( lib->IsEmpty() )
{ {
wxString msg = wxString::Format( _( msg.Printf( _( "Error '%s' occurred loading part file '%s'." ),
"No parts found in part file '%s'." ), GetChars( exc.Problem() ), GetChars( filename ) );
GetChars( filename )
);
DisplayError( this, msg ); DisplayError( this, msg );
return; return;
} }
if( lib->GetCount() > 1 ) if( lib->GetCount() > 1 )
{ {
wxString msg = wxString::Format( _( msg.Printf( _( "More than one part in part file '%s'." ), GetChars( filename ) );
"More than one part in part file '%s'." ),
GetChars( filename )
);
wxMessageBox( msg, _( "Warning" ), wxOK | wxICON_EXCLAMATION, this ); wxMessageBox( msg, _( "Warning" ), wxOK | wxICON_EXCLAMATION, this );
} }

View File

@ -1,8 +1,8 @@
/* /*
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2016 Wayne Stambaugh <stambaughw@gmail.com> * Copyright (C) 2016-2017 Wayne Stambaugh <stambaughw@gmail.com>
* Copyright (C) 2016 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2016-2017 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -66,7 +66,8 @@ SYMBOL_LIB_TABLE::SYMBOL_LIB_TABLE( SYMBOL_LIB_TABLE* aFallBackTable ) :
} }
void SYMBOL_LIB_TABLE::Parse( LIB_TABLE_LEXER* in ) throw() void SYMBOL_LIB_TABLE::Parse( LIB_TABLE_LEXER* in )
throw( IO_ERROR, PARSE_ERROR )
{ {
T tok; T tok;
@ -188,7 +189,7 @@ void SYMBOL_LIB_TABLE::Parse( LIB_TABLE_LEXER* in ) throw()
void SYMBOL_LIB_TABLE::Format( OUTPUTFORMATTER* out, int nestLevel ) const void SYMBOL_LIB_TABLE::Format( OUTPUTFORMATTER* out, int nestLevel ) const
throw() throw( IO_ERROR, boost::interprocess::lock_exception )
{ {
out->Print( nestLevel, "(sym_lib_table\n" ); out->Print( nestLevel, "(sym_lib_table\n" );

View File

@ -1,8 +1,8 @@
/* /*
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2016 Wayne Stambaugh <stambaughw@verizon.net> * Copyright (C) 2016-2017 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2016 KiCad Developers, see change_log.txt for contributors. * Copyright (C) 2016-2017 KiCad Developers, see change_log.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -101,9 +101,11 @@ class SYMBOL_LIB_TABLE : public LIB_TABLE
{ {
public: public:
virtual void Parse( LIB_TABLE_LEXER* aLexer ) throw() override; virtual void Parse( LIB_TABLE_LEXER* aLexer )
throw( IO_ERROR, PARSE_ERROR ) override;
virtual void Format( OUTPUTFORMATTER* out, int nestLevel ) const throw() override; virtual void Format( OUTPUTFORMATTER* out, int nestLevel ) const
throw( IO_ERROR, boost::interprocess::lock_exception ) override;
/** /**
* Constructor SYMBOL_LIB_TABLE * Constructor SYMBOL_LIB_TABLE

View File

@ -2,8 +2,8 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2010-2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com> * Copyright (C) 2010-2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2012-2016 Wayne Stambaugh <stambaughw@verizon.net> * Copyright (C) 2012-2017 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2012-2016 KiCad Developers, see change_log.txt for contributors. * Copyright (C) 2012-2017 KiCad Developers, see change_log.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -279,9 +279,11 @@ class LIB_TABLE : public PROJECT::_ELEM
public: public:
virtual void Parse( LIB_TABLE_LEXER* aLexer ) throw() = 0; virtual void Parse( LIB_TABLE_LEXER* aLexer )
throw( IO_ERROR, PARSE_ERROR ) = 0;
virtual void Format( OUTPUTFORMATTER* out, int nestLevel ) const throw() = 0; virtual void Format( OUTPUTFORMATTER* out, int nestLevel ) const
throw( IO_ERROR, boost::interprocess::lock_exception ) = 0;
/** /**
* Constructor LIB_TABLE * Constructor LIB_TABLE