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:
- Implement auto-completion support in wxTextEntry.
- Implement switching to default video mode in wxDisplay (soren).

View File

@@ -32,12 +32,8 @@ class WXDLLIMPEXP_CORE wxTextEntry: public wxTextEntryBase
{
public:
wxTextEntry()
: m_editable(true),
m_maxLength(0)
{ }
virtual ~wxTextEntry() {};
wxTextEntry();
virtual ~wxTextEntry();
virtual bool IsEditable() const;
@@ -88,10 +84,18 @@ public:
// --------------
virtual wxTextWidgetImpl * GetTextPeer() const;
wxTextCompleter *OSXGetCompleter() const { return m_completer; }
protected:
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;
// 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
single-line text control using the given @a choices.
Notice that currently this function is only implemented in wxGTK2 and
wxMSW ports and does nothing under the other platforms.
Notice that currently this function is only implemented in wxGTK2,
wxMSW and wxOSX/Cocoa ports and does nothing under the other platforms.
@since 2.9.0
@@ -75,7 +75,7 @@ public:
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.
Currently this method is only implemented in wxMSW and wxOSX/Cocoa.
@since 2.9.2

View File

@@ -45,6 +45,7 @@
#include "wx/filefn.h"
#include "wx/sysopt.h"
#include "wx/thread.h"
#include "wx/textcompleter.h"
#include "wx/osx/private.h"
#include "wx/osx/cocoa/private/textimpl.h"
@@ -293,21 +294,49 @@ protected :
forPartialWordRange:(NSRange)charRange indexOfSelectedItem:(int*)index
{
NSMutableArray* matches = NULL;
NSString* partialString;
partialString = [[textView string] substringWithRange:charRange];
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;
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:)];
// 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;
}

View File

@@ -45,9 +45,22 @@
#include "wx/filefn.h"
#include "wx/sysopt.h"
#include "wx/thread.h"
#include "wx/textcompleter.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
{
return GetTextPeer()->GetStringValue() ;
@@ -224,4 +237,23 @@ wxTextWidgetImpl * wxTextEntry::GetTextPeer() const
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