1///////////////////////////////////////////////////////////////////////////// 2// Name: src/osx/iphone/textctrl.mm 3// Purpose: wxTextCtrl 4// Author: Stefan Csomor 5// Modified by: Ryan Norton (MLTE GetLineLength and GetLineText) 6// Created: 1998-01-01 7// Copyright: (c) Stefan Csomor 8// Licence: wxWindows licence 9///////////////////////////////////////////////////////////////////////////// 10 11#include "wx/wxprec.h" 12 13#if wxUSE_TEXTCTRL 14 15#include "wx/textctrl.h" 16 17#ifndef WX_PRECOMP 18 #include "wx/intl.h" 19 #include "wx/app.h" 20 #include "wx/utils.h" 21 #include "wx/dc.h" 22 #include "wx/button.h" 23 #include "wx/menu.h" 24 #include "wx/settings.h" 25 #include "wx/msgdlg.h" 26 #include "wx/toplevel.h" 27#endif 28 29#ifdef __DARWIN__ 30 #include <sys/types.h> 31 #include <sys/stat.h> 32#else 33 #include <stat.h> 34#endif 35 36#if wxUSE_STD_IOSTREAM 37 #if wxUSE_IOSTREAMH 38 #include <fstream.h> 39 #else 40 #include <fstream> 41 #endif 42#endif 43 44#include "wx/filefn.h" 45#include "wx/sysopt.h" 46#include "wx/thread.h" 47 48#include "wx/osx/private.h" 49#include "wx/osx/iphone/private/textimpl.h" 50 51// currently for some reasong the UITextField leads to a recursion when the keyboard should be shown, so let's leave the code 52// in case this gets resolved... 53 54#define wxOSX_IPHONE_USE_TEXTFIELD 1 55 56class wxMacEditHelper 57{ 58public : 59 wxMacEditHelper( UITextView* textView ) 60 { 61 m_textView = textView; 62 m_formerState = YES; 63 if ( textView ) 64 { 65 m_formerState = [textView isEditable]; 66 [textView setEditable:YES]; 67 } 68 } 69 70 ~wxMacEditHelper() 71 { 72 if ( m_textView ) 73 [m_textView setEditable:m_formerState]; 74 } 75 76protected : 77 BOOL m_formerState ; 78 UITextView* m_textView; 79} ; 80 81#if wxOSX_IPHONE_USE_TEXTFIELD 82 83@interface wxUITextFieldDelegate : NSObject<UITextFieldDelegate> 84{ 85} 86 87@end 88 89 90@interface wxUITextField : UITextField 91{ 92} 93 94@end 95 96@interface wxNSSecureTextField : UITextField<UITextFieldDelegate> 97{ 98} 99 100@end 101 102@implementation wxNSSecureTextField 103 104+ (void)initialize 105{ 106 static BOOL initialized = NO; 107 if (!initialized) 108 { 109 initialized = YES; 110 wxOSXIPhoneClassAddWXMethods( self ); 111 } 112} 113 114- (void)controlTextDidChange:(NSNotification *)aNotification 115{ 116 wxUnusedVar(aNotification); 117 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( self ); 118 if ( impl ) 119 impl->controlTextDidChange(); 120} 121 122- (void)controlTextDidEndEditing:(NSNotification *)aNotification 123{ 124 wxUnusedVar(aNotification); 125 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( self ); 126 if ( impl ) 127 { 128 impl->DoNotifyFocusEvent( false, NULL ); 129 } 130} 131 132@end 133 134#if 0 135@implementation wxUITextFieldEditor 136 137- (void) keyDown:(NSEvent*) event 138{ 139 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( (WXWidget) [self delegate] ); 140 lastKeyDownEvent = event; 141 if ( impl == NULL || !impl->DoHandleKeyEvent(event) ) 142 [super keyDown:event]; 143 lastKeyDownEvent = nil; 144} 145 146- (void) keyUp:(NSEvent*) event 147{ 148 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( (WXWidget) [self delegate] ); 149 if ( impl == NULL || !impl->DoHandleKeyEvent(event) ) 150 [super keyUp:event]; 151} 152 153- (void) flagsChanged:(NSEvent*) event 154{ 155 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( (WXWidget) [self delegate] ); 156 if ( impl == NULL || !impl->DoHandleKeyEvent(event) ) 157 [super flagsChanged:event]; 158} 159 160- (BOOL) performKeyEquivalent:(NSEvent*) event 161{ 162 BOOL retval = [super performKeyEquivalent:event]; 163 return retval; 164} 165 166- (void) insertText:(id) str 167{ 168 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( (WXWidget) [self delegate] ); 169 if ( impl == NULL || lastKeyDownEvent==nil || !impl->DoHandleCharEvent(lastKeyDownEvent, str) ) 170 { 171 [super insertText:str]; 172 } 173} 174 175@end 176 177#endif 178 179 180@implementation wxUITextFieldDelegate 181 182- (BOOL)textFieldShouldReturn:(UITextField *)textField 183{ 184 // the user pressed the "Done" button, so dismiss the keyboard 185 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( textField ); 186 if ( impl ) 187 { 188 wxWindow* wxpeer = (wxWindow*) impl->GetWXPeer(); 189 if ( wxpeer && wxpeer->GetWindowStyle() & wxTE_PROCESS_ENTER ) 190 { 191 wxCommandEvent event(wxEVT_TEXT_ENTER, wxpeer->GetId()); 192 event.SetEventObject( wxpeer ); 193 event.SetString( static_cast<wxTextCtrl*>(wxpeer)->GetValue() ); 194 wxpeer->HandleWindowEvent( event ); 195 } 196 } 197 198 [textField resignFirstResponder]; 199 return YES; 200} 201 202/* 203- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField; // return NO to disallow editing. 204- (void)textFieldDidBeginEditing:(UITextField *)textField; // became first responder 205- (BOOL)textFieldShouldEndEditing:(UITextField *)textField; // return YES to allow editing to stop and to resign first responder status. NO to disallow the editing session to end 206- (void)textFieldDidEndEditing:(UITextField *)textField; // may be called if forced even if shouldEndEditing returns NO (e.g. view removed from window) or endEditing:YES called 207 208- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string; // return NO to not change text 209 210- (BOOL)textFieldShouldClear:(UITextField *)textField; // called when clear button pressed. return NO to ignore (no notifications) 211*/ 212 213@end 214 215 216@implementation wxUITextField 217 218+ (void)initialize 219{ 220 static BOOL initialized = NO; 221 if (!initialized) 222 { 223 initialized = YES; 224 wxOSXIPhoneClassAddWXMethods( self ); 225 } 226} 227 228#if 0 229- (void)controlTextDidChange:(NSNotification *)aNotification 230{ 231 wxUnusedVar(aNotification); 232 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( self ); 233 if ( impl ) 234 impl->controlTextDidChange(); 235} 236#endif 237 238- (BOOL)textFieldShouldReturn:(UITextField *)textField 239{ 240 wxUnusedVar(textField); 241 242 243 return NO; 244} 245 246- (void)controlTextDidEndEditing:(NSNotification *)aNotification 247{ 248 wxUnusedVar(aNotification); 249 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( self ); 250 if ( impl ) 251 { 252 impl->DoNotifyFocusEvent( false, NULL ); 253 } 254} 255@end 256 257#endif 258 259@interface wxUITextViewDelegate : NSObject<UITextViewDelegate> 260{ 261} 262 263- (void)textViewDidChange:(UITextView *)textView; 264- (void)textViewDidBeginEditing:(UITextView *)textView; 265- (void)textViewDidEndEditing:(UITextView *)textView; 266- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text; 267 268@end 269 270@implementation wxUITextViewDelegate 271 272- (void)textViewDidChange:(UITextView *)textView 273{ 274 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( textView ); 275 if ( impl ) 276 impl->controlTextDidChange(); 277} 278 279- (void)textViewDidBeginEditing:(UITextView *)textView 280{ 281 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( textView ); 282 if ( impl ) 283 impl->DoNotifyFocusEvent(true, NULL); 284} 285 286- (void)textViewDidEndEditing:(UITextView *)textView 287{ 288 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( textView ); 289 if ( impl ) 290 impl->DoNotifyFocusEvent(false, NULL); 291} 292 293- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text 294{ 295 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( textView ); 296 if ( impl ) 297 { 298 if ( !impl->GetWXPeer()->HasFlag(wxTE_MULTILINE) && [text isEqualToString:@"\n"]) 299 { 300 [textView resignFirstResponder]; 301 return NO; 302 } 303 } 304 return YES; 305} 306 307 308@end 309 310// 311// wxUITextViewControl 312// 313 314wxUITextViewControl::wxUITextViewControl( wxTextCtrl *wxPeer, UITextView* v) : 315 wxWidgetIPhoneImpl(wxPeer, v), 316 wxTextWidgetImpl(wxPeer) 317{ 318 m_textView = v; 319 m_delegate= [[wxUITextViewDelegate alloc] init]; 320 321 [m_textView setDelegate:m_delegate]; 322} 323 324wxUITextViewControl::~wxUITextViewControl() 325{ 326 if (m_textView) 327 { 328 [m_textView setDelegate: nil]; 329 } 330 [m_delegate release]; 331} 332 333bool wxUITextViewControl::CanFocus() const 334{ 335 return true; 336} 337 338wxString wxUITextViewControl::GetStringValue() const 339{ 340 if (m_textView) 341 { 342 wxString result = wxCFStringRef::AsString([m_textView text], m_wxPeer->GetFont().GetEncoding()); 343 wxMacConvertNewlines13To10( &result ) ; 344 return result; 345 } 346 return wxEmptyString; 347} 348 349void wxUITextViewControl::SetStringValue( const wxString &str) 350{ 351 wxString st = str; 352 wxMacConvertNewlines10To13( &st ); 353 wxMacEditHelper helper(m_textView); 354 355 if (m_textView) 356 [m_textView setText: wxCFStringRef( st , m_wxPeer->GetFont().GetEncoding() ).AsNSString()]; 357} 358 359void wxUITextViewControl::Copy() 360{ 361 if (m_textView) 362 [m_textView copy:nil]; 363 364} 365 366void wxUITextViewControl::Cut() 367{ 368 if (m_textView) 369 [m_textView cut:nil]; 370} 371 372void wxUITextViewControl::Paste() 373{ 374 if (m_textView) 375 [m_textView paste:nil]; 376} 377 378bool wxUITextViewControl::CanPaste() const 379{ 380 return true; 381} 382 383void wxUITextViewControl::SetEditable(bool editable) 384{ 385 if (m_textView) 386 [m_textView setEditable: editable]; 387} 388 389void wxUITextViewControl::GetSelection( long* from, long* to) const 390{ 391 if (m_textView) 392 { 393 NSRange range = [m_textView selectedRange]; 394 *from = range.location; 395 *to = range.location + range.length; 396 } 397} 398 399void wxUITextViewControl::SetSelection( long from , long to ) 400{ 401 long textLength = [[m_textView text] length]; 402 if ((from == -1) && (to == -1)) 403 { 404 from = 0 ; 405 to = textLength ; 406 } 407 else 408 { 409 from = wxMin(textLength,wxMax(from,0)) ; 410 if ( to == -1 ) 411 to = textLength; 412 else 413 to = wxMax(0,wxMin(textLength,to)) ; 414 } 415 416 NSRange selrange = NSMakeRange(from, to-from); 417 [m_textView setSelectedRange:selrange]; 418 [m_textView scrollRangeToVisible:selrange]; 419} 420 421void wxUITextViewControl::WriteText(const wxString& str) 422{ 423 wxString st = str; 424 wxMacConvertNewlines10To13( &st ); 425 wxMacEditHelper helper(m_textView); 426 427 wxCFStringRef insert( st , m_wxPeer->GetFont().GetEncoding() ); 428 NSMutableString* subst = [NSMutableString stringWithString:[m_textView text]]; 429 [subst replaceCharactersInRange:[m_textView selectedRange] withString:insert.AsNSString()]; 430 431 [m_textView setText:subst]; 432} 433 434void wxUITextViewControl::SetFont( const wxFont & font , const wxColour& WXUNUSED(foreground) , long WXUNUSED(windowStyle), bool WXUNUSED(ignoreBlack) ) 435{ 436 if ([m_textView respondsToSelector:@selector(setFont:)]) 437 [m_textView setFont: font.OSXGetUIFont()]; 438} 439 440bool wxUITextViewControl::GetStyle(long position, wxTextAttr& style) 441{ 442 if (m_textView && position >=0) 443 { 444 // UIFont* font = NULL; 445 // NSColor* bgcolor = NULL; 446 // NSColor* fgcolor = NULL; 447 // NOTE: It appears that other platforms accept GetStyle with the position == length 448 // but that UITextStorage does not accept length as a valid position. 449 // Therefore we return the default control style in that case. 450 /* 451 if (position < [[m_textView string] length]) 452 { 453 UITextStorage* storage = [m_textView textStorage]; 454 font = [[storage attribute:NSFontAttributeName atIndex:position effectiveRange:NULL] autorelease]; 455 bgcolor = [[storage attribute:NSBackgroundColorAttributeName atIndex:position effectiveRange:NULL] autorelease]; 456 fgcolor = [[storage attribute:NSForegroundColorAttributeName atIndex:position effectiveRange:NULL] autorelease]; 457 } 458 else 459 { 460 NSDictionary* attrs = [m_textView typingAttributes]; 461 font = [[attrs objectForKey:NSFontAttributeName] autorelease]; 462 bgcolor = [[attrs objectForKey:NSBackgroundColorAttributeName] autorelease]; 463 fgcolor = [[attrs objectForKey:NSForegroundColorAttributeName] autorelease]; 464 } 465 */ 466 /* 467 if (font) 468 style.SetFont(wxFont(font)); 469 470 if (bgcolor) 471 style.SetBackgroundColour(wxColour(bgcolor)); 472 473 if (fgcolor) 474 style.SetTextColour(wxColour(fgcolor)); 475 */ 476 return true; 477 } 478 479 return false; 480} 481 482void wxUITextViewControl::SetStyle(long start, 483 long end, 484 const wxTextAttr& style) 485{ 486 if (m_textView) { 487 NSRange range = NSMakeRange(start, end-start); 488 if (start == -1 && end == -1) 489 range = [m_textView selectedRange]; 490/* 491 UITextStorage* storage = [m_textView textStorage]; 492 493 wxFont font = style.GetFont(); 494 if (style.HasFont() && font.IsOk()) 495 [storage addAttribute:NSFontAttributeName value:font.OSXGetNSFont() range:range]; 496 497 wxColour bgcolor = style.GetBackgroundColour(); 498 if (style.HasBackgroundColour() && bgcolor.IsOk()) 499 [storage addAttribute:NSBackgroundColorAttributeName value:bgcolor.OSXGetNSColor() range:range]; 500 501 wxColour fgcolor = style.GetTextColour(); 502 if (style.HasTextColour() && fgcolor.IsOk()) 503 [storage addAttribute:NSForegroundColorAttributeName value:fgcolor.OSXGetNSColor() range:range]; 504*/ 505 } 506} 507 508void wxUITextViewControl::CheckSpelling(bool check) 509{ 510} 511 512wxSize wxUITextViewControl::GetBestSize() const 513{ 514 wxRect r; 515 516 GetBestRect(&r); 517 518 /* 519 if (m_textView && [m_textView layoutManager]) 520 { 521 NSRect rect = [[m_textView layoutManager] usedRectForTextContainer: [m_textView textContainer]]; 522 wxSize size = wxSize(rect.size.width, rect.size.height); 523 size.x += [m_textView textContainerInset].width; 524 size.y += [m_textView textContainerInset].height; 525 return size; 526 } 527 return wxSize(0,0); 528 */ 529 530 wxSize sz = r.GetSize(); 531 if ( sz.y < 31 ) 532 sz.y = 31; 533 534 return sz; 535} 536 537#if wxOSX_IPHONE_USE_TEXTFIELD 538 539// 540// wxUITextFieldControl 541// 542 543wxUITextFieldControl::wxUITextFieldControl( wxTextCtrl *wxPeer, UITextField* w ) : 544 wxWidgetIPhoneImpl(wxPeer, w), 545 wxTextWidgetImpl(wxPeer) 546{ 547 m_textField = w; 548 m_delegate = [[wxUITextFieldDelegate alloc] init]; 549 [m_textField setDelegate: m_delegate]; 550 m_selStart = m_selEnd = 0; 551} 552 553wxUITextFieldControl::~wxUITextFieldControl() 554{ 555 if (m_textField) 556 [m_textField setDelegate: nil]; 557 [m_delegate release]; 558} 559 560wxString wxUITextFieldControl::GetStringValue() const 561{ 562 return wxCFStringRef::AsString([m_textField text], m_wxPeer->GetFont().GetEncoding()); 563} 564 565void wxUITextFieldControl::SetStringValue( const wxString &str) 566{ 567// wxMacEditHelper helper(m_textField); 568 [m_textField setText: wxCFStringRef( str , m_wxPeer->GetFont().GetEncoding() ).AsNSString()]; 569} 570 571wxSize wxUITextFieldControl::GetBestSize() const 572{ 573 wxRect r; 574 575 GetBestRect(&r); 576 wxSize sz = r.GetSize(); 577 if ( sz.y < 31 ) 578 sz.y = 31; 579 return sz; 580} 581 582void wxUITextFieldControl::Copy() 583{ 584 [m_textField copy:nil]; 585} 586 587void wxUITextFieldControl::Cut() 588{ 589 [m_textField cut:nil]; 590} 591 592void wxUITextFieldControl::Paste() 593{ 594 [m_textField paste:nil]; 595} 596 597bool wxUITextFieldControl::CanPaste() const 598{ 599 return true; 600} 601 602void wxUITextFieldControl::SetEditable(bool editable) 603{ 604} 605 606void wxUITextFieldControl::GetSelection( long* from, long* to) const 607{ 608 *from = m_selStart; 609 *to = m_selEnd; 610} 611 612void wxUITextFieldControl::SetSelection( long from , long to ) 613{ 614 long textLength = [[m_textField text] length]; 615 if ((from == -1) && (to == -1)) 616 { 617 from = 0 ; 618 to = textLength ; 619 } 620 else 621 { 622 from = wxMin(textLength,wxMax(from,0)) ; 623 if ( to == -1 ) 624 to = textLength; 625 else 626 to = wxMax(0,wxMin(textLength,to)) ; 627 } 628 629 m_selStart = from; 630 m_selEnd = to; 631} 632 633void wxUITextFieldControl::WriteText(const wxString& str) 634{ 635#if 0 636 NSEvent* formerEvent = m_lastKeyDownEvent; 637 UIText* editor = [m_textField currentEditor]; 638 if ( editor ) 639 { 640 wxMacEditHelper helper(m_textField); 641 [editor insertText:wxCFStringRef( str , m_wxPeer->GetFont().GetEncoding() ).AsNSString()]; 642 } 643 else 644#endif 645 { 646 wxString val = GetStringValue() ; 647 long start , end ; 648 GetSelection( &start , &end ) ; 649 val.Remove( start , end - start ) ; 650 val.insert( start , str ) ; 651 SetStringValue( val ) ; 652 SetSelection( start + str.length() , start + str.length() ) ; 653 } 654#if 0 655 m_lastKeyDownEvent = formerEvent; 656#endif 657} 658 659void wxUITextFieldControl::controlAction(WXWidget WXUNUSED(slf), 660 void* WXUNUSED(_cmd), void *WXUNUSED(sender)) 661{ 662 wxWindow* wxpeer = (wxWindow*) GetWXPeer(); 663 if ( wxpeer && (wxpeer->GetWindowStyle() & wxTE_PROCESS_ENTER) ) 664 { 665 wxCommandEvent event(wxEVT_TEXT_ENTER, wxpeer->GetId()); 666 event.SetEventObject( wxpeer ); 667 event.SetString( static_cast<wxTextCtrl*>(wxpeer)->GetValue() ); 668 wxpeer->HandleWindowEvent( event ); 669 } 670} 671 672bool wxUITextFieldControl::SetHint(const wxString& hint) 673{ 674 wxCFStringRef hintstring(hint); 675 [m_textField setPlaceholder:hintstring.AsNSString()]; 676 return true; 677} 678 679#endif 680 681// 682// 683// 684 685wxWidgetImplType* wxWidgetImpl::CreateTextControl( wxTextCtrl* wxpeer, 686 wxWindowMac* WXUNUSED(parent), 687 wxWindowID WXUNUSED(id), 688 const wxString& str, 689 const wxPoint& pos, 690 const wxSize& size, 691 long style, 692 long WXUNUSED(extraStyle)) 693{ 694 CGRect r = wxOSXGetFrameForControl( wxpeer, pos , size ) ; 695 wxWidgetIPhoneImpl* c = NULL; 696 wxTextWidgetImpl* t = NULL; 697 id<UITextInputTraits> tv = nil; 698 699#if wxOSX_IPHONE_USE_TEXTFIELD 700 if ( style & wxTE_MULTILINE || style & wxTE_RICH || style & wxTE_RICH2 ) 701#endif 702 { 703 UITextView * v = nil; 704 v = [[UITextView alloc] initWithFrame:r]; 705 tv = v; 706 707 wxUITextViewControl* tc = new wxUITextViewControl( wxpeer, v ); 708 c = tc; 709 t = tc; 710 } 711#if wxOSX_IPHONE_USE_TEXTFIELD 712 else 713 { 714 wxUITextField* v = [[wxUITextField alloc] initWithFrame:r]; 715 tv = v; 716 717 v.textColor = [UIColor blackColor]; 718 v.font = [UIFont systemFontOfSize:17.0]; 719 v.backgroundColor = [UIColor whiteColor]; 720 721 v.clearButtonMode = UITextFieldViewModeNever; 722 723 [v setBorderStyle:UITextBorderStyleBezel]; 724 if ( style & wxNO_BORDER ) 725 v.borderStyle = UITextBorderStyleNone; 726 727 wxUITextFieldControl* tc = new wxUITextFieldControl( wxpeer, v ); 728 c = tc; 729 t = tc; 730 } 731#endif 732 733 if ( style & wxTE_PASSWORD ) 734 [tv setSecureTextEntry:YES]; 735 736 if ( !(style & wxTE_MULTILINE) ) 737 { 738 [tv setAutocorrectionType:UITextAutocorrectionTypeNo]; 739 [tv setReturnKeyType:UIReturnKeyDone]; 740 } 741 [tv setKeyboardType:UIKeyboardTypeDefault]; 742 743 t->SetStringValue(str); 744 745 return c; 746} 747 748 749#endif // wxUSE_TEXTCTRL 750