m_enumStrings = NULL;
m_customCompleter = NULL;
- m_connectedTextChangedEvent = false;
+ m_connectedCharEvent = false;
// Create an object exposing IAutoComplete interface which we'll later
// use to get IAutoComplete2 as the latter can't be created directly,
if ( SUCCEEDED(hr) )
{
pAutoComplete2->SetOptions(ACO_AUTOSUGGEST |
+ ACO_AUTOAPPEND |
ACO_UPDOWNKEYDROPSLIST);
pAutoComplete2->Release();
}
// We postpone connecting to this event until we really need to do
// it (however we don't disconnect from it when we don't need it
// any more because we don't have wxUNBIND_OR_DISCONNECT_HACK...).
- if ( !m_connectedTextChangedEvent )
+ if ( !m_connectedCharEvent )
{
- m_connectedTextChangedEvent = true;
-
- wxBIND_OR_CONNECT_HACK(m_win, wxEVT_COMMAND_TEXT_UPDATED,
- wxCommandEventHandler,
- wxTextAutoCompleteData::OnTextChanged,
+ m_connectedCharEvent = true;
+
+ // Use the special wxEVT_AFTER_CHAR and not the usual
+ // wxEVT_CHAR here because we need to have the updated value of
+ // the text control in this handler in order to provide
+ // completions for the correct prefix and unfortunately we
+ // don't have any way to let DefWindowProc() run from our
+ // wxEVT_CHAR handler (as we must also let the other handlers
+ // defined at wx level run first).
+ //
+ // Notice that we can't use wxEVT_COMMAND_TEXT_UPDATED here
+ // neither as, due to our use of ACO_AUTOAPPEND, we get
+ // EN_CHANGE notifications from the control every time
+ // IAutoComplete auto-appends something to it.
+ wxBIND_OR_CONNECT_HACK(m_win, wxEVT_AFTER_CHAR,
+ wxKeyEventHandler,
+ wxTextAutoCompleteData::OnAfterChar,
this);
}
// the currently valid choices according to the custom completer.
void UpdateStringsFromCustomCompleter()
{
+ // As we use ACO_AUTOAPPEND, the selected part of the text is usually
+ // the one appended by us so don't consider it as part of the
+ // user-entered prefix.
+ long from, to;
+ m_entry->GetSelection(&from, &to);
+
+ if ( to == from )
+ from = m_entry->GetLastPosition(); // Take all if no selection.
+
+ const wxString prefix = m_entry->GetRange(0, from);
+
// For efficiency we access m_strings directly instead of creating
// another wxArrayString, normally this should save us an unnecessary
// memory allocation on the subsequent calls.
m_enumStrings->m_strings.clear();
- m_customCompleter->GetCompletions(m_entry->GetValue(),
- m_enumStrings->m_strings);
+ m_customCompleter->GetCompletions(prefix, m_enumStrings->m_strings);
DoRefresh();
}
- void OnTextChanged(wxCommandEvent& event)
+ void OnAfterChar(wxKeyEvent& event)
{
- if ( m_customCompleter )
+ // Notice that we must not refresh the completions when the user
+ // presses Backspace as this would result in adding back the just
+ // erased character(s) because of ACO_AUTOAPPEND option we use.
+ if ( m_customCompleter && event.GetKeyCode() != WXK_BACK )
UpdateStringsFromCustomCompleter();
event.Skip();
wxTextCompleter *m_customCompleter;
// Initially false, set to true after connecting OnTextChanged() handler.
- bool m_connectedTextChangedEvent;
+ bool m_connectedCharEvent;
wxDECLARE_NO_COPY_CLASS(wxTextAutoCompleteData);