]> git.saurik.com Git - wxWidgets.git/blob - src/osx/cocoa/textctrl.mm
changing disclosure triangle to allow for label
[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 @interface wxNSSecureTextField : NSSecureTextField
82 {
83 }
84 @end
85
86 @implementation wxNSSecureTextField
87
88 + (void)initialize
89 {
90 static BOOL initialized = NO;
91 if (!initialized)
92 {
93 initialized = YES;
94 wxOSXCocoaClassAddWXMethods( self );
95 }
96 }
97
98 - (void)controlTextDidChange:(NSNotification *)aNotification
99 {
100 wxUnusedVar(aNotification);
101 wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
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
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
124 @end
125
126 @interface wxNSTextScrollView : NSScrollView
127 {
128 }
129 @end
130
131 @interface wxNSTextView : NSTextView
132 {
133 wxNSTextScrollView* scrollView;
134 }
135
136 - (void)setScrollView: (wxNSTextScrollView *) sv;
137 - (wxNSTextScrollView*) scrollView;
138
139 @end
140
141 @implementation wxNSTextScrollView
142
143 + (void)initialize
144 {
145 static BOOL initialized = NO;
146 if (!initialized)
147 {
148 initialized = YES;
149 wxOSXCocoaClassAddWXMethods( self );
150 }
151 }
152
153 - (void)textDidChange:(NSNotification *)aNotification
154 {
155 wxUnusedVar(aNotification);
156 wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
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 }
168
169 - (BOOL)textView:(NSTextView *)aTextView doCommandBySelector:(SEL)commandSelector
170 {
171 wxUnusedVar(aTextView);
172 wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
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 }
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
228 @end
229
230 @implementation wxNSTextField
231
232 + (void)initialize
233 {
234 static BOOL initialized = NO;
235 if (!initialized)
236 {
237 initialized = YES;
238 wxOSXCocoaClassAddWXMethods( self );
239 }
240 }
241
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 }
257
258 - (void)controlTextDidChange:(NSNotification *)aNotification
259 {
260 wxUnusedVar(aNotification);
261 wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
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 }
273
274 typedef 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 {
278 wxUnusedVar(textView);
279 wxUnusedVar(control);
280 if (commandSelector == @selector(insertNewline:))
281 {
282 wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
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 }
298
299 - (void)controlTextDidEndEditing:(NSNotification *)aNotification
300 {
301 wxUnusedVar(aNotification);
302 wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
303 if ( impl )
304 {
305 impl->DoNotifyFocusEvent( false, NULL );
306 }
307 }
308 @end
309
310 // wxNSTextViewControl
311
312 wxNSTextViewControl::wxNSTextViewControl( wxTextCtrl *wxPeer, WXWidget w ) : wxWidgetCocoaImpl(wxPeer, w)
313 {
314 wxNSTextScrollView* sv = (wxNSTextScrollView*) w;
315 m_scrollView = sv;
316
317 [m_scrollView setHasVerticalScroller:YES];
318 [m_scrollView setHasHorizontalScroller:NO];
319 [m_scrollView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
320 NSSize contentSize = [m_scrollView contentSize];
321
322 wxNSTextView* tv = [[wxNSTextView alloc] initWithFrame: NSMakeRect(0, 0,
323 contentSize.width, contentSize.height)];
324 m_textView = tv;
325 [tv setVerticallyResizable:YES];
326 [tv setHorizontallyResizable:NO];
327 [tv setAutoresizingMask:NSViewWidthSizable];
328
329 [m_scrollView setDocumentView: tv];
330
331 [tv setDelegate: w];
332 [tv setScrollView:sv];
333 }
334
335 wxNSTextViewControl::~wxNSTextViewControl()
336 {
337 if (m_textView)
338 [m_textView setDelegate: nil];
339 }
340
341 wxString wxNSTextViewControl::GetStringValue() const
342 {
343 if (m_textView)
344 {
345 wxCFStringRef cf( (CFStringRef) [[m_textView string] retain] );
346 wxString result = cf.AsString(m_wxPeer->GetFont().GetEncoding());
347 wxMacConvertNewlines13To10( &result ) ;
348 return result;
349 }
350 return wxEmptyString;
351 }
352 void wxNSTextViewControl::SetStringValue( const wxString &str)
353 {
354 wxString st = str;
355 wxMacConvertNewlines10To13( &st );
356 wxMacEditHelper helper(m_textView);
357
358 if (m_textView)
359 [m_textView setString: wxCFStringRef( st , m_wxPeer->GetFont().GetEncoding() ).AsNSString()];
360 }
361 void wxNSTextViewControl::Copy()
362 {
363 if (m_textView)
364 [m_textView copy:nil];
365
366 }
367
368 void wxNSTextViewControl::Cut()
369 {
370 if (m_textView)
371 [m_textView cut:nil];
372 }
373
374 void wxNSTextViewControl::Paste()
375 {
376 if (m_textView)
377 [m_textView paste:nil];
378 }
379
380 bool wxNSTextViewControl::CanPaste() const
381 {
382 return true;
383 }
384
385 void wxNSTextViewControl::SetEditable(bool editable)
386 {
387 if (m_textView)
388 [m_textView setEditable: editable];
389 }
390
391 void 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
401 void wxNSTextViewControl::SetSelection( long from , long to )
402 {
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
418 NSRange selrange = NSMakeRange(from, to-from);
419 [m_textView setSelectedRange:selrange];
420 [m_textView scrollRangeToVisible:selrange];
421 }
422
423 void wxNSTextViewControl::WriteText(const wxString& str)
424 {
425 wxString st = str;
426 wxMacConvertNewlines10To13( &st );
427 wxMacEditHelper helper(m_textView);
428
429 [m_textView insertText:wxCFStringRef( st , m_wxPeer->GetFont().GetEncoding() ).AsNSString()];
430 }
431
432 void wxNSTextViewControl::SetFont( const wxFont & font , const wxColour& foreground , long windowStyle, bool ignoreBlack )
433 {
434 if ([m_textView respondsToSelector:@selector(setFont:)])
435 [m_textView setFont: font.OSXGetNSFont()];
436 }
437
438
439 // wxNSTextFieldControl
440
441 wxNSTextFieldControl::wxNSTextFieldControl( wxTextCtrl *wxPeer, WXWidget w ) : wxWidgetCocoaImpl(wxPeer, w)
442 {
443 m_textField = (NSTextField*) w;
444 [m_textField setDelegate: w];
445 m_selStart = m_selEnd = 0;
446 }
447
448 wxNSTextFieldControl::~wxNSTextFieldControl()
449 {
450 if (m_textField)
451 [m_textField setDelegate: nil];
452 }
453
454 wxString wxNSTextFieldControl::GetStringValue() const
455 {
456 wxCFStringRef cf( (CFStringRef) [[m_textField stringValue] retain] );
457 return cf.AsString(m_wxPeer->GetFont().GetEncoding());
458 }
459
460 void wxNSTextFieldControl::SetStringValue( const wxString &str)
461 {
462 wxMacEditHelper helper(m_textField);
463 [m_textField setStringValue: wxCFStringRef( str , m_wxPeer->GetFont().GetEncoding() ).AsNSString()];
464 }
465
466 void wxNSTextFieldControl::Copy()
467 {
468 NSText* editor = [m_textField currentEditor];
469 if ( editor )
470 {
471 [editor copy:nil];
472 }
473 }
474
475 void wxNSTextFieldControl::Cut()
476 {
477 NSText* editor = [m_textField currentEditor];
478 if ( editor )
479 {
480 [editor cut:nil];
481 }
482 }
483
484 void wxNSTextFieldControl::Paste()
485 {
486 NSText* editor = [m_textField currentEditor];
487 if ( editor )
488 {
489 [editor paste:nil];
490 }
491 }
492
493 bool wxNSTextFieldControl::CanPaste() const
494 {
495 return true;
496 }
497
498 void wxNSTextFieldControl::SetEditable(bool editable)
499 {
500 [m_textField setEditable:editable];
501 }
502
503 void wxNSTextFieldControl::GetSelection( long* from, long* to) const
504 {
505 NSText* editor = [m_textField currentEditor];
506 if ( editor )
507 {
508 NSRange range = [editor selectedRange];
509 *from = range.location;
510 *to = range.location + range.length;
511 }
512 else
513 {
514 *from = m_selStart;
515 *to = m_selEnd;
516 }
517 }
518
519 void wxNSTextFieldControl::SetSelection( long from , long to )
520 {
521 long textLength = [[m_textField stringValue] length];
522 if ((from == -1) && (to == -1))
523 {
524 from = 0 ;
525 to = textLength ;
526 }
527 else
528 {
529 from = wxMin(textLength,wxMax(from,0)) ;
530 if ( to == -1 )
531 to = textLength;
532 else
533 to = wxMax(0,wxMin(textLength,to)) ;
534 }
535
536 NSText* editor = [m_textField currentEditor];
537 if ( editor )
538 {
539 [editor setSelectedRange:NSMakeRange(from, to-from)];
540 }
541 else
542 {
543 m_selStart = from;
544 m_selEnd = to;
545 }
546 }
547
548 void wxNSTextFieldControl::WriteText(const wxString& str)
549 {
550 NSText* editor = [m_textField currentEditor];
551 if ( editor )
552 {
553 wxMacEditHelper helper(m_textField);
554 [editor insertText:wxCFStringRef( str , m_wxPeer->GetFont().GetEncoding() ).AsNSString()];
555 }
556 else
557 {
558 wxString val = GetStringValue() ;
559 long start , end ;
560 GetSelection( &start , &end ) ;
561 val.Remove( start , end - start ) ;
562 val.insert( start , str ) ;
563 SetStringValue( val ) ;
564 SetSelection( start + str.length() , start + str.length() ) ;
565 }
566 }
567
568 void wxNSTextFieldControl::controlAction(WXWidget WXUNUSED(slf),
569 void* WXUNUSED(_cmd), void *WXUNUSED(sender))
570 {
571 wxWindow* wxpeer = (wxWindow*) GetWXPeer();
572 if ( wxpeer && (wxpeer->GetWindowStyle() & wxTE_PROCESS_ENTER) )
573 {
574 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, wxpeer->GetId());
575 event.SetEventObject( wxpeer );
576 event.SetString( static_cast<wxTextCtrl*>(wxpeer)->GetValue() );
577 wxpeer->HandleWindowEvent( event );
578 }
579 }
580
581 //
582 //
583 //
584
585 wxWidgetImplType* wxWidgetImpl::CreateTextControl( wxTextCtrl* wxpeer,
586 wxWindowMac* WXUNUSED(parent),
587 wxWindowID WXUNUSED(id),
588 const wxString& str,
589 const wxPoint& pos,
590 const wxSize& size,
591 long style,
592 long WXUNUSED(extraStyle))
593 {
594 NSRect r = wxOSXGetFrameForControl( wxpeer, pos , size ) ;
595 wxWidgetCocoaImpl* c = NULL;
596
597 if ( style & wxTE_MULTILINE || style & wxTE_RICH || style & wxTE_RICH2 )
598 {
599 wxNSTextScrollView* v = nil;
600 v = [[wxNSTextScrollView alloc] initWithFrame:r];
601 c = new wxNSTextViewControl( wxpeer, v );
602 static_cast<wxNSTextViewControl*>(c)->SetStringValue(str);
603 }
604 else
605 {
606 NSTextField* v = nil;
607 if ( style & wxTE_PASSWORD )
608 v = [[wxNSSecureTextField alloc] initWithFrame:r];
609 else
610 v = [[wxNSTextField alloc] initWithFrame:r];
611
612 if ( style & wxNO_BORDER )
613 {
614 // FIXME: How can we remove the native control's border?
615 // setBordered is separate from the text ctrl's border.
616 }
617
618 [v setBezeled:NO];
619 [v setBordered:NO];
620
621 c = new wxNSTextFieldControl( wxpeer, v );
622 static_cast<wxNSTextFieldControl*>(c)->SetStringValue(str);
623 }
624
625 return c;
626 }
627
628
629 #endif // wxUSE_TEXTCTRL