1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/gtk/msgdlg.cpp
3 // Purpose:     wxMessageDialog for GTK+2
4 // Author:      Vaclav Slavik
5 // Modified by:
6 // Created:     2003/02/28
7 // Copyright:   (c) Vaclav Slavik, 2003
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
13 
14 
15 #if wxUSE_MSGDLG && !defined(__WXGPE__)
16 
17 #include "wx/msgdlg.h"
18 
19 #ifndef WX_PRECOMP
20     #include "wx/intl.h"
21 #endif
22 
23 #include "wx/modalhook.h"
24 
25 #include "wx/gtk/private.h"
26 #include "wx/gtk/private/messagetype.h"
27 #include "wx/gtk/private/mnemonics.h"
28 #include "wx/gtk/private/dialogcount.h"
29 
30 wxIMPLEMENT_CLASS(wxMessageDialog, wxDialog);
31 
wxMessageDialog(wxWindow * parent,const wxString & message,const wxString & caption,long style,const wxPoint & WXUNUSED (pos))32 wxMessageDialog::wxMessageDialog(wxWindow *parent,
33                                  const wxString& message,
34                                  const wxString& caption,
35                                  long style,
36                                  const wxPoint& WXUNUSED(pos))
37                : wxMessageDialogBase
38                  (
39                     parent,
40                     message,
41                     caption,
42                     style
43                  )
44 {
45 }
46 
GetDefaultYesLabel() const47 wxString wxMessageDialog::GetDefaultYesLabel() const
48 {
49 #ifdef __WXGTK4__
50     return wxConvertMnemonicsToGTK(wxGetStockLabel(wxID_YES));
51 #else
52     return "gtk-yes";
53 #endif
54 }
55 
GetDefaultNoLabel() const56 wxString wxMessageDialog::GetDefaultNoLabel() const
57 {
58 #ifdef __WXGTK4__
59     return wxConvertMnemonicsToGTK(wxGetStockLabel(wxID_NO));
60 #else
61     return "gtk-no";
62 #endif
63 }
64 
GetDefaultOKLabel() const65 wxString wxMessageDialog::GetDefaultOKLabel() const
66 {
67 #ifdef __WXGTK4__
68     return wxConvertMnemonicsToGTK(wxGetStockLabel(wxID_OK));
69 #else
70     return "gtk-ok";
71 #endif
72 }
73 
GetDefaultCancelLabel() const74 wxString wxMessageDialog::GetDefaultCancelLabel() const
75 {
76 #ifdef __WXGTK4__
77     return wxConvertMnemonicsToGTK(wxGetStockLabel(wxID_CANCEL));
78 #else
79     return "gtk-cancel";
80 #endif
81 }
82 
GetDefaultHelpLabel() const83 wxString wxMessageDialog::GetDefaultHelpLabel() const
84 {
85 #ifdef __WXGTK4__
86     return wxConvertMnemonicsToGTK(wxGetStockLabel(wxID_HELP));
87 #else
88     return "gtk-help";
89 #endif
90 }
91 
DoSetCustomLabel(wxString & var,const ButtonLabel & label)92 void wxMessageDialog::DoSetCustomLabel(wxString& var, const ButtonLabel& label)
93 {
94     int stockId = label.GetStockId();
95     if ( stockId == wxID_NONE )
96     {
97         wxMessageDialogBase::DoSetCustomLabel(var, label);
98         var = wxConvertMnemonicsToGTK(var);
99     }
100     else // stock label
101     {
102 #ifdef __WXGTK4__
103         var = wxConvertMnemonicsToGTK(wxGetStockLabel(stockId));
104 #else
105         var = wxGetStockGtkID(stockId);
106 #endif
107     }
108 }
109 
GTKCreateMsgDialog()110 void wxMessageDialog::GTKCreateMsgDialog()
111 {
112     // Avoid crash if wxMessageBox() is called before GTK is initialized
113     if (g_type_class_peek(GDK_TYPE_DISPLAY) == NULL)
114         return;
115 
116     GtkWindow * const parent = m_parent ? GTK_WINDOW(m_parent->m_widget) : NULL;
117 
118     GtkMessageType type = GTK_MESSAGE_ERROR;
119     GtkButtonsType buttons = GTK_BUTTONS_NONE;
120 
121     // when using custom labels, we have to add all the buttons ourselves
122     if ( !HasCustomLabels() )
123     {
124         // "Help" button is not supported by predefined combinations so we
125         // always need to create the buttons manually when it's used.
126         if ( !(m_dialogStyle & wxHELP) )
127         {
128             if ( m_dialogStyle & wxYES_NO )
129             {
130                 if ( !(m_dialogStyle & wxCANCEL) )
131                     buttons = GTK_BUTTONS_YES_NO;
132                 //else: no standard GTK_BUTTONS_YES_NO_CANCEL so leave as NONE
133             }
134             else if ( m_dialogStyle & wxOK )
135             {
136                 buttons = m_dialogStyle & wxCANCEL ? GTK_BUTTONS_OK_CANCEL
137                                                    : GTK_BUTTONS_OK;
138             }
139         }
140     }
141 
142     if ( !wxGTKImpl::ConvertMessageTypeFromWX(GetEffectiveIcon(), &type) )
143     {
144         // if no style is explicitly specified, detect the suitable icon
145         // ourselves (this can be disabled by using wxICON_NONE)
146         type = m_dialogStyle & wxYES ? GTK_MESSAGE_QUESTION : GTK_MESSAGE_INFO;
147     }
148 
149     wxString message;
150     bool needsExtMessage = false;
151     if (!m_extendedMessage.empty())
152     {
153         message = m_message;
154         needsExtMessage = true;
155     }
156     else // extended message not needed
157     {
158         message = GetFullMessage();
159     }
160 
161     m_widget = gtk_message_dialog_new(parent,
162                                       GTK_DIALOG_MODAL,
163                                       type,
164                                       buttons,
165                                       "%s",
166                                       (const char*)wxGTK_CONV(message));
167 
168     if ( needsExtMessage )
169     {
170         gtk_message_dialog_format_secondary_text
171         (
172             (GtkMessageDialog *)m_widget,
173             "%s",
174             (const char *)wxGTK_CONV(m_extendedMessage)
175         );
176     }
177 
178     g_object_ref(m_widget);
179 
180     if (m_caption != wxMessageBoxCaptionStr)
181         gtk_window_set_title(GTK_WINDOW(m_widget), wxGTK_CONV(m_caption));
182 
183     GtkDialog * const dlg = GTK_DIALOG(m_widget);
184 
185     if ( m_dialogStyle & wxSTAY_ON_TOP )
186     {
187         gtk_window_set_keep_above(GTK_WINDOW(m_widget), TRUE);
188     }
189 
190     // we need to add buttons manually if we use custom labels or always for
191     // Yes/No/Cancel dialog as GTK+ doesn't support it natively
192     const bool addButtons = buttons == GTK_BUTTONS_NONE;
193 
194 
195     if ( addButtons )
196     {
197         if ( m_dialogStyle & wxHELP )
198         {
199             gtk_dialog_add_button(dlg, wxGTK_CONV(GetHelpLabel()),
200                                   GTK_RESPONSE_HELP);
201         }
202 
203         if ( m_dialogStyle & wxYES_NO ) // Yes/No or Yes/No/Cancel dialog
204         {
205             // Add the buttons in the correct order which is, according to
206             // http://library.gnome.org/devel/hig-book/stable/windows-alert.html.en
207             // the following one:
208             //
209             // [Help]                  [Alternative] [Cancel] [Affirmative]
210 
211             gtk_dialog_add_button(dlg, wxGTK_CONV(GetNoLabel()),
212                                   GTK_RESPONSE_NO);
213 
214             if ( m_dialogStyle & wxCANCEL )
215             {
216                 gtk_dialog_add_button(dlg, wxGTK_CONV(GetCancelLabel()),
217                                       GTK_RESPONSE_CANCEL);
218             }
219 
220             gtk_dialog_add_button(dlg, wxGTK_CONV(GetYesLabel()),
221                                   GTK_RESPONSE_YES);
222         }
223         else // Ok or Ok/Cancel dialog
224         {
225             gtk_dialog_add_button(dlg, wxGTK_CONV(GetOKLabel()), GTK_RESPONSE_OK);
226             if ( m_dialogStyle & wxCANCEL )
227             {
228                 gtk_dialog_add_button(dlg, wxGTK_CONV(GetCancelLabel()),
229                                       GTK_RESPONSE_CANCEL);
230             }
231         }
232     }
233 
234     gint defaultButton;
235     if ( m_dialogStyle & wxCANCEL_DEFAULT )
236         defaultButton = GTK_RESPONSE_CANCEL;
237     else if ( m_dialogStyle & wxNO_DEFAULT )
238         defaultButton = GTK_RESPONSE_NO;
239     else if ( m_dialogStyle & wxYES_NO )
240         defaultButton = GTK_RESPONSE_YES;
241     else if ( m_dialogStyle & wxOK )
242         defaultButton = GTK_RESPONSE_OK;
243     else // No need to change the default value, whatever it is.
244         defaultButton = GTK_RESPONSE_NONE;
245 
246     if ( defaultButton != GTK_RESPONSE_NONE )
247         gtk_dialog_set_default_response(dlg, defaultButton);
248 }
249 
ShowModal()250 int wxMessageDialog::ShowModal()
251 {
252     WX_HOOK_MODAL_DIALOG();
253 
254     if ( !m_widget )
255     {
256         GTKCreateMsgDialog();
257         wxCHECK_MSG( m_widget, wxID_CANCEL,
258                      wxT("failed to create GtkMessageDialog") );
259     }
260 
261     // break the mouse capture as it would interfere with modal dialog (see
262     // wxDialog::ShowModal)
263     GTKReleaseMouseAndNotify();
264 
265     // This should be necessary, but otherwise the
266     // parent TLW will disappear..
267     if (m_parent)
268         gtk_window_present( GTK_WINDOW(m_parent->m_widget) );
269 
270     wxOpenModalDialogLocker modalLocker;
271 
272     gint result = gtk_dialog_run(GTK_DIALOG(m_widget));
273     GTKDisconnect(m_widget);
274     gtk_widget_destroy(m_widget);
275     g_object_unref(m_widget);
276     m_widget = NULL;
277 
278     switch (result)
279     {
280         default:
281             wxFAIL_MSG(wxT("unexpected GtkMessageDialog return code"));
282             wxFALLTHROUGH;
283 
284         case GTK_RESPONSE_CANCEL:
285         case GTK_RESPONSE_DELETE_EVENT:
286         case GTK_RESPONSE_CLOSE:
287             return wxID_CANCEL;
288         case GTK_RESPONSE_OK:
289             return wxID_OK;
290         case GTK_RESPONSE_YES:
291             return wxID_YES;
292         case GTK_RESPONSE_NO:
293             return wxID_NO;
294         case GTK_RESPONSE_HELP:
295             return wxID_HELP;
296     }
297 }
298 
299 
300 #endif // wxUSE_MSGDLG && !defined(__WXGPE__)
301