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