#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"
- (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 )
[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
- (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 )
{
- (void) setFieldEditor:(wxNSTextFieldEditor*) editor
{
- fieldEditor = editor;
+ if ( editor != fieldEditor )
+ {
+ [editor retain];
+ [fieldEditor release];
+ fieldEditor = editor;
+ }
}
- (wxNSTextFieldEditor*) fieldEditor
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;
}
void wxNSTextFieldControl::Init(WXWidget w)
{
- NSTextField wxOSX_10_6_AND_LATER(<NSTextFieldDelegate>) *tf = (NSTextField*) w;
+ NSTextField wxOSX_10_6_AND_LATER(<NSTextFieldDelegate>) *tf = (NSTextField wxOSX_10_6_AND_LATER(<NSTextFieldDelegate>)*) w;
m_textField = tf;
[m_textField setDelegate: tf];
m_selStart = m_selEnd = 0;