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 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 <wx/app.h>
26#include <wx/stockitem.h>
27#include <wx/richmsgdlg.h>
28#include <wx/choicdlg.h>
29#include <wx/crt.h>
30#include <confirm.h>
32#include <functional>
33#include <unordered_map>
34#include <pgm_base.h>
35#include "cli/cli_names.h"
36
37// Set of dialogs that have been chosen not to be shown again
38static std::unordered_map<unsigned long, int> doNotShowAgainDlgs;
39
40
41KIDIALOG::KIDIALOG( wxWindow* aParent, const wxString& aMessage, const wxString& aCaption,
42 long aStyle )
43 : wxRichMessageDialog( aParent, aMessage, aCaption, aStyle | wxCENTRE | wxSTAY_ON_TOP ),
44 m_hash( 0 ),
45 m_cancelMeansCancel( true )
46{
47}
48
49
50KIDIALOG::KIDIALOG( wxWindow* aParent, const wxString& aMessage, KD_TYPE aType,
51 const wxString& aCaption )
52 : wxRichMessageDialog( aParent, aMessage, getCaption( aType, aCaption ), getStyle( aType ) ),
53 m_hash( 0 ),
54 m_cancelMeansCancel( true )
55{
56}
57
58
59void KIDIALOG::DoNotShowCheckbox( wxString aUniqueId, int line )
60{
61 ShowCheckBox( _( "Do not show again" ), false );
62
63 m_hash = std::hash<wxString>{}( aUniqueId ) + line;
64}
65
66
68{
69 return doNotShowAgainDlgs.count( m_hash ) > 0;
70}
71
72
74{
76}
77
78
79bool KIDIALOG::Show( bool aShow )
80{
81 // We should check the do-not-show-again setting only when the dialog is displayed
82 if( aShow )
83 {
84 // Check if this dialog should be shown to the user
85 auto it = doNotShowAgainDlgs.find( m_hash );
86
87 if( it != doNotShowAgainDlgs.end() )
88 return it->second;
89 }
90
91 int ret = wxRichMessageDialog::Show( aShow );
92
93 // Has the user asked not to show the dialog again?
94 // Note that we don't save a Cancel value unless the Cancel button is being used for some
95 // other function (which is actually more common than it being used for Cancel).
96 if( IsCheckBoxChecked() && (!m_cancelMeansCancel || ret != wxID_CANCEL ) )
98
99 return ret;
100}
101
102
104{
105 // Check if this dialog should be shown to the user
106 auto it = doNotShowAgainDlgs.find( m_hash );
107
108 if( it != doNotShowAgainDlgs.end() )
109 return it->second;
110
111 int ret = wxRichMessageDialog::ShowModal();
112
113 // Has the user asked not to show the dialog again?
114 // Note that we don't save a Cancel value unless the Cancel button is being used for some
115 // other function (which is actually more common than it being used for Cancel).
116 if( IsCheckBoxChecked() && (!m_cancelMeansCancel || ret != wxID_CANCEL ) )
118
119 return ret;
120}
121
122
123wxString KIDIALOG::getCaption( KD_TYPE aType, const wxString& aCaption )
124{
125 if( !aCaption.IsEmpty() )
126 return aCaption;
127
128 switch( aType )
129 {
130 case KD_NONE: /* fall through */
131 case KD_INFO: return _( "Message" );
132 case KD_QUESTION: return _( "Question" );
133 case KD_WARNING: return _( "Warning" );
134 case KD_ERROR: return _( "Error" );
135 }
136
137 return wxEmptyString;
138}
139
140
142{
143 long style = wxOK | wxCENTRE | wxSTAY_ON_TOP;
144
145 switch( aType )
146 {
147 case KD_NONE: break;
148 case KD_INFO: style |= wxICON_INFORMATION; break;
149 case KD_QUESTION: style |= wxICON_QUESTION; break;
150 case KD_WARNING: style |= wxICON_WARNING; break;
151 case KD_ERROR: style |= wxICON_ERROR; break;
152 }
153
154 return style;
155}
156
157
158bool OverrideLock( wxWindow* aParent, const wxString& aMessage )
159{
160#ifdef __APPLE__
161 // wxMessageDialog gets the button spacing wrong on Mac so we have to use wxRichMessageDialog.
162 // Note that its warning icon is more like wxMessageDialog's error icon, so we use it instead
163 // of wxICON_ERROR.
164 wxRichMessageDialog dlg( aParent, aMessage, _( "File Open Warning" ),
165 wxYES_NO | wxICON_WARNING | wxCENTER );
166 dlg.SetExtendedMessage( _( "Interleaved saves may produce very unexpected results." )
167 + wxS( "\n" ) );
168 dlg.SetYesNoLabels( _( "Cancel" ), _( "Open Anyway" ) );
169#else
170 wxMessageDialog dlg( aParent, aMessage, _( "File Open Warning" ),
171 wxYES_NO | wxICON_ERROR | wxCENTER );
172 dlg.SetExtendedMessage( _( "Interleaved saves may produce very unexpected results." ) );
173 dlg.SetYesNoLabels( _( "Cancel" ), _( "Open Anyway" ) );
174#endif
175
176 return dlg.ShowModal() == wxID_NO;
177}
178
179
180int UnsavedChangesDialog( wxWindow* parent, const wxString& aMessage, bool* aApplyToAll )
181{
182 static bool s_apply_to_all = false;
183
184 wxRichMessageDialog dlg( parent, aMessage, _( "Save Changes?" ),
185 wxYES_NO | wxCANCEL | wxYES_DEFAULT | wxICON_WARNING | wxCENTER );
186 dlg.SetExtendedMessage( _( "If you don't save, all your changes will be permanently lost." )
187 + wxS( "\n" ) );
188 dlg.SetYesNoLabels( _( "Save" ), _( "Discard Changes" ) );
189
190 if( aApplyToAll )
191 dlg.ShowCheckBox( _( "Apply to all" ), s_apply_to_all );
192
193 int ret = dlg.ShowModal();
194
195 if( aApplyToAll )
196 {
197 *aApplyToAll = dlg.IsCheckBoxChecked();
198 s_apply_to_all = dlg.IsCheckBoxChecked();
199 }
200
201 // Returns wxID_YES, wxID_NO, or wxID_CANCEL
202 return ret;
203}
204
205
206int UnsavedChangesDialog( wxWindow* parent, const wxString& aMessage )
207{
208#ifdef __APPLE__
209 // wxMessageDialog gets the button order (and spacing) wrong on Mac so we have to use
210 // wxRichMessageDialog.
211 return UnsavedChangesDialog( parent, aMessage, nullptr );
212#else
213 #ifdef _WIN32
214 // wxMessageDialog on windows invokes TaskDialogIndirect which is a native function for a dialog
215 // As a result it skips wxWidgets for modal management...and we don't parent frames properly
216 // among other things for Windows to do the right thing by default
217 // Disable all the windows manually to avoid being able to hit this dialog from the tool frame and kicad frame at the same time
218 wxWindowDisabler disable( true );
219 #endif
220
221 wxMessageDialog dlg( parent, aMessage, _( "Save Changes?" ),
222 wxYES_NO | wxCANCEL | wxYES_DEFAULT | wxICON_WARNING | wxCENTER );
223 dlg.SetExtendedMessage( _( "If you don't save, all your changes will be permanently lost." ) );
224 dlg.SetYesNoLabels( _( "Save" ), _( "Discard Changes" ) );
225
226 // Returns wxID_YES, wxID_NO, or wxID_CANCEL
227 return dlg.ShowModal();
228#endif
229}
230
231
232bool ConfirmRevertDialog( wxWindow* parent, const wxString& aMessage )
233{
234 wxMessageDialog dlg( parent, aMessage, wxEmptyString,
235 wxOK | wxCANCEL | wxOK_DEFAULT | wxICON_WARNING | wxCENTER );
236 dlg.SetExtendedMessage( _( "Your current changes will be permanently lost." ) );
237 dlg.SetOKCancelLabels( _( "Revert" ), _( "Cancel" ) );
238
239 return dlg.ShowModal() == wxID_OK;
240}
241
242
243bool HandleUnsavedChanges( wxWindow* aParent, const wxString& aMessage,
244 const std::function<bool()>& aSaveFunction )
245{
246 switch( UnsavedChangesDialog( aParent, aMessage ) )
247 {
248 case wxID_YES: return aSaveFunction();
249 case wxID_NO: return true;
250 default:
251 case wxID_CANCEL: return false;
252 }
253}
254
255
256int OKOrCancelDialog( wxWindow* aParent, const wxString& aWarning, const wxString& aMessage,
257 const wxString& aDetailedMessage, const wxString& aOKLabel,
258 const wxString& aCancelLabel, bool* aApplyToAll )
259{
260 wxRichMessageDialog dlg( aParent, aMessage, aWarning,
261 wxOK | wxCANCEL | wxOK_DEFAULT | wxICON_WARNING | wxCENTER );
262
263 dlg.SetOKCancelLabels( ( aOKLabel.IsEmpty() ) ? _( "OK" ) : aOKLabel,
264 ( aCancelLabel.IsEmpty() ) ? _( "Cancel" ) : aCancelLabel );
265
266 if( !aDetailedMessage.IsEmpty() )
267 dlg.SetExtendedMessage( aDetailedMessage );
268
269 if( aApplyToAll )
270 dlg.ShowCheckBox( _( "Apply to all" ), true );
271
272 int ret = dlg.ShowModal();
273
274 if( aApplyToAll )
275 *aApplyToAll = dlg.IsCheckBoxChecked();
276
277 // Returns wxID_OK or wxID_CANCEL
278 return ret;
279}
280
281
282// DisplayError should be deprecated, use DisplayErrorMessage instead
283void DisplayError( wxWindow* aParent, const wxString& aText, int aDisplayTime )
284{
285 if( !wxTheApp || !wxTheApp->IsMainLoopRunning() )
286 {
287 wxLogError( "%s", aText );
288 return;
289 }
290
291 if( !Pgm().IsGUI() )
292 {
293 wxFprintf( stderr, aText );
294 return;
295 }
296
297 wxMessageDialog* dlg;
298 int icon = aDisplayTime > 0 ? wxICON_INFORMATION : wxICON_ERROR;
299
300 dlg = new wxMessageDialog( aParent, aText, _( "Warning" ),
301 wxOK | wxCENTRE | wxRESIZE_BORDER | icon | wxSTAY_ON_TOP );
302
303 dlg->ShowModal();
304 dlg->Destroy();
305}
306
307
308void DisplayErrorMessage( wxWindow* aParent, const wxString& aText, const wxString& aExtraInfo )
309{
310 if( !wxTheApp || !wxTheApp->IsMainLoopRunning() )
311 {
312 wxLogError( "%s %s", aText, aExtraInfo );
313 return;
314 }
315
316 if( !Pgm().IsGUI() )
317 {
318 wxFprintf( stderr, aText );
319 return;
320 }
321
322 wxMessageDialog* dlg;
323
324 dlg = new wxMessageDialog( aParent, aText, _( "Error" ),
325 wxOK | wxCENTRE | wxRESIZE_BORDER | wxICON_ERROR | wxSTAY_ON_TOP );
326
327 if( !aExtraInfo.IsEmpty() )
328 dlg->SetExtendedMessage( aExtraInfo );
329
330 dlg->ShowModal();
331 dlg->Destroy();
332}
333
334
335void DisplayInfoMessage( wxWindow* aParent, const wxString& aMessage, const wxString& aExtraInfo )
336{
337 if( !wxTheApp || !wxTheApp->GetTopWindow() )
338 {
339 wxLogDebug( "%s %s", aMessage, aExtraInfo );
340 return;
341 }
342
343 if( !Pgm().IsGUI() )
344 {
345 wxFprintf( stdout, "%s %s", aMessage, aExtraInfo );
346 return;
347 }
348
349 wxMessageDialog* dlg;
350 int icon = wxICON_INFORMATION;
351
352 dlg = new wxMessageDialog( aParent, aMessage, _( "Information" ),
353 wxOK | wxCENTRE | wxRESIZE_BORDER | icon | wxSTAY_ON_TOP );
354
355 if( !aExtraInfo.IsEmpty() )
356 dlg->SetExtendedMessage( aExtraInfo );
357
358 dlg->ShowModal();
359 dlg->Destroy();
360}
361
362
363bool IsOK( wxWindow* aParent, const wxString& aMessage )
364{
365 // wxMessageDialog no longer responds correctly to the <ESC> key (on at least OSX and MSW)
366 // so we're now using wxRichMessageDialog.
367 //
368 // Note also that we have to repurpose an OK/Cancel version of it because otherwise wxWidgets
369 // uses "destructive" spacing for the "No" button.
370
371#ifdef __APPLE__
372 // Why is wxICON_QUESTION a light-bulb on Mac? That has more of a hint or info connotation.
373 int icon = wxICON_WARNING;
374#else
375 int icon = wxICON_QUESTION;
376#endif
377
378#if !defined( __WXGTK__ )
379 wxRichMessageDialog dlg( aParent, aMessage, _( "Confirmation" ),
380 wxOK | wxCANCEL | wxOK_DEFAULT | wxCENTRE | icon | wxSTAY_ON_TOP );
381#else
382 wxMessageDialog dlg( aParent, aMessage, _( "Confirmation" ),
383 wxOK | wxCANCEL | wxOK_DEFAULT | wxCENTRE | icon | wxSTAY_ON_TOP );
384#endif
385
386 dlg.SetOKCancelLabels( _( "Yes" ), _( "No" ) );
387
388 return dlg.ShowModal() == wxID_OK;
389}
390
391
392int SelectSingleOption( wxWindow* aParent, const wxString& aTitle,
393 const wxString& aMessage, const wxArrayString& aOptions )
394{
395 wxSingleChoiceDialog dlg( aParent, aMessage, aTitle, aOptions );
396
397 if( dlg.ShowModal() != wxID_OK )
398 return -1;
399
400 return dlg.GetSelection();
401}
402
KD_TYPE
< Dialog type. Selects appropriate icon and default dialog title
Definition: confirm.h:49
@ KD_INFO
Definition: confirm.h:49
@ KD_QUESTION
Definition: confirm.h:49
@ KD_ERROR
Definition: confirm.h:49
@ KD_NONE
Definition: confirm.h:49
@ KD_WARNING
Definition: confirm.h:49
void ForceShowAgain()
Definition: confirm.cpp:73
bool DoNotShowAgain() const
Definition: confirm.cpp:67
bool m_cancelMeansCancel
Definition: confirm.h:79
static long getStyle(KD_TYPE aType)
Definition: confirm.cpp:141
unsigned long m_hash
Definition: confirm.h:78
KIDIALOG(wxWindow *aParent, const wxString &aMessage, const wxString &aCaption, long aStyle=wxOK)
Definition: confirm.cpp:41
void DoNotShowCheckbox(wxString file, int line)
Checks the 'do not show again' setting for the dialog.
Definition: confirm.cpp:59
int ShowModal() override
Definition: confirm.cpp:103
static wxString getCaption(KD_TYPE aType, const wxString &aCaption)
Definition: confirm.cpp:123
bool Show(bool aShow=true) override
Definition: confirm.cpp:79
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:392
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:256
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:363
static std::unordered_map< unsigned long, int > doNotShowAgainDlgs
Definition: confirm.cpp:38
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:283
bool OverrideLock(wxWindow *aParent, const wxString &aMessage)
Display a dialog indicating the file is already open, with an option to reset the lock.
Definition: confirm.cpp:158
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition: confirm.cpp:335
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:243
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:308
int UnsavedChangesDialog(wxWindow *parent, const wxString &aMessage, bool *aApplyToAll)
A specialized version of HandleUnsavedChanges which handles an apply-to-all checkbox.
Definition: confirm.cpp:180
bool ConfirmRevertDialog(wxWindow *parent, const wxString &aMessage)
Display a confirmation dialog for a revert action.
Definition: confirm.cpp:232
This file is part of the common library.
#define _(s)
see class PGM_BASE
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:115