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 ...@@ -137,6 +137,7 @@ set(PCB_COMMON_SRCS
../pcbnew/legacy_plugin.cpp ../pcbnew/legacy_plugin.cpp
../pcbnew/kicad_plugin.cpp ../pcbnew/kicad_plugin.cpp
../pcbnew/gpcb_plugin.cpp ../pcbnew/gpcb_plugin.cpp
../pcbnew/pcb_netlist.cpp
pcb_plot_params_keywords.cpp pcb_plot_params_keywords.cpp
pcb_keywords.cpp pcb_keywords.cpp
../pcbnew/pcb_parser.cpp ../pcbnew/pcb_parser.cpp
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <footprint_info.h> #include <footprint_info.h>
#include <io_mgr.h> #include <io_mgr.h>
#include <fp_lib_table.h> #include <fp_lib_table.h>
#include <fpid.h>
#include <class_module.h> #include <class_module.h>
...@@ -182,6 +183,31 @@ bool FOOTPRINT_LIST::ReadFootprintFiles( FP_LIB_TABLE& aTable ) ...@@ -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 bool FOOTPRINT_INFO::InLibrary( const wxString& aLibrary ) const
{ {
if( aLibrary.IsEmpty() ) if( aLibrary.IsEmpty() )
......
...@@ -31,10 +31,14 @@ ...@@ -31,10 +31,14 @@
#include <set> #include <set>
#include <appl_wxstruct.h> #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_lexer.h>
#include <fp_lib_table.h> #include <fp_lib_table.h>
using namespace FP_LIB_TABLE_T; using namespace FP_LIB_TABLE_T;
...@@ -251,6 +255,35 @@ const FP_LIB_TABLE::ROW* FP_LIB_TABLE::findRow( const wxString& aNickName ) ...@@ -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 ) bool FP_LIB_TABLE::InsertRow( const ROW& aRow, bool doReplace )
{ {
ensureIndex(); ensureIndex();
...@@ -281,7 +314,7 @@ const FP_LIB_TABLE::ROW* FP_LIB_TABLE::FindRow( const wxString& aLibraryNickName ...@@ -281,7 +314,7 @@ const FP_LIB_TABLE::ROW* FP_LIB_TABLE::FindRow( const wxString& aLibraryNickName
if( !row ) if( !row )
{ {
wxString msg = wxString::Format( _("lib table contains no logical lib '%s'" ), wxString msg = wxString::Format( _( "lib table contains no logical lib '%s'" ),
GetChars( aLibraryNickName ) ); GetChars( aLibraryNickName ) );
THROW_IO_ERROR( msg ); THROW_IO_ERROR( msg );
} }
...@@ -320,6 +353,185 @@ bool FP_LIB_TABLE::IsEmpty() const ...@@ -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 FP_LIB_TABLE::LoadGlobalTable( FP_LIB_TABLE& aTable ) throw (IO_ERROR, PARSE_ERROR )
{ {
bool tableExists = true; bool tableExists = true;
......
/** /**
* @file reporter.h * @file reporter.cpp
*/ */
/* /*
* 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.
...@@ -43,3 +43,13 @@ REPORTER& WX_TEXT_CTRL_REPORTER::Report( const wxString& aText ) ...@@ -43,3 +43,13 @@ REPORTER& WX_TEXT_CTRL_REPORTER::Report( const wxString& aText )
m_textCtrl->AppendText( aText ); m_textCtrl->AppendText( aText );
return *this; 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( ...@@ -9,6 +9,7 @@ include_directories(
./dialogs ./dialogs
../3d-viewer ../3d-viewer
../pcbnew ../pcbnew
../pcbnew/dialogs
../polygon ../polygon
../common ../common
${INC_AFTER} ${INC_AFTER}
...@@ -22,6 +23,8 @@ set( CVPCB_DIALOGS ...@@ -22,6 +23,8 @@ set( CVPCB_DIALOGS
dialogs/dialog_cvpcb_config_fbp.cpp dialogs/dialog_cvpcb_config_fbp.cpp
dialogs/dialog_display_options.cpp dialogs/dialog_display_options.cpp
dialogs/dialog_display_options_base.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 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 <fctsys.h>
#include <appl_wxstruct.h> #include <appl_wxstruct.h>
...@@ -9,6 +33,8 @@ ...@@ -9,6 +33,8 @@
#include <gestfich.h> #include <gestfich.h>
#include <param_config.h> #include <param_config.h>
#include <wildcards_and_files_ext.h> #include <wildcards_and_files_ext.h>
#include <fp_lib_table.h>
#include <confirm.h>
#include <cvpcb.h> #include <cvpcb.h>
#include <cvpcb_mainframe.h> #include <cvpcb_mainframe.h>
...@@ -59,8 +85,24 @@ void CVPCB_MAINFRAME::LoadProjectFile( const wxString& aFileName ) ...@@ -59,8 +85,24 @@ void CVPCB_MAINFRAME::LoadProjectFile( const wxString& aFileName )
if( m_NetlistFileExtension.IsEmpty() ) if( m_NetlistFileExtension.IsEmpty() )
m_NetlistFileExtension = wxT( "net" ); 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 ); 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 @@ ...@@ -36,6 +36,9 @@
#include <bitmaps.h> #include <bitmaps.h>
#include <msgpanel.h> #include <msgpanel.h>
#include <wildcards_and_files_ext.h> #include <wildcards_and_files_ext.h>
#include <fpid.h>
#include <fp_lib_table.h>
#include <pcbcommon.h>
#include <io_mgr.h> #include <io_mgr.h>
#include <class_module.h> #include <class_module.h>
...@@ -473,10 +476,59 @@ EDA_COLOR_T DISPLAY_FOOTPRINTS_FRAME::GetGridColor() const ...@@ -473,10 +476,59 @@ EDA_COLOR_T DISPLAY_FOOTPRINTS_FRAME::GetGridColor() const
MODULE* DISPLAY_FOOTPRINTS_FRAME::Get_Module( const wxString& aFootprintName ) 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 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 ) ); PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::LEGACY ) );
for( unsigned i = 0; i < parent->m_ModuleLibNames.GetCount(); ++i ) for( unsigned i = 0; i < parent->m_ModuleLibNames.GetCount(); ++i )
...@@ -493,19 +545,13 @@ MODULE* DISPLAY_FOOTPRINTS_FRAME::Get_Module( const wxString& aFootprintName ) ...@@ -493,19 +545,13 @@ MODULE* DISPLAY_FOOTPRINTS_FRAME::Get_Module( const wxString& aFootprintName )
fn.GetFullName().GetData() ); fn.GetFullName().GetData() );
// @todo we should not be using wxMessageBox directly. // @todo we should not be using wxMessageBox directly.
wxMessageBox( msg, titleLibLoadError, wxOK | wxICON_ERROR, this ); wxMessageBox( msg, wxEmptyString, wxOK | wxICON_ERROR, this );
continue; continue;
} }
MODULE* footprint = pi->FootprintLoad( libPath, aFootprintName ); footprint = pi->FootprintLoad( libPath, aFootprintName );
if( footprint )
{
footprint->SetParent( (EDA_ITEM*) GetBoard() );
footprint->SetPosition( wxPoint( 0, 0 ) );
return footprint;
}
} }
#endif
} }
catch( IO_ERROR ioe ) catch( IO_ERROR ioe )
{ {
...@@ -513,6 +559,13 @@ MODULE* DISPLAY_FOOTPRINTS_FRAME::Get_Module( const wxString& aFootprintName ) ...@@ -513,6 +559,13 @@ MODULE* DISPLAY_FOOTPRINTS_FRAME::Get_Module( const wxString& aFootprintName )
return NULL; 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() ); wxString msg = wxString::Format( _( "Footprint '%s' not found" ), aFootprintName.GetData() );
DisplayError( this, msg ); DisplayError( this, msg );
return NULL; return NULL;
...@@ -532,6 +585,7 @@ void DISPLAY_FOOTPRINTS_FRAME::InitDisplay() ...@@ -532,6 +585,7 @@ void DISPLAY_FOOTPRINTS_FRAME::InitDisplay()
FOOTPRINT_INFO* module_info = parentframe->m_footprints.GetModuleInfo( footprintName ); FOOTPRINT_INFO* module_info = parentframe->m_footprints.GetModuleInfo( footprintName );
const wxChar *libname; const wxChar *libname;
if( module_info ) if( module_info )
libname = GetChars( module_info->GetLibraryPath() ); libname = GetChars( module_info->GetLibraryPath() );
else else
......
...@@ -135,8 +135,14 @@ void FOOTPRINTS_LISTBOX::SetFootprints( FOOTPRINT_LIST& aList, const wxString& a ...@@ -135,8 +135,14 @@ void FOOTPRINTS_LISTBOX::SetFootprints( FOOTPRINT_LIST& aList, const wxString& a
{ {
if( aFilterType == UNFILTERED ) if( aFilterType == UNFILTERED )
{ {
#if !defined( USE_FP_LIB_TABLE )
msg.Printf( wxT( "%3zu %s" ), newList.GetCount() + 1, msg.Printf( wxT( "%3zu %s" ), newList.GetCount() + 1,
GetChars( aList.GetItem( ii ).m_Module ) ); 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 ); newList.Add( msg );
continue; continue;
} }
...@@ -153,8 +159,14 @@ void FOOTPRINTS_LISTBOX::SetFootprints( FOOTPRINT_LIST& aList, const wxString& a ...@@ -153,8 +159,14 @@ void FOOTPRINTS_LISTBOX::SetFootprints( FOOTPRINT_LIST& aList, const wxString& a
&& (aComponent->GetNetCount() != aList.GetItem( ii ).m_padCount) ) && (aComponent->GetNetCount() != aList.GetItem( ii ).m_padCount) )
continue; continue;
#if !defined( USE_FP_LIB_TABLE )
msg.Printf( wxT( "%3zu %s" ), newList.GetCount() + 1, msg.Printf( wxT( "%3zu %s" ), newList.GetCount() + 1,
aList.GetItem( ii ).m_Module.GetData() ); 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 ); newList.Add( msg );
} }
...@@ -169,9 +181,24 @@ void FOOTPRINTS_LISTBOX::SetFootprints( FOOTPRINT_LIST& aList, const wxString& a ...@@ -169,9 +181,24 @@ void FOOTPRINTS_LISTBOX::SetFootprints( FOOTPRINT_LIST& aList, const wxString& a
selection = 0; selection = 0;
DeleteAllItems(); DeleteAllItems();
if( m_footprintList.GetCount() )
{
SetItemCount( m_footprintList.GetCount() ); SetItemCount( m_footprintList.GetCount() );
SetSelection( selection, true ); SetSelection( selection, true );
Refresh(); 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 ) ...@@ -124,7 +124,21 @@ void LIBRARY_LISTBOX::SetLibraryList( const wxArrayString& aList )
if( GetCount() == 0 || oldSelection < 0 || oldSelection >= GetCount() ) if( GetCount() == 0 || oldSelection < 0 || oldSelection >= GetCount() )
SetSelection( 0, true ); 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 @@ ...@@ -28,22 +28,25 @@
*/ */
#include <fctsys.h> #include <fctsys.h>
#include <build_version.h>
#include <appl_wxstruct.h> #include <appl_wxstruct.h>
#include <macros.h> #include <macros.h>
#include <confirm.h> #include <confirm.h>
#include <eda_doc.h> #include <eda_doc.h>
#include <eda_dde.h> #include <eda_dde.h>
#include <gestfich.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_mainframe.h>
#include <cvpcb.h>
#include <cvstruct.h> #include <cvstruct.h>
#include <dialog_cvpcb_config.h> #include <dialog_cvpcb_config.h>
#include <class_DisplayFootprintsFrame.h> #include <class_DisplayFootprintsFrame.h>
#include <cvpcb_id.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_X 450
#define FRAME_MIN_SIZE_Y 300 #define FRAME_MIN_SIZE_Y 300
...@@ -54,6 +57,16 @@ static const wxString KeepCvpcbOpenEntry( wxT( "KeepCvpcbOpen" ) ); ...@@ -54,6 +57,16 @@ static const wxString KeepCvpcbOpenEntry( wxT( "KeepCvpcbOpen" ) );
static const wxString FootprintDocFileEntry( wxT( "footprints_doc_file" ) ); 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 ) BEGIN_EVENT_TABLE( CVPCB_MAINFRAME, EDA_BASE_FRAME )
EVT_MENU_RANGE( wxID_FILE1, wxID_FILE9, CVPCB_MAINFRAME::LoadNetList ) EVT_MENU_RANGE( wxID_FILE1, wxID_FILE9, CVPCB_MAINFRAME::LoadNetList )
...@@ -69,6 +82,10 @@ BEGIN_EVENT_TABLE( CVPCB_MAINFRAME, EDA_BASE_FRAME ) ...@@ -69,6 +82,10 @@ BEGIN_EVENT_TABLE( CVPCB_MAINFRAME, EDA_BASE_FRAME )
EVT_MENU( ID_SAVE_PROJECT_AS, CVPCB_MAINFRAME::SaveProjectFile ) EVT_MENU( ID_SAVE_PROJECT_AS, CVPCB_MAINFRAME::SaveProjectFile )
EVT_MENU( ID_CVPCB_CONFIG_KEEP_OPEN_ON_SAVE, CVPCB_MAINFRAME::OnKeepOpenOnSave ) 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 ) EVT_MENU_RANGE( ID_LANGUAGE_CHOICE, ID_LANGUAGE_CHOICE_END, CVPCB_MAINFRAME::SetLanguage )
// Toolbar events // Toolbar events
...@@ -114,6 +131,11 @@ CVPCB_MAINFRAME::CVPCB_MAINFRAME( const wxString& title, long style ) : ...@@ -114,6 +131,11 @@ CVPCB_MAINFRAME::CVPCB_MAINFRAME( const wxString& title, long style ) :
m_undefinedComponentCnt = 0; m_undefinedComponentCnt = 0;
m_skipComponentSelect = false; m_skipComponentSelect = false;
#if defined( USE_FP_LIB_TABLE )
m_globalFootprintTable = NULL;
m_footprintLibTable = NULL;
#endif
/* Name of the document footprint list /* Name of the document footprint list
* usually located in share/modules/footprints_doc * usually located in share/modules/footprints_doc
* this is of the responsibility to users to create this file * this is of the responsibility to users to create this file
...@@ -185,6 +207,39 @@ CVPCB_MAINFRAME::CVPCB_MAINFRAME( const wxString& title, long style ) : ...@@ -185,6 +207,39 @@ CVPCB_MAINFRAME::CVPCB_MAINFRAME( const wxString& title, long style ) :
Right().BestSize( (int) ( m_FrameSize.x * 0.30 ), m_FrameSize.y ) ); Right().BestSize( (int) ( m_FrameSize.x * 0.30 ), m_FrameSize.y ) );
m_auimgr.Update(); 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 ) ...@@ -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 ) void CVPCB_MAINFRAME::OnKeepOpenOnSave( wxCommandEvent& event )
{ {
m_KeepCvpcbOpen = event.IsChecked(); m_KeepCvpcbOpen = event.IsChecked();
...@@ -523,7 +602,7 @@ void CVPCB_MAINFRAME::OnSelectComponent( wxListEvent& event ) ...@@ -523,7 +602,7 @@ void CVPCB_MAINFRAME::OnSelectComponent( wxListEvent& event )
// selected footprint. // selected footprint.
if( FindFocus() == m_ListCmp || FindFocus() == m_LibraryList ) 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; bool found = false;
...@@ -667,7 +746,12 @@ bool CVPCB_MAINFRAME::LoadFootprintFiles() ...@@ -667,7 +746,12 @@ bool CVPCB_MAINFRAME::LoadFootprintFiles()
return false; return false;
} }
#if !defined( USE_FP_LIB_TABLE )
m_footprints.ReadFootprintFiles( m_ModuleLibNames ); m_footprints.ReadFootprintFiles( m_ModuleLibNames );
#else
if( m_footprintLibTable != NULL )
m_footprints.ReadFootprintFiles( *m_footprintLibTable );
#endif
// Display error messages, if any. // Display error messages, if any.
if( !m_footprints.m_filesNotFound.IsEmpty() || !m_footprints.m_filesInvalid.IsEmpty() ) if( !m_footprints.m_filesNotFound.IsEmpty() || !m_footprints.m_filesInvalid.IsEmpty() )
...@@ -770,7 +854,7 @@ int CVPCB_MAINFRAME::ReadSchematicNetlist() ...@@ -770,7 +854,7 @@ int CVPCB_MAINFRAME::ReadSchematicNetlist()
netlistReader->LoadNetlist(); netlistReader->LoadNetlist();
} }
else else
wxMessageBox( _( "Unknown netlist format" ), wxEmptyString, wxOK | wxICON_ERROR ); wxMessageBox( _( "Unknown netlist format." ), wxEmptyString, wxOK | wxICON_ERROR );
} }
catch( IO_ERROR& ioe ) catch( IO_ERROR& ioe )
{ {
...@@ -852,6 +936,11 @@ void CVPCB_MAINFRAME::CreateScreenCmp() ...@@ -852,6 +936,11 @@ void CVPCB_MAINFRAME::CreateScreenCmp()
wxPoint( 0, 0 ), wxPoint( 0, 0 ),
wxSize( 600, 400 ), wxSize( 600, 400 ),
KICAD_DEFAULT_DRAWFRAME_STYLE ); KICAD_DEFAULT_DRAWFRAME_STYLE );
#if defined( USE_FP_LIB_TABLE )
m_DisplayFootprintFrame->SetFootprintLibTable( m_footprintLibTable );
#endif
m_DisplayFootprintFrame->Show( true ); m_DisplayFootprintFrame->Show( true );
} }
else else
...@@ -913,8 +1002,23 @@ void CVPCB_MAINFRAME::BuildCmpListBox() ...@@ -913,8 +1002,23 @@ void CVPCB_MAINFRAME::BuildCmpListBox()
m_ListCmp->m_ComponentList.Add( msg ); m_ListCmp->m_ComponentList.Add( msg );
} }
if( m_ListCmp->m_ComponentList.Count() )
{
m_ListCmp->SetItemCount( m_ListCmp->m_ComponentList.Count() ); m_ListCmp->SetItemCount( m_ListCmp->m_ComponentList.Count() );
m_ListCmp->SetSelection( 0, true ); 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() ...@@ -932,7 +1036,21 @@ void CVPCB_MAINFRAME::BuildLIBRARY_LISTBOX()
wxFONTWEIGHT_NORMAL ) ); 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 ); m_LibraryList->SetLibraryList( m_ModuleLibNames );
#endif
} }
......
...@@ -5,21 +5,16 @@ ...@@ -5,21 +5,16 @@
#ifndef __CVPCB_H__ #ifndef __CVPCB_H__
#define __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 // config for footprints doc file access
#define DEFAULT_FOOTPRINTS_LIST_FILENAME wxT( "footprints_doc/footprints.pdf" ) #define DEFAULT_FOOTPRINTS_LIST_FILENAME wxT( "footprints_doc/footprints.pdf" )
// Define print format to display a schematic component line // 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 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 FootprintAliasFileExtension;
extern const wxString RetroFileExtension; extern const wxString RetroFileExtension;
......
...@@ -32,5 +32,6 @@ enum id_cvpcb_frm ...@@ -32,5 +32,6 @@ enum id_cvpcb_frm
ID_CVPCB_FOOTPRINT_DISPLAY_PIN_FILTERED_LIST, ID_CVPCB_FOOTPRINT_DISPLAY_PIN_FILTERED_LIST,
ID_CVPCB_FOOTPRINT_DISPLAY_BY_LIBRARY_LIST, ID_CVPCB_FOOTPRINT_DISPLAY_BY_LIBRARY_LIST,
ID_CVPCB_CONFIG_KEEP_OPEN_ON_SAVE, ID_CVPCB_CONFIG_KEEP_OPEN_ON_SAVE,
ID_CVPCB_LIBRARY_LIST ID_CVPCB_LIBRARY_LIST,
ID_CVPCB_LIB_TABLE_EDIT
}; };
...@@ -31,12 +31,11 @@ ...@@ -31,12 +31,11 @@
#include <wx/listctrl.h> #include <wx/listctrl.h>
#include <wx/filename.h> #include <wx/filename.h>
#include <netlist_reader.h> #include <pcb_netlist.h>
#include <footprint_info.h> #include <footprint_info.h>
#include <wxBasePcbFrame.h> #include <wxBasePcbFrame.h>
#include <param_config.h> #include <param_config.h>
#include <cvpcb.h>
/* Forward declarations of all top-level window classes. */ /* Forward declarations of all top-level window classes. */
...@@ -46,6 +45,7 @@ class COMPONENTS_LISTBOX; ...@@ -46,6 +45,7 @@ class COMPONENTS_LISTBOX;
class LIBRARY_LISTBOX; class LIBRARY_LISTBOX;
class DISPLAY_FOOTPRINTS_FRAME; class DISPLAY_FOOTPRINTS_FRAME;
class COMPONENT; class COMPONENT;
class FP_LIB_TABLE;
/** /**
...@@ -55,6 +55,16 @@ class CVPCB_MAINFRAME : public EDA_BASE_FRAME ...@@ -55,6 +55,16 @@ class CVPCB_MAINFRAME : public EDA_BASE_FRAME
{ {
wxArrayString m_footprintListEntries; 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: public:
bool m_KeepCvpcbOpen; bool m_KeepCvpcbOpen;
FOOTPRINTS_LISTBOX* m_FootprintList; FOOTPRINTS_LISTBOX* m_FootprintList;
...@@ -92,6 +102,13 @@ public: ...@@ -92,6 +102,13 @@ public:
*/ */
void OnSelectComponent( wxListEvent& event ); 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 OnQuit( wxCommandEvent& event );
void OnCloseWindow( wxCloseEvent& Event ); void OnCloseWindow( wxCloseEvent& Event );
void OnSize( wxSizeEvent& SizeEvent ); void OnSize( wxSizeEvent& SizeEvent );
...@@ -126,6 +143,15 @@ public: ...@@ -126,6 +143,15 @@ public:
void LoadNetList( wxCommandEvent& event ); void LoadNetList( wxCommandEvent& event );
void ConfigCvpcb( 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 OnKeepOpenOnSave( wxCommandEvent& event );
void DisplayModule( wxCommandEvent& event ); void DisplayModule( wxCommandEvent& event );
......
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
#include <wx/listctrl.h> #include <wx/listctrl.h>
#include <cvpcb.h>
/* Forward declarations of all top-level window classes. */ /* Forward declarations of all top-level window classes. */
class CVPCB_MAINFRAME; class CVPCB_MAINFRAME;
......
...@@ -110,11 +110,17 @@ void CVPCB_MAINFRAME::ReCreateMenuBar() ...@@ -110,11 +110,17 @@ void CVPCB_MAINFRAME::ReCreateMenuBar()
// Menu Preferences: // Menu Preferences:
wxMenu* preferencesMenu = new wxMenu; wxMenu* preferencesMenu = new wxMenu;
#if !defined( USE_FP_LIB_TABLE )
// Libraries to load // Libraries to load
AddMenuItem( preferencesMenu, wxID_PREFERENCES, AddMenuItem( preferencesMenu, wxID_PREFERENCES,
_( "&Libraries" ), _( "&Libraries" ),
_( "Set footprint libraries to load and library search paths" ), _( "Set footprint libraries to load and library search paths" ),
KiBitmap( config_xpm ) ); KiBitmap( config_xpm ) );
#else
AddMenuItem( preferencesMenu, ID_CVPCB_LIB_TABLE_EDIT,
_( "Li&brary Tables" ), _( "Setup footprint libraries" ),
KiBitmap( library_table_xpm ) );
#endif
// Language submenu // Language submenu
wxGetApp().AddMenuLanguageList( preferencesMenu ); wxGetApp().AddMenuLanguageList( preferencesMenu );
......
...@@ -31,6 +31,11 @@ ...@@ -31,6 +31,11 @@
#include <common.h> #include <common.h>
#include <confirm.h> #include <confirm.h>
#include <build_version.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.h>
#include <cvpcb_mainframe.h> #include <cvpcb_mainframe.h>
...@@ -50,7 +55,6 @@ void CVPCB_MAINFRAME::SetNewPkg( const wxString& aFootprintName ) ...@@ -50,7 +55,6 @@ void CVPCB_MAINFRAME::SetNewPkg( const wxString& aFootprintName )
return; return;
// If no component is selected, select the first one // If no component is selected, select the first one
if( m_ListCmp->GetFirstSelected() < 0 ) if( m_ListCmp->GetFirstSelected() < 0 )
{ {
componentIndex = 0; componentIndex = 0;
...@@ -58,11 +62,9 @@ void CVPCB_MAINFRAME::SetNewPkg( const wxString& aFootprintName ) ...@@ -58,11 +62,9 @@ void CVPCB_MAINFRAME::SetNewPkg( const wxString& aFootprintName )
} }
// iterate over the selection // iterate over the selection
while( m_ListCmp->GetFirstSelected() != -1 )
while( m_ListCmp->GetFirstSelected() != -1)
{ {
// Get the component for the current iteration // Get the component for the current iteration
componentIndex = m_ListCmp->GetFirstSelected(); componentIndex = m_ListCmp->GetFirstSelected();
component = m_netlist.GetComponent( componentIndex ); component = m_netlist.GetComponent( componentIndex );
...@@ -70,13 +72,21 @@ void CVPCB_MAINFRAME::SetNewPkg( const wxString& aFootprintName ) ...@@ -70,13 +72,21 @@ void CVPCB_MAINFRAME::SetNewPkg( const wxString& aFootprintName )
return; return;
// Check to see if the component has already a footprint set. // Check to see if the component has already a footprint set.
hasFootprint = !component->GetFPID().empty(); 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 ) ); component->SetFPID( FPID( aFootprintName ) );
#endif
// create the new component description // create the new component description
description.Printf( CMP_FORMAT, componentIndex + 1, description.Printf( CMP_FORMAT, componentIndex + 1,
GetChars( component->GetReference() ), GetChars( component->GetReference() ),
GetChars( component->GetValue() ), GetChars( component->GetValue() ),
...@@ -85,7 +95,6 @@ void CVPCB_MAINFRAME::SetNewPkg( const wxString& aFootprintName ) ...@@ -85,7 +95,6 @@ void CVPCB_MAINFRAME::SetNewPkg( const wxString& aFootprintName )
// If the component hasn't had a footprint associated with it // If the component hasn't had a footprint associated with it
// it now has, so we decrement the count of components without // it now has, so we decrement the count of components without
// a footprint assigned. // a footprint assigned.
if( !hasFootprint ) if( !hasFootprint )
{ {
hasFootprint = true; hasFootprint = true;
...@@ -115,6 +124,7 @@ bool CVPCB_MAINFRAME::ReadNetListAndLinkFiles() ...@@ -115,6 +124,7 @@ bool CVPCB_MAINFRAME::ReadNetListAndLinkFiles()
{ {
COMPONENT* component; COMPONENT* component;
wxString msg; wxString msg;
bool isLegacy = true;
ReadSchematicNetlist(); ReadSchematicNetlist();
...@@ -129,6 +139,87 @@ bool CVPCB_MAINFRAME::ReadNetListAndLinkFiles() ...@@ -129,6 +139,87 @@ bool CVPCB_MAINFRAME::ReadNetListAndLinkFiles()
m_ListCmp->Clear(); m_ListCmp->Clear();
m_undefinedComponentCnt = 0; 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++ ) for( unsigned i = 0; i < m_netlist.GetCount(); i++ )
{ {
component = m_netlist.GetComponent( i ); component = m_netlist.GetComponent( i );
...@@ -137,10 +228,14 @@ bool CVPCB_MAINFRAME::ReadNetListAndLinkFiles() ...@@ -137,10 +228,14 @@ bool CVPCB_MAINFRAME::ReadNetListAndLinkFiles()
GetChars( component->GetReference() ), GetChars( component->GetReference() ),
GetChars( component->GetValue() ), GetChars( component->GetValue() ),
GetChars( FROM_UTF8( component->GetFPID().Format().c_str() ) ) ); GetChars( FROM_UTF8( component->GetFPID().Format().c_str() ) ) );
m_ListCmp->AppendLine( msg ); m_ListCmp->AppendLine( msg );
if( component->GetFPID().empty() ) if( component->GetFPID().empty() )
{
m_undefinedComponentCnt += 1; m_undefinedComponentCnt += 1;
continue;
}
} }
if( !m_netlist.IsEmpty() ) if( !m_netlist.IsEmpty() )
......
...@@ -102,15 +102,7 @@ public: ...@@ -102,15 +102,7 @@ public:
* @return the item stored in list if found * @return the item stored in list if found
* @param aFootprintName = the name of item * @param aFootprintName = the name of item
*/ */
FOOTPRINT_INFO * GetModuleInfo( const wxString & aFootprintName ) FOOTPRINT_INFO* GetModuleInfo( const wxString & aFootprintName );
{
BOOST_FOREACH( FOOTPRINT_INFO& footprint, m_List )
{
if( aFootprintName.CmpNoCase( footprint.m_Module ) == 0 )
return &footprint;
}
return NULL;
}
/** /**
* Function GetItem * Function GetItem
...@@ -159,6 +151,13 @@ public: ...@@ -159,6 +151,13 @@ public:
/// FOOTPRINT object list sort function. /// FOOTPRINT object list sort function.
inline bool operator<( const FOOTPRINT_INFO& item1, const FOOTPRINT_INFO& item2 ) 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; return StrNumCmp( item1.m_Module, item2.m_Module, INT_MAX, true ) < 0;
} }
......
...@@ -31,13 +31,16 @@ ...@@ -31,13 +31,16 @@
#include <vector> #include <vector>
#include <map> #include <map>
//#include <fpid.h>
#include <io_mgr.h> #include <io_mgr.h>
class wxFileName;
class OUTPUTFORMATTER; class OUTPUTFORMATTER;
class MODULE; class MODULE;
class FP_LIB_TABLE_LEXER; class FP_LIB_TABLE_LEXER;
class NETLIST;
class REPORTER;
/** /**
* Class FP_LIB_TABLE * Class FP_LIB_TABLE
...@@ -355,12 +358,50 @@ public: ...@@ -355,12 +358,50 @@ public:
*/ */
const ROW* FindRow( const wxString& aNickName ) throw( IO_ERROR ); 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 * Function IsEmpty
* @return true if the footprint library table is empty. * @return true if the footprint library table is empty.
*/ */
bool IsEmpty() const; 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 * Function ExpandEnvSubsitutions
* replaces any environment variable references with their values and is * replaces any environment variable references with their values and is
......
...@@ -136,4 +136,23 @@ public: ...@@ -136,4 +136,23 @@ public:
REPORTER& Report( const wxString& aText ); 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_ #endif // _REPORTER_H_
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
#include <pcbcommon.h> #include <pcbcommon.h>
#include <wxBasePcbFrame.h> #include <wxBasePcbFrame.h>
#include <msgpanel.h> #include <msgpanel.h>
#include <netlist_reader.h> #include <pcb_netlist.h>
#include <reporter.h> #include <reporter.h>
#include <base_units.h> #include <base_units.h>
......
...@@ -29,11 +29,13 @@ ...@@ -29,11 +29,13 @@
#include <fctsys.h> #include <fctsys.h>
#include <appl_wxstruct.h> #include <appl_wxstruct.h>
#include <confirm.h> #include <confirm.h>
#include <macros.h>
#include <dialog_helpers.h> #include <dialog_helpers.h>
#include <html_messagebox.h> #include <html_messagebox.h>
#include <base_units.h> #include <base_units.h>
#include <wxPcbStruct.h> #include <wxPcbStruct.h>
#include <pcbcommon.h> #include <pcbcommon.h>
#include <pcb_netlist.h>
#include <netlist_reader.h> #include <netlist_reader.h>
#include <reporter.h> #include <reporter.h>
......
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
#include <wx/wx.h> #include <wx/wx.h>
#include <netlist_lexer.h> // netlist_lexer is common to Eeschema and Pcbnew #include <netlist_lexer.h> // netlist_lexer is common to Eeschema and Pcbnew
#include <macros.h> #include <macros.h>
#include <pcb_netlist.h>
#include <netlist_reader.h> #include <netlist_reader.h>
using namespace NL_T; using namespace NL_T;
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <richio.h> #include <richio.h>
#include <kicad_string.h> #include <kicad_string.h>
#include <pcb_netlist.h>
#include <netlist_reader.h> #include <netlist_reader.h>
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <confirm.h> #include <confirm.h>
#include <dialog_helpers.h> #include <dialog_helpers.h>
#include <wxPcbStruct.h> #include <wxPcbStruct.h>
#include <pcb_netlist.h>
#include <netlist_reader.h> #include <netlist_reader.h>
#include <reporter.h> #include <reporter.h>
#include <wildcards_and_files_ext.h> #include <wildcards_and_files_ext.h>
......
...@@ -31,267 +31,13 @@ ...@@ -31,267 +31,13 @@
#include <kicad_string.h> #include <kicad_string.h>
#include <reporter.h> #include <reporter.h>
#include <pcb_netlist.h>
#include <netlist_reader.h> #include <netlist_reader.h>
#include <class_module.h> #include <class_module.h>
#include <wx/regex.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() NETLIST_READER::~NETLIST_READER()
{ {
if( m_lineReader ) if( m_lineReader )
...@@ -308,7 +54,6 @@ NETLIST_READER::~NETLIST_READER() ...@@ -308,7 +54,6 @@ NETLIST_READER::~NETLIST_READER()
} }
NETLIST_READER::NETLIST_FILE_T NETLIST_READER::GuessNetlistFileType( LINE_READER* aLineReader ) NETLIST_READER::NETLIST_FILE_T NETLIST_READER::GuessNetlistFileType( LINE_READER* aLineReader )
{ {
// Orcad Pcb2 netlist format starts by "( {", followed by an unknown comment, // Orcad Pcb2 netlist format starts by "( {", followed by an unknown comment,
...@@ -447,15 +192,18 @@ bool CMP_READER::Load( NETLIST* aNetlist ) throw( IO_ERROR, PARSE_ERROR ) ...@@ -447,15 +192,18 @@ bool CMP_READER::Load( NETLIST* aNetlist ) throw( IO_ERROR, PARSE_ERROR )
// Find the corresponding item in component list: // Find the corresponding item in component list:
COMPONENT* component = aNetlist->GetComponentByReference( reference ); COMPONENT* component = aNetlist->GetComponentByReference( reference );
// the corresponding component could be no more existing in netlist: // The corresponding component could no longer existing in the netlist. This
// this is the case when it is just removed from schematic, // can happed when it is removed from schematic and still exists in footprint
// and still exists in footprint assignment list, before this list is updated // assignment list. This is an usual case during the life of a design.
// This is an usual case during the life of a design
if( component ) if( component )
{
component->SetFPID( FPID( footprint ) ); component->SetFPID( FPID( footprint ) );
}
else else
{
ok = false; // can be used to display a warning in Pcbnew. ok = false; // can be used to display a warning in Pcbnew.
} }
}
return ok; return ok;
} }
...@@ -42,335 +42,8 @@ ...@@ -42,335 +42,8 @@
using namespace NL_T; using namespace NL_T;
class MODULE; class NETLIST;
class LINE_READER; class COMPONENT;
class REPORTER;
/**
* Class COMPONENT_NET
* is used to store the component pin name to net name associations stored in a netlist.
*/
class COMPONENT_NET
{
wxString m_pinName;
wxString m_netNumber;
wxString m_netName;
public:
COMPONENT_NET() {}
COMPONENT_NET( const wxString& aPinName, const wxString& aNetName )
{
m_pinName = aPinName;
m_netName = aNetName;
}
const wxString& GetPinName() const { return m_pinName; }
const wxString& GetNetName() const { return m_netName; }
bool IsValid() const { return !m_pinName.IsEmpty(); }
bool operator <( const COMPONENT_NET& aNet ) const
{
return m_pinName < aNet.m_pinName;
}
#if defined(DEBUG)
/**
* Function Show
* is used to output the object tree, currently for debugging only.
* @param aNestLevel An aid to prettier tree indenting, and is the level
* of nesting of this object within the overall tree.
* @param aReporter A reference to a #REPORTER object to output to.
*/
virtual void Show( int aNestLevel, REPORTER& aReporter );
#endif
};
typedef std::vector< COMPONENT_NET > COMPONENT_NETS;
/**
* Class COMPONENT
* is used to store components and all of their related information found in a netlist.
*/
class COMPONENT
{
COMPONENT_NETS m_nets;
wxArrayString m_footprintFilters; ///< Footprint filters found in netlist.
wxString m_reference; ///< The component reference designator found in netlist.
wxString m_value; ///< The component value found in netlist.
// ZZZ This timestamp is string, not time_t
wxString m_timeStamp; ///< The component full time stamp found in netlist.
/// The name of the component in #m_library used when it was placed on the schematic..
wxString m_name;
/**
* The name of the component library where #m_name was found.
*/
wxString m_library;
/// The #FPID of the footprint assigned to the component.
FPID m_fpid;
/// The #MODULE loaded for #m_footprintName found in #m_footprintLib.
std::auto_ptr< MODULE > m_footprint;
/// Set to true if #m_footprintName or #m_footprintLib was changed when the footprint
/// link file was read.
bool m_footprintChanged;
static COMPONENT_NET m_emptyNet;
public:
COMPONENT( const FPID& aFPID,
const wxString& aReference,
const wxString& aValue,
const wxString& aTimeStamp )
{
m_fpid = aFPID;
m_reference = aReference;
m_value = aValue;
m_timeStamp = aTimeStamp;
m_footprintChanged = false;
}
virtual ~COMPONENT() { };
void AddNet( const wxString& aPinName, const wxString& aNetName )
{
m_nets.push_back( COMPONENT_NET( aPinName, aNetName ) );
}
unsigned GetNetCount() const { return m_nets.size(); }
const COMPONENT_NET& GetNet( unsigned aIndex ) const { return m_nets[aIndex]; }
const COMPONENT_NET& GetNet( const wxString& aPinName );
void SortPins() { sort( m_nets.begin(), m_nets.end() ); }
void SetName( const wxString& aName ) { m_name = aName;}
const wxString& GetName() const { return m_name; }
void SetLibrary( const wxString& aLibrary ) { m_library = aLibrary; }
const wxString& GetLibrary() const { return m_library; }
const wxString& GetReference() const { return m_reference; }
const wxString& GetValue() const { return m_value; }
void SetFPID( const FPID& aFPID )
{
m_footprintChanged = !m_fpid.empty() && (m_fpid != aFPID);
m_fpid = aFPID;
}
const FPID& GetFPID() const { return m_fpid; }
const wxString& GetTimeStamp() const { return m_timeStamp; }
void SetFootprintFilters( const wxArrayString& aFilterList )
{
m_footprintFilters = aFilterList;
}
const wxArrayString& GetFootprintFilters() const { return m_footprintFilters; }
/**
* Function MatchesFootprintFilters
*
* @return true if \a aFootprintName matches any of the footprint filters or no footprint
* filters are defined.
*/
bool MatchesFootprintFilters( const wxString& aFootprintName ) const;
MODULE* GetModule( bool aRelease = false )
{
return ( aRelease ) ? m_footprint.release() : m_footprint.get();
}
void SetModule( MODULE* aModule );
bool IsLibSource( const wxString& aLibrary, const wxString& aName ) const
{
return aLibrary == m_library && aName == m_name;
}
bool FootprintChanged() const { return m_footprintChanged; }
#if defined(DEBUG)
/**
* Function Show
* is used to output the object tree, currently for debugging only.
* @param aNestLevel An aid to prettier tree indenting, and is the level
* of nesting of this object within the overall tree.
* @param aReporter A reference to a #REPORTER object to output to.
*/
virtual void Show( int aNestLevel, REPORTER& aReporter );
#endif
};
typedef boost::ptr_vector< COMPONENT > COMPONENTS;
typedef COMPONENTS::iterator COMPONENTS_ITER;
typedef COMPONENTS::const_iterator COMPONENTS_CITER;
/**
* Class NETLIST
* stores all of information read from a netlist along with the flags used to update
* the NETLIST in the #BOARD.
*/
class NETLIST
{
COMPONENTS m_components; ///< Components found in the netlist.
/// Remove footprints from #BOARD not found in netlist when true.
bool m_deleteExtraFootprints;
/// Do not actually make any changes. Only report changes to #BOARD from netlist
/// when true.
bool m_isDryRun;
/// Find component by time stamp if true or reference designator if false.
bool m_findByTimeStamp;
/// Replace component footprints when they differ from the netlist if true.
bool m_replaceFootprints;
public:
NETLIST() :
m_deleteExtraFootprints( false ),
m_isDryRun( false ),
m_findByTimeStamp( false ),
m_replaceFootprints( false )
{
}
/**
* Function IsEmpty()
* @return true if there are no components in the netlist.
*/
bool IsEmpty() const { return m_components.empty(); }
/**
* Function Clear
* removes all components from the netlist.
*/
void Clear() { m_components.clear(); }
/**
* Function GetCount
* @return the number of components in the netlist.
*/
unsigned GetCount() const { return m_components.size(); }
/**
* Function GetComponent
* returns the #COMPONENT at \a aIndex.
*
* @param aIndex the index in #m_components to fetch.
* @return a pointer to the #COMPONENT at \a Index.
*/
COMPONENT* GetComponent( unsigned aIndex ) { return &m_components[ aIndex ]; }
/**
* Function AddComponent
* adds \a aComponent to the NETLIST.
*
* @note If \a aComponent already exists in the NETLIST, \a aComponent is deleted
* to prevent memory leaks. An assertion is raised in debug builds.
*
* @param aComponent is the COMPONENT to save to the NETLIST.
*/
void AddComponent( COMPONENT* aComponent );
/*
* Function GetComponentByReference
* returns a #COMPONENT by \a aReference.
*
* @param aReference is the reference designator the #COMPONENT.
* @return a pointer to the #COMPONENT that matches \a aReference if found. Otherwise NULL.
*/
COMPONENT* GetComponentByReference( const wxString& aReference );
/*
* Function GetComponentByTimeStamp
* returns a #COMPONENT by \a aTimeStamp.
*
* @param aTimeStamp is the time stamp the #COMPONENT.
* @return a pointer to the #COMPONENT that matches \a aTimeStamp if found. Otherwise NULL.
*/
COMPONENT* GetComponentByTimeStamp( const wxString& aTimeStamp );
void SortByFPID();
void SortByReference();
void SetDeleteExtraFootprints( bool aDeleteExtraFootprints )
{
m_deleteExtraFootprints = aDeleteExtraFootprints;
}
bool GetDeleteExtraFootprints() const { return m_deleteExtraFootprints; }
void SetIsDryRun( bool aIsDryRun ) { m_isDryRun = aIsDryRun; }
bool IsDryRun() const { return m_isDryRun; }
void SetFindByTimeStamp( bool aFindByTimeStamp ) { m_findByTimeStamp = aFindByTimeStamp; }
bool IsFindByTimeStamp() const { return m_findByTimeStamp; }
void SetReplaceFootprints( bool aReplaceFootprints )
{
m_replaceFootprints = aReplaceFootprints;
}
bool GetReplaceFootprints() const { return m_replaceFootprints; }
/**
* Function AnyFootprintsLinked
* @return true if any component with a footprint link is found.
*/
bool AnyFootprintsLinked() const;
/**
* Function AllFootprintsLinked
* @return true if all components have a footprint link.
*/
bool AllFootprintsLinked() const;
/**
* Function NoFootprintsLinked
* @return true if none of the components have a footprint link.
*/
bool NoFootprintsLinked() const { return !AnyFootprintsLinked(); }
/**
* Function AnyFootprintsChanged
* @return true if any components footprints were changed when the footprint link file
* (*.cmp) was loaded.
*/
bool AnyFootprintsChanged() const;
#if defined(DEBUG)
/**
* Function Show
* is used to output the object tree, currently for debugging only.
* @param aNestLevel An aid to prettier tree indenting, and is the level
* of nesting of this object within the overall tree.
* @param aReporter A reference to a #REPORTER object to output to.
*/
virtual void Show( int aNestLevel, REPORTER& aReporter );
#endif
};
/** /**
......
/**
* @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
#ifndef PCB_NETLIST_H
#define PCB_NETLIST_H
/**
* @file pcb_netlist.h
*/
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2012 Jean-Pierre Charras.
* Copyright (C) 2013 Wayne Stambaugh <stambaughw@verizon.net>.
* Copyright (C) 2012 KiCad Developers, see CHANGELOG.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 <boost/ptr_container/ptr_vector.hpp>
#include <wx/arrstr.h>
#include <fpid.h>
class MODULE;
class REPORTER;
/**
* Class COMPONENT_NET
* is used to store the component pin name to net name associations stored in a netlist.
*/
class COMPONENT_NET
{
wxString m_pinName;
wxString m_netNumber;
wxString m_netName;
public:
COMPONENT_NET() {}
COMPONENT_NET( const wxString& aPinName, const wxString& aNetName )
{
m_pinName = aPinName;
m_netName = aNetName;
}
const wxString& GetPinName() const { return m_pinName; }
const wxString& GetNetName() const { return m_netName; }
bool IsValid() const { return !m_pinName.IsEmpty(); }
bool operator <( const COMPONENT_NET& aNet ) const
{
return m_pinName < aNet.m_pinName;
}
#if defined(DEBUG)
/**
* Function Show
* is used to output the object tree, currently for debugging only.
* @param aNestLevel An aid to prettier tree indenting, and is the level
* of nesting of this object within the overall tree.
* @param aReporter A reference to a #REPORTER object to output to.
*/
virtual void Show( int aNestLevel, REPORTER& aReporter );
#endif
};
typedef std::vector< COMPONENT_NET > COMPONENT_NETS;
/**
* Class COMPONENT
* is used to store components and all of their related information found in a netlist.
*/
class COMPONENT
{
COMPONENT_NETS m_nets;
wxArrayString m_footprintFilters; ///< Footprint filters found in netlist.
wxString m_reference; ///< The component reference designator found in netlist.
wxString m_value; ///< The component value found in netlist.
// ZZZ This timestamp is string, not time_t
wxString m_timeStamp; ///< The component full time stamp found in netlist.
/// The name of the component in #m_library used when it was placed on the schematic..
wxString m_name;
/// The name of the component library where #m_name was found.
wxString m_library;
/// The #FPID of the footprint assigned to the component.
FPID m_fpid;
/// The #MODULE loaded for #m_footprintName found in #m_footprintLib.
std::auto_ptr< MODULE > m_footprint;
/// Set to true if #m_footprintName or #m_footprintLib was changed when the footprint
/// link file was read.
bool m_footprintChanged;
static COMPONENT_NET m_emptyNet;
public:
COMPONENT( const FPID& aFPID,
const wxString& aReference,
const wxString& aValue,
const wxString& aTimeStamp )
{
m_fpid = aFPID;
m_reference = aReference;
m_value = aValue;
m_timeStamp = aTimeStamp;
m_footprintChanged = false;
}
virtual ~COMPONENT() { };
void AddNet( const wxString& aPinName, const wxString& aNetName )
{
m_nets.push_back( COMPONENT_NET( aPinName, aNetName ) );
}
unsigned GetNetCount() const { return m_nets.size(); }
const COMPONENT_NET& GetNet( unsigned aIndex ) const { return m_nets[aIndex]; }
const COMPONENT_NET& GetNet( const wxString& aPinName );
void SortPins() { sort( m_nets.begin(), m_nets.end() ); }
void SetName( const wxString& aName ) { m_name = aName;}
const wxString& GetName() const { return m_name; }
void SetLibrary( const wxString& aLibrary ) { m_library = aLibrary; }
const wxString& GetLibrary() const { return m_library; }
const wxString& GetReference() const { return m_reference; }
const wxString& GetValue() const { return m_value; }
void SetFPID( const FPID& aFPID )
{
m_footprintChanged = !m_fpid.empty() && (m_fpid != aFPID);
m_fpid = aFPID;
}
const FPID& GetFPID() const { return m_fpid; }
const wxString& GetTimeStamp() const { return m_timeStamp; }
void SetFootprintFilters( const wxArrayString& aFilterList )
{
m_footprintFilters = aFilterList;
}
const wxArrayString& GetFootprintFilters() const { return m_footprintFilters; }
/**
* Function MatchesFootprintFilters
*
* @return true if \a aFootprintName matches any of the footprint filters or no footprint
* filters are defined.
*/
bool MatchesFootprintFilters( const wxString& aFootprintName ) const;
MODULE* GetModule( bool aRelease = false )
{
return ( aRelease ) ? m_footprint.release() : m_footprint.get();
}
void SetModule( MODULE* aModule );
bool IsLibSource( const wxString& aLibrary, const wxString& aName ) const
{
return aLibrary == m_library && aName == m_name;
}
bool FootprintChanged() const { return m_footprintChanged; }
#if defined(DEBUG)
/**
* Function Show
* is used to output the object tree, currently for debugging only.
* @param aNestLevel An aid to prettier tree indenting, and is the level
* of nesting of this object within the overall tree.
* @param aReporter A reference to a #REPORTER object to output to.
*/
virtual void Show( int aNestLevel, REPORTER& aReporter );
#endif
};
typedef boost::ptr_vector< COMPONENT > COMPONENTS;
typedef COMPONENTS::iterator COMPONENTS_ITER;
typedef COMPONENTS::const_iterator COMPONENTS_CITER;
/**
* Class NETLIST
* stores all of information read from a netlist along with the flags used to update
* the NETLIST in the #BOARD.
*/
class NETLIST
{
COMPONENTS m_components; ///< Components found in the netlist.
/// Remove footprints from #BOARD not found in netlist when true.
bool m_deleteExtraFootprints;
/// Do not actually make any changes. Only report changes to #BOARD from netlist
/// when true.
bool m_isDryRun;
/// Find component by time stamp if true or reference designator if false.
bool m_findByTimeStamp;
/// Replace component footprints when they differ from the netlist if true.
bool m_replaceFootprints;
public:
NETLIST() :
m_deleteExtraFootprints( false ),
m_isDryRun( false ),
m_findByTimeStamp( false ),
m_replaceFootprints( false )
{
}
/**
* Function IsEmpty()
* @return true if there are no components in the netlist.
*/
bool IsEmpty() const { return m_components.empty(); }
/**
* Function Clear
* removes all components from the netlist.
*/
void Clear() { m_components.clear(); }
/**
* Function GetCount
* @return the number of components in the netlist.
*/
unsigned GetCount() const { return m_components.size(); }
/**
* Function GetComponent
* returns the #COMPONENT at \a aIndex.
*
* @param aIndex the index in #m_components to fetch.
* @return a pointer to the #COMPONENT at \a Index.
*/
COMPONENT* GetComponent( unsigned aIndex ) { return &m_components[ aIndex ]; }
/**
* Function AddComponent
* adds \a aComponent to the NETLIST.
*
* @note If \a aComponent already exists in the NETLIST, \a aComponent is deleted
* to prevent memory leaks. An assertion is raised in debug builds.
*
* @param aComponent is the COMPONENT to save to the NETLIST.
*/
void AddComponent( COMPONENT* aComponent );
/*
* Function GetComponentByReference
* returns a #COMPONENT by \a aReference.
*
* @param aReference is the reference designator the #COMPONENT.
* @return a pointer to the #COMPONENT that matches \a aReference if found. Otherwise NULL.
*/
COMPONENT* GetComponentByReference( const wxString& aReference );
/*
* Function GetComponentByTimeStamp
* returns a #COMPONENT by \a aTimeStamp.
*
* @param aTimeStamp is the time stamp the #COMPONENT.
* @return a pointer to the #COMPONENT that matches \a aTimeStamp if found. Otherwise NULL.
*/
COMPONENT* GetComponentByTimeStamp( const wxString& aTimeStamp );
void SortByFPID();
void SortByReference();
void SetDeleteExtraFootprints( bool aDeleteExtraFootprints )
{
m_deleteExtraFootprints = aDeleteExtraFootprints;
}
bool GetDeleteExtraFootprints() const { return m_deleteExtraFootprints; }
void SetIsDryRun( bool aIsDryRun ) { m_isDryRun = aIsDryRun; }
bool IsDryRun() const { return m_isDryRun; }
void SetFindByTimeStamp( bool aFindByTimeStamp ) { m_findByTimeStamp = aFindByTimeStamp; }
bool IsFindByTimeStamp() const { return m_findByTimeStamp; }
void SetReplaceFootprints( bool aReplaceFootprints )
{
m_replaceFootprints = aReplaceFootprints;
}
bool GetReplaceFootprints() const { return m_replaceFootprints; }
/**
* Function AnyFootprintsLinked
* @return true if any component with a footprint link is found.
*/
bool AnyFootprintsLinked() const;
/**
* Function AllFootprintsLinked
* @return true if all components have a footprint link.
*/
bool AllFootprintsLinked() const;
/**
* Function NoFootprintsLinked
* @return true if none of the components have a footprint link.
*/
bool NoFootprintsLinked() const { return !AnyFootprintsLinked(); }
/**
* Function AnyFootprintsChanged
* @return true if any components footprints were changed when the footprint link file
* (*.cmp) was loaded.
*/
bool AnyFootprintsChanged() const;
#if defined(DEBUG)
/**
* Function Show
* is used to output the object tree, currently for debugging only.
* @param aNestLevel An aid to prettier tree indenting, and is the level
* of nesting of this object within the overall tree.
* @param aReporter A reference to a #REPORTER object to output to.
*/
virtual void Show( int aNestLevel, REPORTER& aReporter );
#endif
};
#endif // PCB_NETLIST_H
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