kicad/eeschema/dialogs/dialog_symbol_remap.cpp

266 lines
8.8 KiB
C++

/**
* @file dialog_symbol_remap.cpp
*/
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2017 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2017 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <macros.h>
#include <pgm_base.h>
#include <kiface_i.h>
#include <project.h>
#include <confirm.h>
#include <reporter.h>
#include <wx_html_report_panel.h>
#include <class_library.h>
#include <sch_io_mgr.h>
#include <sch_sheet.h>
#include <sch_component.h>
#include <class_sch_screen.h>
#include <schframe.h>
#include <symbol_lib_table.h>
#include <env_paths.h>
#include <dialog_symbol_remap.h>
DIALOG_SYMBOL_REMAP::DIALOG_SYMBOL_REMAP( SCH_EDIT_FRAME* aParent ) :
DIALOG_SYMBOL_REMAP_BASE( aParent )
{
}
void DIALOG_SYMBOL_REMAP::OnRemapSymbols( wxCommandEvent& aEvent )
{
wxBusyCursor busy;
// The schematic is fully loaded, any legacy library symbols have been rescued. Now
// check to see if the schematic has not been converted to the symbol library table
// method for looking up symbols.
wxFileName prjSymLibTableFileName( Prj().GetProjectPath(),
SYMBOL_LIB_TABLE::GetSymbolLibTableFileName() );
if( !prjSymLibTableFileName.FileExists() )
{
createProjectSymbolLibTable( m_messagePanel->Reporter() );
Prj().SetElem( PROJECT::ELEM_SYMBOL_LIB_TABLE, NULL );
Prj().SchSymbolLibTable();
}
remapSymbolsToLibTable( m_messagePanel->Reporter() );
// Remove all of the libraries from the legacy library list.
wxString paths;
wxArrayString libNames;
PART_LIBS::LibNamesAndPaths( &Prj(), true, &paths, &libNames );
// Reload the the cache symbol library.
Prj().SetElem( PROJECT::ELEM_SCH_PART_LIBS, NULL );
Prj().SchLibs();
}
size_t DIALOG_SYMBOL_REMAP::getLibsNotInGlobalSymbolLibTable( std::vector< PART_LIB* >& aLibs )
{
PART_LIBS* libs = Prj().SchLibs();
for( PART_LIBS_BASE::iterator it = libs->begin(); it != libs->end(); ++it )
{
// Ignore the cache library.
if( it->IsCache() )
continue;
// Check for the obvious library name.
wxString libFileName = it->GetFullFileName();
if( !SYMBOL_LIB_TABLE::GetGlobalLibTable().FindRowByURI( libFileName ) )
aLibs.push_back( &(*it) );
}
return aLibs.size();
}
void DIALOG_SYMBOL_REMAP::createProjectSymbolLibTable( REPORTER& aReporter )
{
wxString msg;
std::vector< PART_LIB* > libs;
if( getLibsNotInGlobalSymbolLibTable( libs ) )
{
SYMBOL_LIB_TABLE prjLibTable;
std::vector< wxString > libNames = SYMBOL_LIB_TABLE::GetGlobalLibTable().GetLogicalLibs();
for( auto lib : libs )
{
wxString libName = lib->GetName();
int libNameInc = 1;
int libNameLen = libName.Length();
// Don't create duplicate table entries.
while( std::find( libNames.begin(), libNames.end(), libName ) != libNames.end() )
{
libName = libName.Left( libNameLen );
libName << libNameInc;
libNameInc++;
}
wxString pluginType = SCH_IO_MGR::ShowType( SCH_IO_MGR::SCH_LEGACY );
wxFileName fn = lib->GetFullFileName();
// Use environment variable substitution where possible. This is based solely
// on the internal user environment variable list. Checking against all of the
// system wide environment variables is probably not a good idea.
wxString fullFileName = NormalizePath( fn, &Pgm().GetLocalEnvVariables(), &Prj() );
// Fall back to the absolute library path.
if( fullFileName.IsEmpty() )
fullFileName = lib->GetFullFileName();
wxFileName tmpFn = fullFileName;
// Don't add symbol libraries that do not exist.
if( tmpFn.Normalize() && tmpFn.FileExists() )
{
msg.Printf( _( "Adding library '%s', file '%s' to project symbol library table." ),
libName, fullFileName );
aReporter.Report( msg, REPORTER::RPT_INFO );
prjLibTable.InsertRow( new SYMBOL_LIB_TABLE_ROW( libName, fullFileName,
pluginType ) );
}
else
{
msg.Printf( _( "Library '%s' not found." ), fullFileName );
aReporter.Report( msg, REPORTER::RPT_WARNING );
}
}
// Don't save empty project symbol library table.
if( !prjLibTable.IsEmpty() )
{
wxFileName fn( Prj().GetProjectPath(), SYMBOL_LIB_TABLE::GetSymbolLibTableFileName() );
try
{
FILE_OUTPUTFORMATTER formatter( fn.GetFullPath() );
prjLibTable.Format( &formatter, 0 );
}
catch( const IO_ERROR& ioe )
{
msg.Printf( _( "Failed to write project symbol library table. Error:\n %s" ),
ioe.What() );
aReporter.Report( msg, REPORTER::RPT_ERROR );
}
aReporter.Report( _( "Created project symbol library table.\n" ), REPORTER::RPT_INFO );
}
}
}
void DIALOG_SYMBOL_REMAP::remapSymbolsToLibTable( REPORTER& aReporter )
{
wxString msg;
SCH_SCREENS schematic;
SCH_COMPONENT* symbol;
SCH_ITEM* item;
SCH_ITEM* nextItem;
SCH_SCREEN* screen;
for( screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
{
for( item = screen->GetDrawItems(); item; item = nextItem )
{
nextItem = item->Next();
if( item->Type() != SCH_COMPONENT_T )
continue;
symbol = dynamic_cast< SCH_COMPONENT* >( item );
if( !remapSymbolToLibTable( symbol ) )
{
msg.Printf( _( "No symbol '%s' found in symbol library table." ),
symbol->GetLibId().GetLibItemName().wx_str() );
aReporter.Report( msg, REPORTER::RPT_WARNING );
}
else
{
msg.Printf( _( "Symbol '%s' mapped to symbol library '%s'." ),
symbol->GetLibId().GetLibItemName().wx_str(),
symbol->GetLibId().GetLibNickname().wx_str() );
aReporter.Report( msg, REPORTER::RPT_ACTION );
screen->SetModify();
}
}
}
aReporter.Report( _( "Symbol library table mapping complete!" ), REPORTER::RPT_INFO );
schematic.UpdateSymbolLinks( true );
}
bool DIALOG_SYMBOL_REMAP::remapSymbolToLibTable( SCH_COMPONENT* aSymbol )
{
wxCHECK_MSG( aSymbol != NULL, false, "Null pointer passed to remapSymbolToLibTable." );
wxCHECK_MSG( aSymbol->GetLibId().GetLibNickname().empty(), false,
"Cannot remap symbol that is already mapped." );
wxCHECK_MSG( !aSymbol->GetLibId().GetLibItemName().empty(), false,
"The symbol LIB_ID name is empty." );
PART_LIBS* libs = Prj().SchLibs();
for( PART_LIBS_BASE::iterator it = libs->begin(); it != libs->end(); ++it )
{
// Ignore the cache library.
if( it->IsCache() )
continue;
LIB_ALIAS* alias = it->FindAlias( aSymbol->GetLibId().GetLibItemName() );
// Found in the same library as the old look up method assuming the user didn't
// change the libraries or library ordering since the last time the schematic was
// loaded.
if( alias )
{
// Find the same library in the symbol library table using the full path and file name.
wxString libFileName = it->GetFullFileName();
const LIB_TABLE_ROW* row = Prj().SchSymbolLibTable()->FindRowByURI( libFileName );
if( row )
{
LIB_ID id = aSymbol->GetLibId();
id.SetLibNickname( row->GetNickName() );
// Don't resolve symbol library links now.
aSymbol->SetLibId( id, nullptr, nullptr );
return true;
}
}
}
return false;
}