307 lines
9.8 KiB
C++
307 lines
9.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 <symbol_lib_table.h>
|
|
|
|
#include <dialog_symbol_remap.h>
|
|
|
|
|
|
DIALOG_SYMBOL_REMAP::DIALOG_SYMBOL_REMAP( wxWindow* aParent ) :
|
|
DIALOG_SYMBOL_REMAP_BASE( aParent )
|
|
{
|
|
}
|
|
|
|
|
|
void DIALOG_SYMBOL_REMAP::OnRemapSymbols( wxCommandEvent& aEvent )
|
|
{
|
|
// 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() );
|
|
}
|
|
|
|
|
|
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 tmp;
|
|
wxString fullFileName;
|
|
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.
|
|
const ENV_VAR_MAP& envMap = Pgm().GetLocalEnvVariables();
|
|
wxFileName envPath;
|
|
|
|
for( auto& entry : envMap )
|
|
{
|
|
envPath.SetPath( entry.second.GetValue() );
|
|
|
|
if( normalizeAbsolutePaths( envPath, fn, &tmp ) )
|
|
{
|
|
fullFileName = "${" + entry.first + "}/";
|
|
|
|
if( !tmp.IsEmpty() )
|
|
fullFileName += tmp;
|
|
|
|
fullFileName += fn.GetFullName();
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Check the project path if no local environment variable paths where found.
|
|
if( fullFileName.IsEmpty() )
|
|
{
|
|
envPath.SetPath( Prj().GetProjectPath() );
|
|
|
|
if( normalizeAbsolutePaths( envPath, fn, &tmp ) )
|
|
{
|
|
fullFileName = wxString( "${" ) + PROJECT_VAR_NAME + wxString( "}/" );
|
|
|
|
if( !tmp.IsEmpty() )
|
|
fullFileName += tmp;
|
|
|
|
fullFileName += fn.GetFullName();
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Fall back to the absolute library path.
|
|
if( fullFileName.IsEmpty() )
|
|
fullFileName = lib->GetFullFileName();
|
|
|
|
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 ) );
|
|
}
|
|
|
|
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 );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
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' founded in symbol library table." ),
|
|
FROM_UTF8( symbol->GetLibId().GetLibItemName() ) );
|
|
aReporter.Report( msg, REPORTER::RPT_WARNING );
|
|
}
|
|
else
|
|
{
|
|
msg.Printf( _( "Symbol '%s' mapped to symbol library '%s'." ),
|
|
FROM_UTF8( symbol->GetLibId().GetLibItemName() ),
|
|
FROM_UTF8( symbol->GetLibId().GetLibNickname() ) );
|
|
aReporter.Report( msg, REPORTER::RPT_ACTION );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
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() );
|
|
aSymbol->SetLibId( id, Prj().SchSymbolLibTable() );
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
bool DIALOG_SYMBOL_REMAP::normalizeAbsolutePaths( const wxFileName& aPathA,
|
|
const wxFileName& aPathB,
|
|
wxString* aResultPath )
|
|
{
|
|
wxCHECK_MSG( aPathA.IsAbsolute(), false, "Arguement 'aPathA' must be an absolute path." );
|
|
wxCHECK_MSG( aPathB.IsAbsolute(), false, "Arguement 'aPathB' must be an absolute path." );
|
|
|
|
if( aPathA.GetPath() == aPathB.GetPath() )
|
|
return true;
|
|
|
|
if( ( aPathA.GetDirCount() > aPathB.GetDirCount() )
|
|
|| ( aPathA.HasVolume() && !aPathB.HasVolume() )
|
|
|| ( !aPathA.HasVolume() && aPathB.HasVolume() )
|
|
|| ( ( aPathA.HasVolume() && aPathB.HasVolume() )
|
|
&& ( aPathA.GetVolume() == aPathB.GetVolume() ) ) )
|
|
return false;
|
|
|
|
wxArrayString aDirs = aPathA.GetDirs();
|
|
wxArrayString bDirs = aPathB.GetDirs();
|
|
|
|
size_t i = 0;
|
|
|
|
while( i < aDirs.GetCount() )
|
|
{
|
|
if( aDirs[i] != bDirs[i] )
|
|
return false;
|
|
|
|
i++;
|
|
}
|
|
|
|
if( aResultPath )
|
|
{
|
|
while( i < bDirs.GetCount() )
|
|
{
|
|
*aResultPath += bDirs[i] + wxT( "/" );
|
|
i++;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|