X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/00ba1af984e6771a2cfd3da8c292e7031c21d242..59cb2555551e9f24481affe86ef8b1bcd519c14f:/src/osx/cocoa/textctrl.mm?ds=sidebyside diff --git a/src/osx/cocoa/textctrl.mm b/src/osx/cocoa/textctrl.mm index 364c3993b2..f22f8de86e 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" @@ -56,11 +57,18 @@ - (void)setSelectable:(BOOL)flag; @end +// An object of this class is created before the text is modified +// programmatically and destroyed as soon as this is done. It does several +// things, like ensuring that the control is editable to allow setting its text +// at all and eating any unwanted focus loss events from textDidEndEditing: +// which don't really correspond to focus change. class wxMacEditHelper { public : wxMacEditHelper( NSView* textView ) { + m_viewPreviouslyEdited = ms_viewCurrentlyEdited; + ms_viewCurrentlyEdited = m_textView = textView; m_formerEditable = YES; if ( textView ) @@ -78,14 +86,27 @@ public : [m_textView setEditable:m_formerEditable]; [m_textView setSelectable:m_formerSelectable]; } + + ms_viewCurrentlyEdited = m_viewPreviouslyEdited; } + // Returns the last view we were instantiated for or NULL. + static NSView *GetCurrentlyEditedView() { return ms_viewCurrentlyEdited; } + protected : BOOL m_formerEditable ; BOOL m_formerSelectable; NSView* m_textView; + + // The original value of ms_viewCurrentlyEdited when this object was + // created. + NSView* m_viewPreviouslyEdited; + + static NSView* ms_viewCurrentlyEdited; } ; +NSView* wxMacEditHelper::ms_viewCurrentlyEdited = nil; + @implementation wxNSSecureTextField + (void)initialize @@ -221,6 +242,15 @@ protected : - (void)textDidEndEditing:(NSNotification *)aNotification { wxUnusedVar(aNotification); + + if ( self == wxMacEditHelper::GetCurrentlyEditedView() ) + { + // This notification is generated as the result of calling our own + // wxTextCtrl method (e.g. WriteText()) and doesn't correspond to any + // real focus loss event so skip generating it. + return; + } + wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self ); if ( impl ) { @@ -257,7 +287,12 @@ protected : - (void) setFieldEditor:(wxNSTextFieldEditor*) editor { - fieldEditor = editor; + if ( editor != fieldEditor ) + { + [editor retain]; + [fieldEditor release]; + fieldEditor = editor; + } } - (wxNSTextFieldEditor*) fieldEditor @@ -293,22 +328,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; } @@ -601,7 +664,7 @@ wxNSTextFieldControl::wxNSTextFieldControl(wxWindow *wxPeer, void wxNSTextFieldControl::Init(WXWidget w) { - NSTextField wxOSX_10_6_AND_LATER() *tf = (NSTextField*) w; + NSTextField wxOSX_10_6_AND_LATER() *tf = (NSTextField wxOSX_10_6_AND_LATER()*) w; m_textField = tf; [m_textField setDelegate: tf]; m_selStart = m_selEnd = 0;