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
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
292bool FIELD_VALIDATOR::DoValidate( const wxString& aValue, wxWindow* aParent )
293{
294 wxString msg;
295
296 if( HasFlag( wxFILTER_EMPTY ) && aValue.empty() )
297 {
298 switch( m_fieldId )
299 {
300 case FIELD_T::SHEET_NAME: msg = _( "A sheet must have a name." ); break;
301 case FIELD_T::SHEET_FILENAME: msg = _( "A sheet must have a file specified." ); break;
302 default: msg = _( "The value of the field cannot be empty." ); break;
303 }
304 }
305
306 if( HasFlag( wxFILTER_EXCLUDE_CHAR_LIST ) && ContainsExcludedCharacters( aValue ) )
307 {
308 wxArrayString badCharsFound;
309
310 for( const wxUniCharRef& excludeChar : GetCharExcludes() )
311 {
312 if( aValue.Find( excludeChar ) != wxNOT_FOUND )
313 {
314 if( excludeChar == '\r' )
315 badCharsFound.Add( _( "carriage return" ) );
316 else if( excludeChar == '\n' )
317 badCharsFound.Add( _( "line feed" ) );
318 else if( excludeChar == '\t' )
319 badCharsFound.Add( _( "tab" ) );
320 else if( excludeChar == ' ' )
321 badCharsFound.Add( _( "space" ) );
322 else
323 badCharsFound.Add( wxString::Format( wxT( "'%c'" ), excludeChar ) );
324 }
325 }
326
327 wxString badChars;
328
329 for( size_t i = 0; i < badCharsFound.GetCount(); i++ )
330 {
331 if( !badChars.IsEmpty() )
332 {
333 if( badCharsFound.GetCount() == 2 )
334 {
335 badChars += _( " or " );
336 }
337 else
338 {
339 if( i < badCharsFound.GetCount() - 2 )
340 badChars += _( ", or " );
341 else
342 badChars += wxT( ", " );
343 }
344 }
345
346 badChars += badCharsFound.Item( i );
347 }
348
349 switch( m_fieldId )
350 {
351 case FIELD_T::REFERENCE:
352 msg.Printf( _( "The reference designator cannot contain %s character(s)." ), badChars );
353 break;
354
355 case FIELD_T::VALUE:
356 msg.Printf( _( "The value field cannot contain %s character(s)." ), badChars );
357 break;
358
359 case FIELD_T::FOOTPRINT:
360 msg.Printf( _( "The footprint field cannot contain %s character(s)." ), badChars );
361 break;
362
363 case FIELD_T::DATASHEET:
364 msg.Printf( _( "The datasheet field cannot contain %s character(s)." ), badChars );
365 break;
366
367 case FIELD_T::SHEET_NAME:
368 msg.Printf( _( "The sheet name cannot contain %s character(s)." ), badChars );
369 break;
370
371 case FIELD_T::SHEET_FILENAME:
372 msg.Printf( _( "The sheet filename cannot contain %s character(s)." ), badChars );
373 break;
374
375 default:
376 msg.Printf( _( "The field cannot contain %s character(s)." ), badChars );
377 break;
378 };
379 }
380 else if( m_fieldId == FIELD_T::REFERENCE && aValue.Contains( wxT( "${" ) ) )
381 {
382 msg.Printf( _( "The reference designator cannot contain text variable references" ) );
383 }
384 else if( m_fieldId == FIELD_T::REFERENCE && UTIL::GetRefDesPrefix( aValue ).IsEmpty() )
385 {
386 msg.Printf( _( "References must start with a letter." ) );
387 }
388
389 if( !msg.empty() )
390 {
391 if( m_validatorWindow )
392 m_validatorWindow->SetFocus();
393
394 wxMessageBox( msg, _( "Field Validation Error" ), wxOK | wxICON_EXCLAMATION, aParent );
395
396 return false;
397 }
398
399 return true;
400}
Provide a custom wxValidator object for limiting the allowable characters when defining an environmen...
Definition: validators.h:69
virtual ~ENV_VAR_NAME_VALIDATOR()
Definition: validators.cpp:72
void OnChar(wxKeyEvent &event)
Definition: validators.cpp:78
ENV_VAR_NAME_VALIDATOR(wxString *aValue=nullptr)
Definition: validators.cpp:56
void OnTextChanged(wxCommandEvent &event)
Definition: validators.cpp:149
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...
Definition: validators.cpp:275
bool DoValidate(const wxString &aValue, wxWindow *aParent)
Definition: validators.cpp:292
FIELD_VALIDATOR(FIELD_T aFieldId, wxString *aValue=nullptr)
Definition: validators.cpp:236
FIELD_T m_fieldId
Definition: validators.h:162
FOOTPRINT_NAME_VALIDATOR(wxString *aValue=nullptr)
Definition: validators.cpp:45
wxString IsValid(const wxString &aVal) const override
Definition: validators.cpp:213
virtual bool Validate(wxWindow *aParent) override
Definition: validators.cpp:189
NETNAME_VALIDATOR(wxString *aVal=nullptr)
Definition: validators.cpp:168
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:225
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...
Custom text control validator definitions.