KiCad PCB EDA Suite
Loading...
Searching...
No Matches
validators.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) 2013 Wayne Stambaugh <[email protected]>
5 * Copyright (C) 2004-2019 KiCad Developers, see change_log.txt for contributors.
6 * Copyright (C) 2018 CERN
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
31#include <string_utils.h>
32#include <confirm.h>
33#include <validators.h>
34#include <template_fieldnames.h>
35
36#include <wx/grid.h>
37#include <wx/textctrl.h>
38#include <wx/textentry.h>
39#include <wx/log.h>
40#include <wx/combo.h>
41
43{
44}
45
46
47void GRID_CELL_TEXT_EDITOR::SetValidator( const wxValidator& validator )
48{
49 // keep our own copy because wxGridCellTextEditor's is annoyingly private
50 m_validator.reset( static_cast<wxValidator*>( validator.Clone() ) );
51
52 wxGridCellTextEditor::SetValidator( *m_validator );
53}
54
55
56void GRID_CELL_TEXT_EDITOR::StartingKey( wxKeyEvent& event )
57{
58 if( m_validator )
59 {
60 m_validator.get()->SetWindow( Text() );
61 m_validator.get()->ProcessEvent( event );
62 }
63
64 if( event.GetSkipped() )
65 {
66 wxGridCellTextEditor::StartingKey( event );
67 event.Skip( false );
68 }
69}
70
71
73 wxTextValidator( wxFILTER_EXCLUDE_CHAR_LIST, aValue )
74{
75 // This list of characters follows the string from footprint.cpp which, in turn mimics the
76 // strings from lib_id.cpp
77 // TODO: Unify forbidden character lists
78 wxString illegalChars = wxS( "%$<>\t\n\r\"\\/:" );
79 SetCharExcludes( illegalChars );
80 }
81
82
84 wxTextValidator( wxFILTER_EXCLUDE_CHAR_LIST | wxFILTER_EMPTY, aValue )
85{
86 // The Windows (DOS) file system forbidden characters already include the forbidden
87 // file name characters for both Posix and OSX systems. The characters *?|"<> are
88 // illegal and filtered by the validator, but /\: are valid (\ and : only on Windows.
89 wxString illegalChars = wxFileName::GetForbiddenChars( wxPATH_DOS );
90 wxTextValidator nameValidator( wxFILTER_EXCLUDE_CHAR_LIST );
91 wxArrayString illegalCharList;
92
93 for( unsigned i = 0; i < illegalChars.size(); i++ )
94 {
95 if( illegalChars[i] == '/' )
96 continue;
97
98#if defined (__WINDOWS__)
99 if( illegalChars[i] == '\\' || illegalChars[i] == ':' )
100 continue;
101#endif
102 illegalCharList.Add( wxString( illegalChars[i] ) );
103 }
104
105 SetExcludes( illegalCharList );
106}
107
108
110 wxTextValidator()
111{
112 Connect( wxEVT_CHAR, wxKeyEventHandler( ENV_VAR_NAME_VALIDATOR::OnChar ) );
113}
114
115
117 : wxTextValidator()
118{
119 wxValidator::Copy( val );
120
121 Connect( wxEVT_CHAR, wxKeyEventHandler( ENV_VAR_NAME_VALIDATOR::OnChar ) );
122}
123
124
126{
127 Disconnect( wxEVT_CHAR, wxKeyEventHandler( ENV_VAR_NAME_VALIDATOR::OnChar ) );
128}
129
130
131void ENV_VAR_NAME_VALIDATOR::OnChar( wxKeyEvent& aEvent )
132{
133 if( !m_validatorWindow )
134 {
135 aEvent.Skip();
136 return;
137 }
138
139 int keyCode = aEvent.GetKeyCode();
140
141 // we don't filter special keys and delete
142 if( keyCode < WXK_SPACE || keyCode == WXK_DELETE || keyCode >= WXK_START )
143 {
144 aEvent.Skip();
145 return;
146 }
147
148 wxUniChar c = (wxUChar) keyCode;
149
150 if( c == wxT( '_' ) )
151 {
152 // OK anywhere
153 aEvent.Skip();
154 }
155 else if( wxIsdigit( c ) )
156 {
157 // not as first character
158 long from, to;
159 GetTextEntry()->GetSelection( &from, &to );
160
161 if( from < 1 )
162 wxBell();
163 else
164 aEvent.Skip();
165 }
166 else if( wxIsalpha( c ) )
167 {
168 // Capitals only.
169
170 if( wxIslower( c ) )
171 {
172 // You may wonder why this scope is so twisted, so make yourself comfortable and read:
173 // 1. Changing the keyCode and/or uniChar in the event and passing it on
174 // doesn't work. Some platforms look at the original copy as long as the event
175 // isn't vetoed.
176 // 2. Inserting characters by hand does not move the cursor, meaning either you insert
177 // text backwards (lp:#1798869) or always append, no matter where is the cursor.
178 // wxTextEntry::{Get/Set}InsertionPoint() do not work at all here.
179 // 3. There is wxTextEntry::ForceUpper(), but it is not yet available in common
180 // wxWidgets packages.
181 //
182 // So here we are, with a command event handler that converts
183 // the text to upper case upon every change.
184 wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( GetTextEntry() );
185
186 if( textCtrl )
187 {
188 textCtrl->Connect( textCtrl->GetId(), wxEVT_COMMAND_TEXT_UPDATED,
189 wxCommandEventHandler( ENV_VAR_NAME_VALIDATOR::OnTextChanged ) );
190 }
191 }
192
193 aEvent.Skip();
194 }
195 else
196 {
197 wxBell();
198 }
199}
200
201
202void ENV_VAR_NAME_VALIDATOR::OnTextChanged( wxCommandEvent& event )
203{
204 wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( event.GetEventObject() );
205
206 if( textCtrl )
207 {
208 if( !textCtrl->IsModified() )
209 return;
210
211 long insertionPoint = textCtrl->GetInsertionPoint();
212 textCtrl->ChangeValue( textCtrl->GetValue().Upper() );
213 textCtrl->SetInsertionPoint( insertionPoint );
214 textCtrl->Disconnect( textCtrl->GetId(), wxEVT_COMMAND_TEXT_UPDATED );
215 }
216
217 event.Skip();
218}
219
220
221bool REGEX_VALIDATOR::Validate( wxWindow* aParent )
222{
223 // If window is disabled, simply return
224 if( !m_validatorWindow->IsEnabled() )
225 return true;
226
227 wxTextEntry* const textEntry = GetTextEntry();
228
229 if( !textEntry )
230 return false;
231
232 bool valid = true;
233 const wxString& value = textEntry->GetValue();
234
235 if( m_regEx.Matches( value ) )
236 {
237 size_t start, len;
238 m_regEx.GetMatch( &start, &len );
239
240 if( start != 0 || len != value.Length() ) // whole string must match
241 valid = false;
242 }
243 else // no match at all
244 {
245 valid = false;
246 }
247
248 if( !valid )
249 {
250 m_validatorWindow->SetFocus();
251 DisplayError( aParent, wxString::Format( _( "Incorrect value: %s" ), value ) );
252 return false;
253 }
254
255 return true;
256}
257
258
259void REGEX_VALIDATOR::compileRegEx( const wxString& aRegEx, int aFlags )
260{
261 if( !m_regEx.Compile( aRegEx, aFlags ) )
262 {
263 throw std::runtime_error( "REGEX_VALIDATOR: Invalid regular expression: "
264 + aRegEx.ToStdString() );
265 }
266
267 m_regExString = aRegEx;
268 m_regExFlags = aFlags;
269}
270
271
273 wxTextValidator(),
274 m_allowSpaces( false )
275{
276}
277
278
280 wxTextValidator( aValidator ),
281 m_allowSpaces( aValidator.m_allowSpaces )
282{
283}
284
285
287 wxTextValidator(),
288 m_allowSpaces( aAllowSpaces )
289{
290}
291
292
293bool NETNAME_VALIDATOR::Validate( wxWindow *aParent )
294{
295 // If window is disabled, simply return
296 if ( !m_validatorWindow->IsEnabled() )
297 return true;
298
299 wxTextEntry * const text = GetTextEntry();
300
301 if ( !text )
302 return false;
303
304 const wxString& errormsg = IsValid( text->GetValue() );
305
306 if( !errormsg.empty() )
307 {
308 m_validatorWindow->SetFocus();
309 wxMessageBox( errormsg, _( "Invalid signal name" ), wxOK | wxICON_EXCLAMATION, aParent );
310 return false;
311 }
312
313 return true;
314}
315
316
317wxString NETNAME_VALIDATOR::IsValid( const wxString& str ) const
318{
319 if( str.Contains( '\r' ) || str.Contains( '\n' ) )
320 return _( "Signal names cannot contain CR or LF characters" );
321
322 if( !m_allowSpaces && ( str.Contains( ' ' ) || str.Contains( '\t' ) ) )
323 return _( "Signal names cannot contain spaces" );
324
325 return wxString();
326}
327
328
329void KIUI::ValidatorTransferToWindowWithoutEvents( wxValidator& aValidator )
330{
331 wxWindow* ctrl = aValidator.GetWindow();
332
333 wxCHECK_RET( ctrl != nullptr, wxS( "Transferring validator data without a control" ) );
334
335 wxEventBlocker orient_update_blocker( ctrl, wxEVT_ANY );
336 aValidator.TransferToWindow();
337}
338
339
340FIELD_VALIDATOR::FIELD_VALIDATOR( int aFieldId, wxString* aValue ) :
341 wxTextValidator( wxFILTER_EXCLUDE_CHAR_LIST, aValue ), m_fieldId( aFieldId )
342{
343 // Fields cannot contain carriage returns, line feeds, or tabs.
344 wxString excludes( wxT( "\r\n\t" ) );
345
346 // The reference and sheet name fields cannot contain spaces.
347 if( aFieldId == REFERENCE_FIELD )
348 {
349 excludes += wxT( " " );
350 }
351 else if( m_fieldId == SHEETNAME_V )
352 {
353 excludes += wxT( "/" );
354 }
355
356 long style = GetStyle();
357
358 // The reference, sheetname and sheetfilename fields cannot be empty.
359 if( aFieldId == REFERENCE_FIELD || aFieldId == SHEETNAME_V || aFieldId == SHEETFILENAME_V )
360 {
361 style |= wxFILTER_EMPTY;
362 }
363
364 SetStyle( style );
365 SetCharExcludes( excludes );
366}
367
368
370 wxTextValidator( aValidator ), m_fieldId( aValidator.m_fieldId )
371{
372}
373
374
375bool FIELD_VALIDATOR::Validate( wxWindow* aParent )
376{
377 // If window is disabled, simply return
378 if( !m_validatorWindow->IsEnabled() )
379 return true;
380
381 wxTextEntry* const text = GetTextEntry();
382
383 if( !text )
384 return false;
385
386 wxString val( text->GetValue() );
387 wxString msg;
388
389 if( HasFlag( wxFILTER_EMPTY ) && val.empty() )
390 msg.Printf( _( "The value of the field cannot be empty." ) );
391
392 if( HasFlag( wxFILTER_EXCLUDE_CHAR_LIST ) && ContainsExcludedCharacters( val ) )
393 {
394 wxArrayString badCharsFound;
395
396 for( const wxUniCharRef& excludeChar : GetCharExcludes() )
397 {
398 if( val.Find( excludeChar ) != wxNOT_FOUND )
399 {
400 if( excludeChar == '\r' )
401 badCharsFound.Add( _( "carriage return" ) );
402 else if( excludeChar == '\n' )
403 badCharsFound.Add( _( "line feed" ) );
404 else if( excludeChar == '\t' )
405 badCharsFound.Add( _( "tab" ) );
406 else if( excludeChar == ' ' )
407 badCharsFound.Add( _( "space" ) );
408 else
409 badCharsFound.Add( wxString::Format( wxT( "'%c'" ), excludeChar ) );
410 }
411 }
412
413 wxString badChars;
414
415 for( size_t i = 0; i < badCharsFound.GetCount(); i++ )
416 {
417 if( !badChars.IsEmpty() )
418 {
419 if( badCharsFound.GetCount() == 2 )
420 {
421 badChars += _( " or " );
422 }
423 else
424 {
425 if( i < badCharsFound.GetCount() - 2 )
426 badChars += _( ", or " );
427 else
428 badChars += wxT( ", " );
429 }
430 }
431
432 badChars += badCharsFound.Item( i );
433 }
434
435 switch( m_fieldId )
436 {
437 case REFERENCE_FIELD:
438 msg.Printf( _( "The reference designator cannot contain %s character(s)." ), badChars );
439 break;
440
441 case VALUE_FIELD:
442 msg.Printf( _( "The value field cannot contain %s character(s)." ), badChars );
443 break;
444
445 case FOOTPRINT_FIELD:
446 msg.Printf( _( "The footprint field cannot contain %s character(s)." ), badChars );
447 break;
448
449 case DATASHEET_FIELD:
450 msg.Printf( _( "The datasheet field cannot contain %s character(s)." ), badChars );
451 break;
452
453 case SHEETNAME_V:
454 msg.Printf( _( "The sheet name cannot contain %s character(s)." ), badChars );
455 break;
456
457 case SHEETFILENAME_V:
458 msg.Printf( _( "The sheet filename cannot contain %s character(s)." ), badChars );
459 break;
460
461 default:
462 msg.Printf( _( "The field cannot contain %s character(s)." ), badChars );
463 break;
464 };
465 }
466 else if( m_fieldId == REFERENCE_FIELD && val.Contains( wxT( "${" ) ) )
467 {
468 msg.Printf( _( "The reference designator cannot contain text variable references" ) );
469 }
470
471 if( !msg.empty() )
472 {
473 m_validatorWindow->SetFocus();
474
475 wxMessageBox( msg, _( "Field Validation Error" ), wxOK | wxICON_EXCLAMATION, aParent );
476
477 return false;
478 }
479
480 return true;
481}
This class provides a custom wxValidator object for limiting the allowable characters when defining a...
Definition: validators.h:105
virtual ~ENV_VAR_NAME_VALIDATOR()
Definition: validators.cpp:125
void OnChar(wxKeyEvent &event)
Definition: validators.cpp:131
ENV_VAR_NAME_VALIDATOR(wxString *aValue=nullptr)
Definition: validators.cpp:109
void OnTextChanged(wxCommandEvent &event)
Definition: validators.cpp:202
A text control validator used for validating the text allowed in fields.
Definition: validators.h:238
FIELD_VALIDATOR(int aFieldId, wxString *aValue=nullptr)
Definition: validators.cpp:340
virtual bool Validate(wxWindow *aParent) override
Override the default Validate() function provided by wxTextValidator to provide better error messages...
Definition: validators.cpp:375
FILE_NAME_WITH_PATH_CHAR_VALIDATOR(wxString *aValue=nullptr)
Definition: validators.cpp:83
FOOTPRINT_NAME_VALIDATOR(wxString *aValue=nullptr)
Definition: validators.cpp:72
std::unique_ptr< wxValidator > m_validator
Definition: validators.h:66
virtual void StartingKey(wxKeyEvent &event) override
Definition: validators.cpp:56
virtual void SetValidator(const wxValidator &validator) override
Definition: validators.cpp:47
wxString IsValid(const wxString &aVal) const override
Definition: validators.cpp:317
virtual bool Validate(wxWindow *aParent) override
Definition: validators.cpp:293
NETNAME_VALIDATOR(wxString *aVal=nullptr)
Definition: validators.cpp:272
wxRegEx m_regEx
Definition: validators.h:181
bool Validate(wxWindow *aParent) override
Definition: validators.cpp:221
wxString m_regExString
Original compilation flags (for copy constructor)
Definition: validators.h:175
int m_regExFlags
Compiled regex.
Definition: validators.h:178
void compileRegEx(const wxString &aRegEx, int aFlags)
< Compiles and stores a regular expression
Definition: validators.cpp:259
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:280
This file is part of the common library.
#define _(s)
void ValidatorTransferToWindowWithoutEvents(wxValidator &aValidator)
Call a text validator's TransferDataToWindow method without firing a text change event.
Definition: validators.cpp:329
@ DATASHEET_FIELD
name of datasheet
@ FOOTPRINT_FIELD
Field Name Module PCB, i.e. "16DIP300".
@ VALUE_FIELD
Field Value of part, i.e. "3.3K".
@ REFERENCE_FIELD
Field Reference of part, i.e. "IC21".
Custom text control validator definitions.
#define SHEETFILENAME_V
Definition: validators.h:47
#define SHEETNAME_V
Definition: validators.h:46