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