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 The KiCad Developers, see AUTHORS.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, see <https://www.gnu.org/licenses/>.
20 */
21
26
27#include <string_utils.h>
28#include <confirm.h>
29#include <name_validation.h>
30#include <validators.h>
31#include <template_fieldnames.h>
32
33#include <wx/grid.h>
34#include <wx/textctrl.h>
35#include <wx/textentry.h>
36#include <wx/log.h>
37#include <wx/combo.h>
38#include <wx/msgdlg.h>
39#include <refdes_utils.h>
40
41
43 wxTextValidator( wxFILTER_EXCLUDE_CHAR_LIST, aValue )
44{
45 SetCharExcludes( GetLibFilenameForbiddenChars() );
46}
47
48
50 wxTextValidator()
51{
52 Connect( wxEVT_CHAR, wxKeyEventHandler( ENV_VAR_NAME_VALIDATOR::OnChar ) );
53}
54
55
57 : wxTextValidator()
58{
59 wxValidator::Copy( val );
60
61 Connect( wxEVT_CHAR, wxKeyEventHandler( ENV_VAR_NAME_VALIDATOR::OnChar ) );
62}
63
64
66{
67 Disconnect( wxEVT_CHAR, wxKeyEventHandler( ENV_VAR_NAME_VALIDATOR::OnChar ) );
68}
69
70
71void ENV_VAR_NAME_VALIDATOR::OnChar( wxKeyEvent& aEvent )
72{
73 if( !m_validatorWindow )
74 {
75 aEvent.Skip();
76 return;
77 }
78
79 int keyCode = aEvent.GetKeyCode();
80
81 // we don't filter special keys and delete
82 if( keyCode < WXK_SPACE || keyCode == WXK_DELETE || keyCode >= WXK_START )
83 {
84 aEvent.Skip();
85 return;
86 }
87
88 wxUniChar c = (wxUChar) keyCode;
89
90 if( c == wxT( '_' ) )
91 {
92 // OK anywhere
93 aEvent.Skip();
94 }
95 else if( wxIsdigit( c ) )
96 {
97 // not as first character
98 long from, to;
99 GetTextEntry()->GetSelection( &from, &to );
100
101 if( from < 1 )
102 wxBell();
103 else
104 aEvent.Skip();
105 }
106 else if( wxIsalpha( c ) )
107 {
108 // Capitals only.
109
110 if( wxIslower( c ) )
111 {
112 // You may wonder why this scope is so twisted, so make yourself comfortable and read:
113 // 1. Changing the keyCode and/or uniChar in the event and passing it on
114 // doesn't work. Some platforms look at the original copy as long as the event
115 // isn't vetoed.
116 // 2. Inserting characters by hand does not move the cursor, meaning either you insert
117 // text backwards (lp:#1798869) or always append, no matter where is the cursor.
118 // wxTextEntry::{Get/Set}InsertionPoint() do not work at all here.
119 // 3. There is wxTextEntry::ForceUpper(), but it is not yet available in common
120 // wxWidgets packages.
121 //
122 // So here we are, with a command event handler that converts
123 // the text to upper case upon every change.
124 wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( GetTextEntry() );
125
126 if( textCtrl )
127 {
128 textCtrl->Connect( textCtrl->GetId(), wxEVT_COMMAND_TEXT_UPDATED,
129 wxCommandEventHandler( ENV_VAR_NAME_VALIDATOR::OnTextChanged ) );
130 }
131 }
132
133 aEvent.Skip();
134 }
135 else
136 {
137 wxBell();
138 }
139}
140
141
142void ENV_VAR_NAME_VALIDATOR::OnTextChanged( wxCommandEvent& event )
143{
144 wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( event.GetEventObject() );
145
146 if( textCtrl )
147 {
148 if( !textCtrl->IsModified() )
149 return;
150
151 long insertionPoint = textCtrl->GetInsertionPoint();
152 textCtrl->ChangeValue( textCtrl->GetValue().Upper() );
153 textCtrl->SetInsertionPoint( insertionPoint );
154 textCtrl->Disconnect( textCtrl->GetId(), wxEVT_COMMAND_TEXT_UPDATED );
155 }
156
157 event.Skip();
158}
159
160
162 wxTextValidator(),
163 m_allowSpaces( true )
164{
165}
166
167
169 wxTextValidator( aValidator ),
170 m_allowSpaces( aValidator.m_allowSpaces )
171{
172}
173
174
176 wxTextValidator(),
177 m_allowSpaces( aAllowSpaces )
178{
179}
180
181
182bool NETNAME_VALIDATOR::Validate( wxWindow *aParent )
183{
184 // If window is disabled, simply return
185 if ( !m_validatorWindow->IsEnabled() )
186 return true;
187
188 wxTextEntry * const text = GetTextEntry();
189
190 if ( !text )
191 return false;
192
193 const wxString& errormsg = IsValid( text->GetValue() );
194
195 if( !errormsg.empty() )
196 {
197 m_validatorWindow->SetFocus();
198 wxMessageBox( errormsg, _( "Invalid signal name" ), wxOK | wxICON_EXCLAMATION, aParent );
199 return false;
200 }
201
202 return true;
203}
204
205
206wxString NETNAME_VALIDATOR::IsValid( const wxString& str ) const
207{
208 if( str.Contains( '\r' ) || str.Contains( '\n' ) )
209 return _( "Signal names cannot contain CR or LF characters" );
210
211 if( !m_allowSpaces && ( str.Contains( ' ' ) || str.Contains( '\t' ) ) )
212 return _( "Signal names cannot contain spaces" );
213
214 return wxString();
215}
216
217
218void KIUI::ValidatorTransferToWindowWithoutEvents( wxValidator& aValidator )
219{
220 wxWindow* ctrl = aValidator.GetWindow();
221
222 wxCHECK_RET( ctrl != nullptr, wxS( "Transferring validator data without a control" ) );
223
224 wxEventBlocker orient_update_blocker( ctrl, wxEVT_ANY );
225 aValidator.TransferToWindow();
226}
227
228
229FIELD_VALIDATOR::FIELD_VALIDATOR( FIELD_T aFieldId, wxString* aValue ) :
230 wxTextValidator( wxFILTER_EXCLUDE_CHAR_LIST, aValue ),
231 m_fieldId( aFieldId )
232{
233 // Fields cannot contain carriage returns, line feeds, or tabs.
234 wxString excludes( wxT( "\r\n\t" ) );
235
236 // The reference and sheet name fields cannot contain spaces.
237 if( aFieldId == FIELD_T::REFERENCE )
238 {
239 excludes += wxT( " " );
240 }
241 else if( m_fieldId == FIELD_T::SHEET_NAME )
242 {
243 excludes += wxT( "/" );
244 }
245
246 long style = GetStyle();
247
248 // The reference, sheetname and sheetfilename fields cannot be empty.
249 if( aFieldId == FIELD_T::REFERENCE
250 || aFieldId == FIELD_T::SHEET_NAME
251 || aFieldId == FIELD_T::SHEET_FILENAME )
252 {
253 style |= wxFILTER_EMPTY;
254 }
255
256 SetStyle( style );
257 SetCharExcludes( excludes );
258}
259
260
262 wxTextValidator( aValidator ),
263 m_fieldId( aValidator.m_fieldId )
264{
265}
266
267
268bool FIELD_VALIDATOR::Validate( wxWindow* aParent )
269{
270 // If window is disabled, simply return
271 if( !m_validatorWindow->IsEnabled() )
272 return true;
273
274 wxTextEntry* const text = GetTextEntry();
275
276 if( !text )
277 return false;
278
279 wxString val( text->GetValue() );
280
281 return DoValidate( val, aParent );
282}
283
284
285wxString GetFieldValidationErrorMessage( FIELD_T aFieldId, const wxString& aValue )
286{
287 FIELD_VALIDATOR validator( aFieldId );
288 wxString msg;
289
290 if( validator.HasFlag( wxFILTER_EMPTY ) && aValue.empty() )
291 {
292 switch( aFieldId )
293 {
294 case FIELD_T::SHEET_NAME: msg = _( "A sheet must have a name." ); break;
295 case FIELD_T::SHEET_FILENAME: msg = _( "A sheet must have a file specified." ); break;
296 default: msg = _( "The value of the field cannot be empty." ); break;
297 }
298 }
299
300 if( msg.empty() && validator.HasFlag( wxFILTER_EXCLUDE_CHAR_LIST ) )
301 {
302 wxArrayString badCharsFound;
303
304 for( const wxUniCharRef& excludeChar : validator.GetCharExcludes() )
305 {
306 if( aValue.Find( excludeChar ) != wxNOT_FOUND )
307 {
308 if( excludeChar == '\r' )
309 badCharsFound.Add( _( "carriage return" ) );
310 else if( excludeChar == '\n' )
311 badCharsFound.Add( _( "line feed" ) );
312 else if( excludeChar == '\t' )
313 badCharsFound.Add( _( "tab" ) );
314 else if( excludeChar == ' ' )
315 badCharsFound.Add( _( "space" ) );
316 else
317 badCharsFound.Add( wxString::Format( wxT( "'%c'" ), excludeChar ) );
318 }
319 }
320
321 if( !badCharsFound.IsEmpty() )
322 {
323 wxString badChars;
324
325 for( size_t i = 0; i < badCharsFound.GetCount(); i++ )
326 {
327 if( !badChars.IsEmpty() )
328 {
329 if( badCharsFound.GetCount() == 2 )
330 {
331 badChars += _( " or " );
332 }
333 else
334 {
335 if( i < badCharsFound.GetCount() - 2 )
336 badChars += _( ", or " );
337 else
338 badChars += wxT( ", " );
339 }
340 }
341
342 badChars += badCharsFound.Item( i );
343 }
344
345 switch( aFieldId )
346 {
348 msg.Printf( _( "The reference designator cannot contain %s character(s)." ), badChars );
349 break;
350
351 case FIELD_T::VALUE:
352 msg.Printf( _( "The value field cannot contain %s character(s)." ), badChars );
353 break;
354
356 msg.Printf( _( "The footprint field cannot contain %s character(s)." ), badChars );
357 break;
358
360 msg.Printf( _( "The datasheet field cannot contain %s character(s)." ), badChars );
361 break;
362
364 msg.Printf( _( "The sheet name cannot contain %s character(s)." ), badChars );
365 break;
366
368 msg.Printf( _( "The sheet filename cannot contain %s character(s)." ), badChars );
369 break;
370
371 default:
372 msg.Printf( _( "The field cannot contain %s character(s)." ), badChars );
373 break;
374 };
375 }
376 }
377
378 if( msg.empty() )
379 {
380 if( aFieldId == FIELD_T::REFERENCE && aValue.Contains( wxT( "${" ) ) )
381 {
382 msg.Printf( _( "The reference designator cannot contain text variable references" ) );
383 }
384 else if( aFieldId == FIELD_T::REFERENCE && UTIL::GetRefDesPrefix( aValue ).IsEmpty() )
385 {
386 msg.Printf( _( "References must start with a letter." ) );
387 }
388 }
389
390 return msg;
391}
392
393
394bool FIELD_VALIDATOR::DoValidate( const wxString& aValue, wxWindow* aParent )
395{
396 wxString msg = GetFieldValidationErrorMessage( m_fieldId, aValue );
397
398 if( !msg.empty() )
399 {
400 if( m_validatorWindow )
401 m_validatorWindow->SetFocus();
402
403 wxMessageBox( msg, _( "Field Validation Error" ), wxOK | wxICON_EXCLAMATION, aParent );
404
405 return false;
406 }
407
408 return true;
409}
virtual ~ENV_VAR_NAME_VALIDATOR()
void OnChar(wxKeyEvent &event)
ENV_VAR_NAME_VALIDATOR(wxString *aValue=nullptr)
void OnTextChanged(wxCommandEvent &event)
A text control validator used for validating the text allowed in fields.
Definition validators.h:138
virtual bool Validate(wxWindow *aParent) override
Override the default Validate() function provided by wxTextValidator to provide better error messages...
bool DoValidate(const wxString &aValue, wxWindow *aParent)
FIELD_VALIDATOR(FIELD_T aFieldId, wxString *aValue=nullptr)
FIELD_T m_fieldId
Definition validators.h:158
FOOTPRINT_NAME_VALIDATOR(wxString *aValue=nullptr)
wxString IsValid(const wxString &aVal) const override
virtual bool Validate(wxWindow *aParent) override
NETNAME_VALIDATOR(wxString *aVal=nullptr)
This file is part of the common library.
#define _(s)
const wxString & GetLibFilenameForbiddenChars()
Characters illegal in a footprint library filename.
Definition lib_id.cpp:40
void ValidatorTransferToWindowWithoutEvents(wxValidator &aValidator)
Call a text validator's TransferDataToWindow method without firing a text change event.
wxString GetRefDesPrefix(const wxString &aRefDes)
Get the (non-numeric) prefix from a refdes - e.g.
Collection of utility functions for component reference designators (refdes)
FIELD_T
The set of all field indices assuming an array like sequence that a SCH_COMPONENT or LIB_PART can hol...
@ FOOTPRINT
Field Name Module PCB, i.e. "16DIP300".
@ DATASHEET
name of datasheet
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
wxString GetFieldValidationErrorMessage(FIELD_T aFieldId, const wxString &aValue)
Return the error message if aValue is invalid for aFieldId.
Custom text control validator definitions.
wxString GetFieldValidationErrorMessage(FIELD_T aFieldId, const wxString &aValue)
Return the error message if aValue is invalid for aFieldId.