bool WIDGET_HOTKEY_LIST::ResolveKeyConflicts( long aKey, const wxString& aSectionTag )
{
    EDA_HOTKEY* conflicting_key = NULL;
    EDA_HOTKEY_CONFIG* conflicting_section = NULL;

    CheckKeyConflicts( aKey, aSectionTag, &conflicting_key, &conflicting_section );

    if( conflicting_key != NULL )
    {
        wxString    info    = wxGetTranslation( conflicting_key->m_InfoMsg );
        wxString    msg     = wxString::Format(
                _( "<%s> is already assigned to \"%s\" in section \"%s\". Are you sure you want "
                   "to change its assignment?" ),
                KeyNameFromKeyCode( aKey ), GetChars( info ),
                *(conflicting_section->m_Title) );

        wxMessageDialog dlg( GetParent(), msg, _( "Confirm change" ), wxYES_NO | wxNO_DEFAULT );

        if( dlg.ShowModal() == wxID_YES )
        {
            conflicting_key->m_KeyCode = 0;
            UpdateFromClientData();
            return true;
        }
        else
        {
            return false;
        }
    }
    else
    {
        return true;
    }
}
bool WIDGET_HOTKEY_LIST::TransferDataToControl()
{
    Freeze();
    DeleteAllItems();
    m_hotkeys.clear();

    for( size_t sec_index = 0; sec_index < m_sections.size(); ++sec_index )
    {
        // LoadSection pushes into m_hotkeys
        LoadSection( m_sections[sec_index].m_section );
        wxASSERT( m_hotkeys.size() == sec_index + 1 );

        wxString section_tag = *( m_sections[sec_index].m_section->m_SectionTag );

        // Create parent tree item
        wxTreeListItem parent = AppendItem( GetRootItem(), m_sections[sec_index].m_name );

        HOTKEY_LIST& each_list = m_hotkeys[sec_index];
        HOTKEY_LIST::iterator hk_it;

        for( hk_it = each_list.begin(); hk_it != each_list.end(); ++hk_it )
        {
            wxTreeListItem item = AppendItem( parent, wxEmptyString );
            SetItemData( item, new WIDGET_HOTKEY_CLIENT_DATA( &*hk_it, section_tag ) );
        }

        Expand( parent );
    }

    UpdateFromClientData();
    Thaw();

    return true;
}
void WIDGET_HOTKEY_LIST::ResetItemToDefault( wxTreeListItem aItem )
{
    WIDGET_HOTKEY_CLIENT_DATA* hkdata = GetHKClientData( aItem );
    EDA_HOTKEY* hk = &hkdata->GetHotkey();
    hk->ResetKeyCodeToDefault();
    UpdateFromClientData();
}
void WIDGET_HOTKEY_LIST::ResetItem( wxTreeListItem aItem )
{
    WIDGET_HOTKEY_CLIENT_DATA* hkdata = GetHKClientData( aItem );
    EDA_HOTKEY* hk = &hkdata->GetHotkey();

    for( size_t sec_index = 0; sec_index < m_sections.size(); ++sec_index )
    {
        wxString& section_tag = *( m_sections[sec_index].m_section->m_SectionTag );

        if( section_tag != hkdata->GetSectionTag() )
            continue;

        HOTKEY_LIST& each_list = m_hotkeys[sec_index];
        HOTKEY_LIST::iterator hk_it;

        for( hk_it = each_list.begin(); hk_it != each_list.end(); ++hk_it )
        {
            if( hk_it->m_Idcommand == hk->m_Idcommand )
            {
                hk->m_KeyCode = hk_it->m_KeyCode;
                break;
            }
        }
    }

    UpdateFromClientData();
}
void WIDGET_HOTKEY_LIST::updateShownItems( const wxString& aFilterStr )
{
    Freeze();
    DeleteAllItems();

    HOTKEY_FILTER filter( aFilterStr );

    for( auto& section: m_hk_store.GetSections() )
    {
        // Create parent tree item
        wxTreeListItem parent = AppendItem( GetRootItem(), section.m_name );

        for( auto& hotkey: section.m_hotkeys )
        {
            if( filter.FilterMatches( hotkey.GetCurrentValue() ) )
            {
                wxTreeListItem item = AppendItem( parent, wxEmptyString );
                SetItemData( item, new WIDGET_HOTKEY_CLIENT_DATA( hotkey ) );
            }
        }

        Expand( parent );
    }

    UpdateFromClientData();
    Thaw();
}
void WIDGET_HOTKEY_LIST::ResetItemToDefault( wxTreeListItem aItem )
{
    WIDGET_HOTKEY_CLIENT_DATA* hkdata = getExpectedHkClientData( aItem );

    if( !hkdata )
        return;

    auto& changed_hk = hkdata->GetChangedHotkey();

    changeHotkey( changed_hk, changed_hk.GetCurrentValue().GetDefaultKeyCode() );
    UpdateFromClientData();
}
void WIDGET_HOTKEY_LIST::ResetItem( wxTreeListItem aItem )
{
    WIDGET_HOTKEY_CLIENT_DATA* hkdata = getExpectedHkClientData( aItem );

    if( !hkdata )
        return;

    auto& changed_hk = hkdata->GetChangedHotkey();
    const auto& orig_hk = changed_hk.GetOriginalValue();

    changeHotkey( changed_hk, orig_hk.m_KeyCode );
    UpdateFromClientData();
}
bool WIDGET_HOTKEY_LIST::TransferDefaultsToControl()
{
    Freeze();

    for( wxTreeListItem item = GetFirstItem(); item.IsOk(); item = GetNextItem( item ) )
    {
        WIDGET_HOTKEY_CLIENT_DATA* hkdata = GetHKClientData( item );
        if( hkdata == NULL)
            continue;

        hkdata->GetHotkey().ResetKeyCodeToDefault();
    }

    UpdateFromClientData();
    Thaw();

    return true;
}
void WIDGET_HOTKEY_LIST::ResetAllHotkeys( bool aResetToDefault )
{
    Freeze();

    // Reset all the hotkeys, not just the ones shown
    // Should not need to check conflicts, as the state we're about
    // to set to a should be consistent
    if( aResetToDefault )
    {
        m_hk_store.ResetAllHotkeysToDefault();
    }
    else
    {
        m_hk_store.ResetAllHotkeysToOriginal();
    }

    UpdateFromClientData();
    Thaw();
}
void WIDGET_HOTKEY_LIST::EditItem( wxTreeListItem aItem )
{
    WIDGET_HOTKEY_CLIENT_DATA* hkdata = getExpectedHkClientData( aItem );

    if( !hkdata )
        return;

    wxString    name = GetItemText( aItem, 0 );
    wxString    current_key = GetItemText( aItem, 1 );

    wxKeyEvent key_event = HK_PROMPT_DIALOG::PromptForKey( GetParent(), name, current_key );
    long key = MapKeypressToKeycode( key_event );

    if( key )
    {
        changeHotkey( hkdata->GetChangedHotkey(), key );
        UpdateFromClientData();
    }
}
void WIDGET_HOTKEY_LIST::EditItem( wxTreeListItem aItem )
{
    WIDGET_HOTKEY_CLIENT_DATA* hkdata = GetHKClientData( aItem );

    if( !hkdata )
    {
        // Activated item was not a hotkey row
        return;
    }

    wxString    name = GetItemText( aItem, 0 );
    wxString    current_key = GetItemText( aItem, 1 );

    wxKeyEvent key_event = HK_PROMPT_DIALOG::PromptForKey( GetParent(), name, current_key );
    long key = MapKeypressToKeycode( key_event );

    if( hkdata && key )
    {
        // See if this key code is handled in hotkeys names list
        bool exists;
        KeyNameFromKeyCode( key, &exists );

        if( exists && hkdata->GetHotkey().m_KeyCode != key )
        {
            wxString tag = hkdata->GetSectionTag();
            bool canUpdate = ResolveKeyConflicts( key, tag );

            if( canUpdate )
            {
                hkdata->GetHotkey().m_KeyCode = key;
            }
        }

        UpdateFromClientData();

        // Trigger a resize in case column widths have changed
        wxSizeEvent dummy_evt;
        OnSize( dummy_evt );
    }
}