From ce409e3699ef5c9915bd17f6ff69f61453629552 Mon Sep 17 00:00:00 2001 From: Wayne Stambaugh Date: Sat, 14 Sep 2013 16:33:22 -0400 Subject: [PATCH] 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. --- common/CMakeLists.txt | 1 + common/footprint_info.cpp | 26 ++ common/fp_lib_table.cpp | 218 ++++++++++++++- common/reporter.cpp | 12 +- cvpcb/CMakeLists.txt | 3 + cvpcb/cfg.cpp | 50 +++- cvpcb/class_DisplayFootprintsFrame.cpp | 74 ++++- cvpcb/class_footprints_listbox.cpp | 33 ++- cvpcb/class_library_listbox.cpp | 16 +- cvpcb/cvframe.cpp | 132 ++++++++- cvpcb/cvpcb.h | 11 +- cvpcb/cvpcb_id.h | 3 +- cvpcb/cvpcb_mainframe.h | 30 +- cvpcb/cvstruct.h | 1 - cvpcb/menubar.cpp | 6 + cvpcb/readwrite_dlgs.cpp | 109 +++++++- include/footprint_info.h | 17 +- include/fp_lib_table.h | 43 ++- include/reporter.h | 19 ++ pcbnew/class_board.cpp | 2 +- pcbnew/dialogs/dialog_netlist.cpp | 2 + pcbnew/kicad_netlist_reader.cpp | 2 + pcbnew/legacy_netlist_reader.cpp | 1 + pcbnew/netlist.cpp | 1 + pcbnew/netlist_reader.cpp | 268 +----------------- pcbnew/netlist_reader.h | 331 +--------------------- pcbnew/pcb_netlist.cpp | 278 +++++++++++++++++++ pcbnew/pcb_netlist.h | 367 +++++++++++++++++++++++++ 28 files changed, 1408 insertions(+), 648 deletions(-) create mode 100644 pcbnew/pcb_netlist.cpp create mode 100644 pcbnew/pcb_netlist.h diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 45a7662fc1..9909a8d54c 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -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 diff --git a/common/footprint_info.cpp b/common/footprint_info.cpp index a82f809d7a..5a4ce2970a 100644 --- a/common/footprint_info.cpp +++ b/common/footprint_info.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include @@ -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() ) diff --git a/common/fp_lib_table.cpp b/common/fp_lib_table.cpp index c90b0c586a..2ab1ad8290 100644 --- a/common/fp_lib_table.cpp +++ b/common/fp_lib_table.cpp @@ -31,10 +31,14 @@ #include #include +#include +#include +#include +#include +#include #include #include - 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; diff --git a/common/reporter.cpp b/common/reporter.cpp index d3297fe4a9..be4372a3b9 100644 --- a/common/reporter.cpp +++ b/common/reporter.cpp @@ -1,5 +1,5 @@ /** - * @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; +} diff --git a/cvpcb/CMakeLists.txt b/cvpcb/CMakeLists.txt index 2447f4cd3e..3e4d8e3f47 100644 --- a/cvpcb/CMakeLists.txt +++ b/cvpcb/CMakeLists.txt @@ -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 diff --git a/cvpcb/cfg.cpp b/cvpcb/cfg.cpp index f6648a3b67..6d1bb55596 100644 --- a/cvpcb/cfg.cpp +++ b/cvpcb/cfg.cpp @@ -1,6 +1,30 @@ -/*************/ -/** 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 #include @@ -9,6 +33,8 @@ #include #include #include +#include +#include #include #include @@ -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 } diff --git a/cvpcb/class_DisplayFootprintsFrame.cpp b/cvpcb/class_DisplayFootprintsFrame.cpp index b868985389..44810b1abc 100644 --- a/cvpcb/class_DisplayFootprintsFrame.cpp +++ b/cvpcb/class_DisplayFootprintsFrame.cpp @@ -36,6 +36,9 @@ #include #include #include +#include +#include +#include #include #include @@ -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 diff --git a/cvpcb/class_footprints_listbox.cpp b/cvpcb/class_footprints_listbox.cpp index 22e0c94477..e50a61fd10 100644 --- a/cvpcb/class_footprints_listbox.cpp +++ b/cvpcb/class_footprints_listbox.cpp @@ -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 + } } diff --git a/cvpcb/class_library_listbox.cpp b/cvpcb/class_library_listbox.cpp index 9c3e6cd0dd..5c7f76256f 100644 --- a/cvpcb/class_library_listbox.cpp +++ b/cvpcb/class_library_listbox.cpp @@ -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 + } } diff --git a/cvpcb/cvframe.cpp b/cvpcb/cvframe.cpp index 6a17bdbc6b..08e669e7d8 100644 --- a/cvpcb/cvframe.cpp +++ b/cvpcb/cvframe.cpp @@ -28,22 +28,25 @@ */ #include +#include #include #include #include #include #include #include +#include +#include +#include +#include #include +#include #include #include #include #include -#include -#include -#include #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 } diff --git a/cvpcb/cvpcb.h b/cvpcb/cvpcb.h index c506ea41df..5b91f21640 100644 --- a/cvpcb/cvpcb.h +++ b/cvpcb/cvpcb.h @@ -5,21 +5,16 @@ #ifndef __CVPCB_H__ #define __CVPCB_H__ -#include - -#include -#include - - // 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; diff --git a/cvpcb/cvpcb_id.h b/cvpcb/cvpcb_id.h index 7ac8ce95ad..6229f87947 100644 --- a/cvpcb/cvpcb_id.h +++ b/cvpcb/cvpcb_id.h @@ -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 }; diff --git a/cvpcb/cvpcb_mainframe.h b/cvpcb/cvpcb_mainframe.h index 69fe7a03bc..7fea960ec2 100644 --- a/cvpcb/cvpcb_mainframe.h +++ b/cvpcb/cvpcb_mainframe.h @@ -31,12 +31,11 @@ #include #include -#include +#include #include #include #include -#include /* 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 ); diff --git a/cvpcb/cvstruct.h b/cvpcb/cvstruct.h index a2d2eb7701..579aa44dc6 100644 --- a/cvpcb/cvstruct.h +++ b/cvpcb/cvstruct.h @@ -30,7 +30,6 @@ #include -#include /* Forward declarations of all top-level window classes. */ class CVPCB_MAINFRAME; diff --git a/cvpcb/menubar.cpp b/cvpcb/menubar.cpp index f7c188d4aa..bceb5170bf 100644 --- a/cvpcb/menubar.cpp +++ b/cvpcb/menubar.cpp @@ -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 ); diff --git a/cvpcb/readwrite_dlgs.cpp b/cvpcb/readwrite_dlgs.cpp index cb239ce3ff..4eb58bf9b5 100644 --- a/cvpcb/readwrite_dlgs.cpp +++ b/cvpcb/readwrite_dlgs.cpp @@ -31,6 +31,11 @@ #include #include #include +#include +#include +#include +#include +#include #include #include @@ -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() ) diff --git a/include/footprint_info.h b/include/footprint_info.h index ccdba621db..0035938cfa 100644 --- a/include/footprint_info.h +++ b/include/footprint_info.h @@ -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; } diff --git a/include/fp_lib_table.h b/include/fp_lib_table.h index f9f64fa9ff..98796040fc 100644 --- a/include/fp_lib_table.h +++ b/include/fp_lib_table.h @@ -31,13 +31,16 @@ #include #include -//#include #include +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 diff --git a/include/reporter.h b/include/reporter.h index 0fcbb7eec7..42d4c1fa34 100644 --- a/include/reporter.h +++ b/include/reporter.h @@ -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_ diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp index a3f47416c3..d7e8dcb6cd 100644 --- a/pcbnew/class_board.cpp +++ b/pcbnew/class_board.cpp @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include diff --git a/pcbnew/dialogs/dialog_netlist.cpp b/pcbnew/dialogs/dialog_netlist.cpp index 2137cf886c..6315e63a00 100644 --- a/pcbnew/dialogs/dialog_netlist.cpp +++ b/pcbnew/dialogs/dialog_netlist.cpp @@ -29,11 +29,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include diff --git a/pcbnew/kicad_netlist_reader.cpp b/pcbnew/kicad_netlist_reader.cpp index 912c13cba2..fb40685ee8 100644 --- a/pcbnew/kicad_netlist_reader.cpp +++ b/pcbnew/kicad_netlist_reader.cpp @@ -28,6 +28,8 @@ #include #include // netlist_lexer is common to Eeschema and Pcbnew #include + +#include #include using namespace NL_T; diff --git a/pcbnew/legacy_netlist_reader.cpp b/pcbnew/legacy_netlist_reader.cpp index 6b415bcf82..e215a67720 100644 --- a/pcbnew/legacy_netlist_reader.cpp +++ b/pcbnew/legacy_netlist_reader.cpp @@ -31,6 +31,7 @@ #include #include +#include #include diff --git a/pcbnew/netlist.cpp b/pcbnew/netlist.cpp index 1f8fe80b29..c1ecf930f1 100644 --- a/pcbnew/netlist.cpp +++ b/pcbnew/netlist.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include diff --git a/pcbnew/netlist_reader.cpp b/pcbnew/netlist_reader.cpp index c1b50fd79e..a970d53940 100644 --- a/pcbnew/netlist_reader.cpp +++ b/pcbnew/netlist_reader.cpp @@ -31,267 +31,13 @@ #include #include +#include #include #include #include -#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( "\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( "\n" ) ); - NestedSpace( aNestLevel+1, aReporter ); - aReporter.Report( wxString::Format( wxT( "\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( "\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( "\n" ) ); - } - - if( !m_nets.empty() ) - { - NestedSpace( aNestLevel+1, aReporter ); - aReporter.Report( wxT( "\n" ) ); - - for( unsigned i = 0; i < m_nets.size(); i++ ) - m_nets[i].Show( aNestLevel+3, aReporter ); - - NestedSpace( aNestLevel+1, aReporter ); - aReporter.Report( "\n" ); - } - - NestedSpace( aNestLevel, aReporter ); - aReporter.Report( "\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( "\n" ); - - if( !m_components.empty() ) - { - NestedSpace( aNestLevel+1, aReporter ); - aReporter.Report( "\n" ); - - for( unsigned i = 0; i < m_components.size(); i++ ) - { - m_components[i].Show( aNestLevel+2, aReporter ); - } - - NestedSpace( aNestLevel+1, aReporter ); - - aReporter.Report( "\n" ); - } - - NestedSpace( aNestLevel, aReporter ); - aReporter.Report( "\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; diff --git a/pcbnew/netlist_reader.h b/pcbnew/netlist_reader.h index ef8600de46..3db2236003 100644 --- a/pcbnew/netlist_reader.h +++ b/pcbnew/netlist_reader.h @@ -42,335 +42,8 @@ using namespace NL_T; -class MODULE; -class LINE_READER; -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 -}; +class NETLIST; +class COMPONENT; /** diff --git a/pcbnew/pcb_netlist.cpp b/pcbnew/pcb_netlist.cpp new file mode 100644 index 0000000000..7e1ee53aa1 --- /dev/null +++ b/pcbnew/pcb_netlist.cpp @@ -0,0 +1,278 @@ +/** + * @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 . + * 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 +#include +#include + +#include +#include + + +#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( "\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( "\n" ) ); + NestedSpace( aNestLevel+1, aReporter ); + aReporter.Report( wxString::Format( wxT( "\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( "\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( "\n" ) ); + } + + if( !m_nets.empty() ) + { + NestedSpace( aNestLevel+1, aReporter ); + aReporter.Report( wxT( "\n" ) ); + + for( unsigned i = 0; i < m_nets.size(); i++ ) + m_nets[i].Show( aNestLevel+3, aReporter ); + + NestedSpace( aNestLevel+1, aReporter ); + aReporter.Report( "\n" ); + } + + NestedSpace( aNestLevel, aReporter ); + aReporter.Report( "\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( "\n" ); + + if( !m_components.empty() ) + { + NestedSpace( aNestLevel+1, aReporter ); + aReporter.Report( "\n" ); + + for( unsigned i = 0; i < m_components.size(); i++ ) + { + m_components[i].Show( aNestLevel+2, aReporter ); + } + + NestedSpace( aNestLevel+1, aReporter ); + + aReporter.Report( "\n" ); + } + + NestedSpace( aNestLevel, aReporter ); + aReporter.Report( "\n" ); +} +#endif diff --git a/pcbnew/pcb_netlist.h b/pcbnew/pcb_netlist.h new file mode 100644 index 0000000000..90605d29a3 --- /dev/null +++ b/pcbnew/pcb_netlist.h @@ -0,0 +1,367 @@ +#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 . + * 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 +#include + +#include + + +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