correction to last commit: Korean and Romanian translations will only be in 2.9.1...
[wxWidgets.git] / src / osx / cocoa / textctrl.mm
CommitLineData
dbeddfb9
SC
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/osx/cocoa/textctrl.mm
3// Purpose: wxTextCtrl
4// Author: Stefan Csomor
5// Modified by: Ryan Norton (MLTE GetLineLength and GetLineText)
6// Created: 1998-01-01
7// RCS-ID: $Id: textctrl.cpp 54820 2008-07-29 20:04:11Z SC $
8// Copyright: (c) Stefan Csomor
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12#include "wx/wxprec.h"
13
14#if wxUSE_TEXTCTRL
15
16#include "wx/textctrl.h"
17
18#ifndef WX_PRECOMP
19 #include "wx/intl.h"
20 #include "wx/app.h"
21 #include "wx/utils.h"
22 #include "wx/dc.h"
23 #include "wx/button.h"
24 #include "wx/menu.h"
25 #include "wx/settings.h"
26 #include "wx/msgdlg.h"
27 #include "wx/toplevel.h"
28#endif
29
30#ifdef __DARWIN__
31 #include <sys/types.h>
32 #include <sys/stat.h>
33#else
34 #include <stat.h>
35#endif
36
37#if wxUSE_STD_IOSTREAM
38 #if wxUSE_IOSTREAMH
39 #include <fstream.h>
40 #else
41 #include <fstream>
42 #endif
43#endif
44
45#include "wx/filefn.h"
46#include "wx/sysopt.h"
47#include "wx/thread.h"
48
49#include "wx/osx/private.h"
1e181c7a 50#include "wx/osx/cocoa/private/textimpl.h"
dbeddfb9 51
5f65ba36
SC
52@interface NSView(EditableView)
53- (BOOL)isEditable;
54- (void)setEditable:(BOOL)flag;
55@end
56
57class wxMacEditHelper
58{
59public :
60 wxMacEditHelper( NSView* textView )
61 {
62 m_textView = textView ;
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 NSView* m_textView;
79} ;
80
e32090ba 81@interface wxNSSecureTextField : NSSecureTextField
4d23a0d3 82{
4d23a0d3 83}
e32090ba
SC
84@end
85
86@implementation wxNSSecureTextField
dbeddfb9 87
4dd9fdf8
SC
88+ (void)initialize
89{
90 static BOOL initialized = NO;
91 if (!initialized)
92 {
93 initialized = YES;
94 wxOSXCocoaClassAddWXMethods( self );
95 }
96}
dbeddfb9 97
4d23a0d3
KO
98- (void)controlTextDidChange:(NSNotification *)aNotification
99{
6331c8c0
SC
100 wxUnusedVar(aNotification);
101 wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
4d23a0d3
KO
102 if ( impl )
103 {
104 wxWindow* wxpeer = (wxWindow*) impl->GetWXPeer();
105 if ( wxpeer ) {
106 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, wxpeer->GetId());
107 event.SetEventObject( wxpeer );
108 event.SetString( static_cast<wxTextCtrl*>(wxpeer)->GetValue() );
109 wxpeer->HandleWindowEvent( event );
110 }
111 }
112}
113
6d109846
SC
114- (void)controlTextDidEndEditing:(NSNotification *)aNotification
115{
116 wxUnusedVar(aNotification);
117 wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
118 if ( impl )
119 {
120 impl->DoNotifyFocusEvent( false, NULL );
121 }
122}
123
e32090ba
SC
124@end
125
1087c6c1 126@interface wxNSTextScrollView : NSScrollView
4d23a0d3 127{
4d23a0d3 128}
1087c6c1
SC
129@end
130
131@interface wxNSTextView : NSTextView
132{
133 wxNSTextScrollView* scrollView;
134}
135
136- (void)setScrollView: (wxNSTextScrollView *) sv;
137- (wxNSTextScrollView*) scrollView;
c824c165
KO
138
139@end
140
1087c6c1 141@implementation wxNSTextScrollView
c824c165
KO
142
143+ (void)initialize
144{
145 static BOOL initialized = NO;
146 if (!initialized)
147 {
148 initialized = YES;
149 wxOSXCocoaClassAddWXMethods( self );
150 }
151}
152
533e2ae1 153- (void)textDidChange:(NSNotification *)aNotification
4d23a0d3 154{
6331c8c0
SC
155 wxUnusedVar(aNotification);
156 wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
4d23a0d3
KO
157 if ( impl )
158 {
159 wxWindow* wxpeer = (wxWindow*) impl->GetWXPeer();
160 if ( wxpeer ) {
161 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, wxpeer->GetId());
162 event.SetEventObject( wxpeer );
163 event.SetString( static_cast<wxTextCtrl*>(wxpeer)->GetValue() );
164 wxpeer->HandleWindowEvent( event );
165 }
166 }
167}
533e2ae1
KO
168
169- (BOOL)textView:(NSTextView *)aTextView doCommandBySelector:(SEL)commandSelector
170{
6331c8c0
SC
171 wxUnusedVar(aTextView);
172 wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
533e2ae1
KO
173 if ( impl )
174 {
175 wxWindow* wxpeer = (wxWindow*) impl->GetWXPeer();
176 if (commandSelector == @selector(insertNewline:))
177 {
178 if ( wxpeer && wxpeer->GetWindowStyle() & wxTE_PROCESS_ENTER )
179 {
180 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, wxpeer->GetId());
181 event.SetEventObject( wxpeer );
182 event.SetString( static_cast<wxTextCtrl*>(wxpeer)->GetValue() );
183 wxpeer->HandleWindowEvent( event );
184 }
185 }
186 }
187
188 return NO;
189}
1087c6c1
SC
190
191- (void)textDidEndEditing:(NSNotification *)aNotification
192{
193 wxUnusedVar(aNotification);
194 wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
195 if ( impl )
196 {
197 impl->DoNotifyFocusEvent( false, NULL );
198 }
199}
200@end
201
202@implementation wxNSTextView
203
204- (BOOL) becomeFirstResponder
205{
206 BOOL val = [super becomeFirstResponder];
207
208 if ( val )
209 {
210 wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( scrollView );
211 if (impl )
212 impl->DoNotifyFocusEvent( true, NULL );
213
214 }
215 return val;
216}
217
218- (void)setScrollView: (wxNSTextScrollView *) sv
219{
220 scrollView = sv;
221}
222
223- (wxNSTextScrollView*) scrollView
224{
225 return scrollView;
226}
227
c824c165
KO
228@end
229
e32090ba 230@implementation wxNSTextField
ffad7b0d 231
e32090ba 232+ (void)initialize
dbeddfb9 233{
e32090ba
SC
234 static BOOL initialized = NO;
235 if (!initialized)
236 {
237 initialized = YES;
238 wxOSXCocoaClassAddWXMethods( self );
239 }
dbeddfb9 240}
e32090ba 241
c3e433b1
SC
242- (void) setEnabled:(BOOL) flag
243{
244 [super setEnabled: flag];
245
246 if (![self drawsBackground]) {
247 // Static text is drawn incorrectly when disabled.
248 // For an explanation, see
249 // http://www.cocoabuilder.com/archive/message/cocoa/2006/7/21/168028
250 if (flag) {
251 [self setTextColor: [NSColor controlTextColor]];
252 } else {
253 [self setTextColor: [NSColor secondarySelectedControlColor]];
254 }
255 }
256}
4d23a0d3 257
ffad7b0d
SC
258- (void)controlTextDidChange:(NSNotification *)aNotification
259{
6331c8c0
SC
260 wxUnusedVar(aNotification);
261 wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
ffad7b0d
SC
262 if ( impl )
263 {
264 wxWindow* wxpeer = (wxWindow*) impl->GetWXPeer();
265 if ( wxpeer ) {
266 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, wxpeer->GetId());
267 event.SetEventObject( wxpeer );
268 event.SetString( static_cast<wxTextCtrl*>(wxpeer)->GetValue() );
269 wxpeer->HandleWindowEvent( event );
270 }
271 }
272}
dbeddfb9 273
2d6aa919
KO
274typedef BOOL (*wxOSX_insertNewlineHandlerPtr)(NSView* self, SEL _cmd, NSControl *control, NSTextView* textView, SEL commandSelector);
275
276- (BOOL)control:(NSControl*)control textView:(NSTextView*)textView doCommandBySelector:(SEL)commandSelector
277{
6331c8c0
SC
278 wxUnusedVar(textView);
279 wxUnusedVar(control);
2d6aa919
KO
280 if (commandSelector == @selector(insertNewline:))
281 {
6331c8c0 282 wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
2d6aa919
KO
283 if ( impl )
284 {
285 wxWindow* wxpeer = (wxWindow*) impl->GetWXPeer();
286 if ( wxpeer && wxpeer->GetWindowStyle() & wxTE_PROCESS_ENTER )
287 {
288 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, wxpeer->GetId());
289 event.SetEventObject( wxpeer );
290 event.SetString( static_cast<wxTextCtrl*>(wxpeer)->GetValue() );
291 wxpeer->HandleWindowEvent( event );
292 }
293 }
294 }
295
296 return NO;
297}
6d109846 298
ffad7b0d
SC
299- (void)controlTextDidEndEditing:(NSNotification *)aNotification
300{
6d109846
SC
301 wxUnusedVar(aNotification);
302 wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
ffad7b0d
SC
303 if ( impl )
304 {
6d109846 305 impl->DoNotifyFocusEvent( false, NULL );
ffad7b0d
SC
306 }
307}
dbeddfb9
SC
308@end
309
c824c165
KO
310// wxNSTextViewControl
311
312wxNSTextViewControl::wxNSTextViewControl( wxTextCtrl *wxPeer, WXWidget w ) : wxWidgetCocoaImpl(wxPeer, w)
313{
1087c6c1
SC
314 wxNSTextScrollView* sv = (wxNSTextScrollView*) w;
315 m_scrollView = sv;
c824c165
KO
316
317 [m_scrollView setHasVerticalScroller:YES];
318 [m_scrollView setHasHorizontalScroller:NO];
319 [m_scrollView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
320 NSSize contentSize = [m_scrollView contentSize];
321
1087c6c1 322 wxNSTextView* tv = [[wxNSTextView alloc] initWithFrame: NSMakeRect(0, 0,
c824c165 323 contentSize.width, contentSize.height)];
1087c6c1
SC
324 m_textView = tv;
325 [tv setVerticallyResizable:YES];
326 [tv setHorizontallyResizable:NO];
327 [tv setAutoresizingMask:NSViewWidthSizable];
c824c165 328
1087c6c1 329 [m_scrollView setDocumentView: tv];
c824c165 330
1087c6c1
SC
331 [tv setDelegate: w];
332 [tv setScrollView:sv];
c824c165
KO
333}
334
335wxNSTextViewControl::~wxNSTextViewControl()
336{
337 if (m_textView)
338 [m_textView setDelegate: nil];
339}
340
341wxString wxNSTextViewControl::GetStringValue() const
342{
343 if (m_textView)
344 {
345 wxCFStringRef cf( (CFStringRef) [[m_textView string] retain] );
50b5e38d
SC
346 wxString result = cf.AsString(m_wxPeer->GetFont().GetEncoding());
347 wxMacConvertNewlines13To10( &result ) ;
348 return result;
c824c165
KO
349 }
350 return wxEmptyString;
351}
352void wxNSTextViewControl::SetStringValue( const wxString &str)
353{
50b5e38d
SC
354 wxString st = str;
355 wxMacConvertNewlines10To13( &st );
5f65ba36 356 wxMacEditHelper helper(m_textView);
50b5e38d 357
c824c165 358 if (m_textView)
50b5e38d 359 [m_textView setString: wxCFStringRef( st , m_wxPeer->GetFont().GetEncoding() ).AsNSString()];
c824c165
KO
360}
361void wxNSTextViewControl::Copy()
362{
363 if (m_textView)
364 [m_textView copy:nil];
365
366}
367
368void wxNSTextViewControl::Cut()
369{
370 if (m_textView)
371 [m_textView cut:nil];
372}
373
374void wxNSTextViewControl::Paste()
375{
376 if (m_textView)
377 [m_textView paste:nil];
378}
379
380bool wxNSTextViewControl::CanPaste() const
381{
382 return true;
383}
384
385void wxNSTextViewControl::SetEditable(bool editable)
386{
387 if (m_textView)
388 [m_textView setEditable: editable];
389}
390
391void wxNSTextViewControl::GetSelection( long* from, long* to) const
392{
393 if (m_textView)
394 {
395 NSRange range = [m_textView selectedRange];
396 *from = range.location;
397 *to = range.location + range.length;
398 }
399}
400
401void wxNSTextViewControl::SetSelection( long from , long to )
402{
50b5e38d
SC
403 long textLength = [[m_textView string] length];
404 if ((from == -1) && (to == -1))
405 {
406 from = 0 ;
407 to = textLength ;
408 }
409 else
410 {
411 from = wxMin(textLength,wxMax(from,0)) ;
412 if ( to == -1 )
413 to = textLength;
414 else
415 to = wxMax(0,wxMin(textLength,to)) ;
416 }
417
2d6aa919
KO
418 NSRange selrange = NSMakeRange(from, to-from);
419 [m_textView setSelectedRange:selrange];
420 [m_textView scrollRangeToVisible:selrange];
c824c165
KO
421}
422
423void wxNSTextViewControl::WriteText(const wxString& str)
424{
50b5e38d
SC
425 wxString st = str;
426 wxMacConvertNewlines10To13( &st );
5f65ba36
SC
427 wxMacEditHelper helper(m_textView);
428
50b5e38d 429 [m_textView insertText:wxCFStringRef( st , m_wxPeer->GetFont().GetEncoding() ).AsNSString()];
c824c165
KO
430}
431
432// wxNSTextFieldControl
433
1e181c7a
SC
434wxNSTextFieldControl::wxNSTextFieldControl( wxTextCtrl *wxPeer, WXWidget w ) : wxWidgetCocoaImpl(wxPeer, w)
435{
e32090ba
SC
436 m_textField = (NSTextField*) w;
437 [m_textField setDelegate: w];
50b5e38d 438 m_selStart = m_selEnd = 0;
1e181c7a
SC
439}
440
441wxNSTextFieldControl::~wxNSTextFieldControl()
442{
c824c165
KO
443 if (m_textField)
444 [m_textField setDelegate: nil];
1e181c7a
SC
445}
446
447wxString wxNSTextFieldControl::GetStringValue() const
448{
e32090ba 449 wxCFStringRef cf( (CFStringRef) [[m_textField stringValue] retain] );
1e181c7a
SC
450 return cf.AsString(m_wxPeer->GetFont().GetEncoding());
451}
50b5e38d 452
1e181c7a
SC
453void wxNSTextFieldControl::SetStringValue( const wxString &str)
454{
5f65ba36 455 wxMacEditHelper helper(m_textField);
e32090ba 456 [m_textField setStringValue: wxCFStringRef( str , m_wxPeer->GetFont().GetEncoding() ).AsNSString()];
1e181c7a 457}
50b5e38d 458
1e181c7a
SC
459void wxNSTextFieldControl::Copy()
460{
e32090ba
SC
461 NSText* editor = [m_textField currentEditor];
462 if ( editor )
463 {
464 [editor copy:nil];
465 }
1e181c7a
SC
466}
467
468void wxNSTextFieldControl::Cut()
469{
e32090ba
SC
470 NSText* editor = [m_textField currentEditor];
471 if ( editor )
472 {
473 [editor cut:nil];
474 }
1e181c7a
SC
475}
476
477void wxNSTextFieldControl::Paste()
478{
e32090ba
SC
479 NSText* editor = [m_textField currentEditor];
480 if ( editor )
481 {
482 [editor paste:nil];
483 }
1e181c7a
SC
484}
485
486bool wxNSTextFieldControl::CanPaste() const
487{
e32090ba 488 return true;
1e181c7a
SC
489}
490
491void wxNSTextFieldControl::SetEditable(bool editable)
492{
e32090ba 493 [m_textField setEditable:editable];
1e181c7a
SC
494}
495
496void wxNSTextFieldControl::GetSelection( long* from, long* to) const
497{
e32090ba
SC
498 NSText* editor = [m_textField currentEditor];
499 if ( editor )
500 {
501 NSRange range = [editor selectedRange];
502 *from = range.location;
503 *to = range.location + range.length;
504 }
50b5e38d
SC
505 else
506 {
507 *from = m_selStart;
508 *to = m_selEnd;
509 }
1e181c7a
SC
510}
511
512void wxNSTextFieldControl::SetSelection( long from , long to )
513{
50b5e38d
SC
514 long textLength = [[m_textField stringValue] length];
515 if ((from == -1) && (to == -1))
516 {
517 from = 0 ;
518 to = textLength ;
519 }
520 else
521 {
522 from = wxMin(textLength,wxMax(from,0)) ;
523 if ( to == -1 )
524 to = textLength;
525 else
526 to = wxMax(0,wxMin(textLength,to)) ;
527 }
528
e32090ba
SC
529 NSText* editor = [m_textField currentEditor];
530 if ( editor )
531 {
532 [editor setSelectedRange:NSMakeRange(from, to-from)];
533 }
50b5e38d
SC
534 else
535 {
536 m_selStart = from;
537 m_selEnd = to;
538 }
1e181c7a
SC
539}
540
541void wxNSTextFieldControl::WriteText(const wxString& str)
542{
50b5e38d
SC
543 NSText* editor = [m_textField currentEditor];
544 if ( editor )
545 {
5f65ba36 546 wxMacEditHelper helper(m_textField);
50b5e38d
SC
547 [editor insertText:wxCFStringRef( str , m_wxPeer->GetFont().GetEncoding() ).AsNSString()];
548 }
549 else
550 {
551 wxString val = GetStringValue() ;
552 long start , end ;
553 GetSelection( &start , &end ) ;
554 val.Remove( start , end - start ) ;
555 val.insert( start , str ) ;
556 SetStringValue( val ) ;
557 SetSelection( start + str.length() , start + str.length() ) ;
558 }
1e181c7a 559}
dbeddfb9 560
6331c8c0
SC
561void wxNSTextFieldControl::controlAction(WXWidget WXUNUSED(slf),
562 void* WXUNUSED(_cmd), void *WXUNUSED(sender))
e32090ba
SC
563{
564 wxWindow* wxpeer = (wxWindow*) GetWXPeer();
565 if ( wxpeer && (wxpeer->GetWindowStyle() & wxTE_PROCESS_ENTER) )
566 {
567 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, wxpeer->GetId());
568 event.SetEventObject( wxpeer );
569 event.SetString( static_cast<wxTextCtrl*>(wxpeer)->GetValue() );
570 wxpeer->HandleWindowEvent( event );
571 }
572}
573
574//
575//
576//
577
dbeddfb9 578wxWidgetImplType* wxWidgetImpl::CreateTextControl( wxTextCtrl* wxpeer,
6331c8c0
SC
579 wxWindowMac* WXUNUSED(parent),
580 wxWindowID WXUNUSED(id),
dbeddfb9
SC
581 const wxString& str,
582 const wxPoint& pos,
583 const wxSize& size,
584 long style,
6331c8c0 585 long WXUNUSED(extraStyle))
dbeddfb9 586{
dbeddfb9 587 NSRect r = wxOSXGetFrameForControl( wxpeer, pos , size ) ;
c824c165 588 wxWidgetCocoaImpl* c = NULL;
e32090ba 589
c824c165 590 if ( style & wxTE_MULTILINE || style & wxTE_RICH || style & wxTE_RICH2 )
b15f9375 591 {
1087c6c1
SC
592 wxNSTextScrollView* v = nil;
593 v = [[wxNSTextScrollView alloc] initWithFrame:r];
c824c165
KO
594 c = new wxNSTextViewControl( wxpeer, v );
595 static_cast<wxNSTextViewControl*>(c)->SetStringValue(str);
596 }
597 else
598 {
6331c8c0 599 NSTextField* v = nil;
c824c165
KO
600 if ( style & wxTE_PASSWORD )
601 v = [[wxNSSecureTextField alloc] initWithFrame:r];
602 else
603 v = [[wxNSTextField alloc] initWithFrame:r];
604
605 if ( style & wxNO_BORDER )
606 {
607 // FIXME: How can we remove the native control's border?
608 // setBordered is separate from the text ctrl's border.
609 }
610
b15f9375
SC
611 [v setBezeled:NO];
612 [v setBordered:NO];
c824c165
KO
613
614 c = new wxNSTextFieldControl( wxpeer, v );
615 static_cast<wxNSTextFieldControl*>(c)->SetStringValue(str);
b15f9375 616 }
dbeddfb9 617
dbeddfb9
SC
618 return c;
619}
620
621
622#endif // wxUSE_TEXTCTRL