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