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