Commit ce409e36 authored by Wayne Stambaugh's avatar Wayne Stambaugh

CvPcb footprint library table implementation.

* Add code to CvPcb to handle assigning component footprints from the
  footprint library table instead of the search path method.
* Add code to CvPcb to allow editing of the footprint library table.
* CvPcb footprint and component panes display fully qualified FPID names.
* Make CvPcb library pane display footprint library table nicknames instead
  of library file names.
* Add code to FP_LIB_TABLE object to test the paths in the table against the
  list of libraries loaded from the project file.
* Add code to FP_LIB_TABLE to convert assigned footprints in a NETLIST from
  legacy format to footprint library table format.
* Split out COMPONENT_NET, COMPONENT, and NETLIST objects from netlist_reader
  files and create new pcb_netlist files.
* Fix minor wxListView scroll bar sizing issues.
* Add new token and code to save and load FPID nickname in board file.
* Add new token and code to save and load FPID nickname in s-expression net
  list file.
* Add WX_STRING_REPORT object to dump strings to a wxString object.
parent 87290e52
......@@ -137,6 +137,7 @@ set(PCB_COMMON_SRCS
../pcbnew/legacy_plugin.cpp
../pcbnew/kicad_plugin.cpp
../pcbnew/gpcb_plugin.cpp
../pcbnew/pcb_netlist.cpp
pcb_plot_params_keywords.cpp
pcb_keywords.cpp
../pcbnew/pcb_parser.cpp
......
......@@ -39,6 +39,7 @@
#include <footprint_info.h>
#include <io_mgr.h>
#include <fp_lib_table.h>
#include <fpid.h>
#include <class_module.h>
......@@ -182,6 +183,31 @@ bool FOOTPRINT_LIST::ReadFootprintFiles( FP_LIB_TABLE& aTable )
}
FOOTPRINT_INFO* FOOTPRINT_LIST::GetModuleInfo( const wxString & aFootprintName )
{
BOOST_FOREACH( FOOTPRINT_INFO& footprint, m_List )
{
#if defined( USE_FP_LIB_TABLE )
FPID fpid;
wxCHECK_MSG( fpid.Parse( TO_UTF8( aFootprintName ) ) < 0, NULL,
wxString::Format( wxT( "<%s> is not a valid FPID." ),
GetChars( aFootprintName ) ) );
wxString libNickname = FROM_UTF8( fpid.GetLibNickname().c_str() );
wxString footprintName = FROM_UTF8( fpid.GetFootprintName().c_str() );
if( libNickname == footprint.m_libName && footprintName == footprint.m_Module )
return &footprint;
#else
if( aFootprintName.CmpNoCase( footprint.m_Module ) == 0 )
return &footprint;
#endif
}
return NULL;
}
bool FOOTPRINT_INFO::InLibrary( const wxString& aLibrary ) const
{
if( aLibrary.IsEmpty() )
......
......@@ -31,10 +31,14 @@
#include <set>
#include <appl_wxstruct.h>
#include <pcb_netlist.h>
#include <reporter.h>
#include <footprint_info.h>
#include <wildcards_and_files_ext.h>
#include <fpid.h>
#include <fp_lib_table_lexer.h>
#include <fp_lib_table.h>
using namespace FP_LIB_TABLE_T;
......@@ -251,6 +255,35 @@ const FP_LIB_TABLE::ROW* FP_LIB_TABLE::findRow( const wxString& aNickName )
}
const FP_LIB_TABLE::ROW* FP_LIB_TABLE::FindRowByURI( const wxString& aURI )
{
FP_LIB_TABLE* cur = this;
do
{
cur->ensureIndex();
for( unsigned i = 0; i < cur->rows.size(); i++ )
{
wxString uri = ExpandSubstitutions( cur->rows[i].GetFullURI() );
if( wxFileName::GetPathSeparator() == wxChar( '\\' ) && uri.Find( wxChar( '/' ) ) >= 0 )
uri.Replace( wxT( "/" ), wxT( "\\" ) );
if( (wxFileName::IsCaseSensitive() && uri == aURI)
|| (!wxFileName::IsCaseSensitive() && uri.Upper() == aURI.Upper() ) )
{
return &cur->rows[i]; // found
}
}
// not found, search fall back table(s), if any
} while( ( cur = cur->fallBack ) != 0 );
return 0; // not found
}
bool FP_LIB_TABLE::InsertRow( const ROW& aRow, bool doReplace )
{
ensureIndex();
......@@ -281,8 +314,8 @@ const FP_LIB_TABLE::ROW* FP_LIB_TABLE::FindRow( const wxString& aLibraryNickName
if( !row )
{
wxString msg = wxString::Format( _("lib table contains no logical lib '%s'" ),
GetChars( aLibraryNickName ) );
wxString msg = wxString::Format( _( "lib table contains no logical lib '%s'" ),
GetChars( aLibraryNickName ) );
THROW_IO_ERROR( msg );
}
......@@ -320,6 +353,185 @@ bool FP_LIB_TABLE::IsEmpty() const
}
bool FP_LIB_TABLE::MissingLegacyLibs( const wxArrayString& aLibNames, wxString* aErrorMsg )
{
bool retv = false;
for( unsigned i = 0; i < aLibNames.GetCount(); i++ )
{
wxFileName fn = wxFileName( wxEmptyString, aLibNames[i], LegacyFootprintLibPathExtension );
wxString legacyLibPath = wxGetApp().FindLibraryPath( fn );
if( legacyLibPath.IsEmpty() )
continue;
if( FindRowByURI( legacyLibPath ) == 0 )
{
retv = true;
if( aErrorMsg )
*aErrorMsg += wxT( "\"" ) + legacyLibPath + wxT( "\"\n" );
}
}
return retv;
}
bool FP_LIB_TABLE::ConvertFromLegacy( NETLIST& aNetList, const wxArrayString& aLibNames,
REPORTER* aReporter ) throw( IO_ERROR )
{
wxString msg;
FPID lastFPID;
COMPONENT* component;
MODULE* module = 0;
bool retv = true;
if( aNetList.IsEmpty() )
return true;
aNetList.SortByFPID();
wxString libPath;
wxFileName fn;
PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::LEGACY ) );
for( unsigned ii = 0; ii < aNetList.GetCount(); ii++ )
{
component = aNetList.GetComponent( ii );
// The footprint hasn't been assigned yet so ignore it.
if( component->GetFPID().empty() )
continue;
if( component->GetFPID() != lastFPID )
{
module = NULL;
for( unsigned ii = 0; ii < aLibNames.GetCount(); ii++ )
{
fn = wxFileName( wxEmptyString, aLibNames[ii], LegacyFootprintLibPathExtension );
libPath = wxGetApp().FindLibraryPath( fn );
if( !libPath )
{
if( aReporter )
{
msg.Printf( _( "Cannot find footprint library file \"%s\" in any of the "
"KiCad legacy library search paths.\n" ),
GetChars( fn.GetFullPath() ) );
aReporter->Report( msg );
}
retv = false;
continue;
}
module = pi->FootprintLoad( libPath,
FROM_UTF8( component->GetFPID().GetFootprintName().c_str() ) );
if( module )
{
lastFPID = component->GetFPID();
break;
}
}
}
if( module == NULL )
{
if( aReporter )
{
msg.Printf( _( "Component `%s` footprint <%s> was not found in any legacy "
"library.\n" ),
GetChars( component->GetReference() ),
GetChars( FROM_UTF8( component->GetFPID().Format().c_str() ) ) );
aReporter->Report( msg );
}
// Clear the footprint assignment since the old library lookup method is no
// longer valid.
FPID emptyFPID;
component->SetFPID( emptyFPID );
retv = false;
continue;
}
else
{
wxLogDebug( wxT( "Found component %s footprint %s in legacy library <%s>." ),
GetChars( component->GetReference() ),
GetChars( GetChars( FROM_UTF8( component->GetFPID().Format().c_str() ) ) ),
GetChars( libPath ) );
wxString libNickname;
FP_LIB_TABLE* cur = this;
do
{
cur->ensureIndex();
for( unsigned i = 0; i < cur->rows.size(); i++ )
{
wxString uri = ExpandSubstitutions( cur->rows[i].GetFullURI() );
if( wxFileName::GetPathSeparator() == wxChar( '\\' )
&& uri.Find( wxChar( '/' ) ) >= 0 )
uri.Replace( wxT( "/"), wxT( "\\" ) );
wxLogDebug( wxT( "Comparing legacy path <%s> to lib table path <%s>." ),
GetChars( libPath ), GetChars( uri ) );
if( uri == libPath )
{
libNickname = cur->rows[i].GetNickName();
break;
}
}
} while( ( cur = cur->fallBack ) != 0 && libNickname.IsEmpty() );
if( libNickname.IsEmpty() )
{
if( aReporter )
{
msg.Printf( _( "Component `%s` footprint <%s> legacy library path <%s > "
"was not found in the footprint library table.\n" ),
GetChars( component->GetReference() ),
GetChars( FROM_UTF8( component->GetFPID().Format().c_str() ) ) );
aReporter->Report( msg );
}
retv = false;
}
else
{
FPID newFPID = lastFPID;
newFPID.SetLibNickname( libNickname );
if( !newFPID.IsValid() )
{
msg.Printf( _( "Component `%s` FPID <%s> is not valid.\n" ),
GetChars( component->GetReference() ),
GetChars( FROM_UTF8( newFPID.Format().c_str() ) ) );
aReporter->Report( msg );
retv = false;
}
else
{
// The footprint name should already be set.
component->SetFPID( newFPID );
}
}
}
}
return retv;
}
bool FP_LIB_TABLE::LoadGlobalTable( FP_LIB_TABLE& aTable ) throw (IO_ERROR, PARSE_ERROR )
{
bool tableExists = true;
......
/**
* @file reporter.h
* @file reporter.cpp
*/
/*
* This program source code file is part of KiCad, a free EDA CAD application.
......@@ -43,3 +43,13 @@ REPORTER& WX_TEXT_CTRL_REPORTER::Report( const wxString& aText )
m_textCtrl->AppendText( aText );
return *this;
}
REPORTER& WX_STRING_REPORTER::Report( const wxString& aText )
{
wxCHECK_MSG( m_string != NULL, *this,
wxT( "No wxString object defined in WX_STRING_REPORTER." ) );
*m_string << aText;
return *this;
}
......@@ -9,6 +9,7 @@ include_directories(
./dialogs
../3d-viewer
../pcbnew
../pcbnew/dialogs
../polygon
../common
${INC_AFTER}
......@@ -22,6 +23,8 @@ set( CVPCB_DIALOGS
dialogs/dialog_cvpcb_config_fbp.cpp
dialogs/dialog_display_options.cpp
dialogs/dialog_display_options_base.cpp
../pcbnew/dialogs/dialog_fp_lib_table.cpp
../pcbnew/dialogs/dialog_fp_lib_table_base.cpp
)
set( CVPCB_SRCS
......
/*************/
/** cfg.cpp **/
/*************/
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2007 Jean-Pierre Charras, jean-pierre.charras
* Copyright (C) 1992-2011 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file cfg.cpp
*/
#include <fctsys.h>
#include <appl_wxstruct.h>
......@@ -9,6 +33,8 @@
#include <gestfich.h>
#include <param_config.h>
#include <wildcards_and_files_ext.h>
#include <fp_lib_table.h>
#include <confirm.h>
#include <cvpcb.h>
#include <cvpcb_mainframe.h>
......@@ -59,8 +85,24 @@ void CVPCB_MAINFRAME::LoadProjectFile( const wxString& aFileName )
if( m_NetlistFileExtension.IsEmpty() )
m_NetlistFileExtension = wxT( "net" );
/* User library path takes precedent over default library search paths. */
// User library path takes precedent over default library search paths.
wxGetApp().InsertLibraryPath( m_UserLibraryPath, 1 );
#if defined( USE_FP_LIB_TABLE )
delete m_footprintLibTable;
// Attempt to load the project footprint library table if it exists.
m_footprintLibTable = new FP_LIB_TABLE();
try
{
m_footprintLibTable->Load( fn, m_globalFootprintTable );
}
catch( IO_ERROR ioe )
{
DisplayError( this, ioe.errorText );
}
#endif
}
......
......@@ -36,6 +36,9 @@
#include <bitmaps.h>
#include <msgpanel.h>
#include <wildcards_and_files_ext.h>
#include <fpid.h>
#include <fp_lib_table.h>
#include <pcbcommon.h>
#include <io_mgr.h>
#include <class_module.h>
......@@ -473,10 +476,59 @@ EDA_COLOR_T DISPLAY_FOOTPRINTS_FRAME::GetGridColor() const
MODULE* DISPLAY_FOOTPRINTS_FRAME::Get_Module( const wxString& aFootprintName )
{
CVPCB_MAINFRAME* parent = ( CVPCB_MAINFRAME* ) GetParent();
MODULE* footprint;
try
{
#if defined( USE_FP_LIB_TABLE )
FPID fpid;
if( fpid.Parse( TO_UTF8( aFootprintName ) ) >= 0 )
{
DisplayInfoMessage( this, wxString::Format( wxT( "Footprint ID <%s> is not valid." ),
GetChars( aFootprintName ) ) );
return NULL;
}
wxString libName = FROM_UTF8( fpid.GetLibNickname().c_str() );
wxLogDebug( wxT( "Load footprint <%s> from library <%s>." ),
fpid.GetFootprintName().c_str(), fpid.GetLibNickname().c_str() );
const FP_LIB_TABLE::ROW* row;
try
{
row = m_footprintLibTable->FindRow( libName );
if( row == NULL )
{
wxString msg;
msg.Printf( _( "No library named <%s> was found in the footprint library table." ),
fpid.GetLibNickname().c_str() );
DisplayInfoMessage( this, msg );
return NULL;
}
}
catch( IO_ERROR ioe )
{
DisplayError( this, ioe.errorText );
}
wxString footprintName = FROM_UTF8( fpid.GetFootprintName().c_str() );
wxString libPath = row->GetFullURI();
libPath = FP_LIB_TABLE::ExpandSubstitutions( libPath );
wxLogDebug( wxT( "Loading footprint <%s> from library <%s>." ),
GetChars( footprintName ), GetChars( libPath ) );
PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::EnumFromStr( row->GetType() ) ) );
footprint = pi->FootprintLoad( libPath, footprintName );
#else
CVPCB_MAINFRAME* parent = ( CVPCB_MAINFRAME* ) GetParent();
PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::LEGACY ) );
for( unsigned i = 0; i < parent->m_ModuleLibNames.GetCount(); ++i )
......@@ -493,19 +545,13 @@ MODULE* DISPLAY_FOOTPRINTS_FRAME::Get_Module( const wxString& aFootprintName )
fn.GetFullName().GetData() );
// @todo we should not be using wxMessageBox directly.
wxMessageBox( msg, titleLibLoadError, wxOK | wxICON_ERROR, this );
wxMessageBox( msg, wxEmptyString, wxOK | wxICON_ERROR, this );
continue;
}
MODULE* footprint = pi->FootprintLoad( libPath, aFootprintName );
if( footprint )
{
footprint->SetParent( (EDA_ITEM*) GetBoard() );
footprint->SetPosition( wxPoint( 0, 0 ) );
return footprint;
}
footprint = pi->FootprintLoad( libPath, aFootprintName );
}
#endif
}
catch( IO_ERROR ioe )
{
......@@ -513,6 +559,13 @@ MODULE* DISPLAY_FOOTPRINTS_FRAME::Get_Module( const wxString& aFootprintName )
return NULL;
}
if( footprint )
{
footprint->SetParent( (EDA_ITEM*) GetBoard() );
footprint->SetPosition( wxPoint( 0, 0 ) );
return footprint;
}
wxString msg = wxString::Format( _( "Footprint '%s' not found" ), aFootprintName.GetData() );
DisplayError( this, msg );
return NULL;
......@@ -532,6 +585,7 @@ void DISPLAY_FOOTPRINTS_FRAME::InitDisplay()
FOOTPRINT_INFO* module_info = parentframe->m_footprints.GetModuleInfo( footprintName );
const wxChar *libname;
if( module_info )
libname = GetChars( module_info->GetLibraryPath() );
else
......
......@@ -135,8 +135,14 @@ void FOOTPRINTS_LISTBOX::SetFootprints( FOOTPRINT_LIST& aList, const wxString& a
{
if( aFilterType == UNFILTERED )
{
#if !defined( USE_FP_LIB_TABLE )
msg.Printf( wxT( "%3zu %s" ), newList.GetCount() + 1,
GetChars( aList.GetItem( ii ).m_Module ) );
#else
msg.Printf( wxT( "%3zu %s:%s" ), newList.GetCount() + 1,
GetChars( aList.GetItem( ii ).GetLibraryName() ),
GetChars( aList.GetItem( ii ).m_Module ) );
#endif
newList.Add( msg );
continue;
}
......@@ -153,8 +159,14 @@ void FOOTPRINTS_LISTBOX::SetFootprints( FOOTPRINT_LIST& aList, const wxString& a
&& (aComponent->GetNetCount() != aList.GetItem( ii ).m_padCount) )
continue;
#if !defined( USE_FP_LIB_TABLE )
msg.Printf( wxT( "%3zu %s" ), newList.GetCount() + 1,
aList.GetItem( ii ).m_Module.GetData() );
#else
msg.Printf( wxT( "%3zu %s:%s" ), newList.GetCount() + 1,
GetChars( aList.GetItem( ii ).GetLibraryName() ),
GetChars( aList.GetItem( ii ).m_Module ) );
#endif
newList.Add( msg );
}
......@@ -169,9 +181,24 @@ void FOOTPRINTS_LISTBOX::SetFootprints( FOOTPRINT_LIST& aList, const wxString& a
selection = 0;
DeleteAllItems();
SetItemCount( m_footprintList.GetCount() );
SetSelection( selection, true );
Refresh();
if( m_footprintList.GetCount() )
{
SetItemCount( m_footprintList.GetCount() );
SetSelection( selection, true );
RefreshItems( 0L, m_footprintList.GetCount()-1 );
#if defined (__WXGTK__ )
// @bug On GTK and wxWidgets 2.8.x, this will assert in debug builds because the
// column parameter is -1. This was the only way to prevent GTK3 from
// ellipsizing long strings down to a few characters. It still doesn't set
// the scroll bars correctly (too short) but it's better than any of the
// other alternatives. If someone knows how to fix this, please do.
SetColumnWidth( -1, wxLIST_AUTOSIZE );
#else
SetColumnWidth( 0, wxLIST_AUTOSIZE );
#endif
}
}
......
......@@ -124,7 +124,21 @@ void LIBRARY_LISTBOX::SetLibraryList( const wxArrayString& aList )
if( GetCount() == 0 || oldSelection < 0 || oldSelection >= GetCount() )
SetSelection( 0, true );
Refresh();
if( m_libraryList.Count() )
{
RefreshItems( 0L, m_libraryList.Count()-1 );
#if defined (__WXGTK__ )
// @bug On GTK and wxWidgets 2.8.x, this will assert in debug builds because the
// column parameter is -1. This was the only way to prevent GTK3 from
// ellipsizing long strings down to a few characters. It still doesn't set
// the scroll bars correctly (too short) but it's better than any of the
// other alternatives. If someone knows how to fix this, please do.
SetColumnWidth( -1, wxLIST_AUTOSIZE );
#else
SetColumnWidth( 0, wxLIST_AUTOSIZE );
#endif
}
}
......
......@@ -28,22 +28,25 @@
*/
#include <fctsys.h>
#include <build_version.h>
#include <appl_wxstruct.h>
#include <macros.h>
#include <confirm.h>
#include <eda_doc.h>
#include <eda_dde.h>
#include <gestfich.h>
#include <html_messagebox.h>
#include <wildcards_and_files_ext.h>
#include <fp_lib_table.h>
#include <netlist_reader.h>
#include <cvpcb_mainframe.h>
#include <cvpcb.h>
#include <cvstruct.h>
#include <dialog_cvpcb_config.h>
#include <class_DisplayFootprintsFrame.h>
#include <cvpcb_id.h>
#include <html_messagebox.h>
#include <wildcards_and_files_ext.h>
#include <build_version.h>
#define FRAME_MIN_SIZE_X 450
#define FRAME_MIN_SIZE_Y 300
......@@ -54,6 +57,16 @@ static const wxString KeepCvpcbOpenEntry( wxT( "KeepCvpcbOpen" ) );
static const wxString FootprintDocFileEntry( wxT( "footprints_doc_file" ) );
/**
* Function InvokePcbLibTableEditor
* shows the modal DIALOG_FP_LIB_TABLE for purposes of editing two lib tables.
*
* @return int - bits 0 and 1 tell whether a change was made to the @a aGlobal
* and/or the @a aProject table, respectively. If set, table was modified.
*/
int InvokePcbLibTableEditor( wxFrame* aParent, FP_LIB_TABLE* aGlobal, FP_LIB_TABLE* aProject );
BEGIN_EVENT_TABLE( CVPCB_MAINFRAME, EDA_BASE_FRAME )
EVT_MENU_RANGE( wxID_FILE1, wxID_FILE9, CVPCB_MAINFRAME::LoadNetList )
......@@ -69,6 +82,10 @@ BEGIN_EVENT_TABLE( CVPCB_MAINFRAME, EDA_BASE_FRAME )
EVT_MENU( ID_SAVE_PROJECT_AS, CVPCB_MAINFRAME::SaveProjectFile )
EVT_MENU( ID_CVPCB_CONFIG_KEEP_OPEN_ON_SAVE, CVPCB_MAINFRAME::OnKeepOpenOnSave )
#if defined( USE_FP_LIB_TABLE )
EVT_MENU( ID_CVPCB_LIB_TABLE_EDIT, CVPCB_MAINFRAME::OnEditFootprintLibraryTable )
#endif
EVT_MENU_RANGE( ID_LANGUAGE_CHOICE, ID_LANGUAGE_CHOICE_END, CVPCB_MAINFRAME::SetLanguage )
// Toolbar events
......@@ -114,6 +131,11 @@ CVPCB_MAINFRAME::CVPCB_MAINFRAME( const wxString& title, long style ) :
m_undefinedComponentCnt = 0;
m_skipComponentSelect = false;
#if defined( USE_FP_LIB_TABLE )
m_globalFootprintTable = NULL;
m_footprintLibTable = NULL;
#endif
/* Name of the document footprint list
* usually located in share/modules/footprints_doc
* this is of the responsibility to users to create this file
......@@ -185,6 +207,39 @@ CVPCB_MAINFRAME::CVPCB_MAINFRAME( const wxString& title, long style ) :
Right().BestSize( (int) ( m_FrameSize.x * 0.30 ), m_FrameSize.y ) );
m_auimgr.Update();
#if defined( USE_FP_LIB_TABLE )
if( m_globalFootprintTable == NULL )
{
try
{
m_globalFootprintTable = new FP_LIB_TABLE();
if( !FP_LIB_TABLE::LoadGlobalTable( *m_globalFootprintTable ) )
{
DisplayInfoMessage( this, wxT( "You have run CvPcb for the first time using the "
"new footprint library table method of finding "
"footprints. CvPcb has either copied the default "
"table or created an empty table in your home "
"folder. You must first configure the library "
"table to include all footprint libraries not "
"included with KiCad. See the \"Footprint Library "
"Table\" section of the CvPcb documentation for "
"more information." ) );
}
}
catch( IO_ERROR ioe )
{
wxString msg;
msg.Printf( _( "An error occurred attempting to load the global footprint library "
"table:\n\n%s" ), GetChars( ioe.errorText ) );
DisplayError( this, msg );
}
m_footprintLibTable = new FP_LIB_TABLE( m_globalFootprintTable );
}
#endif
}
......@@ -466,6 +521,30 @@ void CVPCB_MAINFRAME::ConfigCvpcb( wxCommandEvent& event )
}
#if defined( USE_FP_LIB_TABLE )
void CVPCB_MAINFRAME::OnEditFootprintLibraryTable( wxCommandEvent& aEvent )
{
int r = InvokePcbLibTableEditor( this, m_globalFootprintTable, m_footprintLibTable );
if( r & 1 )
{
FILE_OUTPUTFORMATTER sf( FP_LIB_TABLE::GetGlobalTableFileName() );
m_globalFootprintTable->Format( &sf, 0 );
}
if( r & 2 )
{
wxFileName fn = m_NetlistFileName;
fn.SetName( FP_LIB_TABLE::GetFileName() );
fn.SetExt( wxEmptyString );
FILE_OUTPUTFORMATTER sf( fn.GetFullPath() );
m_footprintLibTable->Format( &sf, 0 );
}
}
#endif
void CVPCB_MAINFRAME::OnKeepOpenOnSave( wxCommandEvent& event )
{
m_KeepCvpcbOpen = event.IsChecked();
......@@ -523,7 +602,7 @@ void CVPCB_MAINFRAME::OnSelectComponent( wxListEvent& event )
// selected footprint.
if( FindFocus() == m_ListCmp || FindFocus() == m_LibraryList )
{
wxString module = FROM_UTF8( component->GetFPID().GetFootprintName().c_str() );
wxString module = FROM_UTF8( component->GetFPID().Format().c_str() );
bool found = false;
......@@ -667,7 +746,12 @@ bool CVPCB_MAINFRAME::LoadFootprintFiles()
return false;
}
#if !defined( USE_FP_LIB_TABLE )
m_footprints.ReadFootprintFiles( m_ModuleLibNames );
#else
if( m_footprintLibTable != NULL )
m_footprints.ReadFootprintFiles( *m_footprintLibTable );
#endif
// Display error messages, if any.
if( !m_footprints.m_filesNotFound.IsEmpty() || !m_footprints.m_filesInvalid.IsEmpty() )
......@@ -770,7 +854,7 @@ int CVPCB_MAINFRAME::ReadSchematicNetlist()
netlistReader->LoadNetlist();
}
else
wxMessageBox( _( "Unknown netlist format" ), wxEmptyString, wxOK | wxICON_ERROR );
wxMessageBox( _( "Unknown netlist format." ), wxEmptyString, wxOK | wxICON_ERROR );
}
catch( IO_ERROR& ioe )
{
......@@ -852,6 +936,11 @@ void CVPCB_MAINFRAME::CreateScreenCmp()
wxPoint( 0, 0 ),
wxSize( 600, 400 ),
KICAD_DEFAULT_DRAWFRAME_STYLE );
#if defined( USE_FP_LIB_TABLE )
m_DisplayFootprintFrame->SetFootprintLibTable( m_footprintLibTable );
#endif
m_DisplayFootprintFrame->Show( true );
}
else
......@@ -913,8 +1002,23 @@ void CVPCB_MAINFRAME::BuildCmpListBox()
m_ListCmp->m_ComponentList.Add( msg );
}
m_ListCmp->SetItemCount( m_ListCmp->m_ComponentList.Count() );
m_ListCmp->SetSelection( 0, true );
if( m_ListCmp->m_ComponentList.Count() )
{
m_ListCmp->SetItemCount( m_ListCmp->m_ComponentList.Count() );
m_ListCmp->SetSelection( 0, true );
m_ListCmp->RefreshItems( 0L, m_ListCmp->m_ComponentList.Count()-1 );
#if defined (__WXGTK__ )
// @bug On GTK and wxWidgets 2.8.x, this will assert in debug builds because the
// column parameter is -1. This was the only way to prevent GTK3 from
// ellipsizing long strings down to a few characters. It still doesn't set
// the scroll bars correctly (too short) but it's better than any of the
// other alternatives. If someone knows how to fix this, please do.
m_ListCmp->SetColumnWidth( -1, wxLIST_AUTOSIZE );
#else
m_ListCmp->SetColumnWidth( 0, wxLIST_AUTOSIZE );
#endif
}
}
......@@ -932,7 +1036,21 @@ void CVPCB_MAINFRAME::BuildLIBRARY_LISTBOX()
wxFONTWEIGHT_NORMAL ) );
}
#if defined( USE_FP_LIB_TABLE )
if( m_footprintLibTable )
{
wxArrayString libNames;
std::vector< wxString > libNickNames = m_footprintLibTable->GetLogicalLibs();
for( unsigned ii = 0; ii < libNickNames.size(); ii++ )
libNames.Add( libNickNames[ii] );
m_LibraryList->SetLibraryList( libNames );
}
#else
m_LibraryList->SetLibraryList( m_ModuleLibNames );
#endif
}
......
......@@ -5,21 +5,16 @@
#ifndef __CVPCB_H__
#define __CVPCB_H__
#include <pcbcommon.h>
#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/foreach.hpp>
// config for footprints doc file access
#define DEFAULT_FOOTPRINTS_LIST_FILENAME wxT( "footprints_doc/footprints.pdf" )
// Define print format to display a schematic component line
#define CMP_FORMAT wxT( "%3d %8s - %16s : %-.32s" )
#define CMP_FORMAT wxT( "%3d %8s - %16s : %s" )
#define FILTERFOOTPRINTKEY "FilterFootprint"
#define LISTB_STYLE (wxSUNKEN_BORDER | wxLC_NO_HEADER | wxLC_REPORT | wxLC_VIRTUAL)
#define LISTB_STYLE ( wxSUNKEN_BORDER | wxLC_NO_HEADER | wxLC_REPORT | wxLC_VIRTUAL | \
wxLC_SINGLE_SEL | wxVSCROLL | wxHSCROLL )
extern const wxString FootprintAliasFileExtension;
extern const wxString RetroFileExtension;
......
......@@ -32,5 +32,6 @@ enum id_cvpcb_frm
ID_CVPCB_FOOTPRINT_DISPLAY_PIN_FILTERED_LIST,
ID_CVPCB_FOOTPRINT_DISPLAY_BY_LIBRARY_LIST,
ID_CVPCB_CONFIG_KEEP_OPEN_ON_SAVE,
ID_CVPCB_LIBRARY_LIST
ID_CVPCB_LIBRARY_LIST,
ID_CVPCB_LIB_TABLE_EDIT
};
......@@ -31,12 +31,11 @@
#include <wx/listctrl.h>
#include <wx/filename.h>
#include <netlist_reader.h>
#include <pcb_netlist.h>
#include <footprint_info.h>
#include <wxBasePcbFrame.h>
#include <param_config.h>
#include <cvpcb.h>
/* Forward declarations of all top-level window classes. */
......@@ -46,6 +45,7 @@ class COMPONENTS_LISTBOX;
class LIBRARY_LISTBOX;
class DISPLAY_FOOTPRINTS_FRAME;
class COMPONENT;
class FP_LIB_TABLE;
/**
......@@ -55,6 +55,16 @@ class CVPCB_MAINFRAME : public EDA_BASE_FRAME
{
wxArrayString m_footprintListEntries;
#if defined( USE_FP_LIB_TABLE )
/// The global footprint library table.
FP_LIB_TABLE* m_globalFootprintTable;
/// The project footprint library table. This is a combination of the project
/// footprint library table and the global footprint table. This is the one to
/// use when finding a #MODULE.
FP_LIB_TABLE* m_footprintLibTable;
#endif
public:
bool m_KeepCvpcbOpen;
FOOTPRINTS_LISTBOX* m_FootprintList;
......@@ -92,6 +102,13 @@ public:
*/
void OnSelectComponent( wxListEvent& event );
/**
* Function OnEditFootrprintLibraryTable
* displays the footprint library table editing dialog and updates the global and local
* footprint tables accordingly.
*/
void OnEditFootrprintLibraryTable( wxCommandEvent& event );
void OnQuit( wxCommandEvent& event );
void OnCloseWindow( wxCloseEvent& Event );
void OnSize( wxSizeEvent& SizeEvent );
......@@ -126,6 +143,15 @@ public:
void LoadNetList( wxCommandEvent& event );
void ConfigCvpcb( wxCommandEvent& event );
/**
* Function OnEditLibraryTable
* envokes the footpirnt library table edit dialog.
*/
#if defined( USE_FP_LIB_TABLE )
void OnEditFootprintLibraryTable( wxCommandEvent& aEvent );
#endif
void OnKeepOpenOnSave( wxCommandEvent& event );
void DisplayModule( wxCommandEvent& event );
......
......@@ -30,7 +30,6 @@
#include <wx/listctrl.h>
#include <cvpcb.h>
/* Forward declarations of all top-level window classes. */
class CVPCB_MAINFRAME;
......
......@@ -110,11 +110,17 @@ void CVPCB_MAINFRAME::ReCreateMenuBar()
// Menu Preferences:
wxMenu* preferencesMenu = new wxMenu;
#if !defined( USE_FP_LIB_TABLE )
// Libraries to load
AddMenuItem( preferencesMenu, wxID_PREFERENCES,
_( "&Libraries" ),
_( "Set footprint libraries to load and library search paths" ),
KiBitmap( config_xpm ) );
#else
AddMenuItem( preferencesMenu, ID_CVPCB_LIB_TABLE_EDIT,
_( "Li&brary Tables" ), _( "Setup footprint libraries" ),
KiBitmap( library_table_xpm ) );
#endif
// Language submenu
wxGetApp().AddMenuLanguageList( preferencesMenu );
......
......@@ -31,6 +31,11 @@
#include <common.h>
#include <confirm.h>
#include <build_version.h>
#include <macros.h>
#include <fpid.h>
#include <fp_lib_table.h>
#include <reporter.h>
#include <html_messagebox.h>
#include <cvpcb.h>
#include <cvpcb_mainframe.h>
......@@ -50,7 +55,6 @@ void CVPCB_MAINFRAME::SetNewPkg( const wxString& aFootprintName )
return;
// If no component is selected, select the first one
if( m_ListCmp->GetFirstSelected() < 0 )
{
componentIndex = 0;
......@@ -58,11 +62,9 @@ void CVPCB_MAINFRAME::SetNewPkg( const wxString& aFootprintName )
}
// iterate over the selection
while( m_ListCmp->GetFirstSelected() != -1)
while( m_ListCmp->GetFirstSelected() != -1 )
{
// Get the component for the current iteration
componentIndex = m_ListCmp->GetFirstSelected();
component = m_netlist.GetComponent( componentIndex );
......@@ -70,13 +72,21 @@ void CVPCB_MAINFRAME::SetNewPkg( const wxString& aFootprintName )
return;
// Check to see if the component has already a footprint set.
hasFootprint = !component->GetFPID().empty();
#if defined( USE_FP_LIB_TABLE )
FPID fpid;
wxCHECK_RET( fpid.Parse( TO_UTF8( aFootprintName ) ) < 0,
wxString::Format( wxT( "<%s> is not a valid FPID." ),
GetChars( aFootprintName ) ) );
component->SetFPID( fpid );
#else
component->SetFPID( FPID( aFootprintName ) );
#endif
// create the new component description
description.Printf( CMP_FORMAT, componentIndex + 1,
GetChars( component->GetReference() ),
GetChars( component->GetValue() ),
......@@ -85,7 +95,6 @@ void CVPCB_MAINFRAME::SetNewPkg( const wxString& aFootprintName )
// If the component hasn't had a footprint associated with it
// it now has, so we decrement the count of components without
// a footprint assigned.
if( !hasFootprint )
{
hasFootprint = true;
......@@ -115,6 +124,7 @@ bool CVPCB_MAINFRAME::ReadNetListAndLinkFiles()
{
COMPONENT* component;
wxString msg;
bool isLegacy = true;
ReadSchematicNetlist();
......@@ -129,6 +139,87 @@ bool CVPCB_MAINFRAME::ReadNetListAndLinkFiles()
m_ListCmp->Clear();
m_undefinedComponentCnt = 0;
if( m_netlist.AnyFootprintsLinked() )
{
for( unsigned i = 0; i < m_netlist.GetCount(); i++ )
{
component = m_netlist.GetComponent( i );
if( component->GetFPID().empty() )
continue;
if( isLegacy )
{
if( !component->GetFPID().IsLegacy() )
isLegacy = false;
}
}
}
else
{
isLegacy = false; // None of the components have footprints assigned.
}
#if defined( USE_FP_LIB_TABLE )
wxString missingLibs;
// Check if footprint links were generated before the footprint library table was implemented.
if( isLegacy )
{
if( m_footprintLibTable->MissingLegacyLibs( m_ModuleLibNames, &missingLibs ) )
{
msg = wxT( "The following legacy libraries are defined in the project file "
"were not found in the footprint library table:\n\n" ) + missingLibs;
msg += wxT( "\nDo you want to update the footprint library table before "
"attempting to update the assigned footprints?" );
if( IsOK( this, msg ) )
{
wxCommandEvent cmd;
OnEditFootprintLibraryTable( cmd );
}
}
msg = wxT( "Some or all of the assigned footprints contain legacy entries. Would you "
"like CvPcb to attempt to convert them to the new footprint library table "
"format?" );
if( IsOK( this, msg ) )
{
msg.Clear();
WX_STRING_REPORTER reporter( &msg );
if( !m_footprintLibTable->ConvertFromLegacy( m_netlist, m_ModuleLibNames, &reporter ) )
{
HTML_MESSAGE_BOX dlg( this, wxEmptyString );
dlg.MessageSet( wxT( "The following errors occurred attempt to convert the "
"footprint assignments:\n\n" ) );
dlg.ListSet( msg );
dlg.MessageSet( wxT( "\nYou will need to reassign them manually if you want them "
"to be updated correctly the next time you import the "
"netlist in Pcbnew." ) );
dlg.ShowModal();
}
m_modified = true;
}
else
{
// Clear the legacy footprint assignments.
for( unsigned i = 0; i < m_netlist.GetCount(); i++ )
{
FPID emptyFPID;
component = m_netlist.GetComponent( i );
component->SetFPID( emptyFPID );
m_modified = true;
}
}
}
#endif
for( unsigned i = 0; i < m_netlist.GetCount(); i++ )
{
component = m_netlist.GetComponent( i );
......@@ -137,10 +228,14 @@ bool CVPCB_MAINFRAME::ReadNetListAndLinkFiles()
GetChars( component->GetReference() ),
GetChars( component->GetValue() ),
GetChars( FROM_UTF8( component->GetFPID().Format().c_str() ) ) );
m_ListCmp->AppendLine( msg );
if( component->GetFPID().empty() )
{
m_undefinedComponentCnt += 1;
continue;
}
}
if( !m_netlist.IsEmpty() )
......
......@@ -102,15 +102,7 @@ public:
* @return the item stored in list if found
* @param aFootprintName = the name of item
*/
FOOTPRINT_INFO * GetModuleInfo( const wxString & aFootprintName )
{
BOOST_FOREACH( FOOTPRINT_INFO& footprint, m_List )
{
if( aFootprintName.CmpNoCase( footprint.m_Module ) == 0 )
return &footprint;
}
return NULL;
}
FOOTPRINT_INFO* GetModuleInfo( const wxString & aFootprintName );
/**
* Function GetItem
......@@ -159,6 +151,13 @@ public:
/// FOOTPRINT object list sort function.
inline bool operator<( const FOOTPRINT_INFO& item1, const FOOTPRINT_INFO& item2 )
{
#if defined( USE_FP_LIB_TABLE )
int retv = StrNumCmp( item1.m_libName, item2.m_libName, INT_MAX, true );
if( retv != 0 )
return retv < 0;
#endif
return StrNumCmp( item1.m_Module, item2.m_Module, INT_MAX, true ) < 0;
}
......
......@@ -31,13 +31,16 @@
#include <vector>
#include <map>
//#include <fpid.h>
#include <io_mgr.h>
class wxFileName;
class OUTPUTFORMATTER;
class MODULE;
class FP_LIB_TABLE_LEXER;
class NETLIST;
class REPORTER;
/**
* Class FP_LIB_TABLE
......@@ -355,12 +358,50 @@ public:
*/
const ROW* FindRow( const wxString& aNickName ) throw( IO_ERROR );
/**
* Function FindRowByURI
* returns a #ROW if aURE is found in this table or in any chained
* fallBack table fragments, else NULL.
*/
const ROW* FindRowByURI( const wxString& aURI );
/**
* Function IsEmpty
* @return true if the footprint library table is empty.
*/
bool IsEmpty() const;
/**
* Function MissingLegacyLibs
* tests the list of \a aLibNames by URI to determine if any of them are missing from
* the #FP_LIB_TABLE.
*
* @note The missing legacy footprint library test is performed by using old library
* file path lookup method. If the library is found, it is compared against all
* of the URIs in the table rather than the nickname. This was done because the
* user could change the nicknames from the default table. Using the full path
* is more reliable.
*
* @param aLibNames is the list of legacy library names.
* @param aErrorMsg is a pointer to a wxString object to store the URIs of any missing
* legacy library paths. Can be NULL.
* @return true if there are missing legacy libraries. Otherwise false.
*/
bool MissingLegacyLibs( const wxArrayString& aLibNames, wxString* aErrorMsg = NULL );
/**
* Function ConvertFromLegacy
* converts the footprint names in \a aNetList from the legacy fromat to the #FPID format.
*
* @param aNetList is the #NETLIST object to convert.
* @param aLibNames is the list of legacy footprint library names from the currently loaded
* project.
* @param aReporter is the #REPORTER object to dump messages into.
* @return true if all footprint names were successfully converted to a valid FPID.
*/
bool ConvertFromLegacy( NETLIST& aNetList, const wxArrayString& aLibNames,
REPORTER* aReporter = NULL ) throw( IO_ERROR );
/**
* Function ExpandEnvSubsitutions
* replaces any environment variable references with their values and is
......
......@@ -136,4 +136,23 @@ public:
REPORTER& Report( const wxString& aText );
};
/**
* Class WX_STRING_REPROTER
* is a wrapper for reporting to a wxString object.
*/
class WX_STRING_REPORTER : public REPORTER
{
wxString* m_string;
public:
WX_STRING_REPORTER( wxString* aString ) :
REPORTER(),
m_string( aString )
{
}
REPORTER& Report( const wxString& aText );
};
#endif // _REPORTER_H_
......@@ -39,7 +39,7 @@
#include <pcbcommon.h>
#include <wxBasePcbFrame.h>
#include <msgpanel.h>
#include <netlist_reader.h>
#include <pcb_netlist.h>
#include <reporter.h>
#include <base_units.h>
......
......@@ -29,11 +29,13 @@
#include <fctsys.h>
#include <appl_wxstruct.h>
#include <confirm.h>
#include <macros.h>
#include <dialog_helpers.h>
#include <html_messagebox.h>
#include <base_units.h>
#include <wxPcbStruct.h>
#include <pcbcommon.h>
#include <pcb_netlist.h>
#include <netlist_reader.h>
#include <reporter.h>
......
......@@ -28,6 +28,8 @@
#include <wx/wx.h>
#include <netlist_lexer.h> // netlist_lexer is common to Eeschema and Pcbnew
#include <macros.h>
#include <pcb_netlist.h>
#include <netlist_reader.h>
using namespace NL_T;
......
......@@ -31,6 +31,7 @@
#include <richio.h>
#include <kicad_string.h>
#include <pcb_netlist.h>
#include <netlist_reader.h>
......
......@@ -33,6 +33,7 @@
#include <confirm.h>
#include <dialog_helpers.h>
#include <wxPcbStruct.h>
#include <pcb_netlist.h>
#include <netlist_reader.h>
#include <reporter.h>
#include <wildcards_and_files_ext.h>
......
......@@ -31,267 +31,13 @@
#include <kicad_string.h>
#include <reporter.h>
#include <pcb_netlist.h>
#include <netlist_reader.h>
#include <class_module.h>
#include <wx/regex.h>
#if defined(DEBUG)
/**
* Function NestedSpace
* outputs nested space for pretty indenting.
* @param aNestLevel The nest count
* @param aReporter A reference to a #REPORTER object where to output.
* @return REPORTER& for continuation.
**/
static REPORTER& NestedSpace( int aNestLevel, REPORTER& aReporter )
{
for( int i = 0; i < aNestLevel; ++i )
aReporter.Report( wxT( " " ) );
return aReporter;
}
void COMPONENT_NET::Show( int aNestLevel, REPORTER& aReporter )
{
NestedSpace( aNestLevel, aReporter );
aReporter.Report( wxString::Format( wxT( "<pin_name=%s net_name=%s>\n" ),
GetChars( m_pinName ), GetChars( m_netName ) ) );
}
#endif
void COMPONENT::SetModule( MODULE* aModule )
{
m_footprint.reset( aModule );
if( aModule == NULL )
return;
aModule->SetReference( m_reference );
aModule->SetValue( m_value );
aModule->SetFPID( m_fpid );
aModule->SetPath( m_timeStamp );
}
COMPONENT_NET COMPONENT::m_emptyNet;
const COMPONENT_NET& COMPONENT::GetNet( const wxString& aPinName )
{
for( unsigned i = 0; i < m_nets.size(); i++ )
{
if( m_nets[i].GetPinName() == aPinName )
return m_nets[i];
}
return m_emptyNet;
}
bool COMPONENT::MatchesFootprintFilters( const wxString& aFootprintName ) const
{
if( m_footprintFilters.GetCount() == 0 )
return true;
// The matching is case insensitive
wxString name = aFootprintName.Upper();
for( unsigned ii = 0; ii < m_footprintFilters.GetCount(); ii++ )
{
if( name.Matches( m_footprintFilters[ii].Upper() ) )
return true;
}
return false;
}
#if defined(DEBUG)
void COMPONENT::Show( int aNestLevel, REPORTER& aReporter )
{
NestedSpace( aNestLevel, aReporter );
aReporter.Report( wxT( "<component>\n" ) );
NestedSpace( aNestLevel+1, aReporter );
aReporter.Report( wxString::Format( wxT( "<ref=%s value=%s name=%s library=%s fpid=%s "
" timestamp=%s>\n" ),
GetChars( m_reference ), GetChars( m_value ),
GetChars( m_name ), GetChars( m_library ),
m_fpid.Format().c_str(),
GetChars( m_timeStamp ) ) );
if( !m_footprintFilters.IsEmpty() )
{
NestedSpace( aNestLevel+1, aReporter );
aReporter.Report( wxT( "<fp_filters>\n" ) );
for( unsigned i = 0; i < m_footprintFilters.GetCount(); i++ )
{
NestedSpace( aNestLevel+2, aReporter );
aReporter.Report( wxString::Format( wxT( "<%s>\n" ),
GetChars( m_footprintFilters[i] ) ) );
}
NestedSpace( aNestLevel+1, aReporter );
aReporter.Report( wxT( "</fp_filters>\n" ) );
}
if( !m_nets.empty() )
{
NestedSpace( aNestLevel+1, aReporter );
aReporter.Report( wxT( "<nets>\n" ) );
for( unsigned i = 0; i < m_nets.size(); i++ )
m_nets[i].Show( aNestLevel+3, aReporter );
NestedSpace( aNestLevel+1, aReporter );
aReporter.Report( "</nets>\n" );
}
NestedSpace( aNestLevel, aReporter );
aReporter.Report( "</component>\n" );
}
#endif
void NETLIST::AddComponent( COMPONENT* aComponent )
{
m_components.push_back( aComponent );
}
COMPONENT* NETLIST::GetComponentByReference( const wxString& aReference )
{
COMPONENT* component = NULL;
for( unsigned i = 0; i < m_components.size(); i++ )
{
if( m_components[i].GetReference() == aReference )
{
component = &m_components[i];
break;
}
}
return component;
}
COMPONENT* NETLIST::GetComponentByTimeStamp( const wxString& aTimeStamp )
{
COMPONENT* component = NULL;
for( unsigned i = 0; i < m_components.size(); i++ )
{
if( m_components[i].GetTimeStamp() == aTimeStamp )
{
component = &m_components[i];
break;
}
}
return component;
}
/**
* Function ByFPID
* is a helper function used to sort the component list used by loadNewModules.
*/
static bool ByFPID( const COMPONENT& ref, const COMPONENT& cmp )
{
return ref.GetFPID() > cmp.GetFPID();
}
void NETLIST::SortByFPID()
{
m_components.sort( ByFPID );
}
/**
* Operator <
* compares two #COMPONENT objects by reference designator.
*/
bool operator < ( const COMPONENT& item1, const COMPONENT& item2 )
{
return StrNumCmp( item1.GetReference(), item2.GetReference(), INT_MAX, true ) < 0;
}
void NETLIST::SortByReference()
{
m_components.sort();
}
bool NETLIST::AnyFootprintsLinked() const
{
for( unsigned i = 0; i < m_components.size(); i++ )
{
if( !m_components[i].GetFPID().empty() )
return true;
}
return false;
}
bool NETLIST::AllFootprintsLinked() const
{
for( unsigned i = 0; i < m_components.size(); i++ )
{
if( m_components[i].GetFPID().empty() )
return false;
}
return true;
}
bool NETLIST::AnyFootprintsChanged() const
{
for( unsigned i = 0; i < m_components.size(); i++ )
{
if( m_components[i].FootprintChanged() )
return true;
}
return false;
}
#if defined( DEBUG )
void NETLIST::Show( int aNestLevel, REPORTER& aReporter )
{
NestedSpace( aNestLevel, aReporter );
aReporter.Report( "<netlist>\n" );
if( !m_components.empty() )
{
NestedSpace( aNestLevel+1, aReporter );
aReporter.Report( "<components>\n" );
for( unsigned i = 0; i < m_components.size(); i++ )
{
m_components[i].Show( aNestLevel+2, aReporter );
}
NestedSpace( aNestLevel+1, aReporter );
aReporter.Report( "</components>\n" );
}
NestedSpace( aNestLevel, aReporter );
aReporter.Report( "</netlist>\n" );
}
#endif
NETLIST_READER::~NETLIST_READER()
{
if( m_lineReader )
......@@ -308,7 +54,6 @@ NETLIST_READER::~NETLIST_READER()
}
NETLIST_READER::NETLIST_FILE_T NETLIST_READER::GuessNetlistFileType( LINE_READER* aLineReader )
{
// Orcad Pcb2 netlist format starts by "( {", followed by an unknown comment,
......@@ -447,14 +192,17 @@ bool CMP_READER::Load( NETLIST* aNetlist ) throw( IO_ERROR, PARSE_ERROR )
// Find the corresponding item in component list:
COMPONENT* component = aNetlist->GetComponentByReference( reference );
// the corresponding component could be no more existing in netlist:
// this is the case when it is just removed from schematic,
// and still exists in footprint assignment list, before this list is updated
// This is an usual case during the life of a design
// The corresponding component could no longer existing in the netlist. This
// can happed when it is removed from schematic and still exists in footprint
// assignment list. This is an usual case during the life of a design.
if( component )
{
component->SetFPID( FPID( footprint ) );
}
else
{
ok = false; // can be used to display a warning in Pcbnew.
}
}
return ok;
......
This diff is collapsed.
/**
* @file pcb_netlist.cpp
*/
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 1992-2011 Jean-Pierre Charras.
* Copyright (C) 2013 Wayne Stambaugh <stambaughw@verizon.net>.
* Copyright (C) 1992-2011 KiCad Developers, see change_log.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <macros.h>
#include <kicad_string.h>
#include <reporter.h>
#include <pcb_netlist.h>
#include <class_module.h>
#if defined(DEBUG)
/**
* Function NestedSpace
* outputs nested space for pretty indenting.
* @param aNestLevel The nest count
* @param aReporter A reference to a #REPORTER object where to output.
* @return REPORTER& for continuation.
**/
static REPORTER& NestedSpace( int aNestLevel, REPORTER& aReporter )
{
for( int i = 0; i < aNestLevel; ++i )
aReporter.Report( wxT( " " ) );
return aReporter;
}
void COMPONENT_NET::Show( int aNestLevel, REPORTER& aReporter )
{
NestedSpace( aNestLevel, aReporter );
aReporter.Report( wxString::Format( wxT( "<pin_name=%s net_name=%s>\n" ),
GetChars( m_pinName ), GetChars( m_netName ) ) );
}
#endif
void COMPONENT::SetModule( MODULE* aModule )
{
m_footprint.reset( aModule );
if( aModule == NULL )
return;
aModule->SetReference( m_reference );
aModule->SetValue( m_value );
aModule->SetFPID( m_fpid );
aModule->SetPath( m_timeStamp );
}
COMPONENT_NET COMPONENT::m_emptyNet;
const COMPONENT_NET& COMPONENT::GetNet( const wxString& aPinName )
{
for( unsigned i = 0; i < m_nets.size(); i++ )
{
if( m_nets[i].GetPinName() == aPinName )
return m_nets[i];
}
return m_emptyNet;
}
bool COMPONENT::MatchesFootprintFilters( const wxString& aFootprintName ) const
{
if( m_footprintFilters.GetCount() == 0 )
return true;
// The matching is case insensitive
wxString name = aFootprintName.Upper();
for( unsigned ii = 0; ii < m_footprintFilters.GetCount(); ii++ )
{
if( name.Matches( m_footprintFilters[ii].Upper() ) )
return true;
}
return false;
}
#if defined(DEBUG)
void COMPONENT::Show( int aNestLevel, REPORTER& aReporter )
{
NestedSpace( aNestLevel, aReporter );
aReporter.Report( wxT( "<component>\n" ) );
NestedSpace( aNestLevel+1, aReporter );
aReporter.Report( wxString::Format( wxT( "<ref=%s value=%s name=%s library=%s fpid=%s "
"timestamp=%s>\n" ),
GetChars( m_reference ), GetChars( m_value ),
GetChars( m_name ), GetChars( m_library ),
m_fpid.Format().c_str(),
GetChars( m_timeStamp ) ) );
if( !m_footprintFilters.IsEmpty() )
{
NestedSpace( aNestLevel+1, aReporter );
aReporter.Report( wxT( "<fp_filters>\n" ) );
for( unsigned i = 0; i < m_footprintFilters.GetCount(); i++ )
{
NestedSpace( aNestLevel+2, aReporter );
aReporter.Report( wxString::Format( wxT( "<%s>\n" ),
GetChars( m_footprintFilters[i] ) ) );
}
NestedSpace( aNestLevel+1, aReporter );
aReporter.Report( wxT( "</fp_filters>\n" ) );
}
if( !m_nets.empty() )
{
NestedSpace( aNestLevel+1, aReporter );
aReporter.Report( wxT( "<nets>\n" ) );
for( unsigned i = 0; i < m_nets.size(); i++ )
m_nets[i].Show( aNestLevel+3, aReporter );
NestedSpace( aNestLevel+1, aReporter );
aReporter.Report( "</nets>\n" );
}
NestedSpace( aNestLevel, aReporter );
aReporter.Report( "</component>\n" );
}
#endif
void NETLIST::AddComponent( COMPONENT* aComponent )
{
m_components.push_back( aComponent );
}
COMPONENT* NETLIST::GetComponentByReference( const wxString& aReference )
{
COMPONENT* component = NULL;
for( unsigned i = 0; i < m_components.size(); i++ )
{
if( m_components[i].GetReference() == aReference )
{
component = &m_components[i];
break;
}
}
return component;
}
COMPONENT* NETLIST::GetComponentByTimeStamp( const wxString& aTimeStamp )
{
COMPONENT* component = NULL;
for( unsigned i = 0; i < m_components.size(); i++ )
{
if( m_components[i].GetTimeStamp() == aTimeStamp )
{
component = &m_components[i];
break;
}
}
return component;
}
/**
* Function ByFPID
* is a helper function used to sort the component list used by loadNewModules.
*/
static bool ByFPID( const COMPONENT& ref, const COMPONENT& cmp )
{
return ref.GetFPID() > cmp.GetFPID();
}
void NETLIST::SortByFPID()
{
m_components.sort( ByFPID );
}
/**
* Operator <
* compares two #COMPONENT objects by reference designator.
*/
bool operator < ( const COMPONENT& item1, const COMPONENT& item2 )
{
return StrNumCmp( item1.GetReference(), item2.GetReference(), INT_MAX, true ) < 0;
}
void NETLIST::SortByReference()
{
m_components.sort();
}
bool NETLIST::AnyFootprintsLinked() const
{
for( unsigned i = 0; i < m_components.size(); i++ )
{
if( !m_components[i].GetFPID().empty() )
return true;
}
return false;
}
bool NETLIST::AllFootprintsLinked() const
{
for( unsigned i = 0; i < m_components.size(); i++ )
{
if( m_components[i].GetFPID().empty() )
return false;
}
return true;
}
#if defined( DEBUG )
void NETLIST::Show( int aNestLevel, REPORTER& aReporter )
{
NestedSpace( aNestLevel, aReporter );
aReporter.Report( "<netlist>\n" );
if( !m_components.empty() )
{
NestedSpace( aNestLevel+1, aReporter );
aReporter.Report( "<components>\n" );
for( unsigned i = 0; i < m_components.size(); i++ )
{
m_components[i].Show( aNestLevel+2, aReporter );
}
NestedSpace( aNestLevel+1, aReporter );
aReporter.Report( "</components>\n" );
}
NestedSpace( aNestLevel, aReporter );
aReporter.Report( "</netlist>\n" );
}
#endif
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment