Add support for dynamic auto-completion in wxTextEntry.
Add wxTextCompleter class which allows to return the possible completions dynamically and wxTextCompleter::AutoComplete() overload using it. So far this is only implemented for wxMSW. Also fix calling wxTextEntry::AutoComplete(wxArrayString) multiple times under MSW, this didn't correctly update the list of shown completions before. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@67511 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
parent
6b30ffedb1
commit
ea98f11c2f
@ -3929,6 +3929,7 @@ COND_USE_GUI_1_ALL_GUI_HEADERS = \
|
|||||||
wx/statbox.h \
|
wx/statbox.h \
|
||||||
wx/stattext.h \
|
wx/stattext.h \
|
||||||
wx/statusbr.h \
|
wx/statusbr.h \
|
||||||
|
wx/textcompleter.h \
|
||||||
wx/textctrl.h \
|
wx/textctrl.h \
|
||||||
wx/textdlg.h \
|
wx/textdlg.h \
|
||||||
wx/textentry.h \
|
wx/textentry.h \
|
||||||
|
@ -905,6 +905,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file!
|
|||||||
wx/statbox.h
|
wx/statbox.h
|
||||||
wx/stattext.h
|
wx/stattext.h
|
||||||
wx/statusbr.h
|
wx/statusbr.h
|
||||||
|
wx/textcompleter.h
|
||||||
wx/textctrl.h
|
wx/textctrl.h
|
||||||
wx/textdlg.h
|
wx/textdlg.h
|
||||||
wx/textentry.h
|
wx/textentry.h
|
||||||
|
@ -6741,6 +6741,10 @@ SOURCE=..\..\include\wx\tbarbase.h
|
|||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\..\include\wx\textcompleter.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=..\..\include\wx\textctrl.h
|
SOURCE=..\..\include\wx\textctrl.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
@ -5643,6 +5643,9 @@
|
|||||||
RelativePath="..\..\include\wx\tbarbase.h">
|
RelativePath="..\..\include\wx\tbarbase.h">
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
|
RelativePath="..\..\include\wx\textcompleter.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
RelativePath="..\..\include\wx\textctrl.h">
|
RelativePath="..\..\include\wx\textctrl.h">
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
|
@ -7544,6 +7544,10 @@
|
|||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
|
RelativePath="..\..\include\wx\textcompleter.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
RelativePath="..\..\include\wx\textctrl.h"
|
RelativePath="..\..\include\wx\textctrl.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
@ -7540,6 +7540,10 @@
|
|||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
|
RelativePath="..\..\include\wx\textcompleter.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
RelativePath="..\..\include\wx\textctrl.h"
|
RelativePath="..\..\include\wx\textctrl.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
@ -466,6 +466,7 @@ All (GUI):
|
|||||||
- Added wxRichMessageDialog (Rickard Westerlund, GSoC 2010 project).
|
- Added wxRichMessageDialog (Rickard Westerlund, GSoC 2010 project).
|
||||||
- Added wxCommandLinkButton (Rickard Westerlund, GSoC 2010 project).
|
- Added wxCommandLinkButton (Rickard Westerlund, GSoC 2010 project).
|
||||||
- Added wxUIActionSimulator (Steven Lamerton, GSoC 2010 project).
|
- Added wxUIActionSimulator (Steven Lamerton, GSoC 2010 project).
|
||||||
|
- Added support for dynamic auto-completion in wxTextEntry.
|
||||||
- wxAUI: support auto-orientable toolbars (wsu).
|
- wxAUI: support auto-orientable toolbars (wsu).
|
||||||
- wxAUI: add support for icons in pane title bars (triton).
|
- wxAUI: add support for icons in pane title bars (triton).
|
||||||
- Added wxPanel::SetBackgroundBitmap().
|
- Added wxPanel::SetBackgroundBitmap().
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
#ifndef _WX_MSW_TEXTENTRY_H_
|
#ifndef _WX_MSW_TEXTENTRY_H_
|
||||||
#define _WX_MSW_TEXTENTRY_H_
|
#define _WX_MSW_TEXTENTRY_H_
|
||||||
|
|
||||||
|
class wxTextAutoCompleteData; // private class used only by wxTextEntry itself
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// wxTextEntry: common part of wxComboBox and (single line) wxTextCtrl
|
// wxTextEntry: common part of wxComboBox and (single line) wxTextCtrl
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@ -18,12 +20,8 @@
|
|||||||
class WXDLLIMPEXP_CORE wxTextEntry : public wxTextEntryBase
|
class WXDLLIMPEXP_CORE wxTextEntry : public wxTextEntryBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
wxTextEntry()
|
wxTextEntry();
|
||||||
{
|
virtual ~wxTextEntry();
|
||||||
#if wxUSE_OLE
|
|
||||||
m_enumStrings = NULL;
|
|
||||||
#endif // wxUSE_OLE
|
|
||||||
}
|
|
||||||
|
|
||||||
// implement wxTextEntryBase pure virtual methods
|
// implement wxTextEntryBase pure virtual methods
|
||||||
virtual void WriteText(const wxString& text);
|
virtual void WriteText(const wxString& text);
|
||||||
@ -78,6 +76,7 @@ protected:
|
|||||||
#if wxUSE_OLE
|
#if wxUSE_OLE
|
||||||
virtual bool DoAutoCompleteStrings(const wxArrayString& choices);
|
virtual bool DoAutoCompleteStrings(const wxArrayString& choices);
|
||||||
virtual bool DoAutoCompleteFileNames();
|
virtual bool DoAutoCompleteFileNames();
|
||||||
|
virtual bool DoAutoCompleteCustom(wxTextCompleter *completer);
|
||||||
#endif // wxUSE_OLE
|
#endif // wxUSE_OLE
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -85,8 +84,16 @@ private:
|
|||||||
virtual WXHWND GetEditHWND() const = 0;
|
virtual WXHWND GetEditHWND() const = 0;
|
||||||
|
|
||||||
#if wxUSE_OLE
|
#if wxUSE_OLE
|
||||||
// enumerator for strings currently used for auto-completion or NULL
|
// Get the auto-complete object creating it if necessary. Returns NULL if
|
||||||
class wxIEnumString *m_enumStrings;
|
// creating it failed.
|
||||||
|
wxTextAutoCompleteData *GetOrCreateCompleter();
|
||||||
|
|
||||||
|
// Various auto-completion-related stuff, only used if any of AutoComplete()
|
||||||
|
// methods are called. Use the function above to access it.
|
||||||
|
wxTextAutoCompleteData *m_autoCompleteData;
|
||||||
|
|
||||||
|
// It needs to call our GetEditableWindow() and GetEditHWND() methods.
|
||||||
|
friend class wxTextAutoCompleteData;
|
||||||
#endif // wxUSE_OLE
|
#endif // wxUSE_OLE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
31
include/wx/textcompleter.h
Normal file
31
include/wx/textcompleter.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Name: wx/textcompleter.h
|
||||||
|
// Purpose: Declaration of wxTextCompleter class.
|
||||||
|
// Author: Vadim Zeitlin
|
||||||
|
// Created: 2011-04-13
|
||||||
|
// RCS-ID: $Id: wxhead.h,v 1.12 2010-04-22 12:44:51 zeitlin Exp $
|
||||||
|
// Copyright: (c) 2011 Vadim Zeitlin <vadim@wxwidgets.org>
|
||||||
|
// Licence: wxWindows licence
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef _WX_TEXTCOMPLETER_H_
|
||||||
|
#define _WX_TEXTCOMPLETER_H_
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// wxTextCompleter: used by wxTextEnter::AutoComplete()
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class WXDLLIMPEXP_CORE wxTextCompleter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
wxTextCompleter() { }
|
||||||
|
|
||||||
|
virtual void GetCompletions(const wxString& prefix, wxArrayString& res) = 0;
|
||||||
|
|
||||||
|
virtual ~wxTextCompleter();
|
||||||
|
|
||||||
|
private:
|
||||||
|
wxDECLARE_NO_COPY_CLASS(wxTextCompleter);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _WX_TEXTCOMPLETER_H_
|
@ -16,6 +16,7 @@
|
|||||||
typedef long wxTextPos;
|
typedef long wxTextPos;
|
||||||
|
|
||||||
class WXDLLIMPEXP_FWD_BASE wxArrayString;
|
class WXDLLIMPEXP_FWD_BASE wxArrayString;
|
||||||
|
class WXDLLIMPEXP_FWD_CORE wxTextCompleter;
|
||||||
class WXDLLIMPEXP_FWD_CORE wxTextEntryHintData;
|
class WXDLLIMPEXP_FWD_CORE wxTextEntryHintData;
|
||||||
class WXDLLIMPEXP_FWD_CORE wxWindow;
|
class WXDLLIMPEXP_FWD_CORE wxWindow;
|
||||||
|
|
||||||
@ -106,7 +107,7 @@ public:
|
|||||||
|
|
||||||
// these functions allow to auto-complete the text already entered into the
|
// these functions allow to auto-complete the text already entered into the
|
||||||
// control using either the given fixed list of strings, the paths from the
|
// control using either the given fixed list of strings, the paths from the
|
||||||
// file system or, in the future, an arbitrary user-defined completer
|
// file system or an arbitrary user-defined completer
|
||||||
//
|
//
|
||||||
// they all return true if completion was enabled or false on error (most
|
// they all return true if completion was enabled or false on error (most
|
||||||
// commonly meaning that this functionality is not available under the
|
// commonly meaning that this functionality is not available under the
|
||||||
@ -118,6 +119,12 @@ public:
|
|||||||
bool AutoCompleteFileNames()
|
bool AutoCompleteFileNames()
|
||||||
{ return DoAutoCompleteFileNames(); }
|
{ return DoAutoCompleteFileNames(); }
|
||||||
|
|
||||||
|
// notice that we take ownership of the pointer and will delete it
|
||||||
|
//
|
||||||
|
// if the pointer is NULL auto-completion is disabled
|
||||||
|
bool AutoComplete(wxTextCompleter *completer)
|
||||||
|
{ return DoAutoCompleteCustom(completer); }
|
||||||
|
|
||||||
|
|
||||||
// status
|
// status
|
||||||
// ------
|
// ------
|
||||||
@ -224,6 +231,7 @@ protected:
|
|||||||
virtual bool DoAutoCompleteStrings(const wxArrayString& WXUNUSED(choices))
|
virtual bool DoAutoCompleteStrings(const wxArrayString& WXUNUSED(choices))
|
||||||
{ return false; }
|
{ return false; }
|
||||||
virtual bool DoAutoCompleteFileNames() { return false; }
|
virtual bool DoAutoCompleteFileNames() { return false; }
|
||||||
|
virtual bool DoAutoCompleteCustom(wxTextCompleter *completer);
|
||||||
|
|
||||||
|
|
||||||
// class which should be used to temporarily disable text change events
|
// class which should be used to temporarily disable text change events
|
||||||
|
85
interface/wx/textcompleter.h
Normal file
85
interface/wx/textcompleter.h
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Name: wx/textcompleter.h
|
||||||
|
// Purpose: interface of wxTextCompleter
|
||||||
|
// Author: Vadim Zeitlin
|
||||||
|
// Created: 2011-04-13
|
||||||
|
// RCS-ID: $Id$
|
||||||
|
// Copyright: (c) 2011 Vadim Zeitlin <vadim@wxwindows.org>
|
||||||
|
// Licence: wxWindows licence
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
@class wxTextCompleter
|
||||||
|
|
||||||
|
Base class for custom text completer objects.
|
||||||
|
|
||||||
|
Custom completer objects used with wxTextEntry::AutoComplete() must derive
|
||||||
|
from this class and implement its pure virtual method returning the
|
||||||
|
completions. You would typically use a custom completer when the total
|
||||||
|
number of completions is too big for performance to be acceptable if all of
|
||||||
|
them need to be returned at once but if they can be generated
|
||||||
|
hierarchically, i.e. only the first component initially, then the second
|
||||||
|
one after the user finished entering the first one and so on.
|
||||||
|
|
||||||
|
Here is a simple example of a custom completer that completes the names of
|
||||||
|
some chess pieces. Of course, as the total list here has only four items it
|
||||||
|
would have been much simpler to just specify the array containing all the
|
||||||
|
completions in this example but the same approach could be used when the
|
||||||
|
total number of completions is much higher provided the number of
|
||||||
|
possibilities for each word is still relatively small:
|
||||||
|
@code
|
||||||
|
class MyTextCompleter : public wxTextCompleter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void GetCompletions(const wxString& prefix, wxArrayString& res)
|
||||||
|
{
|
||||||
|
const wxString firstWord = prefix.BeforeFirst(' ');
|
||||||
|
if ( firstWord == "white" )
|
||||||
|
{
|
||||||
|
res.push_back("white pawn");
|
||||||
|
res.push_back("white rook");
|
||||||
|
}
|
||||||
|
else if ( firstWord == "black" )
|
||||||
|
{
|
||||||
|
res.push_back("black king");
|
||||||
|
res.push_back("black queen");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res.push_back("white");
|
||||||
|
res.push_back("black");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
...
|
||||||
|
wxTextCtrl *text = ...;
|
||||||
|
text->AutoComplete(new MyTextCompleter);
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@library{wxcore}
|
||||||
|
|
||||||
|
@since 2.9.2
|
||||||
|
*/
|
||||||
|
class wxTextCompleter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
Pure virtual method returning all possible completions for the given
|
||||||
|
prefix.
|
||||||
|
|
||||||
|
The custom completer should examine the provided prefix and return all
|
||||||
|
the possible completions for it in the output array @a res.
|
||||||
|
|
||||||
|
Please notice that the returned values should start with the prefix,
|
||||||
|
otherwise they will be simply ignored, making adding them to the array
|
||||||
|
in the first place useless.
|
||||||
|
|
||||||
|
@param prefix
|
||||||
|
The possibly empty prefix that the user had already entered.
|
||||||
|
@param res
|
||||||
|
Initially empty array that should be filled with all possible
|
||||||
|
completions (possibly none if there are no valid possibilities
|
||||||
|
starting with the given prefix).
|
||||||
|
*/
|
||||||
|
virtual void GetCompletions(const wxString& prefix, wxArrayString& res) = 0;
|
||||||
|
};
|
@ -60,6 +60,40 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool AutoComplete(const wxArrayString& choices);
|
bool AutoComplete(const wxArrayString& choices);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Enable auto-completion using the provided completer object.
|
||||||
|
|
||||||
|
This method should be used instead of AutoComplete() overload taking
|
||||||
|
the array of possible completions if the total number of strings is too
|
||||||
|
big as it allows to return the completions dynamically, depending on
|
||||||
|
the text already entered by user and so is more efficient.
|
||||||
|
|
||||||
|
The specified @a completer object will be used to retrieve the list of
|
||||||
|
possible completions for the already entered text and will be deleted
|
||||||
|
by wxTextEntry itself when it's not needed any longer.
|
||||||
|
|
||||||
|
Notice that you need to include @c wx/textcompleter.h in order to
|
||||||
|
define your class inheriting from wxTextCompleter.
|
||||||
|
|
||||||
|
Currently this method is only implemented in wxMSW port.
|
||||||
|
|
||||||
|
@since 2.9.2
|
||||||
|
|
||||||
|
@param completer
|
||||||
|
The object to be used for generating completions if non-@NULL. If
|
||||||
|
it is @NULL, auto-completion is disabled. The wxTextEntry object
|
||||||
|
takes ownership of this pointer and will delete it in any case
|
||||||
|
(i.e. even if this method returns @false).
|
||||||
|
|
||||||
|
@return
|
||||||
|
@true if the auto-completion was enabled or @false if the operation
|
||||||
|
failed, typically because auto-completion is not supported by the
|
||||||
|
current platform.
|
||||||
|
|
||||||
|
@see wxTextCompleter
|
||||||
|
*/
|
||||||
|
bool AutoComplete(wxTextCompleter *completer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Call this function to enable auto-completion of the text typed in a
|
Call this function to enable auto-completion of the text typed in a
|
||||||
single-line text control using all valid file system paths.
|
single-line text control using all valid file system paths.
|
||||||
|
@ -50,6 +50,7 @@
|
|||||||
#include "wx/textdlg.h"
|
#include "wx/textdlg.h"
|
||||||
#include "wx/imaglist.h"
|
#include "wx/imaglist.h"
|
||||||
#include "wx/wupdlock.h"
|
#include "wx/wupdlock.h"
|
||||||
|
#include "wx/textcompleter.h"
|
||||||
|
|
||||||
#include "wx/persist/toplevel.h"
|
#include "wx/persist/toplevel.h"
|
||||||
#include "wx/persist/treebook.h"
|
#include "wx/persist/treebook.h"
|
||||||
@ -98,6 +99,7 @@ enum
|
|||||||
TextEntry_DisableAutoComplete = TextEntry_Begin,
|
TextEntry_DisableAutoComplete = TextEntry_Begin,
|
||||||
TextEntry_AutoCompleteFixed,
|
TextEntry_AutoCompleteFixed,
|
||||||
TextEntry_AutoCompleteFilenames,
|
TextEntry_AutoCompleteFilenames,
|
||||||
|
TextEntry_AutoCompleteCustom,
|
||||||
|
|
||||||
TextEntry_SetHint,
|
TextEntry_SetHint,
|
||||||
TextEntry_End
|
TextEntry_End
|
||||||
@ -172,6 +174,7 @@ protected:
|
|||||||
void OnDisableAutoComplete(wxCommandEvent& event);
|
void OnDisableAutoComplete(wxCommandEvent& event);
|
||||||
void OnAutoCompleteFixed(wxCommandEvent& event);
|
void OnAutoCompleteFixed(wxCommandEvent& event);
|
||||||
void OnAutoCompleteFilenames(wxCommandEvent& event);
|
void OnAutoCompleteFilenames(wxCommandEvent& event);
|
||||||
|
void OnAutoCompleteCustom(wxCommandEvent& event);
|
||||||
|
|
||||||
void OnSetHint(wxCommandEvent& event);
|
void OnSetHint(wxCommandEvent& event);
|
||||||
|
|
||||||
@ -300,6 +303,7 @@ BEGIN_EVENT_TABLE(WidgetsFrame, wxFrame)
|
|||||||
EVT_MENU(TextEntry_DisableAutoComplete, WidgetsFrame::OnDisableAutoComplete)
|
EVT_MENU(TextEntry_DisableAutoComplete, WidgetsFrame::OnDisableAutoComplete)
|
||||||
EVT_MENU(TextEntry_AutoCompleteFixed, WidgetsFrame::OnAutoCompleteFixed)
|
EVT_MENU(TextEntry_AutoCompleteFixed, WidgetsFrame::OnAutoCompleteFixed)
|
||||||
EVT_MENU(TextEntry_AutoCompleteFilenames, WidgetsFrame::OnAutoCompleteFilenames)
|
EVT_MENU(TextEntry_AutoCompleteFilenames, WidgetsFrame::OnAutoCompleteFilenames)
|
||||||
|
EVT_MENU(TextEntry_AutoCompleteCustom, WidgetsFrame::OnAutoCompleteCustom)
|
||||||
|
|
||||||
EVT_MENU(TextEntry_SetHint, WidgetsFrame::OnSetHint)
|
EVT_MENU(TextEntry_SetHint, WidgetsFrame::OnSetHint)
|
||||||
|
|
||||||
@ -414,6 +418,8 @@ WidgetsFrame::WidgetsFrame(const wxString& title)
|
|||||||
wxT("Fixed-&list auto-completion"));
|
wxT("Fixed-&list auto-completion"));
|
||||||
menuTextEntry->AppendRadioItem(TextEntry_AutoCompleteFilenames,
|
menuTextEntry->AppendRadioItem(TextEntry_AutoCompleteFilenames,
|
||||||
wxT("&Files names auto-completion"));
|
wxT("&Files names auto-completion"));
|
||||||
|
menuTextEntry->AppendRadioItem(TextEntry_AutoCompleteCustom,
|
||||||
|
wxT("&Custom auto-completion"));
|
||||||
menuTextEntry->AppendSeparator();
|
menuTextEntry->AppendSeparator();
|
||||||
menuTextEntry->Append(TextEntry_SetHint, "Set help &hint");
|
menuTextEntry->Append(TextEntry_SetHint, "Set help &hint");
|
||||||
|
|
||||||
@ -981,7 +987,7 @@ void WidgetsFrame::OnAutoCompleteFilenames(wxCommandEvent& WXUNUSED(event))
|
|||||||
|
|
||||||
if ( entry->AutoCompleteFileNames() )
|
if ( entry->AutoCompleteFileNames() )
|
||||||
{
|
{
|
||||||
wxLogMessage("Enable auto completion of file names.");
|
wxLogMessage("Enabled auto completion of file names.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -989,6 +995,112 @@ void WidgetsFrame::OnAutoCompleteFilenames(wxCommandEvent& WXUNUSED(event))
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WidgetsFrame::OnAutoCompleteCustom(wxCommandEvent& WXUNUSED(event))
|
||||||
|
{
|
||||||
|
wxTextEntryBase *entry = CurrentPage()->GetTextEntry();
|
||||||
|
wxCHECK_RET( entry, "menu item should be disabled" );
|
||||||
|
|
||||||
|
// This is a simple (and hence rather useless) example of a custom
|
||||||
|
// completer class that completes the first word (only) initially and only
|
||||||
|
// build the list of the possible second words once the first word is
|
||||||
|
// known. This allows to avoid building the full 676000 item list of
|
||||||
|
// possible strings all at once as the we have 1000 possibilities for the
|
||||||
|
// first word (000..999) and 676 (aa..zz) for the second one.
|
||||||
|
class CustomTextCompleter : public wxTextCompleter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void GetCompletions(const wxString& prefix, wxArrayString& res)
|
||||||
|
{
|
||||||
|
// This is used for illustrative purposes only and shows how many
|
||||||
|
// completions we return every time when we're called.
|
||||||
|
class LogCompletions
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LogCompletions(const wxString& prefix, const wxArrayString& res)
|
||||||
|
: m_prefix(prefix),
|
||||||
|
m_res(res)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~LogCompletions()
|
||||||
|
{
|
||||||
|
wxLogMessage("Returning %lu possible completions for "
|
||||||
|
"prefix \"%s\"",
|
||||||
|
m_res.size(), m_prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const wxString& m_prefix;
|
||||||
|
const wxArrayString& m_res;
|
||||||
|
} logCompletions(prefix, res);
|
||||||
|
|
||||||
|
|
||||||
|
// Normally it doesn't make sense to complete empty control, there
|
||||||
|
// are too many choices and listing them all wouldn't be helpful.
|
||||||
|
if ( prefix.empty() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// The only valid strings start with 3 digits so check for their
|
||||||
|
// presence proposing to complete the remaining ones.
|
||||||
|
if ( !wxIsdigit(prefix[0]) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( prefix.length() == 1 )
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < 10; i++ )
|
||||||
|
for ( int j = 0; j < 10; j++ )
|
||||||
|
res.push_back(wxString::Format("%s%02d",
|
||||||
|
prefix, 10*i + j));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if ( !wxIsdigit(prefix[1]) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( prefix.length() == 2 )
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < 10; i++ )
|
||||||
|
res.push_back(wxString::Format("%s%d", prefix, i));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if ( !wxIsdigit(prefix[2]) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Next we must have a space and two letters.
|
||||||
|
wxString prefix2(prefix);
|
||||||
|
if ( prefix.length() == 3 )
|
||||||
|
prefix2 += ' ';
|
||||||
|
else if ( prefix[3] != ' ' )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( prefix2.length() == 4 )
|
||||||
|
{
|
||||||
|
for ( char c = 'a'; c <= 'z'; c++ )
|
||||||
|
for ( char d = 'a'; d <= 'z'; d++ )
|
||||||
|
res.push_back(wxString::Format("%s%c%c", prefix2, c, d));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if ( !wxIslower(prefix[4]) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( prefix.length() == 5 )
|
||||||
|
{
|
||||||
|
for ( char c = 'a'; c <= 'z'; c++ )
|
||||||
|
res.push_back(prefix + c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if ( entry->AutoComplete(new CustomTextCompleter) )
|
||||||
|
{
|
||||||
|
wxLogMessage("Enabled custom auto completer for \"NNN XX\" items "
|
||||||
|
"(where N is a digit and X is a letter).");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wxLogMessage("AutoComplete() failed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void WidgetsFrame::OnSetHint(wxCommandEvent& WXUNUSED(event))
|
void WidgetsFrame::OnSetHint(wxCommandEvent& WXUNUSED(event))
|
||||||
{
|
{
|
||||||
wxTextEntryBase *entry = CurrentPage()->GetTextEntry();
|
wxTextEntryBase *entry = CurrentPage()->GetTextEntry();
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#endif //WX_PRECOMP
|
#endif //WX_PRECOMP
|
||||||
|
|
||||||
#include "wx/textentry.h"
|
#include "wx/textentry.h"
|
||||||
|
#include "wx/textcompleter.h"
|
||||||
#include "wx/clipbrd.h"
|
#include "wx/clipbrd.h"
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@ -368,4 +369,22 @@ bool wxTextEntryBase::SendTextUpdatedEvent(wxWindow *win)
|
|||||||
return win->HandleWindowEvent(event);
|
return win->HandleWindowEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// auto-completion stubs
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
wxTextCompleter::~wxTextCompleter()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wxTextEntryBase::DoAutoCompleteCustom(wxTextCompleter *completer)
|
||||||
|
{
|
||||||
|
// We don't do anything here but we still need to delete the completer for
|
||||||
|
// consistency with the ports that do implement this method and take
|
||||||
|
// ownership of the pointer.
|
||||||
|
delete completer;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // wxUSE_TEXTCTRL || wxUSE_COMBOBOX
|
#endif // wxUSE_TEXTCTRL || wxUSE_COMBOBOX
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#if wxUSE_TEXTCTRL || wxUSE_COMBOBOX
|
#if wxUSE_TEXTCTRL || wxUSE_COMBOBOX
|
||||||
|
|
||||||
#include "wx/textentry.h"
|
#include "wx/textentry.h"
|
||||||
|
#include "wx/textcompleter.h"
|
||||||
#include "wx/dynlib.h"
|
#include "wx/dynlib.h"
|
||||||
|
|
||||||
#include "wx/msw/private.h"
|
#include "wx/msw/private.h"
|
||||||
@ -54,6 +55,7 @@
|
|||||||
|
|
||||||
#include "wx/msw/ole/oleutils.h"
|
#include "wx/msw/ole/oleutils.h"
|
||||||
#include <shldisp.h>
|
#include <shldisp.h>
|
||||||
|
#include <shobjidl.h>
|
||||||
|
|
||||||
#if defined(__MINGW32__) || defined (__WATCOMC__) || defined(__CYGWIN__)
|
#if defined(__MINGW32__) || defined (__WATCOMC__) || defined(__CYGWIN__)
|
||||||
// needed for IID_IAutoComplete, IID_IAutoComplete2 and ACO_AUTOSUGGEST
|
// needed for IID_IAutoComplete, IID_IAutoComplete2 and ACO_AUTOSUGGEST
|
||||||
@ -74,15 +76,15 @@ DEFINE_GUID(CLSID_AutoComplete,
|
|||||||
class wxIEnumString : public IEnumString
|
class wxIEnumString : public IEnumString
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
wxIEnumString(const wxArrayString& strings) : m_strings(strings)
|
wxIEnumString()
|
||||||
{
|
{
|
||||||
m_index = 0;
|
m_index = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChangeStrings(const wxArrayString& strings)
|
wxIEnumString(const wxIEnumString& other)
|
||||||
|
: m_strings(other.m_strings),
|
||||||
|
m_index(other.m_index)
|
||||||
{
|
{
|
||||||
m_strings = strings;
|
|
||||||
Reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DECLARE_IUNKNOWN_METHODS;
|
DECLARE_IUNKNOWN_METHODS;
|
||||||
@ -145,8 +147,7 @@ public:
|
|||||||
if ( !ppEnum )
|
if ( !ppEnum )
|
||||||
return E_POINTER;
|
return E_POINTER;
|
||||||
|
|
||||||
wxIEnumString *e = new wxIEnumString(m_strings);
|
wxIEnumString *e = new wxIEnumString(*this);
|
||||||
e->m_index = m_index;
|
|
||||||
|
|
||||||
e->AddRef();
|
e->AddRef();
|
||||||
*ppEnum = e;
|
*ppEnum = e;
|
||||||
@ -165,7 +166,9 @@ private:
|
|||||||
wxArrayString m_strings;
|
wxArrayString m_strings;
|
||||||
unsigned m_index;
|
unsigned m_index;
|
||||||
|
|
||||||
wxDECLARE_NO_COPY_CLASS(wxIEnumString);
|
friend class wxTextAutoCompleteData;
|
||||||
|
|
||||||
|
wxDECLARE_NO_ASSIGN_CLASS(wxIEnumString);
|
||||||
};
|
};
|
||||||
|
|
||||||
BEGIN_IID_TABLE(wxIEnumString)
|
BEGIN_IID_TABLE(wxIEnumString)
|
||||||
@ -175,12 +178,244 @@ END_IID_TABLE;
|
|||||||
|
|
||||||
IMPLEMENT_IUNKNOWN_METHODS(wxIEnumString)
|
IMPLEMENT_IUNKNOWN_METHODS(wxIEnumString)
|
||||||
|
|
||||||
|
|
||||||
|
// This class gathers the auto-complete-related we use. It is allocated on
|
||||||
|
// demand by wxTextEntry when AutoComplete() is called.
|
||||||
|
class wxTextAutoCompleteData wxBIND_OR_CONNECT_HACK_ONLY_BASE_CLASS
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// The constructor associates us with the given text entry.
|
||||||
|
wxTextAutoCompleteData(wxTextEntry *entry)
|
||||||
|
: m_entry(entry),
|
||||||
|
m_win(entry->GetEditableWindow())
|
||||||
|
{
|
||||||
|
m_autoComplete = NULL;
|
||||||
|
m_autoCompleteDropDown = NULL;
|
||||||
|
m_enumStrings = NULL;
|
||||||
|
m_customCompleter = NULL;
|
||||||
|
|
||||||
|
m_connectedTextChangedEvent = false;
|
||||||
|
|
||||||
|
// Create an object exposing IAutoComplete interface which we'll later
|
||||||
|
// use to get IAutoComplete2 as the latter can't be created directly,
|
||||||
|
// apparently.
|
||||||
|
HRESULT hr = CoCreateInstance
|
||||||
|
(
|
||||||
|
CLSID_AutoComplete,
|
||||||
|
NULL,
|
||||||
|
CLSCTX_INPROC_SERVER,
|
||||||
|
IID_IAutoComplete,
|
||||||
|
reinterpret_cast<void **>(&m_autoComplete)
|
||||||
|
);
|
||||||
|
if ( FAILED(hr) )
|
||||||
|
{
|
||||||
|
wxLogApiError(wxT("CoCreateInstance(CLSID_AutoComplete)"), hr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a string enumerator and initialize the completer with it.
|
||||||
|
m_enumStrings = new wxIEnumString;
|
||||||
|
m_enumStrings->AddRef();
|
||||||
|
hr = m_autoComplete->Init(m_entry->GetEditHWND(), m_enumStrings,
|
||||||
|
NULL, NULL);
|
||||||
|
if ( FAILED(hr) )
|
||||||
|
{
|
||||||
|
wxLogApiError(wxT("IAutoComplete::Init"), hr);
|
||||||
|
|
||||||
|
m_enumStrings->Release();
|
||||||
|
m_enumStrings = NULL;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// As explained in DoRefresh(), we need to call IAutoCompleteDropDown::
|
||||||
|
// ResetEnumerator() if we want to be able to change the completions on
|
||||||
|
// the fly. In principle we could live without it, i.e. return true
|
||||||
|
// from IsOk() even if this QueryInterface() fails, but it doesn't look
|
||||||
|
// like this is ever going to have in practice anyhow as the shell-
|
||||||
|
// provided IAutoComplete always implements IAutoCompleteDropDown too.
|
||||||
|
hr = m_autoComplete->QueryInterface
|
||||||
|
(
|
||||||
|
IID_IAutoCompleteDropDown,
|
||||||
|
reinterpret_cast<void **>(&m_autoCompleteDropDown)
|
||||||
|
);
|
||||||
|
if ( FAILED(hr) )
|
||||||
|
{
|
||||||
|
wxLogApiError(wxT("IAutoComplete::QI(IAutoCompleteDropDown)"), hr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally set the completion options using IAutoComplete2.
|
||||||
|
IAutoComplete2 *pAutoComplete2 = NULL;
|
||||||
|
hr = m_autoComplete->QueryInterface
|
||||||
|
(
|
||||||
|
IID_IAutoComplete2,
|
||||||
|
reinterpret_cast<void **>(&pAutoComplete2)
|
||||||
|
);
|
||||||
|
if ( SUCCEEDED(hr) )
|
||||||
|
{
|
||||||
|
pAutoComplete2->SetOptions(ACO_AUTOSUGGEST |
|
||||||
|
ACO_UPDOWNKEYDROPSLIST);
|
||||||
|
pAutoComplete2->Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~wxTextAutoCompleteData()
|
||||||
|
{
|
||||||
|
delete m_customCompleter;
|
||||||
|
|
||||||
|
if ( m_enumStrings )
|
||||||
|
m_enumStrings->Release();
|
||||||
|
if ( m_autoCompleteDropDown )
|
||||||
|
m_autoCompleteDropDown->Release();
|
||||||
|
if ( m_autoComplete )
|
||||||
|
m_autoComplete->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must be called after creating this object to verify if initializing it
|
||||||
|
// succeeded.
|
||||||
|
bool IsOk() const
|
||||||
|
{
|
||||||
|
return m_autoComplete && m_autoCompleteDropDown && m_enumStrings;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChangeStrings(const wxArrayString& strings)
|
||||||
|
{
|
||||||
|
m_enumStrings->m_strings = strings;
|
||||||
|
|
||||||
|
DoRefresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Takes ownership of the pointer if it is non-NULL.
|
||||||
|
bool ChangeCustomCompleter(wxTextCompleter *completer)
|
||||||
|
{
|
||||||
|
delete m_customCompleter;
|
||||||
|
m_customCompleter = completer;
|
||||||
|
|
||||||
|
if ( m_customCompleter )
|
||||||
|
{
|
||||||
|
// 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 )
|
||||||
|
{
|
||||||
|
m_connectedTextChangedEvent = true;
|
||||||
|
|
||||||
|
wxBIND_OR_CONNECT_HACK(m_win, wxEVT_COMMAND_TEXT_UPDATED,
|
||||||
|
wxCommandEventHandler,
|
||||||
|
wxTextAutoCompleteData::OnTextChanged,
|
||||||
|
this);
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateStringsFromCustomCompleter();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisableCompletion()
|
||||||
|
{
|
||||||
|
// We currently simply reset the list of possible strings as this seems
|
||||||
|
// to effectively disable auto-completion just fine. We could (and
|
||||||
|
// probably should) use IAutoComplete::Enable(FALSE) for this too but
|
||||||
|
// then we'd need to call Enable(TRUE) to turn it on back again later.
|
||||||
|
|
||||||
|
m_enumStrings->m_strings.clear();
|
||||||
|
m_enumStrings->Reset();
|
||||||
|
|
||||||
|
ChangeCustomCompleter(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Must be called after changing wxIEnumString::m_strings to really make
|
||||||
|
// the changes stick.
|
||||||
|
void DoRefresh()
|
||||||
|
{
|
||||||
|
m_enumStrings->Reset();
|
||||||
|
|
||||||
|
// This is completely and utterly not documented and in fact the
|
||||||
|
// current MSDN seems to try to discourage us from using it by saying
|
||||||
|
// that "there is no reason to use this method unless the drop-down
|
||||||
|
// list is currently visible" but actually we absolutely must call it
|
||||||
|
// to force the auto-completer (and not just its drop-down!) to refresh
|
||||||
|
// the list of completions which could have changed now. Without this
|
||||||
|
// call the new choices returned by GetCompletions() that hadn't been
|
||||||
|
// returned by it before are simply silently ignored.
|
||||||
|
m_autoCompleteDropDown->ResetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the strings returned by our string enumerator to correspond to
|
||||||
|
// the currently valid choices according to the custom completer.
|
||||||
|
void UpdateStringsFromCustomCompleter()
|
||||||
|
{
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
DoRefresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnTextChanged(wxCommandEvent& event)
|
||||||
|
{
|
||||||
|
if ( m_customCompleter )
|
||||||
|
UpdateStringsFromCustomCompleter();
|
||||||
|
|
||||||
|
event.Skip();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// The text entry we're associated with.
|
||||||
|
wxTextEntry * const m_entry;
|
||||||
|
|
||||||
|
// The window of this text entry.
|
||||||
|
wxWindow * const m_win;
|
||||||
|
|
||||||
|
// The auto-completer object itself.
|
||||||
|
IAutoComplete *m_autoComplete;
|
||||||
|
|
||||||
|
// Its IAutoCompleteDropDown interface needed for ResetEnumerator() call.
|
||||||
|
IAutoCompleteDropDown *m_autoCompleteDropDown;
|
||||||
|
|
||||||
|
// Enumerator for strings currently used for auto-completion.
|
||||||
|
wxIEnumString *m_enumStrings;
|
||||||
|
|
||||||
|
// Custom completer or NULL if none.
|
||||||
|
wxTextCompleter *m_customCompleter;
|
||||||
|
|
||||||
|
// Initially false, set to true after connecting OnTextChanged() handler.
|
||||||
|
bool m_connectedTextChangedEvent;
|
||||||
|
|
||||||
|
|
||||||
|
wxDECLARE_NO_COPY_CLASS(wxTextAutoCompleteData);
|
||||||
|
};
|
||||||
|
|
||||||
#endif // HAS_AUTOCOMPLETE
|
#endif // HAS_AUTOCOMPLETE
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// wxTextEntry implementation
|
// wxTextEntry implementation
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// initialization and destruction
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
wxTextEntry::wxTextEntry()
|
||||||
|
{
|
||||||
|
#ifdef HAS_AUTOCOMPLETE
|
||||||
|
m_autoCompleteData = NULL;
|
||||||
|
#endif // HAS_AUTOCOMPLETE
|
||||||
|
}
|
||||||
|
|
||||||
|
wxTextEntry::~wxTextEntry()
|
||||||
|
{
|
||||||
|
#ifdef HAS_AUTOCOMPLETE
|
||||||
|
delete m_autoCompleteData;
|
||||||
|
#endif // HAS_AUTOCOMPLETE
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// operations on text
|
// operations on text
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@ -333,66 +568,65 @@ bool wxTextEntry::DoAutoCompleteFileNames()
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Disable the other kinds of completion now that we use the built-in file
|
||||||
|
// names completion.
|
||||||
|
if ( m_autoCompleteData )
|
||||||
|
m_autoCompleteData->DisableCompletion();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wxTextAutoCompleteData *wxTextEntry::GetOrCreateCompleter()
|
||||||
|
{
|
||||||
|
if ( !m_autoCompleteData )
|
||||||
|
{
|
||||||
|
wxTextAutoCompleteData * const ac = new wxTextAutoCompleteData(this);
|
||||||
|
if ( ac->IsOk() )
|
||||||
|
m_autoCompleteData = ac;
|
||||||
|
else
|
||||||
|
delete ac;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_autoCompleteData;
|
||||||
|
}
|
||||||
|
|
||||||
bool wxTextEntry::DoAutoCompleteStrings(const wxArrayString& choices)
|
bool wxTextEntry::DoAutoCompleteStrings(const wxArrayString& choices)
|
||||||
{
|
{
|
||||||
// if we had an old enumerator we must reuse it as IAutoComplete doesn't
|
wxTextAutoCompleteData * const ac = GetOrCreateCompleter();
|
||||||
// free it if we call Init() again (see #10968) -- and it's also simpler
|
if ( !ac )
|
||||||
if ( m_enumStrings )
|
|
||||||
{
|
|
||||||
m_enumStrings->ChangeStrings(choices);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create an object exposing IAutoComplete interface (don't go for
|
|
||||||
// IAutoComplete2 immediately as, presumably, it might be not available on
|
|
||||||
// older systems as otherwise why do we have both -- although in practice I
|
|
||||||
// don't know when can this happen)
|
|
||||||
IAutoComplete *pAutoComplete = NULL;
|
|
||||||
HRESULT hr = CoCreateInstance
|
|
||||||
(
|
|
||||||
CLSID_AutoComplete,
|
|
||||||
NULL,
|
|
||||||
CLSCTX_INPROC_SERVER,
|
|
||||||
IID_IAutoComplete,
|
|
||||||
reinterpret_cast<void **>(&pAutoComplete)
|
|
||||||
);
|
|
||||||
if ( FAILED(hr) )
|
|
||||||
{
|
|
||||||
wxLogApiError(wxT("CoCreateInstance(CLSID_AutoComplete)"), hr);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
// associate it with our strings
|
ac->ChangeStrings(choices);
|
||||||
m_enumStrings = new wxIEnumString(choices);
|
|
||||||
m_enumStrings->AddRef();
|
return true;
|
||||||
hr = pAutoComplete->Init(GetEditHwnd(), m_enumStrings, NULL, NULL);
|
}
|
||||||
m_enumStrings->Release();
|
|
||||||
if ( FAILED(hr) )
|
bool wxTextEntry::DoAutoCompleteCustom(wxTextCompleter *completer)
|
||||||
|
{
|
||||||
|
// First deal with the case when we just want to disable auto-completion.
|
||||||
|
if ( !completer )
|
||||||
{
|
{
|
||||||
wxLogApiError(wxT("IAutoComplete::Init"), hr);
|
if ( m_autoCompleteData )
|
||||||
return false;
|
m_autoCompleteData->DisableCompletion();
|
||||||
|
//else: Nothing to do, we hadn't used auto-completion even before.
|
||||||
}
|
}
|
||||||
|
else // Have a valid completer.
|
||||||
// if IAutoComplete2 is available, set more user-friendly options
|
|
||||||
IAutoComplete2 *pAutoComplete2 = NULL;
|
|
||||||
hr = pAutoComplete->QueryInterface
|
|
||||||
(
|
|
||||||
IID_IAutoComplete2,
|
|
||||||
reinterpret_cast<void **>(&pAutoComplete2)
|
|
||||||
);
|
|
||||||
if ( SUCCEEDED(hr) )
|
|
||||||
{
|
{
|
||||||
pAutoComplete2->SetOptions(ACO_AUTOSUGGEST | ACO_UPDOWNKEYDROPSLIST);
|
wxTextAutoCompleteData * const ac = GetOrCreateCompleter();
|
||||||
pAutoComplete2->Release();
|
if ( !ac )
|
||||||
|
{
|
||||||
|
// Delete the custom completer for consistency with the case when
|
||||||
|
// we succeed to avoid memory leaks in user code.
|
||||||
|
delete completer;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This gives ownership of the custom completer to m_autoCompleteData.
|
||||||
|
if ( !ac->ChangeCustomCompleter(completer) )
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the docs are unclear about when can we release it but it seems safe to
|
|
||||||
// do it immediately, presumably the edit control itself keeps a reference
|
|
||||||
// to the auto completer object
|
|
||||||
pAutoComplete->Release();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user