void LEGACY_NETLIST_READER::loadFootprintFilters() throw( IO_ERROR, PARSE_ERROR )
{
    wxArrayString filters;
    wxString      cmpRef;
    char*         line;
    COMPONENT*    component = NULL;     // Suppress compil warning

    while( ( line = m_lineReader->ReadLine() ) != NULL )
    {
        if( strnicmp( line, "$endlist", 8 ) == 0 )   // end of list for the current component
        {
            wxASSERT( component != NULL );
            component->SetFootprintFilters( filters );
            component = NULL;
            filters.Clear();
            continue;
        }

        if( strnicmp( line, "$endfootprintlist", 4 ) == 0 )
            // End of this section
            return;

        if( strnicmp( line, "$component", 10 ) == 0 ) // New component reference found
        {
            cmpRef = FROM_UTF8( line + 11 );
            cmpRef.Trim( true );
            cmpRef.Trim( false );

            component = m_netlist->GetComponentByReference( cmpRef );

            // Cannot happen if the netlist is valid.
            if( component == NULL )
            {
                wxString msg;
                msg.Printf( _( "Cannot find component \'%s\' in footprint filter section "
                               "of netlist." ), GetChars( cmpRef ) );
                THROW_PARSE_ERROR( msg, m_lineReader->GetSource(), line, m_lineReader->LineNumber(),
                                   m_lineReader->Length() );
            }
        }
        else
        {
            // Add new filter to list
            wxString fp = FROM_UTF8( line + 1 );
            fp.Trim( false );
            fp.Trim( true );
            filters.Add( fp );
        }
    }
}
Beispiel #2
0
void CVPCB_MAINFRAME::SendMessageToEESCHEMA()
{
    if( m_netlist.IsEmpty() )
        return;

    int selection = m_compListBox->GetSelection();

    if ( selection < 0 )
        selection = 0;

    if( m_netlist.GetComponent( selection ) == NULL )
        return;

    COMPONENT* component = m_netlist.GetComponent( selection );

    std::string packet = StrPrintf( "$PART: \"%s\"", TO_UTF8( component->GetReference() ) );

    if( Kiface().IsSingle() )
        SendCommand( MSG_TO_SCH, packet.c_str() );
    else
        Kiway().ExpressMail( FRAME_SCH, MAIL_CROSS_PROBE, packet, this );
}
void CVPCB_MAINFRAME::SetNewPkg( const wxString& aFootprintName, int aIndex )
{
    COMPONENT* component;

    if( m_netlist.IsEmpty() )
        return;

    component = m_netlist.GetComponent( aIndex );

    if( component == NULL )
        return;

    LIB_ID fpid;

    if( !aFootprintName.IsEmpty() )
    {
        wxCHECK_RET( fpid.Parse( aFootprintName, LIB_ID::ID_PCB ) < 0,
                     wxString::Format( _( "\"%s\" is not a valid LIB_ID." ), aFootprintName ) );
    }

    component->SetFPID( fpid );

    // create the new component description
    wxString   description = wxString::Format( CMP_FORMAT, aIndex + 1,
                        GetChars( component->GetReference() ),
                        GetChars( component->GetValue() ),
                        GetChars( FROM_UTF8( component->GetFPID().Format().c_str() ) ) );

    // Set the new description and deselect the processed component
    m_compListBox->SetString( aIndex, description );

    // Mark this "session" as modified
    m_modified = true;

    // update the statusbar
    DisplayStatus();
}
Beispiel #4
0
void CVPCB_MAINFRAME::BuildCmpListBox()
{
    wxString    msg;
    COMPONENT*  component;
    wxFont      guiFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT );

    if( m_compListBox == NULL )
    {
        m_compListBox = new COMPONENTS_LISTBOX( this, ID_CVPCB_COMPONENT_LIST,
                                                wxDefaultPosition, wxDefaultSize );
        m_compListBox->SetFont( wxFont( guiFont.GetPointSize(),
                                        wxFONTFAMILY_MODERN,
                                        wxFONTSTYLE_NORMAL,
                                        wxFONTWEIGHT_NORMAL ) );
    }

    m_compListBox->m_ComponentList.Clear();

    for( unsigned i = 0;  i < m_netlist.GetCount();  i++ )
    {
        component = m_netlist.GetComponent( i );

        msg.Printf( CMP_FORMAT, m_compListBox->GetCount() + 1,
                    GetChars( component->GetReference() ),
                    GetChars( component->GetValue() ),
                    GetChars( FROM_UTF8( component->GetFPID().Format().c_str() ) ) );
        m_compListBox->m_ComponentList.Add( msg );
    }

    if( m_compListBox->m_ComponentList.Count() )
    {
        m_compListBox->SetItemCount( m_compListBox->m_ComponentList.Count() );
        m_compListBox->SetSelection( 0, true );
        m_compListBox->RefreshItems( 0L, m_compListBox->m_ComponentList.Count()-1 );
        m_compListBox->UpdateWidth();
    }
}
void KICAD_NETLIST_PARSER::parseComponent() throw( IO_ERROR, PARSE_ERROR, boost::bad_pointer )
{
   /* Parses a section like
     * (comp (ref P1)
     * (value DB25FEMELLE)
     * (footprint DB25FC)
     * (libsource (lib conn) (part DB25))
     * (sheetpath (names /) (tstamps /))
     * (tstamp 3256759C))
     *
     * other fields (unused) are skipped
     * A component need a reference, value, footprint name and a full time stamp
     * The full time stamp is the sheetpath time stamp + the component time stamp
     */
    FPID     fpid;
    wxString footprint;
    wxString tmp;
    wxString ref;
    wxString value;
    wxString library;
    wxString name;
    wxString pathtimestamp, timestamp;

    // The token comp was read, so the next data is (ref P1)
    while( (token = NextTok()) != T_RIGHT )
    {
        if( token == T_LEFT )
            token = NextTok();

        switch( token )
        {
        case T_ref:
            NeedSYMBOLorNUMBER();
            ref = FROM_UTF8( CurText() );
            NeedRIGHT();
            break;

        case T_value:
            NeedSYMBOLorNUMBER();
            value = FROM_UTF8( CurText() );
            NeedRIGHT();
            break;

        case T_footprint:
            NeedSYMBOLorNUMBER();
            footprint = FromUTF8();
            NeedRIGHT();
            break;

        case T_libsource:
            // Read libsource
            while( (token = NextTok()) != T_RIGHT )
            {
                if( token == T_LEFT )
                    token = NextTok();

                if( token == T_lib )
                {
                    NeedSYMBOLorNUMBER();
                    library = FROM_UTF8( CurText() );
                    NeedRIGHT();
                }
                else if( token == T_part )
                {
                    NeedSYMBOLorNUMBER();
                    name = FROM_UTF8( CurText() );
                    NeedRIGHT();
                }
                else
                {
                    Expecting( "part or lib" );
                }
            }
            break;

        case T_sheetpath:
            while( ( token = NextTok() ) != T_tstamps );
            NeedSYMBOLorNUMBER();
            pathtimestamp = FROM_UTF8( CurText() );
            NeedRIGHT();
            NeedRIGHT();
            break;

        case T_tstamp:
            NeedSYMBOLorNUMBER();
            timestamp = FROM_UTF8( CurText() );
            NeedRIGHT();
            break;

        default:
            // Skip not used data (i.e all other tokens)
            skipCurrent();
            break;
        }
    }

    if( !footprint.IsEmpty() && fpid.Parse( footprint ) >= 0 )
    {
        wxString error;
        error.Printf( _( "invalid PFID in\nfile: <%s>\nline: %d\noffset: %d" ),
                      GetChars( CurSource() ), CurLineNumber(), CurOffset() );

        THROW_IO_ERROR( error );
    }

    pathtimestamp += timestamp;
    COMPONENT* component = new COMPONENT( fpid, ref, value, pathtimestamp );
    component->SetName( name );
    component->SetLibrary( library );
    m_netlist->AddComponent( component );
}
void KICAD_NETLIST_PARSER::parseNet() throw( IO_ERROR, PARSE_ERROR )
{
    /* Parses a section like
     * (net (code 20) (name /PC-A0)
     *  (node (ref BUS1) (pin 62))
     *  (node (ref U3) (pin 3))
     *  (node (ref U9) (pin M6)))
     */

    COMPONENT* component = NULL;
    wxString   code;
    wxString   name;
    wxString   reference;
    wxString   pin;
    int        nodecount = 0;

    // The token net was read, so the next data is (code <number>)
    while( (token = NextTok()) != T_RIGHT )
    {
        if( token == T_LEFT )
            token = NextTok();

        switch( token )
        {
        case T_code:
            NeedSYMBOLorNUMBER();
            code = FROM_UTF8( CurText() );
            NeedRIGHT();
            break;

        case T_name:
            NeedSYMBOLorNUMBER();
            name = FROM_UTF8( CurText() );
            NeedRIGHT();

            if( name.IsEmpty() )      // Give a dummy net name like N-000109
                name = wxT("N-00000") + code;

            break;

        case T_node:
            while( (token = NextTok()) != T_RIGHT )
            {
                if( token == T_LEFT )
                    token = NextTok();

                switch( token )
                {
                case T_ref:
                    NeedSYMBOLorNUMBER();
                    reference = FROM_UTF8( CurText() );
                    NeedRIGHT();
                    break;

                case T_pin:
                    NeedSYMBOLorNUMBER();
                    pin = FROM_UTF8( CurText() );
                    NeedRIGHT();
                    break;

                default:
                    skipCurrent();
                    break;
                }
            }


            component = m_netlist->GetComponentByReference( reference );

            // Cannot happen if the netlist is valid.
            if( component == NULL )
            {
                wxString msg;
                msg.Printf( _( "Cannot find component with reference \"%s\" in netlist." ),
                               GetChars( reference ) );
                THROW_PARSE_ERROR( msg, m_lineReader->GetSource(), m_lineReader->Line(),
                                   m_lineReader->LineNumber(), m_lineReader->Length() );
            }

            component->AddNet( pin, name );
            nodecount++;
            break;

        default:
            skipCurrent();
            break;
        }
    }
}
Beispiel #7
0
void PCB_EDIT_FRAME::LoadFootprints( NETLIST& aNetlist, REPORTER* aReporter )
{
    wxString   msg;
    LIB_ID     lastFPID;
    COMPONENT* component;
    MODULE*    module = 0;
    MODULE*    fpOnBoard;

    if( aNetlist.IsEmpty() || Prj().PcbFootprintLibs()->IsEmpty() )
        return;

    aNetlist.SortByFPID();

    for( unsigned ii = 0; ii < aNetlist.GetCount(); ii++ )
    {
        component = aNetlist.GetComponent( ii );

#if ALLOW_PARTIAL_FPID
        // The FPID is ok as long as there is a footprint portion coming
        // from eeschema.
        if( !component->GetFPID().GetLibItemName().size() )
#else
        if( component->GetFPID().empty() )
#endif
        {
            if( aReporter )
            {
                msg.Printf( _( "No footprint defined for symbol \"%s\".\n" ),
                            GetChars( component->GetReference() ) );
                aReporter->Report( msg, REPORTER::RPT_ERROR );
            }

            continue;
        }

        // Check if component footprint is already on BOARD and only load the footprint from
        // the library if it's needed.  Nickname can be blank.
        if( aNetlist.IsFindByTimeStamp() )
            fpOnBoard = m_Pcb->FindModule( aNetlist.GetComponent( ii )->GetTimeStamp(), true );
        else
            fpOnBoard = m_Pcb->FindModule( aNetlist.GetComponent( ii )->GetReference() );

        bool footprintMisMatch = fpOnBoard &&
                                 fpOnBoard->GetFPID() != component->GetFPID();

        if( footprintMisMatch && !aNetlist.GetReplaceFootprints() )
        {
            if( aReporter )
            {
                msg.Printf( _( "Footprint of symbol \"%s\" changed: board footprint \"%s\", netlist footprint \"%s\"\n" ),
                            GetChars( component->GetReference() ),
                            GetChars( fpOnBoard->GetFPID().Format() ),
                            GetChars( component->GetFPID().Format() ) );
                aReporter->Report( msg, REPORTER::RPT_WARNING );
            }

            continue;
        }

        if( !aNetlist.GetReplaceFootprints() )
            footprintMisMatch = false;

        if( fpOnBoard && !footprintMisMatch )   // nothing else to do here
            continue;

        if( component->GetFPID() != lastFPID )
        {
            module = NULL;

#if ALLOW_PARTIAL_FPID
            // The LIB_ID is ok as long as there is a footprint portion coming
            // the library if it's needed.  Nickname can be blank.
            if( !component->GetFPID().GetLibItemName().size() )
#else
            if( !component->GetFPID().IsValid() )
#endif
            {
                if( aReporter )
                {
                    msg.Printf( _( "Component \"%s\" footprint ID \"%s\" is not "
                                   "valid.\n" ),
                                GetChars( component->GetReference() ),
                                GetChars( component->GetFPID().Format() ) );
                    aReporter->Report( msg, REPORTER::RPT_ERROR );
                }

                continue;
            }

            // loadFootprint() can find a footprint with an empty nickname in fpid.
            module = PCB_BASE_FRAME::loadFootprint( component->GetFPID() );

            if( module )
            {
                lastFPID = component->GetFPID();
            }
            else
            {
                if( aReporter )
                {
                    msg.Printf( _( "Component \"%s\" footprint \"%s\" was not found in "
                                   "any libraries in the footprint library table.\n" ),
                                GetChars( component->GetReference() ),
                                GetChars( component->GetFPID().GetLibItemName() ) );
                    aReporter->Report( msg, REPORTER::RPT_ERROR );
                }

                continue;
            }
        }
        else
        {
            // Footprint already loaded from a library, duplicate it (faster)
            if( module == NULL )
                continue;            // Module does not exist in any library.

            module = new MODULE( *module );
        }

        if( module )
            component->SetModule( module );
    }
}
bool CVPCB_MAINFRAME::ReadNetListAndLinkFiles()
{
    wxString        msg;
    bool            hasMissingNicks = false;
    FP_LIB_TABLE*   tbl = FootprintLibs();

    ReadSchematicNetlist();

    if( m_ListCmp == NULL )
        return false;

    LoadProjectFile( m_NetlistFileName.GetFullPath() );
    LoadFootprintFiles();
    BuildFOOTPRINTS_LISTBOX();
    BuildLIBRARY_LISTBOX();

    m_ListCmp->Clear();
    m_undefinedComponentCnt = 0;

    if( m_netlist.AnyFootprintsLinked() )
    {
        for( unsigned i = 0;  i < m_netlist.GetCount();  i++ )
        {
            COMPONENT* component = m_netlist.GetComponent( i );

            if( component->GetFPID().empty() )
                continue;

            if( component->GetFPID().IsLegacy() )
                hasMissingNicks = true;
        }
    }

    // Check if footprint links were generated before the footprint library table was implemented.
    if( hasMissingNicks )
    {
        msg = wxT(
            "Some of the assigned footprints are legacy entries (are missing lib nicknames). "
            "Would you like CvPcb to attempt to convert them to the new required FPID format? "
            "(If you answer no, then these assignments will be cleared out and you will "
            "have to re-assign these footprints yourself.)"
            );

        if( IsOK( this, msg ) )
        {
            msg.Clear();

            try
            {
                for( unsigned i = 0;  i < m_netlist.GetCount();  i++ )
                {
                    COMPONENT* component = m_netlist.GetComponent( i );

                    if( component->GetFPID().IsLegacy() )
                    {
                        int guess = guessNickname( tbl, (FPID*) &component->GetFPID() );

                        switch( guess )
                        {
                        case 0:
                            DBG(printf("%s: guessed OK ref:%s  fpid:%s\n", __func__,
                                TO_UTF8( component->GetReference() ), component->GetFPID().Format().c_str() );)
                            m_modified = true;
                            break;

                        case 1:
                            msg += wxString::Format( _(
                                    "Component '%s' footprint '%s' was <b>not found</b> in any library.\n" ),
                                    GetChars( component->GetReference() ),
                                    GetChars( component->GetFPID().GetFootprintName() )
                                    );
                            break;

                        case 2:
                            msg += wxString::Format( _(
                                    "Component '%s' footprint '%s' was found in <b>multiple</b> libraries.\n" ),
                                    GetChars( component->GetReference() ),
                                    GetChars( component->GetFPID().GetFootprintName() )
                                    );
                            break;
                        }
                    }
                }
            }
Beispiel #9
0
void CVPCB_MAINFRAME::OnSelectComponent( wxListEvent& event )
{
    if( m_skipComponentSelect )
        return;

    wxString   libraryName;
    COMPONENT* component = NULL;
    int        filter = FOOTPRINTS_LISTBOX::UNFILTERED;

    if( m_mainToolBar->GetToolToggled( ID_CVPCB_FOOTPRINT_DISPLAY_FILTERED_LIST ) )
        filter |= FOOTPRINTS_LISTBOX::BY_COMPONENT;

    if( m_mainToolBar->GetToolToggled( ID_CVPCB_FOOTPRINT_DISPLAY_PIN_FILTERED_LIST ) )
        filter |= FOOTPRINTS_LISTBOX::BY_PIN_COUNT;

    if( m_mainToolBar->GetToolToggled( ID_CVPCB_FOOTPRINT_DISPLAY_BY_LIBRARY_LIST ) )
        filter |= FOOTPRINTS_LISTBOX::BY_LIBRARY;

    component = GetSelectedComponent();
    libraryName = m_libListBox->GetSelectedLibrary();
    m_footprintListBox->SetFootprints( m_footprints, libraryName, component, filter );

    // Tell AuiMgr that objects are changed !
    if( m_auimgr.GetManagedWindow() )   // Be sure Aui Manager is initialized
        // (could be not the case when starting CvPcb
        m_auimgr.Update();

    if( component == NULL )
        return;

    // Preview of the already assigned footprint.
    // Find the footprint that was already chosen for this component and select it,
    // but only if the selection is made from the component list or the library list.
    // If the selection is made from the footprint list, do not change the current
    // selected footprint.
    if( FindFocus() == m_compListBox || FindFocus() == m_libListBox )
    {
        wxString module = FROM_UTF8( component->GetFPID().Format().c_str() );

        bool found = false;

        for( int ii = 0; ii < m_footprintListBox->GetCount(); ii++ )
        {
            wxString footprintName;
            wxString msg = m_footprintListBox->OnGetItemText( ii, 0 );
            msg.Trim( true );
            msg.Trim( false );
            footprintName = msg.AfterFirst( wxChar( ' ' ) );

            if( module.Cmp( footprintName ) == 0 )
            {
                m_footprintListBox->SetSelection( ii, true );
                found = true;
                break;
            }
        }

        if( !found )
        {
            int ii = m_footprintListBox->GetSelection();

            if ( ii >= 0 )
                m_footprintListBox->SetSelection( ii, false );

            if( GetFpViewerFrame() )
            {
                CreateScreenCmp();
            }
        }
    }

    SendMessageToEESCHEMA();
    DisplayStatus();
}
/**
 * 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;
}
/**
 * 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();
}
Beispiel #12
0
void CVPCB_MAINFRAME::AutomaticFootprintMatching( wxCommandEvent& event )
{
    FOOTPRINT_EQUIVALENCE_LIST equiv_List;
    COMPONENT*           component;
    wxString             msg, error_msg;
    size_t               ii;

    if( m_netlist.IsEmpty() )
        return;

    if( buildEquivalenceList( equiv_List, &error_msg ) )
        wxMessageBox( error_msg, _( "Equivalence File Load Error" ), wxOK |  wxICON_WARNING, this );

    // Sort the association list by component value.
    // When sorted, find duplicate definitions (i.e. 2 or more items
    // having the same component value) is more easy.
    std::sort( equiv_List.begin(), equiv_List.end(), sortListbyCmpValue );

    // Display the number of footprint/component equivalences.
    msg.Printf( _( "%lu footprint/cmp equivalences found." ), (unsigned long)equiv_List.size() );
    SetStatusText( msg, 0 );

    // Now, associate each free component with a footprint, when the association
    // is found in list
    m_skipComponentSelect = true;
    ii = 0;
    error_msg.Empty();

    for( unsigned kk = 0;  kk < m_netlist.GetCount();  kk++ )
    {
        component = m_netlist.GetComponent( kk );

        bool found = false;
        m_compListBox->SetSelection( ii++, true );

        if( !component->GetFPID().empty() ) // the component has already a footprint
            continue;

        // Here a first attempt is made. We can have multiple equivItem of the same value.
        // When happens, using the footprint filter of components can remove the ambiguity by
        // filtering equivItem so one can use multiple equiv_List (for polar and
        // non-polar caps for example)
        for( unsigned idx = 0; idx < equiv_List.size(); idx++ )
        {
            FOOTPRINT_EQUIVALENCE& equivItem = equiv_List[idx];

            if( equivItem.m_ComponentValue.CmpNoCase( component->GetValue() ) != 0 )
                continue;

            const FOOTPRINT_INFO *module = m_FootprintsList.GetModuleInfo( equivItem.m_FootprintFPID );

            bool equ_is_unique = true;
            unsigned next = idx+1;
            int  previous = idx-1;

            if( next < equiv_List.size() &&
                    equivItem.m_ComponentValue == equiv_List[next].m_ComponentValue )
                equ_is_unique = false;

            if( previous >= 0 &&
                    equivItem.m_ComponentValue == equiv_List[previous].m_ComponentValue )
                equ_is_unique = false;

            // If the equivalence is unique, no ambiguity: use the association
            if( module && equ_is_unique )
            {
                SetNewPkg( equivItem.m_FootprintFPID );
                found = true;
                break;
            }

            // The equivalence is not unique: use the footprint filter to try to remove
            // ambiguity
            if( module )
            {
                size_t filtercount = component->GetFootprintFilters().GetCount();
                found = ( 0 == filtercount ); // if no entries, do not filter

                for( size_t jj = 0; jj < filtercount && !found; jj++ )
                {
                    found = module->GetFootprintName().Matches( component->GetFootprintFilters()[jj] );
                }
            }
            else
            {
                msg.Printf( _( "Component %s: footprint %s not found in any of the project "
                               "footprint libraries." ),
                            GetChars( component->GetReference() ),
                            GetChars( equivItem.m_FootprintFPID ) );

                if( ! error_msg.IsEmpty() )
                    error_msg << wxT("\n\n");

                error_msg += msg;
            }

            if( found )
            {
                SetNewPkg( equivItem.m_FootprintFPID );
                break;
            }
        }

        if( found )
            continue;

        // obviously the last chance: there's only one filter matching one footprint
        if( 1 == component->GetFootprintFilters().GetCount() )
        {
            // we do not need to analyze wildcards: single footprint do not
            // contain them and if there are wildcards it just will not match any
            const FOOTPRINT_INFO* module = m_FootprintsList.GetModuleInfo( component->GetFootprintFilters()[0] );

            if( module )
                SetNewPkg( component->GetFootprintFilters()[0] );
        }
    }

    if( !error_msg.IsEmpty() )
        wxMessageBox( error_msg, _( "CvPcb Warning" ), wxOK | wxICON_WARNING, this );

    m_skipComponentSelect = false;
}
bool DIALOG_NETLIST::verifyFootprints( const wxString&         aNetlistFilename,
                                       const wxString &        aCmpFilename,
                                       std::vector< MODULE* >& aDuplicates,
                                       wxArrayString&          aMissing,
                                       std::vector< MODULE* >& aNotInNetlist )
{
    wxString        msg;
    MODULE*         module;
    MODULE*         nextModule;
    NETLIST         netlist;
    wxBusyCursor    dummy;           // Shows an hourglass while calculating.
    NETLIST_READER* netlistReader;
    COMPONENT*      component;

    try
    {
        netlistReader = NETLIST_READER::GetNetlistReader( &netlist, aNetlistFilename,
                        aCmpFilename );

        if( netlistReader == NULL )
        {
            msg.Printf( _( "Cannot open netlist file \"%s\"." ), GetChars( aNetlistFilename ) );
            wxMessageBox( msg, _( "Netlist Load Error." ), wxOK | wxICON_ERROR );
            return false;
        }

        std::auto_ptr< NETLIST_READER > nlr( netlistReader );
        netlistReader->LoadNetlist();
    }
    catch( const IO_ERROR& ioe )
    {
        msg.Printf( _( "Error loading netlist file:\n%s" ), ioe.errorText.GetData() );
        wxMessageBox( msg, _( "Netlist Load Error" ), wxOK | wxICON_ERROR );
        return false;
    }

    BOARD* pcb = m_parent->GetBoard();

    // Search for duplicate footprints.
    module = pcb->m_Modules;

    for( ; module != NULL; module = module->Next() )
    {
        nextModule = module->Next();

        for( ; nextModule != NULL; nextModule = nextModule->Next() )
        {
            if( module->GetReference().CmpNoCase( nextModule->GetReference() ) == 0 )
            {
                aDuplicates.push_back( module );
                break;
            }
        }
    }

    // Search for component footprints in the netlist but not on the board.
    for( unsigned ii = 0; ii < netlist.GetCount(); ii++ )
    {
        component = netlist.GetComponent( ii );

        module = pcb->FindModuleByReference( component->GetReference() );

        if( module == NULL )
        {
            aMissing.Add( component->GetReference() );
            aMissing.Add( component->GetValue() );
        }
    }

    // Search for component footprints found on board but not in netlist.
    module = pcb->m_Modules;

    for( ; module != NULL; module = module->Next() )
    {

        component = netlist.GetComponentByReference( module->GetReference() );

        if( component == NULL )
            aNotInNetlist.push_back( module );
    }

    return true;
}
void CVPCB_MAINFRAME::SetNewPkg( const wxString& aFootprintName )
{
    COMPONENT* component;
    bool       hasFootprint = false;
    int        componentIndex;

    if( m_netlist.IsEmpty() )
        return;

    // If no component is selected, select the first one
    if( m_compListBox->GetFirstSelected() < 0 )
    {
        componentIndex = 0;
        m_compListBox->SetSelection( componentIndex, true );
    }

    // iterate over the selection
    while( m_compListBox->GetFirstSelected() != -1 )
    {
        // Get the component for the current iteration
        componentIndex = m_compListBox->GetFirstSelected();
        component = m_netlist.GetComponent( componentIndex );

        if( component == NULL )
            return;

        // Check to see if the component has already a footprint set.
        hasFootprint = !component->GetFPID().empty();

        FPID fpid;

        if( !aFootprintName.IsEmpty() )
        {
            wxCHECK_RET( fpid.Parse( aFootprintName ) < 0,
                         wxString::Format( wxT( "<%s> is not a valid FPID." ),
                                           GetChars( aFootprintName ) ) );
        }

        component->SetFPID( fpid );

        // create the new component description
        wxString   description = wxString::Format( CMP_FORMAT, componentIndex + 1,
                            GetChars( component->GetReference() ),
                            GetChars( component->GetValue() ),
                            GetChars( FROM_UTF8( component->GetFPID().Format().c_str() ) ) );

        // 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;
            m_undefinedComponentCnt -= 1;
        }

        // Set the new description and deselect the processed component
        m_compListBox->SetString( componentIndex, description );
        m_compListBox->SetSelection( componentIndex, false );
    }

    // Mark this "session" as modified
    m_modified = true;

    // select the next component, if there is one
    if( componentIndex < (m_compListBox->GetCount() - 1) )
        componentIndex++;

    m_compListBox->SetSelection( componentIndex, true );

    // update the statusbar
    DisplayStatus();
}
Beispiel #15
0
bool CVPCB_MAINFRAME::ReadNetListAndLinkFiles()
{
    COMPONENT* component;
    wxString   msg;
    bool       isLegacy = true;

    ReadSchematicNetlist();

    if( m_ListCmp == NULL )
        return false;

    LoadProjectFile( m_NetlistFileName.GetFullPath() );
    LoadFootprintFiles();
    BuildFOOTPRINTS_LISTBOX();
    BuildLIBRARY_LISTBOX();

    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.
    }

    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;
            }
        }
    }

    for( unsigned i = 0;  i < m_netlist.GetCount();  i++ )
    {
        component = m_netlist.GetComponent( i );

        msg.Printf( CMP_FORMAT, m_ListCmp->GetCount() + 1,
                    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() )
        m_ListCmp->SetSelection( 0, true );

    DisplayStatus();

    UpdateTitle();

    UpdateFileHistory( m_NetlistFileName.GetFullPath() );

    return true;
}
void KICAD_NETLIST_PARSER::parseLibPartList() throw( IO_ERROR, PARSE_ERROR )
{
   /* Parses a section like
    *   (libpart (lib device) (part C)
    *  (aliases
    *    (alias Cxx)
    *    (alias Cyy))
    *     (description "Condensateur non polarise")
    *     (footprints
    *       (fp SM*)
    *       (fp C?)
    *       (fp C1-1))
    *     (fields
    *       (field (name Reference) C)
    *       (field (name Value) C))
    *     (pins
    *       (pin (num 1) (name ~) (type passive))
    *       (pin (num 2) (name ~) (type passive))))
    *
    * Currently footprints section/fp are read and data stored
    * other fields (unused) are skipped
    */
    COMPONENT*        component = NULL;
    wxString          libName;
    wxString          libPartName;
    wxArrayString     footprintFilters;
    wxArrayString     aliases;

    // The last token read was libpart, so read the next token
    while( (token = NextTok()) != T_RIGHT )
    {
        if( token == T_LEFT )
            token = NextTok();

        switch( token )
        {
        case T_lib:
            NeedSYMBOLorNUMBER();
            libName = FROM_UTF8( CurText() );
            NeedRIGHT();
            break;

        case T_part:
            NeedSYMBOLorNUMBER();
            libPartName = FROM_UTF8( CurText() );
            NeedRIGHT();
            break;

        case T_footprints:
            // Read all fp elements (footprint filter item)
            while( (token = NextTok()) != T_RIGHT )
            {
                if( token == T_LEFT )
                    token = NextTok();

                if( token != T_fp )
                    Expecting( T_fp );

                NeedSYMBOLorNUMBER();
                footprintFilters.Add( FROM_UTF8( CurText() ) );
                NeedRIGHT();
            }

            break;

        case T_aliases:
            while( (token = NextTok()) != T_RIGHT )
            {
                if( token == T_LEFT )
                    token = NextTok();

                if( token != T_alias )
                    Expecting( T_alias );

                NeedSYMBOLorNUMBER();
                aliases.Add( FROM_UTF8( CurText() ) );
                NeedRIGHT();
            }
            break;
        default:
            // Skip not used data (i.e all other tokens)
            skipCurrent();
            break;
        }
    }

    // Find all of the components that reference this component library part definition.
    for( unsigned i = 0;  i < m_netlist->GetCount();  i++ )
    {
        component = m_netlist->GetComponent( i );

        if( component->IsLibSource( libName, libPartName ) )
            component->SetFootprintFilters( footprintFilters );

        for( unsigned jj = 0; jj < aliases.GetCount(); jj++ )
        {
            if( component->IsLibSource( libName, aliases[jj] ) )
                component->SetFootprintFilters( footprintFilters );
        }

    }
}
bool CVPCB_MAINFRAME::ReadNetListAndFpFiles( const std::string& aNetlist )
{
    wxString        msg;
    bool            hasMissingNicks = false;

    ReadSchematicNetlist( aNetlist );

    if( m_compListBox == NULL )
        return false;

    LoadProjectFile();

    wxSafeYield();

    LoadFootprintFiles();

    BuildFOOTPRINTS_LISTBOX();
    BuildLIBRARY_LISTBOX();

    m_compListBox->Clear();

    if( m_netlist.AnyFootprintsLinked() )
    {
        for( unsigned i = 0;  i < m_netlist.GetCount();  i++ )
        {
            COMPONENT* component = m_netlist.GetComponent( i );

            if( component->GetFPID().empty() )
                continue;

            if( component->GetFPID().IsLegacy() )
                hasMissingNicks = true;
        }
    }

    // Check if footprint links were generated before the footprint library table was implemented.
    if( hasMissingNicks )
    {
        msg = _(
            "Some of the assigned footprints are legacy entries (are missing lib nicknames). "
            "Would you like CvPcb to attempt to convert them to the new required LIB_ID format? "
            "(If you answer no, then these assignments will be cleared out and you will "
            "have to re-assign these footprints yourself.)"
            );

        if( IsOK( this, msg ) )
        {
            msg.Clear();

            try
            {
                for( unsigned i = 0;  i < m_netlist.GetCount();  i++ )
                {
                    COMPONENT* component = m_netlist.GetComponent( i );

                    if( component->GetFPID().IsLegacy() )
                    {
                        // get this first here, it's possibly obsoleted if we get it too soon.
                        FP_LIB_TABLE*   tbl = Prj().PcbFootprintLibs( Kiway() );

                        int guess = guessNickname( tbl, (LIB_ID*) &component->GetFPID() );

                        switch( guess )
                        {
                        case 0:
                            DBG(printf("%s: guessed OK ref:%s  fpid:%s\n", __func__,
                                TO_UTF8( component->GetReference() ), component->GetFPID().Format().c_str() );)
                            m_modified = true;
                            break;

                        case 1:
                            msg += wxString::Format( _(
                                    "Component \"%s\" footprint \"%s\" was <b>not found</b> in any library.\n" ),
                                    GetChars( component->GetReference() ),
                                    GetChars( component->GetFPID().GetLibItemName() )
                                    );
                            break;

                        case 2:
                            msg += wxString::Format( _(
                                    "Component \"%s\" footprint \"%s\" was found in <b>multiple</b> libraries.\n" ),
                                    GetChars( component->GetReference() ),
                                    GetChars( component->GetFPID().GetLibItemName() )
                                    );
                            break;
                        }
                    }
                }
            }
COMPONENT* LEGACY_NETLIST_READER::loadComponent( char* aText )
    throw( PARSE_ERROR, boost::bad_pointer )
{
    char*    text;
    wxString msg;
    wxString timeStamp;         // the full time stamp read from netlist
    wxString footprintName;     // the footprint name read from netlist
    wxString value;             // the component value read from netlist
    wxString reference;         // the component schematic reference designator read from netlist
    wxString name;              // the name of component that was placed in the schematic
    char     line[1024];

    strcpy( line, aText );

    value = wxT( "~" );

    // Sample component line:   /40C08647 $noname R20 4.7K {Lib=R}

    // Read time stamp (first word)
    if( ( text = strtok( line, " ()\t\n" ) ) == NULL )
    {
        msg = _( "Cannot parse time stamp in component section of netlist." );
        THROW_PARSE_ERROR( msg, m_lineReader->GetSource(), line, m_lineReader->LineNumber(),
                           m_lineReader->Length() );
    }

    timeStamp = FROM_UTF8( text );

    // Read footprint name (second word)
    if( ( text = strtok( NULL, " ()\t\n" ) ) == NULL )
    {
        msg = _( "Cannot parse footprint name in component section of netlist." );
        THROW_PARSE_ERROR( msg, m_lineReader->GetSource(), aText, m_lineReader->LineNumber(),
                           m_lineReader->Length() );
    }

    footprintName = FROM_UTF8( text );

    // The footprint name will have to be looked up in the *.cmp file.
    if( footprintName == wxT( "$noname" ) )
        footprintName = wxEmptyString;

    // Read schematic reference designator (third word)
    if( ( text = strtok( NULL, " ()\t\n" ) ) == NULL )
    {
        msg = _( "Cannot parse reference designator in component section of netlist." );
        THROW_PARSE_ERROR( msg, m_lineReader->GetSource(), aText, m_lineReader->LineNumber(),
                           m_lineReader->Length() );
    }

    reference = FROM_UTF8( text );

    // Read schematic value (forth word)
    if( ( text = strtok( NULL, " ()\t\n" ) ) == NULL )
    {
        msg = _( "Cannot parse value in component section of netlist." );
        THROW_PARSE_ERROR( msg, m_lineReader->GetSource(), aText, m_lineReader->LineNumber(),
                           m_lineReader->Length() );
    }

    value = FROM_UTF8( text );

    // Read component name (fifth word) {Lib=C}
    // This is an optional field (a comment), which does not always exists
    if( ( text = strtok( NULL, " ()\t\n" ) ) != NULL )
    {
        name = FROM_UTF8( text ).AfterFirst( wxChar( '=' ) ).BeforeLast( wxChar( '}' ) );
    }

    FPID fpid;

    if( !footprintName.IsEmpty() )
        fpid.SetFootprintName( footprintName );

    COMPONENT* component = new COMPONENT( fpid, reference, value, timeStamp );
    component->SetName( name );
    m_netlist->AddComponent( component );
    return component;
}
bool CMP_READER::Load( NETLIST* aNetlist ) throw( IO_ERROR, PARSE_ERROR )
{
    wxCHECK_MSG( aNetlist != NULL,true, wxT( "No netlist passed to CMP_READER::Load()" ) );

    wxString reference;    // Stores value read from line like Reference = BUS1;
    wxString timestamp;    // Stores value read from line like TimeStamp = /32307DE2/AA450F67;
    wxString footprint;    // Stores value read from line like IdModule  = CP6;
    wxString buffer;
    wxString value;

    bool ok = true;

    while( m_lineReader->ReadLine() )
    {
        buffer = FROM_UTF8( m_lineReader->Line() );

        if( !buffer.StartsWith( wxT( "BeginCmp" ) ) )
            continue;

        // Begin component description.
        reference.Empty();
        footprint.Empty();
        timestamp.Empty();

        while( m_lineReader->ReadLine() )
        {
            buffer = FROM_UTF8( m_lineReader->Line() );

            if( buffer.StartsWith( wxT( "EndCmp" ) ) )
                break;

            // store string value, stored between '=' and ';' delimiters.
            value = buffer.AfterFirst( '=' );
            value = value.BeforeLast( ';' );
            value.Trim( true );
            value.Trim( false );

            if( buffer.StartsWith( wxT( "Reference" ) ) )
            {
                reference = value;
                continue;
            }

            if( buffer.StartsWith( wxT( "IdModule  =" ) ) )
            {
                footprint = value;
                continue;
            }

            if( buffer.StartsWith( wxT( "TimeStamp =" ) ) )
            {
                timestamp = value;
                continue;
            }
        }

        // Find the corresponding item in component list:
        COMPONENT* component = aNetlist->GetComponentByReference( reference );

        // The corresponding component could no longer existing in the netlist.  This
        // can happen 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 )
        {
            FPID fpid;

            if( !footprint.IsEmpty() && fpid.Parse( footprint ) >= 0 )
            {
                wxString error;
                error.Printf( _( "invalid footprint ID in\nfile: <%s>\nline: %d" ),
                              GetChars( m_lineReader->GetSource() ),
                              m_lineReader->LineNumber() );

                THROW_IO_ERROR( error );
            }

            // For checking purpose, store the existing FPID (if any) in the alternate fpid copy
            // if this existing FPID differs from the FPID read from the .cmp file.
            // CvPcb can ask for user to chose the right FPID.
            // It happens if the FPID was modified outside CvPcb.
            if( fpid != component->GetFPID() && !component->GetFPID().empty() )
                component->SetAltFPID( component->GetFPID() );

            component->SetFPID( fpid );
        }
        else
        {
            ok = false;     // can be used to display a warning in Pcbnew.
        }
    }

    return ok;
}
void CVPCB_MAINFRAME::AssocieModule( wxCommandEvent& event )
{
    FOOTPRINT_ALIAS_LIST aliases;
    FOOTPRINT_ALIAS*     alias;
    COMPONENT*           component;
    wxFileName           fn;
    wxString             msg, tmp;
    char                 Line[1024];
    FILE*                file;
    size_t               ii;

    SEARCH_STACK&        search = Kiface().KifaceSearch();

    if( m_netlist.IsEmpty() )
        return;

    // Find equivalents in all available files.
    for( ii = 0; ii < m_AliasLibNames.GetCount(); ii++ )
    {
        fn = m_AliasLibNames[ii];

        if( !fn.HasExt() )
        {
            fn.SetExt( FootprintAliasFileExtension );
            // above fails if filename has more than one point
        }
        else
        {
            fn.SetExt( fn.GetExt() + wxT( "." ) + FootprintAliasFileExtension );
        }

        tmp = search.FindValidPath( fn.GetFullPath() );

        if( !tmp )
        {
            msg.Printf( _( "Footprint alias library file '%s' could not be found in the "
                           "default search paths." ),
                        GetChars( fn.GetFullName() ) );
            wxMessageBox( msg, FMT_TITLE_LIB_LOAD_ERROR, wxOK | wxICON_ERROR );
            continue;
        }

        file = wxFopen( tmp, wxT( "rt" ) );

        if( file == NULL )
        {
            msg.Printf( _( "Error opening alias library '%s'." ), GetChars( tmp ) );
            wxMessageBox( msg, FMT_TITLE_LIB_LOAD_ERROR, wxOK | wxICON_ERROR );
            continue;
        }

        while( GetLine( file, Line, NULL, sizeof(Line) ) != NULL )
        {
            char* text = Line;
            wxString value, footprint, wtext = FROM_UTF8( Line );

            value = GetQuotedText( wtext );

            if( text == NULL || ( *text == 0 ) || value.IsEmpty() )
                continue;

            footprint = GetQuotedText( wtext );

            if( footprint.IsEmpty() )
                continue;

            value.Replace( wxT( " " ), wxT( "_" ) );

            alias = new FOOTPRINT_ALIAS();
            alias->m_Name = value;
            alias->m_FootprintName = footprint;
            aliases.push_back( alias );
        }

        fclose( file );
    }

    // Display the number of footprint aliases.
    msg.Printf( _( "%d footprint aliases found." ), aliases.size() );
    SetStatusText( msg, 0 );

    m_skipComponentSelect = true;
    ii = 0;

    for( unsigned kk = 0;  kk < m_netlist.GetCount();  kk++ )
    {
        component = m_netlist.GetComponent( kk );

        bool found = false;
        m_compListBox->SetSelection( ii++, true );

        if( !component->GetFPID().empty() )
            continue;

        BOOST_FOREACH( FOOTPRINT_ALIAS& alias, aliases )
        {

            if( alias.m_Name.CmpNoCase( component->GetValue() ) != 0 )
                continue;

            // filter alias so one can use multiple aliases (for polar and
            // nonpolar caps for example)
            const FOOTPRINT_INFO *module = m_footprints.GetModuleInfo( alias.m_FootprintName );

            if( module )
            {
                size_t filtercount = component->GetFootprintFilters().GetCount();
                found = ( 0 == filtercount ); // if no entries, do not filter

                for( size_t jj = 0; jj < filtercount && !found; jj++ )
                {
                    found = module->GetFootprintName().Matches( component->GetFootprintFilters()[jj] );
                }
            }
            else
            {
                msg.Printf( _( "Component %s: footprint %s not found in any of the project "
                               "footprint libraries." ),
                            GetChars( component->GetReference() ),
                            GetChars( alias.m_FootprintName ) );
                wxMessageBox( msg, _( "CvPcb Error" ), wxOK | wxICON_ERROR, this );
            }

            if( found )
            {
                SetNewPkg( alias.m_FootprintName );
                break;
            }

        }

        // obviously the last chance: there's only one filter matching one footprint
        if( !found && 1 == component->GetFootprintFilters().GetCount() )
        {
            // we do not need to analyse wildcards: single footprint do not
            // contain them and if there are wildcards it just will not match any
            const FOOTPRINT_INFO* module = m_footprints.GetModuleInfo( component->GetFootprintFilters()[0] );

            if( module )
            {
                SetNewPkg( component->GetFootprintFilters()[0] );
            }
        }
    }

    m_skipComponentSelect = false;
}
Beispiel #21
0
void CVPCB_MAINFRAME::DisplayStatus()
{
    wxString   msg;
    COMPONENT* component;

    if( wxWindow::FindFocus() == m_compListBox || wxWindow::FindFocus() == m_libListBox )
    {
        msg.Printf( _( "Components: %d, unassigned: %d" ), (int) m_netlist.GetCount(),
                    m_undefinedComponentCnt );
        SetStatusText( msg, 0 );

        msg.Empty();

        component = GetSelectedComponent();

        if( component )
        {
            for( unsigned ii = 0;  ii < component->GetFootprintFilters().GetCount();  ii++ )
            {
                if( msg.IsEmpty() )
                    msg += component->GetFootprintFilters()[ii];
                else
                    msg += wxT( ", " ) + component->GetFootprintFilters()[ii];
            }

            msg = _( "Filter list: " ) + msg;
        }

        SetStatusText( msg, 1 );
    }
    else
    {
        wxString footprintName = m_footprintListBox->GetSelectedFootprint();

        FOOTPRINT_INFO* module = m_footprints.GetModuleInfo( footprintName );

        if( module )    // can be NULL if no netlist loaded
        {
            msg = _( "Description: " ) + module->GetDoc();
            SetStatusText( msg, 0 );

            msg  = _( "Key words: " ) + module->GetKeywords();
            SetStatusText( msg, 1 );
        }
    }

    msg.Empty();
    wxString filters;

    if( m_footprintListBox )
    {
        if( m_mainToolBar->GetToolToggled( ID_CVPCB_FOOTPRINT_DISPLAY_FILTERED_LIST ) )
            filters = _( "key words" );

        if( m_mainToolBar->GetToolToggled( ID_CVPCB_FOOTPRINT_DISPLAY_PIN_FILTERED_LIST ) )
        {
            if( !filters.IsEmpty() )
                filters += wxT( "+" );

            filters += _( "pin count" );
        }

        if( m_mainToolBar->GetToolToggled( ID_CVPCB_FOOTPRINT_DISPLAY_BY_LIBRARY_LIST ) )
        {
            if( !filters.IsEmpty() )
                filters += wxT( "+" );

            filters += _( "library" );
        }

        if( filters.IsEmpty() )
            msg = _( "No filtering" );
        else
            msg.Printf( _( "Filtered by %s" ), GetChars( filters ) );

        msg << wxT( ": " ) << m_footprintListBox->GetCount();

        SetStatusText( msg, 2 );
    }
}
Beispiel #22
0
void PCB_EDIT_FRAME::loadFootprints( NETLIST& aNetlist, REPORTER* aReporter )
    throw( IO_ERROR, PARSE_ERROR )
{
    wxString   msg;
    FPID       lastFPID;
    COMPONENT* component;
    MODULE*    module = 0;
    MODULE*    fpOnBoard;

    if( aNetlist.IsEmpty() || FootprintLibs()->IsEmpty() )
        return;

    aNetlist.SortByFPID();

    for( unsigned ii = 0; ii < aNetlist.GetCount(); ii++ )
    {
        component = aNetlist.GetComponent( ii );

#if ALLOW_PARTIAL_FPID
        // The FPID is ok as long as there is a footprint portion coming
        // from eeschema.
        if( !component->GetFPID().GetFootprintName().size() )
#else
        if( component->GetFPID().empty() )
#endif
        {
            if( aReporter )
            {
                msg.Printf( _( "No footprint defined for component '%s'.\n" ),
                            GetChars( component->GetReference() ) );
                aReporter->Report( msg );
            }

            continue;
        }

        // Check if component footprint is already on BOARD and only load the footprint from
        // the library if it's needed.  Nickname can be blank.
        if( aNetlist.IsFindByTimeStamp() )
            fpOnBoard = m_Pcb->FindModule( aNetlist.GetComponent( ii )->GetTimeStamp(), true );
        else
            fpOnBoard = m_Pcb->FindModule( aNetlist.GetComponent( ii )->GetReference() );

        bool footprintMisMatch = fpOnBoard &&
                                 fpOnBoard->GetFPID() != component->GetFPID();

        if( footprintMisMatch && !aNetlist.GetReplaceFootprints() )
        {
            if( aReporter )
            {
                msg.Printf( _( "* Warning: component '%s' has footprint '%s' and should be '%s'\n" ),
                            GetChars( component->GetReference() ),
                            fpOnBoard->GetFPID().GetFootprintName().c_str(),
                            component->GetFPID().GetFootprintName().c_str() );
                aReporter->Report( msg );
            }

            continue;
        }

        if( !aNetlist.GetReplaceFootprints() )
            footprintMisMatch = false;

        bool loadFootprint = (fpOnBoard == NULL) || footprintMisMatch;

        if( loadFootprint && (component->GetFPID() != lastFPID) )
        {
            module = NULL;

#if ALLOW_PARTIAL_FPID
            // The FPID is ok as long as there is a footprint portion coming
            // the library if it's needed.  Nickname can be blank.
            if( !component->GetFPID().GetFootprintName().size() )
#else
            if( !component->GetFPID().IsValid() )
#endif
            {
                if( aReporter )
                {
                    msg.Printf( _( "*** Warning: Component '%s' footprint ID '%s' is not "
                                   "valid. ***\n" ),
                                GetChars( component->GetReference() ),
                                component->GetFPID().GetFootprintName().c_str() );
                    aReporter->Report( msg );
                }

                continue;
            }

            // loadFootprint() can find a footprint with an empty nickname in fpid.
            module = PCB_BASE_FRAME::loadFootprint( component->GetFPID() );

            if( module )
            {
                lastFPID = component->GetFPID();
            }
            else
            {
                if( aReporter )
                {
                    wxString msg;
                    msg.Printf( _( "*** Warning: component '%s' footprint '%s' was not found in "
                                   "any libraries in the footprint library table. ***\n" ),
                                GetChars( component->GetReference() ),
                                component->GetFPID().GetFootprintName().c_str() );
                    aReporter->Report( msg );
                }

                continue;
            }
        }
        else
        {
            // Footprint already loaded from a library, duplicate it (faster)
            if( module == NULL )
                continue;            // Module does not exist in any library.

            module = new MODULE( *module );
        }

        if( loadFootprint && module != NULL )
            component->SetModule( module );
    }
}
bool BOARD_NETLIST_UPDATER::UpdateNetlist( NETLIST& aNetlist )
{
    wxString msg;
    m_errorCount = 0;
    m_warningCount = 0;

    if( !m_isDryRun )
    {
        m_board->SetStatus( 0 );
    }

    for( int i = 0; i < (int) aNetlist.GetCount();  i++ )
    {
        COMPONENT* component = aNetlist.GetComponent( i );
        MODULE* footprint = NULL;

        msg.Printf( _( "Processing component \"%s:%s:%s\".\n" ),
                    GetChars( component->GetReference() ),
                    GetChars( component->GetTimeStamp() ),
                    GetChars( component->GetFPID().Format() ) );
        m_reporter->Report( msg, REPORTER::RPT_INFO );

        if( aNetlist.IsFindByTimeStamp() )
            footprint = m_board->FindModule( component->GetTimeStamp(), true );
        else
            footprint = m_board->FindModule( component->GetReference() );

        if( footprint )        // An existing footprint.
        {
            MODULE* newFootprint = replaceComponent( aNetlist, footprint, component );

            if( newFootprint )
                footprint = newFootprint;
        }
        else
        {
            footprint = addNewComponent( component );
        }

        if( footprint )
        {
            updateComponentParameters( footprint, component );
            updateComponentPadConnections( footprint, component );
        }
    }

    //aNetlist.GetDeleteExtraFootprints()

    if( m_deleteUnusedComponents )
        deleteUnusedComponents( aNetlist );

    if( m_deleteSinglePadNets )
        deleteSinglePadNets();

    if( !m_isDryRun )
    {
        m_commit.Push( _( "Update netlist" ) );
        m_frame->Compile_Ratsnest( NULL, false );
        m_board->GetRatsnest()->ProcessBoard();
        testConnectivity( aNetlist );
    }

    // Update the ratsnest
    m_reporter->Report( wxT( "" ), REPORTER::RPT_ACTION );
    m_reporter->Report( wxT( "" ), REPORTER::RPT_ACTION );

    msg.Printf( _( "Total warnings: %d, errors: %d." ), m_warningCount, m_errorCount );
    m_reporter->Report( msg, REPORTER::RPT_ACTION );

    if( m_errorCount )
    {
        m_reporter->Report( _( "Errors occured during the netlist update. Unless you "
                               "fix them, your board will not be consistent with the schematics." ),
                            REPORTER::RPT_ERROR );

        return false;
    }
    else
    {
        m_reporter->Report( _( "Netlist update successful!" ), REPORTER::RPT_ACTION );
    }

    return true;
}
/**
 * Function convertFromLegacy
 * converts the footprint names in \a aNetList from the legacy format 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.
 */
static bool convertFromLegacy( FP_LIB_TABLE* aTbl, SEARCH_STACK& aSStack, NETLIST& aNetList,
        const wxArrayString& aLibNames, REPORTER* aReporter = NULL ) throw( IO_ERROR )
{
    wxString   msg;
    FPID       lastFPID;
    COMPONENT* component;
    MODULE*    module = 0;
    bool       retv = true;

    if( aNetList.IsEmpty() )
        return true;

    aNetList.SortByFPID();

    wxString   libPath;

    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++ )
            {
                wxFileName fn( wxEmptyString, aLibNames[ii], LegacyFootprintLibPathExtension );

                libPath = aSStack.FindValidPath( fn.GetFullPath() );

                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, component->GetFPID().GetFootprintName() );

                if( module )
                {
                    lastFPID = component->GetFPID();
                    break;
                }
            }
        }

        if( !module )
        {
            if( aReporter )
            {
                msg.Printf( _( "Component '%s' footprint '%s' was not found in any legacy "
                               "library.\n" ),
                            GetChars( component->GetReference() ),
                            GetChars( component->GetFPID().Format() ) );
                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
        {
            wxString    libNickname;

            const FP_LIB_TABLE::ROW* row;

            if( ( row = aTbl->FindRowByURI( libPath ) ) != NULL )
                libNickname = row->GetNickName();

            if( libNickname.IsEmpty() )
            {
                if( aReporter )
                {
                    msg.Printf( _( "Component '%s' with footprint '%s' and legacy library path '%s' "
                                   "was not found in the footprint library table.\n" ),
                                GetChars( component->GetReference() ),
                                GetChars( component->GetFPID().Format() ),
                                GetChars( libPath )
                                );
                    aReporter->Report( msg );
                }

                retv = false;
            }
            else
            {
                FPID newFPID = lastFPID;
                newFPID.SetLibNickname( libNickname );

                if( !newFPID.IsValid() )
                {
                    if( aReporter )
                    {
                        msg.Printf( _( "Component '%s' FPID '%s' is not valid.\n" ),
                                    GetChars( component->GetReference() ),
                                    GetChars( newFPID.Format() ) );
                        aReporter->Report( msg );
                    }

                    retv = false;
                }
                else
                {
                    // The footprint name should already be set.
                    component->SetFPID( newFPID );
                }
            }
        }
    }

    return retv;
}