From c729f16fa54e8484d8600fcb423c0983d71abab2 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 17 Apr 2011 23:14:15 +0000 Subject: [PATCH] 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 --- docs/changes.txt | 1 + include/wx/osx/textentry.h | 16 +++++++---- interface/wx/textentry.h | 6 ++-- src/osx/cocoa/textctrl.mm | 59 ++++++++++++++++++++++++++++---------- src/osx/textentry_osx.cpp | 32 +++++++++++++++++++++ 5 files changed, 90 insertions(+), 24 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 7fb9a23609..e742a78807 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -525,6 +525,7 @@ MSW: OSX: +- Implement auto-completion support in wxTextEntry. - Implement switching to default video mode in wxDisplay (soren). diff --git a/include/wx/osx/textentry.h b/include/wx/osx/textentry.h index bf4d6fbd3e..b51e97bbd5 100644 --- a/include/wx/osx/textentry.h +++ b/include/wx/osx/textentry.h @@ -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 diff --git a/interface/wx/textentry.h b/interface/wx/textentry.h index 565bbaf597..a5894931ba 100644 --- a/interface/wx/textentry.h +++ b/interface/wx/textentry.h @@ -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 diff --git a/src/osx/cocoa/textctrl.mm b/src/osx/cocoa/textctrl.mm index 364c3993b2..f8e4f22bf2 100644 --- a/src/osx/cocoa/textctrl.mm +++ b/src/osx/cocoa/textctrl.mm @@ -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,22 +294,50 @@ protected : forPartialWordRange:(NSRange)charRange indexOfSelectedItem:(int*)index { 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; } diff --git a/src/osx/textentry_osx.cpp b/src/osx/textentry_osx.cpp index 5f51fca1b7..8061d068e4 100644 --- a/src/osx/textentry_osx.cpp +++ b/src/osx/textentry_osx.cpp @@ -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(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 -- 2.45.2