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