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