Implement auto-completion support for wxTextEntry in wxOSX/Cocoa.

Both completing a set of fixed strings and dynamic completion using a custom
completer are supported, although completing the file names remains MSW-only
for now.

Note that, unlike under MSW, auto-completion under Mac is not automatic and
has to be triggered manually by calling complete: method. This is done by
pressing F5 key by default. In the future we should call it automatically on a
timer event to make it more obviously discoverable.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@67526 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2011-04-17 23:14:15 +00:00
parent ed7dda9251
commit c729f16fa5
5 changed files with 90 additions and 24 deletions

View File

@@ -525,6 +525,7 @@ MSW:
OSX: OSX:
- Implement auto-completion support in wxTextEntry.
- Implement switching to default video mode in wxDisplay (soren). - Implement switching to default video mode in wxDisplay (soren).

View File

@@ -32,12 +32,8 @@ class WXDLLIMPEXP_CORE wxTextEntry: public wxTextEntryBase
{ {
public: public:
wxTextEntry() wxTextEntry();
: m_editable(true), virtual ~wxTextEntry();
m_maxLength(0)
{ }
virtual ~wxTextEntry() {};
virtual bool IsEditable() const; virtual bool IsEditable() const;
@@ -88,10 +84,18 @@ public:
// -------------- // --------------
virtual wxTextWidgetImpl * GetTextPeer() const; virtual wxTextWidgetImpl * GetTextPeer() const;
wxTextCompleter *OSXGetCompleter() const { return m_completer; }
protected: protected:
virtual wxString DoGetValue() const; virtual wxString DoGetValue() const;
virtual bool DoAutoCompleteStrings(const wxArrayString& choices);
virtual bool DoAutoCompleteCustom(wxTextCompleter *completer);
// The object providing auto-completions or NULL if none.
wxTextCompleter *m_completer;
bool m_editable; bool m_editable;
// need to make this public because of the current implementation via callbacks // need to make this public because of the current implementation via callbacks

View File

@@ -46,8 +46,8 @@ public:
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 the given @a choices. single-line text control using the given @a choices.
Notice that currently this function is only implemented in wxGTK2 and Notice that currently this function is only implemented in wxGTK2,
wxMSW ports and does nothing under the other platforms. wxMSW and wxOSX/Cocoa ports and does nothing under the other platforms.
@since 2.9.0 @since 2.9.0
@@ -75,7 +75,7 @@ public:
Notice that you need to include @c wx/textcompleter.h in order to Notice that you need to include @c wx/textcompleter.h in order to
define your class inheriting from wxTextCompleter. define your class inheriting from wxTextCompleter.
Currently this method is only implemented in wxMSW port. Currently this method is only implemented in wxMSW and wxOSX/Cocoa.
@since 2.9.2 @since 2.9.2

View File

@@ -45,6 +45,7 @@
#include "wx/filefn.h" #include "wx/filefn.h"
#include "wx/sysopt.h" #include "wx/sysopt.h"
#include "wx/thread.h" #include "wx/thread.h"
#include "wx/textcompleter.h"
#include "wx/osx/private.h" #include "wx/osx/private.h"
#include "wx/osx/cocoa/private/textimpl.h" #include "wx/osx/cocoa/private/textimpl.h"
@@ -293,22 +294,50 @@ protected :
forPartialWordRange:(NSRange)charRange indexOfSelectedItem:(int*)index forPartialWordRange:(NSRange)charRange indexOfSelectedItem:(int*)index
{ {
NSMutableArray* matches = NULL; NSMutableArray* matches = NULL;
NSString* partialString;
partialString = [[textView string] substringWithRange:charRange];
matches = [NSMutableArray array];
wxTextWidgetImpl* impl = (wxTextWidgetImpl* ) wxWidgetImpl::FindFromWXWidget( self );
wxArrayString completions;
// adapt to whatever strategy we have for getting the strings
// impl->GetTextEntry()->GetCompletions(wxCFStringRef::AsString(partialString), completions);
for (size_t i = 0; i < completions.GetCount(); ++i )
[matches addObject: wxCFStringRef(completions[i]).AsNSString()];
// [matches sortUsingSelector:@selector(compare:)]; wxTextWidgetImpl* impl = (wxNSTextFieldControl * ) wxWidgetImpl::FindFromWXWidget( self );
wxTextEntry * const entry = impl->GetTextEntry();
wxTextCompleter * const completer = entry->OSXGetCompleter();
if ( completer )
{
const wxString prefix = entry->GetValue();
if ( completer->Start(prefix) )
{
const wxString
wordStart = wxCFStringRef::AsString(
[[textView string] substringWithRange:charRange]
);
matches = [NSMutableArray array];
for ( ;; )
{
const wxString s = completer->GetNext();
if ( s.empty() )
break;
// Normally the completer should return only the strings
// starting with the prefix, but there could be exceptions
// and, for compatibility with MSW which simply ignores all
// entries that don't match the current text control contents,
// we ignore them as well. Besides, our own wxTextCompleterFixed
// doesn't respect this rule and, moreover, we need to extract
// just the rest of the string anyhow.
wxString completion;
if ( s.StartsWith(prefix, &completion) )
{
// We discarded the entire prefix above but actually we
// should include the part of it that consists of the
// beginning of the current word, otherwise it would be
// lost when completion is accepted as OS X supposes that
// our matches do start with the "partial word range"
// passed to us.
const wxCFStringRef fullWord(wordStart + completion);
[matches addObject: fullWord.AsNSString()];
}
}
}
}
return matches; return matches;
} }

View File

@@ -45,9 +45,22 @@
#include "wx/filefn.h" #include "wx/filefn.h"
#include "wx/sysopt.h" #include "wx/sysopt.h"
#include "wx/thread.h" #include "wx/thread.h"
#include "wx/textcompleter.h"
#include "wx/osx/private.h" #include "wx/osx/private.h"
wxTextEntry::wxTextEntry()
{
m_completer = NULL;
m_editable = true;
m_maxLength = 0;
}
wxTextEntry::~wxTextEntry()
{
delete m_completer;
}
wxString wxTextEntry::DoGetValue() const wxString wxTextEntry::DoGetValue() const
{ {
return GetTextPeer()->GetStringValue() ; return GetTextPeer()->GetStringValue() ;
@@ -224,4 +237,23 @@ wxTextWidgetImpl * wxTextEntry::GetTextPeer() const
return win ? dynamic_cast<wxTextWidgetImpl *>(win->GetPeer()) : NULL; return win ? dynamic_cast<wxTextWidgetImpl *>(win->GetPeer()) : NULL;
} }
// ----------------------------------------------------------------------------
// Auto-completion
// ----------------------------------------------------------------------------
bool wxTextEntry::DoAutoCompleteStrings(const wxArrayString& choices)
{
wxTextCompleterFixed * const completer = new wxTextCompleterFixed;
completer->SetCompletions(choices);
return DoAutoCompleteCustom(completer);
}
bool wxTextEntry::DoAutoCompleteCustom(wxTextCompleter *completer)
{
m_completer = completer;
return true;
}
#endif // wxUSE_TEXTCTRL #endif // wxUSE_TEXTCTRL