KiCad PCB EDA Suite
Loading...
Searching...
No Matches
confirm.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2007 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 1992-2023, 2024 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include <confirm.h>
26
27#include <functional>
28#include <wx/app.h>
29#include <wx/stockitem.h>
30#include <wx/richmsgdlg.h>
31#include <wx/msgdlg.h>
32#include <wx/choicdlg.h>
33#include <wx/crt.h>
34
35
41static const wxChar traceConfirm[] = wxT( "KICAD_CONFIRM" );
42
43
44bool AskOverrideLock( wxWindow* aParent, const wxString& aMessage )
45{
46#ifdef __APPLE__
47 // wxMessageDialog gets the button spacing wrong on Mac so we have to use wxRichMessageDialog.
48 // Note that its warning icon is more like wxMessageDialog's error icon, so we use it instead
49 // of wxICON_ERROR.
50 wxRichMessageDialog dlg( aParent, aMessage, _( "File Open Warning" ),
51 wxYES_NO | wxICON_WARNING | wxCENTER );
52 dlg.SetExtendedMessage( _( "Interleaved saves may produce very unexpected results." )
53 + wxS( "\n" ) );
54 dlg.SetYesNoLabels( _( "Cancel" ), _( "Open Anyway" ) );
55#else
56 wxMessageDialog dlg( aParent, aMessage, _( "File Open Warning" ),
57 wxYES_NO | wxICON_ERROR | wxCENTER );
58 dlg.SetExtendedMessage( _( "Interleaved saves may produce very unexpected results." ) );
59 dlg.SetYesNoLabels( _( "Cancel" ), _( "Open Anyway" ) );
60#endif
61
62 return dlg.ShowModal() == wxID_NO;
63}
64
65
66int UnsavedChangesDialog( wxWindow* parent, const wxString& aMessage, bool* aApplyToAll )
67{
68 static bool s_apply_to_all = false;
69
70 wxRichMessageDialog dlg( parent, aMessage, _( "Save Changes?" ),
71 wxYES_NO | wxCANCEL | wxYES_DEFAULT | wxICON_WARNING | wxCENTER );
72 dlg.SetExtendedMessage( _( "If you don't save, all your changes will be permanently lost." )
73 + wxS( "\n" ) );
74 dlg.SetYesNoLabels( _( "Save" ), _( "Discard Changes" ) );
75
76 if( aApplyToAll )
77 dlg.ShowCheckBox( _( "Apply to all" ), s_apply_to_all );
78
79 int ret = dlg.ShowModal();
80
81 if( aApplyToAll )
82 {
83 *aApplyToAll = dlg.IsCheckBoxChecked();
84 s_apply_to_all = dlg.IsCheckBoxChecked();
85 }
86
87 // Returns wxID_YES, wxID_NO, or wxID_CANCEL
88 return ret;
89}
90
91
92int UnsavedChangesDialog( wxWindow* parent, const wxString& aMessage )
93{
94#ifdef __APPLE__
95 // wxMessageDialog gets the button order (and spacing) wrong on Mac so we have to use
96 // wxRichMessageDialog.
97 return UnsavedChangesDialog( parent, aMessage, nullptr );
98#else
99 #ifdef _WIN32
100 // wxMessageDialog on windows invokes TaskDialogIndirect which is a native function for a dialog
101 // As a result it skips wxWidgets for modal management...and we don't parent frames properly
102 // among other things for Windows to do the right thing by default
103 // Disable all the windows manually to avoid being able to hit this dialog from the tool frame
104 // and kicad frame at the same time.
105 wxWindowDisabler disable( true );
106 #endif
107
108 wxMessageDialog dlg( parent, aMessage, _( "Save Changes?" ),
109 wxYES_NO | wxCANCEL | wxYES_DEFAULT | wxICON_WARNING | wxCENTER );
110 dlg.SetExtendedMessage( _( "If you don't save, all your changes will be permanently lost." ) );
111 dlg.SetYesNoLabels( _( "Save" ), _( "Discard Changes" ) );
112
113 // Returns wxID_YES, wxID_NO, or wxID_CANCEL
114 return dlg.ShowModal();
115#endif
116}
117
118
119bool ConfirmRevertDialog( wxWindow* parent, const wxString& aMessage )
120{
121 wxMessageDialog dlg( parent, aMessage, wxEmptyString,
122 wxOK | wxCANCEL | wxOK_DEFAULT | wxICON_WARNING | wxCENTER );
123 dlg.SetExtendedMessage( _( "Your current changes will be permanently lost." ) );
124 dlg.SetOKCancelLabels( _( "Revert" ), _( "Cancel" ) );
125
126 return dlg.ShowModal() == wxID_OK;
127}
128
129
130bool HandleUnsavedChanges( wxWindow* aParent, const wxString& aMessage,
131 const std::function<bool()>& aSaveFunction )
132{
133 switch( UnsavedChangesDialog( aParent, aMessage ) )
134 {
135 case wxID_YES: return aSaveFunction();
136 case wxID_NO: return true;
137 default:
138 case wxID_CANCEL: return false;
139 }
140}
141
142
143int OKOrCancelDialog( wxWindow* aParent, const wxString& aWarning, const wxString& aMessage,
144 const wxString& aDetailedMessage, const wxString& aOKLabel,
145 const wxString& aCancelLabel, bool* aApplyToAll )
146{
147 wxRichMessageDialog dlg( aParent, aMessage, aWarning,
148 wxOK | wxCANCEL | wxOK_DEFAULT | wxICON_WARNING | wxCENTER );
149
150 dlg.SetOKCancelLabels( ( aOKLabel.IsEmpty() ) ? _( "OK" ) : aOKLabel,
151 ( aCancelLabel.IsEmpty() ) ? _( "Cancel" ) : aCancelLabel );
152
153 if( !aDetailedMessage.IsEmpty() )
154 dlg.SetExtendedMessage( aDetailedMessage );
155
156 if( aApplyToAll )
157 dlg.ShowCheckBox( _( "Apply to all" ), true );
158
159 int ret = dlg.ShowModal();
160
161 if( aApplyToAll )
162 *aApplyToAll = dlg.IsCheckBoxChecked();
163
164 // Returns wxID_OK or wxID_CANCEL
165 return ret;
166}
167
168
169// DisplayError should be deprecated, use DisplayErrorMessage instead
170void DisplayError( wxWindow* aParent, const wxString& aText, int aDisplayTime )
171{
172 if( !wxTheApp || !wxTheApp->IsMainLoopRunning() )
173 {
174 wxLogError( "%s", aText );
175 return;
176 }
177
178 if( !wxTheApp->IsGUI() )
179 {
180 wxFprintf( stderr, aText );
181 return;
182 }
183
184 wxMessageDialog* dlg;
185 int icon = aDisplayTime > 0 ? wxICON_INFORMATION : wxICON_ERROR;
186
187 dlg = new wxMessageDialog( aParent, aText, _( "Warning" ),
188 wxOK | wxCENTRE | wxRESIZE_BORDER | icon | wxSTAY_ON_TOP );
189
190 dlg->ShowModal();
191 dlg->Destroy();
192}
193
194
195void DisplayErrorMessage( wxWindow* aParent, const wxString& aText, const wxString& aExtraInfo )
196{
197 if( !wxTheApp || !wxTheApp->IsMainLoopRunning() )
198 {
199 wxLogError( "%s %s", aText, aExtraInfo );
200 return;
201 }
202
203 if( !wxTheApp->IsGUI() )
204 {
205 wxFprintf( stderr, aText );
206 return;
207 }
208
209 wxMessageDialog* dlg;
210
211 dlg = new wxMessageDialog( aParent, aText, _( "Error" ),
212 wxOK | wxCENTRE | wxRESIZE_BORDER | wxICON_ERROR | wxSTAY_ON_TOP );
213
214 if( !aExtraInfo.IsEmpty() )
215 dlg->SetExtendedMessage( aExtraInfo );
216
217 dlg->ShowModal();
218 dlg->Destroy();
219}
220
221
222void DisplayInfoMessage( wxWindow* aParent, const wxString& aMessage, const wxString& aExtraInfo )
223{
224 if( !wxTheApp || !wxTheApp->GetTopWindow() )
225 {
226 wxLogTrace( traceConfirm, wxS( "%s %s" ), aMessage, aExtraInfo );
227 return;
228 }
229
230 if( !wxTheApp->IsGUI() )
231 {
232 wxFprintf( stdout, "%s %s", aMessage, aExtraInfo );
233 return;
234 }
235
236 wxMessageDialog* dlg;
237 int icon = wxICON_INFORMATION;
238
239 dlg = new wxMessageDialog( aParent, aMessage, _( "Information" ),
240 wxOK | wxCENTRE | wxRESIZE_BORDER | icon | wxSTAY_ON_TOP );
241
242 if( !aExtraInfo.IsEmpty() )
243 dlg->SetExtendedMessage( aExtraInfo );
244
245 dlg->ShowModal();
246 dlg->Destroy();
247}
248
249
250bool IsOK( wxWindow* aParent, const wxString& aMessage )
251{
252 // wxMessageDialog no longer responds correctly to the <ESC> key (on at least OSX and MSW)
253 // so we're now using wxRichMessageDialog.
254 //
255 // Note also that we have to repurpose an OK/Cancel version of it because otherwise wxWidgets
256 // uses "destructive" spacing for the "No" button.
257
258#ifdef __APPLE__
259 // Why is wxICON_QUESTION a light-bulb on Mac? That has more of a hint or info connotation.
260 int icon = wxICON_WARNING;
261#else
262 int icon = wxICON_QUESTION;
263#endif
264
265#if !defined( __WXGTK__ )
266 wxRichMessageDialog dlg( aParent, aMessage, _( "Confirmation" ),
267 wxOK | wxCANCEL | wxOK_DEFAULT | wxCENTRE | icon | wxSTAY_ON_TOP );
268#else
269 wxMessageDialog dlg( aParent, aMessage, _( "Confirmation" ),
270 wxOK | wxCANCEL | wxOK_DEFAULT | wxCENTRE | icon | wxSTAY_ON_TOP );
271#endif
272
273 dlg.SetOKCancelLabels( _( "Yes" ), _( "No" ) );
274
275 return dlg.ShowModal() == wxID_OK;
276}
277
278
279int SelectSingleOption( wxWindow* aParent, const wxString& aTitle,
280 const wxString& aMessage, const wxArrayString& aOptions )
281{
282 wxSingleChoiceDialog dlg( aParent, aMessage, aTitle, aOptions );
283
284 if( dlg.ShowModal() != wxID_OK )
285 return -1;
286
287 return dlg.GetSelection();
288}
289
bool AskOverrideLock(wxWindow *aParent, const wxString &aMessage)
Display a dialog indicating the file is already open, with an option to reset the lock.
Definition: confirm.cpp:44
int SelectSingleOption(wxWindow *aParent, const wxString &aTitle, const wxString &aMessage, const wxArrayString &aOptions)
Display a dialog with radioboxes asking the user to select an option.
Definition: confirm.cpp:279
int OKOrCancelDialog(wxWindow *aParent, const wxString &aWarning, const wxString &aMessage, const wxString &aDetailedMessage, const wxString &aOKLabel, const wxString &aCancelLabel, bool *aApplyToAll)
Display a warning dialog with aMessage and returns the user response.
Definition: confirm.cpp:143
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:250
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:170
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition: confirm.cpp:222
bool HandleUnsavedChanges(wxWindow *aParent, const wxString &aMessage, const std::function< bool()> &aSaveFunction)
Display a dialog with Save, Cancel and Discard Changes buttons.
Definition: confirm.cpp:130
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:195
int UnsavedChangesDialog(wxWindow *parent, const wxString &aMessage, bool *aApplyToAll)
A specialized version of HandleUnsavedChanges which handles an apply-to-all checkbox.
Definition: confirm.cpp:66
bool ConfirmRevertDialog(wxWindow *parent, const wxString &aMessage)
Display a confirmation dialog for a revert action.
Definition: confirm.cpp:119
This file is part of the common library.
#define _(s)
static const wxChar traceConfirm[]
Flag to enable confirmation dialog debugging output.
Definition: confirm.cpp:41