]> git.saurik.com Git - wxWidgets.git/blob - src/osx/cocoa/textctrl.mm
supporting kill focus for single line text controls
[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 wxNSSecureTextField : NSSecureTextField
53 {
54 }
55 @end
56
57 @implementation wxNSSecureTextField
58
59 + (void)initialize
60 {
61 static BOOL initialized = NO;
62 if (!initialized)
63 {
64 initialized = YES;
65 wxOSXCocoaClassAddWXMethods( self );
66 }
67 }
68
69 - (void)controlTextDidChange:(NSNotification *)aNotification
70 {
71 wxUnusedVar(aNotification);
72 wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
73 if ( impl )
74 {
75 wxWindow* wxpeer = (wxWindow*) impl->GetWXPeer();
76 if ( wxpeer ) {
77 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, wxpeer->GetId());
78 event.SetEventObject( wxpeer );
79 event.SetString( static_cast<wxTextCtrl*>(wxpeer)->GetValue() );
80 wxpeer->HandleWindowEvent( event );
81 }
82 }
83 }
84
85 - (void)controlTextDidEndEditing:(NSNotification *)aNotification
86 {
87 wxUnusedVar(aNotification);
88 wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
89 if ( impl )
90 {
91 impl->DoNotifyFocusEvent( false, NULL );
92 }
93 }
94
95 @end
96
97 @interface wxNSTextView : NSScrollView
98 {
99 }
100
101 @end
102
103 @implementation wxNSTextView
104
105 + (void)initialize
106 {
107 static BOOL initialized = NO;
108 if (!initialized)
109 {
110 initialized = YES;
111 wxOSXCocoaClassAddWXMethods( self );
112 }
113 }
114
115 - (void)textDidChange:(NSNotification *)aNotification
116 {
117 wxUnusedVar(aNotification);
118 wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
119 if ( impl )
120 {
121 wxWindow* wxpeer = (wxWindow*) impl->GetWXPeer();
122 if ( wxpeer ) {
123 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, wxpeer->GetId());
124 event.SetEventObject( wxpeer );
125 event.SetString( static_cast<wxTextCtrl*>(wxpeer)->GetValue() );
126 wxpeer->HandleWindowEvent( event );
127 }
128 }
129 }
130
131 - (BOOL)textView:(NSTextView *)aTextView doCommandBySelector:(SEL)commandSelector
132 {
133 wxUnusedVar(aTextView);
134 wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
135 if ( impl )
136 {
137 wxWindow* wxpeer = (wxWindow*) impl->GetWXPeer();
138 if (commandSelector == @selector(insertNewline:))
139 {
140 if ( wxpeer && wxpeer->GetWindowStyle() & wxTE_PROCESS_ENTER )
141 {
142 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, wxpeer->GetId());
143 event.SetEventObject( wxpeer );
144 event.SetString( static_cast<wxTextCtrl*>(wxpeer)->GetValue() );
145 wxpeer->HandleWindowEvent( event );
146 }
147 }
148 }
149
150 return NO;
151 }
152 @end
153
154 @implementation wxNSTextField
155
156 + (void)initialize
157 {
158 static BOOL initialized = NO;
159 if (!initialized)
160 {
161 initialized = YES;
162 wxOSXCocoaClassAddWXMethods( self );
163 }
164 }
165
166 - (void) setEnabled:(BOOL) flag
167 {
168 [super setEnabled: flag];
169
170 if (![self drawsBackground]) {
171 // Static text is drawn incorrectly when disabled.
172 // For an explanation, see
173 // http://www.cocoabuilder.com/archive/message/cocoa/2006/7/21/168028
174 if (flag) {
175 [self setTextColor: [NSColor controlTextColor]];
176 } else {
177 [self setTextColor: [NSColor secondarySelectedControlColor]];
178 }
179 }
180 }
181
182 - (void)controlTextDidChange:(NSNotification *)aNotification
183 {
184 wxUnusedVar(aNotification);
185 wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
186 if ( impl )
187 {
188 wxWindow* wxpeer = (wxWindow*) impl->GetWXPeer();
189 if ( wxpeer ) {
190 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, wxpeer->GetId());
191 event.SetEventObject( wxpeer );
192 event.SetString( static_cast<wxTextCtrl*>(wxpeer)->GetValue() );
193 wxpeer->HandleWindowEvent( event );
194 }
195 }
196 }
197
198 typedef BOOL (*wxOSX_insertNewlineHandlerPtr)(NSView* self, SEL _cmd, NSControl *control, NSTextView* textView, SEL commandSelector);
199
200 - (BOOL)control:(NSControl*)control textView:(NSTextView*)textView doCommandBySelector:(SEL)commandSelector
201 {
202 wxUnusedVar(textView);
203 wxUnusedVar(control);
204 if (commandSelector == @selector(insertNewline:))
205 {
206 wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
207 if ( impl )
208 {
209 wxWindow* wxpeer = (wxWindow*) impl->GetWXPeer();
210 if ( wxpeer && wxpeer->GetWindowStyle() & wxTE_PROCESS_ENTER )
211 {
212 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, wxpeer->GetId());
213 event.SetEventObject( wxpeer );
214 event.SetString( static_cast<wxTextCtrl*>(wxpeer)->GetValue() );
215 wxpeer->HandleWindowEvent( event );
216 }
217 }
218 }
219
220 return NO;
221 }
222
223 - (void)controlTextDidEndEditing:(NSNotification *)aNotification
224 {
225 wxUnusedVar(aNotification);
226 wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
227 if ( impl )
228 {
229 impl->DoNotifyFocusEvent( false, NULL );
230 }
231 }
232 @end
233
234 // wxNSTextViewControl
235
236 wxNSTextViewControl::wxNSTextViewControl( wxTextCtrl *wxPeer, WXWidget w ) : wxWidgetCocoaImpl(wxPeer, w)
237 {
238 m_scrollView = (NSScrollView*) w;
239
240 [m_scrollView setHasVerticalScroller:YES];
241 [m_scrollView setHasHorizontalScroller:NO];
242 [m_scrollView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
243 NSSize contentSize = [m_scrollView contentSize];
244
245 m_textView = [[NSTextView alloc] initWithFrame: NSMakeRect(0, 0,
246 contentSize.width, contentSize.height)];
247 [m_textView setVerticallyResizable:YES];
248 [m_textView setHorizontallyResizable:NO];
249 [m_textView setAutoresizingMask:NSViewWidthSizable];
250
251 [m_scrollView setDocumentView: m_textView];
252
253 [m_textView setDelegate: w];
254 }
255
256 wxNSTextViewControl::~wxNSTextViewControl()
257 {
258 if (m_textView)
259 [m_textView setDelegate: nil];
260 }
261
262 wxString wxNSTextViewControl::GetStringValue() const
263 {
264 if (m_textView)
265 {
266 wxCFStringRef cf( (CFStringRef) [[m_textView string] retain] );
267 return cf.AsString(m_wxPeer->GetFont().GetEncoding());
268 }
269 return wxEmptyString;
270 }
271 void wxNSTextViewControl::SetStringValue( const wxString &str)
272 {
273 if (m_textView)
274 [m_textView setString: wxCFStringRef( str , m_wxPeer->GetFont().GetEncoding() ).AsNSString()];
275 }
276 void wxNSTextViewControl::Copy()
277 {
278 if (m_textView)
279 [m_textView copy:nil];
280
281 }
282
283 void wxNSTextViewControl::Cut()
284 {
285 if (m_textView)
286 [m_textView cut:nil];
287 }
288
289 void wxNSTextViewControl::Paste()
290 {
291 if (m_textView)
292 [m_textView paste:nil];
293 }
294
295 bool wxNSTextViewControl::CanPaste() const
296 {
297 return true;
298 }
299
300 void wxNSTextViewControl::SetEditable(bool editable)
301 {
302 if (m_textView)
303 [m_textView setEditable: editable];
304 }
305
306 void wxNSTextViewControl::GetSelection( long* from, long* to) const
307 {
308 if (m_textView)
309 {
310 NSRange range = [m_textView selectedRange];
311 *from = range.location;
312 *to = range.location + range.length;
313 }
314 }
315
316 void wxNSTextViewControl::SetSelection( long from , long to )
317 {
318 NSRange selrange = NSMakeRange(from, to-from);
319 [m_textView setSelectedRange:selrange];
320 [m_textView scrollRangeToVisible:selrange];
321 }
322
323 void wxNSTextViewControl::WriteText(const wxString& str)
324 {
325 // temp hack to get logging working early
326 wxString former = GetStringValue();
327 SetStringValue( former + str );
328 SetSelection(GetStringValue().length(), GetStringValue().length());
329 }
330
331 // wxNSTextFieldControl
332
333 wxNSTextFieldControl::wxNSTextFieldControl( wxTextCtrl *wxPeer, WXWidget w ) : wxWidgetCocoaImpl(wxPeer, w)
334 {
335 m_textField = (NSTextField*) w;
336 [m_textField setDelegate: w];
337 }
338
339 wxNSTextFieldControl::~wxNSTextFieldControl()
340 {
341 if (m_textField)
342 [m_textField setDelegate: nil];
343 }
344
345 wxString wxNSTextFieldControl::GetStringValue() const
346 {
347 wxCFStringRef cf( (CFStringRef) [[m_textField stringValue] retain] );
348 return cf.AsString(m_wxPeer->GetFont().GetEncoding());
349 }
350 void wxNSTextFieldControl::SetStringValue( const wxString &str)
351 {
352 [m_textField setStringValue: wxCFStringRef( str , m_wxPeer->GetFont().GetEncoding() ).AsNSString()];
353 }
354 void wxNSTextFieldControl::Copy()
355 {
356 NSText* editor = [m_textField currentEditor];
357 if ( editor )
358 {
359 [editor copy:nil];
360 }
361 }
362
363 void wxNSTextFieldControl::Cut()
364 {
365 NSText* editor = [m_textField currentEditor];
366 if ( editor )
367 {
368 [editor cut:nil];
369 }
370 }
371
372 void wxNSTextFieldControl::Paste()
373 {
374 NSText* editor = [m_textField currentEditor];
375 if ( editor )
376 {
377 [editor paste:nil];
378 }
379 }
380
381 bool wxNSTextFieldControl::CanPaste() const
382 {
383 return true;
384 }
385
386 void wxNSTextFieldControl::SetEditable(bool editable)
387 {
388 [m_textField setEditable:editable];
389 }
390
391 void wxNSTextFieldControl::GetSelection( long* from, long* to) const
392 {
393 NSText* editor = [m_textField currentEditor];
394 if ( editor )
395 {
396 NSRange range = [editor selectedRange];
397 *from = range.location;
398 *to = range.location + range.length;
399 }
400 }
401
402 void wxNSTextFieldControl::SetSelection( long from , long to )
403 {
404 NSText* editor = [m_textField currentEditor];
405 if ( editor )
406 {
407 [editor setSelectedRange:NSMakeRange(from, to-from)];
408 }
409 }
410
411 void wxNSTextFieldControl::WriteText(const wxString& str)
412 {
413 // temp hack to get logging working early
414 wxString former = GetStringValue();
415 SetStringValue( former + str );
416 SetSelection(GetStringValue().length(), GetStringValue().length());
417 }
418
419 void wxNSTextFieldControl::controlAction(WXWidget WXUNUSED(slf),
420 void* WXUNUSED(_cmd), void *WXUNUSED(sender))
421 {
422 wxWindow* wxpeer = (wxWindow*) GetWXPeer();
423 if ( wxpeer && (wxpeer->GetWindowStyle() & wxTE_PROCESS_ENTER) )
424 {
425 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, wxpeer->GetId());
426 event.SetEventObject( wxpeer );
427 event.SetString( static_cast<wxTextCtrl*>(wxpeer)->GetValue() );
428 wxpeer->HandleWindowEvent( event );
429 }
430 }
431
432 //
433 //
434 //
435
436 wxWidgetImplType* wxWidgetImpl::CreateTextControl( wxTextCtrl* wxpeer,
437 wxWindowMac* WXUNUSED(parent),
438 wxWindowID WXUNUSED(id),
439 const wxString& str,
440 const wxPoint& pos,
441 const wxSize& size,
442 long style,
443 long WXUNUSED(extraStyle))
444 {
445 NSRect r = wxOSXGetFrameForControl( wxpeer, pos , size ) ;
446 wxWidgetCocoaImpl* c = NULL;
447
448 if ( style & wxTE_MULTILINE || style & wxTE_RICH || style & wxTE_RICH2 )
449 {
450 wxNSTextView* v = nil;
451 v = [[wxNSTextView alloc] initWithFrame:r];
452 c = new wxNSTextViewControl( wxpeer, v );
453 static_cast<wxNSTextViewControl*>(c)->SetStringValue(str);
454 }
455 else
456 {
457 NSTextField* v = nil;
458 if ( style & wxTE_PASSWORD )
459 v = [[wxNSSecureTextField alloc] initWithFrame:r];
460 else
461 v = [[wxNSTextField alloc] initWithFrame:r];
462
463 if ( style & wxNO_BORDER )
464 {
465 // FIXME: How can we remove the native control's border?
466 // setBordered is separate from the text ctrl's border.
467 }
468
469 [v setBezeled:NO];
470 [v setBordered:NO];
471
472 c = new wxNSTextFieldControl( wxpeer, v );
473 static_cast<wxNSTextFieldControl*>(c)->SetStringValue(str);
474 }
475
476 return c;
477 }
478
479
480 #endif // wxUSE_TEXTCTRL