]> git.saurik.com Git - wxWidgets.git/blob - src/osx/cocoa/msgdlg.mm
using suppression of idle processing (delayed destruction happened too early eg when...
[wxWidgets.git] / src / osx / cocoa / msgdlg.mm
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/cocoa/msgdlg.mm
3 // Purpose: wxMessageDialog
4 // Author: Stefan Csomor
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #include "wx/msgdlg.h"
15
16 #ifndef WX_PRECOMP
17 #include "wx/intl.h"
18 #include "wx/app.h"
19 #endif
20
21 #include "wx/control.h"
22 #include "wx/thread.h"
23 #include "wx/evtloop.h"
24 #include "wx/osx/private.h"
25
26
27 IMPLEMENT_CLASS(wxMessageDialog, wxDialog)
28
29
30 namespace
31 {
32 NSAlertStyle GetAlertStyleFromWXStyle( long style )
33 {
34 NSAlertStyle alertType = NSWarningAlertStyle;
35 if (style & wxICON_EXCLAMATION)
36 alertType = NSCriticalAlertStyle;
37 else if (style & wxICON_HAND)
38 alertType = NSWarningAlertStyle;
39 else if (style & wxICON_INFORMATION)
40 alertType = NSInformationalAlertStyle;
41 else if (style & wxICON_QUESTION)
42 alertType = NSInformationalAlertStyle;
43 return alertType;
44 }
45 }
46
47 wxMessageDialog::wxMessageDialog(wxWindow *parent,
48 const wxString& message,
49 const wxString& caption,
50 long style,
51 const wxPoint& WXUNUSED(pos))
52 : wxMessageDialogBase(parent, message, caption, style)
53 {
54 m_sheetDelegate = [[ModalDialogDelegate alloc] init];
55 [(ModalDialogDelegate*)m_sheetDelegate setImplementation: this];
56 }
57
58 wxMessageDialog::~wxMessageDialog()
59 {
60 [m_sheetDelegate release];
61 }
62
63 int wxMessageDialog::ShowModal()
64 {
65 wxCFEventLoopPauseObservers pause;
66
67 int resultbutton = wxID_CANCEL;
68
69 const long style = GetMessageDialogStyle();
70
71 wxASSERT_MSG( (style & 0x3F) != wxYES, wxT("this style is not supported on Mac") );
72
73 // work out what to display
74 // if the extended text is empty then we use the caption as the title
75 // and the message as the text (for backwards compatibility)
76 // but if the extended message is not empty then we use the message as the title
77 // and the extended message as the text because that makes more sense
78
79 wxString msgtitle,msgtext;
80 if(m_extendedMessage.IsEmpty())
81 {
82 msgtitle = m_caption;
83 msgtext = m_message;
84 }
85 else
86 {
87 msgtitle = m_message;
88 msgtext = m_extendedMessage;
89 }
90
91
92 if ( !wxIsMainThread() )
93 {
94 CFStringRef defaultButtonTitle = NULL;
95 CFStringRef alternateButtonTitle = NULL;
96 CFStringRef otherButtonTitle = NULL;
97
98 wxCFStringRef cfTitle( msgtitle, GetFont().GetEncoding() );
99 wxCFStringRef cfText( msgtext, GetFont().GetEncoding() );
100
101 wxCFStringRef cfNoString( wxControl::GetLabelText(GetNoLabel()), GetFont().GetEncoding() );
102 wxCFStringRef cfYesString( wxControl::GetLabelText(GetYesLabel()), GetFont().GetEncoding() );
103 wxCFStringRef cfOKString( wxControl::GetLabelText(GetOKLabel()), GetFont().GetEncoding()) ;
104 wxCFStringRef cfCancelString( wxControl::GetLabelText(GetCancelLabel()), GetFont().GetEncoding() );
105
106 NSAlertStyle alertType = GetAlertStyleFromWXStyle(style);
107
108 int m_buttonId[4] = { 0, 0, 0, wxID_CANCEL /* time-out */ };
109
110 if (style & wxYES_NO)
111 {
112 if ( style & wxNO_DEFAULT )
113 {
114 defaultButtonTitle = cfNoString;
115 alternateButtonTitle = cfYesString;
116 m_buttonId[0] = wxID_NO;
117 m_buttonId[1] = wxID_YES;
118 }
119 else
120 {
121 defaultButtonTitle = cfYesString;
122 alternateButtonTitle = cfNoString;
123 m_buttonId[0] = wxID_YES;
124 m_buttonId[1] = wxID_NO;
125 }
126 if (style & wxCANCEL)
127 {
128 otherButtonTitle = cfCancelString;
129 m_buttonId[2] = wxID_CANCEL;
130 }
131 }
132 else
133 {
134 // the MSW implementation even shows an OK button if it is not specified, we'll do the same
135 m_buttonId[0] = wxID_OK;
136 // using null as default title does not work on earlier systems
137 defaultButtonTitle = cfOKString;
138 if (style & wxCANCEL)
139 {
140 alternateButtonTitle = cfCancelString;
141 m_buttonId[1] = wxID_CANCEL;
142 }
143 }
144
145 wxASSERT_MSG( !(style & wxHELP), "wxHELP not supported in non-GUI thread" );
146
147 CFOptionFlags exitButton;
148 OSStatus err = CFUserNotificationDisplayAlert(
149 0, alertType, NULL, NULL, NULL, cfTitle, cfText,
150 defaultButtonTitle, alternateButtonTitle, otherButtonTitle, &exitButton );
151 if (err == noErr)
152 resultbutton = m_buttonId[exitButton];
153 }
154 else
155 {
156 NSAlert* alert = (NSAlert*)ConstructNSAlert();
157
158 int button = -1;
159 button = [alert runModal];
160 [alert release];
161 ModalFinishedCallback(alert, button);
162 }
163
164 return GetReturnCode();
165 }
166
167 void wxMessageDialog::ShowWindowModal()
168 {
169 NSAlert* alert = (NSAlert*)ConstructNSAlert();
170
171 wxNonOwnedWindow* parentWindow = NULL;
172
173 m_modality = wxDIALOG_MODALITY_WINDOW_MODAL;
174
175 if (GetParent())
176 parentWindow = dynamic_cast<wxNonOwnedWindow*>(wxGetTopLevelParent(GetParent()));
177
178 wxASSERT_MSG(parentWindow, "Window modal display requires parent.");
179
180 if (parentWindow)
181 {
182 NSWindow* nativeParent = parentWindow->GetWXWindow();
183 [alert beginSheetModalForWindow: nativeParent modalDelegate: m_sheetDelegate
184 didEndSelector: @selector(sheetDidEnd:returnCode:contextInfo:)
185 contextInfo: nil];
186 }
187 }
188
189 void wxMessageDialog::ModalFinishedCallback(void* WXUNUSED(panel), int resultCode)
190 {
191 int resultbutton = wxID_CANCEL;
192 if ( resultCode < NSAlertFirstButtonReturn )
193 resultbutton = wxID_CANCEL;
194 else
195 {
196 if ( resultCode - NSAlertFirstButtonReturn < m_buttonCount )
197 resultbutton = m_buttonId[ resultCode - NSAlertFirstButtonReturn ];
198 else
199 resultbutton = wxID_CANCEL;
200 }
201 SetReturnCode(resultbutton);
202
203 if (GetModality() == wxDIALOG_MODALITY_WINDOW_MODAL)
204 SendWindowModalDialogEvent ( wxEVT_WINDOW_MODAL_DIALOG_CLOSED );
205 }
206
207 void* wxMessageDialog::ConstructNSAlert()
208 {
209 const long style = GetMessageDialogStyle();
210
211 wxASSERT_MSG( (style & 0x3F) != wxYES, wxT("this style is not supported on Mac") );
212
213 // work out what to display
214 // if the extended text is empty then we use the caption as the title
215 // and the message as the text (for backwards compatibility)
216 // but if the extended message is not empty then we use the message as the title
217 // and the extended message as the text because that makes more sense
218
219 wxString msgtitle,msgtext;
220 if(m_extendedMessage.IsEmpty())
221 {
222 msgtitle = m_caption;
223 msgtext = m_message;
224 }
225 else
226 {
227 msgtitle = m_message;
228 msgtext = m_extendedMessage;
229 }
230
231 NSAlert* alert = [[NSAlert alloc] init];
232 NSAlertStyle alertType = GetAlertStyleFromWXStyle(style);
233
234 wxCFStringRef cfNoString( wxControl::GetLabelText(GetNoLabel()), GetFont().GetEncoding() );
235 wxCFStringRef cfYesString( wxControl::GetLabelText(GetYesLabel()), GetFont().GetEncoding() );
236 wxCFStringRef cfOKString( wxControl::GetLabelText(GetOKLabel()), GetFont().GetEncoding() );
237 wxCFStringRef cfCancelString( wxControl::GetLabelText(GetCancelLabel()), GetFont().GetEncoding() );
238
239 wxCFStringRef cfTitle( msgtitle, GetFont().GetEncoding() );
240 wxCFStringRef cfText( msgtext, GetFont().GetEncoding() );
241
242 [alert setMessageText:cfTitle.AsNSString()];
243 [alert setInformativeText:cfText.AsNSString()];
244 [alert setAlertStyle:alertType];
245
246 m_buttonCount = 0;
247
248 if (style & wxYES_NO)
249 {
250 if ( style & wxNO_DEFAULT )
251 {
252 [alert addButtonWithTitle:cfNoString.AsNSString()];
253 m_buttonId[ m_buttonCount++ ] = wxID_NO;
254 [alert addButtonWithTitle:cfYesString.AsNSString()];
255 m_buttonId[ m_buttonCount++ ] = wxID_YES;
256 }
257 else
258 {
259 [alert addButtonWithTitle:cfYesString.AsNSString()];
260 m_buttonId[ m_buttonCount++ ] = wxID_YES;
261 [alert addButtonWithTitle:cfNoString.AsNSString()];
262 m_buttonId[ m_buttonCount++ ] = wxID_NO;
263 }
264
265 if (style & wxCANCEL)
266 {
267 [alert addButtonWithTitle:cfCancelString.AsNSString()];
268 m_buttonId[ m_buttonCount++ ] = wxID_CANCEL;
269 }
270 }
271 // the MSW implementation even shows an OK button if it is not specified, we'll do the same
272 else
273 {
274 if ( style & wxCANCEL_DEFAULT )
275 {
276 [alert addButtonWithTitle:cfCancelString.AsNSString()];
277 m_buttonId[ m_buttonCount++ ] = wxID_CANCEL;
278
279 [alert addButtonWithTitle:cfOKString.AsNSString()];
280 m_buttonId[ m_buttonCount++ ] = wxID_OK;
281 }
282 else
283 {
284 [alert addButtonWithTitle:cfOKString.AsNSString()];
285 m_buttonId[ m_buttonCount++ ] = wxID_OK;
286 if (style & wxCANCEL)
287 {
288 [alert addButtonWithTitle:cfCancelString.AsNSString()];
289 m_buttonId[ m_buttonCount++ ] = wxID_CANCEL;
290 }
291 }
292
293 }
294
295 if ( style & wxHELP )
296 {
297 wxCFStringRef cfHelpString( GetHelpLabel(), GetFont().GetEncoding() );
298 [alert addButtonWithTitle:cfHelpString.AsNSString()];
299 m_buttonId[ m_buttonCount++ ] = wxID_HELP;
300 }
301
302 wxASSERT_MSG( m_buttonCount <= WXSIZEOF(m_buttonId), "Too many buttons" );
303
304 return alert;
305 }