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