void FOOTPRINTS_LISTBOX::SetFootprints( FOOTPRINT_LIST& aList, const wxString& aLibName,
                                        COMPONENT* aComponent, int aFilterType )
{
    wxArrayString   newList;
    wxString        msg;
    wxString        oldSelection;

    if( GetSelection() >= 0 && GetSelection() < (int)m_footprintList.GetCount() )
        oldSelection = m_footprintList[ GetSelection() ];

    for( unsigned ii = 0; ii < aList.GetCount(); ii++ )
    {
        if( aFilterType == UNFILTERED )
        {
            msg.Printf( wxT( "%3d %s:%s" ), int( newList.GetCount() + 1 ),
                        GetChars( aList.GetItem( ii ).GetNickname() ),
                        GetChars( aList.GetItem( ii ).GetFootprintName() ) );
            newList.Add( msg );
            continue;
        }

        if( (aFilterType & BY_LIBRARY) && !aLibName.IsEmpty()
                && !aList.GetItem( ii ).InLibrary( aLibName ) )
            continue;

        if( (aFilterType & BY_COMPONENT) && aComponent
                && !aComponent->MatchesFootprintFilters( aList.GetItem( ii ).GetFootprintName() ) )
            continue;

        if( (aFilterType & BY_PIN_COUNT) && aComponent
                && aComponent->GetNetCount() != aList.GetItem( ii ).GetUniquePadCount() )
            continue;

        msg.Printf( wxT( "%3d %s:%s" ), int( newList.GetCount() + 1 ),
                    GetChars( aList.GetItem( ii ).GetNickname() ),
                    GetChars( aList.GetItem( ii ).GetFootprintName() ) );
        newList.Add( msg );
    }

    if( newList == m_footprintList )
        return;

    m_footprintList = newList;

    int selection = m_footprintList.Index( oldSelection );

    if( selection == wxNOT_FOUND )
        selection = 0;

    DeleteAllItems();

    if( m_footprintList.GetCount() )
    {
        SetItemCount( m_footprintList.GetCount() );
        SetSelection( selection, true );
        RefreshItems( 0L, m_footprintList.GetCount()-1 );
        UpdateWidth();
    }
}
static void DisplayCmpDoc( wxString& aName )
{
    FOOTPRINT_INFO* module_info = MList.GetModuleInfo( aName );

    if( !module_info )
    {
        aName.Empty();
        return;
    }

    aName  = _( "Description: " ) + module_info->GetDoc();
    aName += _( "\nKey words: " ) + module_info->GetKeywords();
}
wxString PCB_BASE_FRAME::SelectFootprint( EDA_DRAW_FRAME* aWindow,
                                          const wxString& aLibraryName,
                                          const wxString& aMask,
                                          const wxString& aKeyWord,
                                          FP_LIB_TABLE*   aTable )
{
    static wxString oldName;    // Save the name of the last module loaded.

    wxString        fpname;
    wxString        msg;
    wxArrayString   libraries;

    std::vector< wxArrayString > rows;

    wxASSERT( aTable != NULL );

    MList.ReadFootprintFiles( aTable, !aLibraryName ? NULL : &aLibraryName );

    if( MList.GetErrorCount() )
    {
        MList.DisplayErrors( this );
        return wxEmptyString;
    }

    if( MList.GetCount() == 0 )
    {
        wxString tmp;

        for( unsigned i = 0;  i < libraries.GetCount();  i++ )
        {
            tmp += libraries[i] + wxT( "\n" );
        }

        msg.Printf( _( "No footprints could be read from library file(s):\n\n%s\nin any of "
                       "the library search paths.  Verify your system is configured properly "
                       "so the footprint libraries can be found." ), GetChars( tmp ) );
        DisplayError( aWindow, msg );
        return wxEmptyString;
    }

    if( !aKeyWord.IsEmpty() )       // Create a list of modules found by keyword.
    {
        for( unsigned ii = 0; ii < MList.GetCount(); ii++ )
        {
            if( KeyWordOk( aKeyWord, MList.GetItem( ii ).GetKeywords() ) )
            {
                wxArrayString   cols;
                cols.Add( MList.GetItem( ii ).GetFootprintName() );
                cols.Add( MList.GetItem( ii ).GetNickname() );
                rows.push_back( cols );
            }
        }
    }
    else if( !aMask.IsEmpty() )     // Create a list of modules found by pattern
    {
        for( unsigned ii = 0; ii < MList.GetCount(); ii++ )
        {
            const wxString& candidate = MList.GetItem( ii ).GetFootprintName();

            if( WildCompareString( aMask, candidate, false ) )
            {
                wxArrayString   cols;
                cols.Add( MList.GetItem( ii ).GetFootprintName() );
                cols.Add( MList.GetItem( ii ).GetNickname() );
                rows.push_back( cols );
            }
        }
    }
    else                            // Create the full list of modules
    {
        for( unsigned ii = 0; ii < MList.GetCount(); ii++ )
        {
            wxArrayString   cols;
            cols.Add( MList.GetItem( ii ).GetFootprintName() );
            cols.Add( MList.GetItem( ii ).GetNickname() );
            rows.push_back( cols );
        }
    }

    if( !rows.empty() )
    {
        wxArrayString headers;

        headers.Add( _( "Module" ) );
        headers.Add( _( "Library" ) );

        msg.Printf( _( "Modules [%d items]" ), (int) rows.size() );

        EDA_LIST_DIALOG dlg( aWindow, msg, headers, rows, oldName, DisplayCmpDoc );

        if( dlg.ShowModal() == wxID_OK )
        {
            fpname = dlg.GetTextSelection();

            fpname = dlg.GetTextSelection( 1 ) + wxT( ":" ) + fpname;

            SkipNextLeftButtonReleaseEvent();
        }
        else
            fpname.Empty();
    }
    else
    {
        DisplayError( aWindow, _( "No footprint found." ) );
        fpname.Empty();
    }

    if( fpname != wxEmptyString )
        oldName = fpname;

    wxLogDebug( wxT( "Footprint '%s' was selected." ), GetChars( fpname ) );

    return fpname;
}
void FOOTPRINTS_LISTBOX::SetFootprints( FOOTPRINT_LIST& aList, const wxString& aLibName,
                                        COMPONENT* aComponent, int aFilterType )
{
    wxArrayString   newList;
    wxString        msg;
    wxString        oldSelection;

    if( GetSelection() >= 0 && GetSelection() < (int)m_footprintList.GetCount() )
        oldSelection = m_footprintList[ GetSelection() ];

    for( unsigned ii = 0; ii < aList.GetCount(); ii++ )
    {
        if( aFilterType == UNFILTERED )
        {
            msg.Printf( wxT( "%3zu %s:%s" ), newList.GetCount() + 1,
                        GetChars( aList.GetItem( ii ).GetNickname() ),
                        GetChars( aList.GetItem( ii ).GetFootprintName() ) );
            newList.Add( msg );
            continue;
        }

        if( (aFilterType & BY_LIBRARY) && !aLibName.IsEmpty()
          && !aList.GetItem( ii ).InLibrary( aLibName ) )
            continue;

        if( (aFilterType & BY_COMPONENT) && aComponent
          && !aComponent->MatchesFootprintFilters( aList.GetItem( ii ).GetFootprintName() ) )
            continue;

        if( (aFilterType & BY_PIN_COUNT) && aComponent
          && aComponent->GetNetCount() != aList.GetItem( ii ).GetPadCount() )
            continue;

        msg.Printf( wxT( "%3zu %s:%s" ), newList.GetCount() + 1,
                    GetChars( aList.GetItem( ii ).GetNickname() ),
                    GetChars( aList.GetItem( ii ).GetFootprintName() ) );
        newList.Add( msg );
    }

    if( newList == m_footprintList )
        return;

    m_footprintList = newList;

    int selection = m_footprintList.Index( oldSelection );

    if( selection == wxNOT_FOUND )
        selection = 0;

    DeleteAllItems();

    if( m_footprintList.GetCount() )
    {
        SetItemCount( m_footprintList.GetCount() );
        SetSelection( selection, true );
        RefreshItems( 0L, m_footprintList.GetCount()-1 );

#if defined (__WXGTK__ ) //&& wxMINOR_VERSION == 8
        // @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
    }
}
void FOOTPRINTS_LISTBOX::SetFootprints( FOOTPRINT_LIST& aList, const wxString& aLibName,
                                        COMPONENT* aComponent,
                                        const wxString &aFootPrintFilterPattern,
                                        int aFilterType )
{
    wxArrayString   newList;
    wxString        msg;
    wxString        oldSelection;

    EDA_PATTERN_MATCH_WILDCARD patternFilter;
    patternFilter.SetPattern( aFootPrintFilterPattern.Lower() );    // Use case insensitive search

    if( GetSelection() >= 0 && GetSelection() < (int)m_footprintList.GetCount() )
        oldSelection = m_footprintList[ GetSelection() ];

    for( unsigned ii = 0; ii < aList.GetCount(); ii++ )
    {
        if( aFilterType == UNFILTERED_FP_LIST )
        {
            msg.Printf( wxT( "%3d %s:%s" ), int( newList.GetCount() + 1 ),
                        GetChars( aList.GetItem( ii ).GetNickname() ),
                        GetChars( aList.GetItem( ii ).GetFootprintName() ) );
            newList.Add( msg );
            continue;
        }

        if( (aFilterType & FILTERING_BY_LIBRARY) && !aLibName.IsEmpty()
            && !aList.GetItem( ii ).InLibrary( aLibName ) )
            continue;

        if( (aFilterType & FILTERING_BY_COMPONENT_KEYWORD) && aComponent
            && !aComponent->MatchesFootprintFilters( aList.GetItem( ii ).GetFootprintName() ) )
            continue;

        if( (aFilterType & FILTERING_BY_PIN_COUNT) && aComponent
            && aComponent->GetNetCount() != aList.GetItem( ii ).GetUniquePadCount() )
            continue;

        // We can search (Using case insensitive search) in full FPID or only
        // in the fp name itself.
        // After tests, only in the fp name itself looks better.
        // However, the code to take in account the nickname is just commented, no removed.
        wxString currname = //aList.GetItem( ii ).GetNickname().Lower() + ":" +
                            aList.GetItem( ii ).GetFootprintName().Lower();

        if( (aFilterType & FILTERING_BY_NAME) && !aFootPrintFilterPattern.IsEmpty()
            && patternFilter.Find( currname ) == EDA_PATTERN_NOT_FOUND )
        {
            continue;
        }

        msg.Printf( wxT( "%3d %s:%s" ), int( newList.GetCount() + 1 ),
                    GetChars( aList.GetItem( ii ).GetNickname() ),
                    GetChars( aList.GetItem( ii ).GetFootprintName() ) );
        newList.Add( msg );
    }

    if( newList == m_footprintList )
        return;

    m_footprintList = newList;

    int selection = m_footprintList.Index( oldSelection );

    if( selection == wxNOT_FOUND )
        selection = 0;

    DeleteAllItems();

    if( m_footprintList.GetCount() )
    {
        SetItemCount( m_footprintList.GetCount() );
        SetSelection( selection, true );
        RefreshItems( 0L, m_footprintList.GetCount()-1 );
        UpdateWidth();
    }
}