KiCad PCB EDA Suite
Loading...
Searching...
No Matches
template_fieldnames.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) 2010 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.TXT for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21#include "template_fieldnames.h"
22
23#include <mutex>
24
25#include <template_fieldnames_lexer.h>
26#include <string_utils.h>
27
28using namespace TFIELD_T;
29
30// N.B. Do not change these values without transitioning the file format
31#define REFERENCE_UNTRANSLATED "Reference"
32#define VALUE_UNTRANSLATED "Value"
33#define FOOTPRINT_UNTRANSLATED "Footprint"
34#define DATASHEET_UNTRANSLATED "Datasheet"
35#define DESCRIPTION_UNTRANSLATED "Description"
36#define SHEET_NAME_UNTRANSLATED "Sheetname"
37#define SHEET_FILE_UNTRANSLATED "Sheetfile"
38#define INTERSHEET_REFS_UNTRANSLATED "Intersheetrefs"
39#define USER_FIELD_UNTRANSLATED_FORMAT "Field%d"
40
49
50
51wxString GetDefaultFieldName( FIELD_T aFieldId, TRANSLATION aTranslation )
52{
53 if( aTranslation == UNTRANSLATED )
54 {
55 switch( aFieldId )
56 {
57 case FIELD_T::REFERENCE: return s_UntranslatedReference; // The symbol reference, R1, C1, etc.
58 case FIELD_T::VALUE: return s_UntranslatedValue; // The symbol value
59 case FIELD_T::FOOTPRINT: return s_UntranslatedFootprint; // The footprint for use with Pcbnew
60 case FIELD_T::DATASHEET: return s_UntranslatedDatasheet; // Link to a datasheet for symbol
61 case FIELD_T::DESCRIPTION: return s_UntranslatedDescription; // The symbol description
65 default: return GetUserFieldName( 42, aTranslation );
66 }
67 }
68 else
69 {
70 switch( aFieldId )
71 {
72 case FIELD_T::REFERENCE: return _( REFERENCE_UNTRANSLATED ); // The symbol reference, R1, C1, etc.
73 case FIELD_T::VALUE: return _( VALUE_UNTRANSLATED ); // The symbol value
74 case FIELD_T::FOOTPRINT: return _( FOOTPRINT_UNTRANSLATED ); // The footprint for use with Pcbnew
75 case FIELD_T::DATASHEET: return _( DATASHEET_UNTRANSLATED ); // Link to a datasheet for symbol
76 case FIELD_T::DESCRIPTION: return _( DESCRIPTION_UNTRANSLATED ); // The symbol description
80 default: return GetUserFieldName( 42, aTranslation );
81 }
82 }
83}
84
85
86wxString GetUserFieldName( int aFieldNdx, TRANSLATION aTranslation )
87{
88 if( aTranslation == UNTRANSLATED )
89 return wxString::Format( wxS( USER_FIELD_UNTRANSLATED_FORMAT ), aFieldNdx );
90 else
91 return wxString::Format( _( USER_FIELD_UNTRANSLATED_FORMAT ), aFieldNdx );
92}
93
94
95bool FieldNamesAreDuplicates( const wxString& aLhs, const wxString& aRhs,
96 std::initializer_list<FIELD_T> aMandatoryFields )
97{
98 if( aLhs == aRhs )
99 return true;
100
101 // If they don't even match case-insensitively they can't both be variants of the same
102 // untranslated mandatory field name.
103 if( aLhs.CmpNoCase( aRhs ) != 0 )
104 return false;
105
106 // Mandatory field names are folded case-insensitively by the s-expression parser, so any
107 // case variant of an untranslated mandatory name collides with that mandatory field.
108 for( FIELD_T fieldId : aMandatoryFields )
109 {
110 if( aLhs.CmpNoCase( GetDefaultFieldName( fieldId, UNTRANSLATED ) ) == 0 )
111 return true;
112 }
113
114 return false;
115}
116
117
118bool FieldNamesAreDuplicates( const wxString& aLhs, const wxString& aRhs )
119{
120 return FieldNamesAreDuplicates( aLhs, aRhs, MANDATORY_FIELDS );
121}
122
123
125{
126 out->Print( "(field (name %s)", out->Quotew( m_Name ).c_str() );
127
128 if( m_Visible )
129 out->Print( " visible" );
130
131 if( m_URL )
132 out->Print( " url" );
133
134 out->Print( ")" );
135}
136
137
138void TEMPLATE_FIELDNAME::Parse( TEMPLATE_FIELDNAMES_LEXER* in )
139{
140 T tok;
141
142 in->NeedLEFT(); // begin (name ...)
143
144 if( ( tok = in->NextTok() ) != T_name )
145 in->Expecting( T_name );
146
147 in->NeedSYMBOLorNUMBER();
148
149 m_Name = From_UTF8( in->CurText() );
150
151 in->NeedRIGHT(); // end (name ...)
152
153 while( (tok = in->NextTok() ) != T_RIGHT && tok != T_EOF )
154 {
155 // "visible" has no '(' prefix, "value" does, so T_LEFT is optional.
156 if( tok == T_LEFT )
157 tok = in->NextTok();
158
159 switch( tok )
160 {
161 case T_value:
162 // older format; silently skip
163 in->NeedSYMBOLorNUMBER();
164 in->NeedRIGHT();
165 break;
166
167 case T_visible:
168 m_Visible = true;
169 break;
170
171 case T_url:
172 m_URL = true;
173 break;
174
175 default:
176 in->Expecting( "value|url|visible" );
177 break;
178 }
179 }
180}
181
182
183void TEMPLATES::Format( OUTPUTFORMATTER* out, SCOPE aScope ) const
184{
185 // We'll keep this general, and include the \n, even though the only known
186 // use at this time will not want the newlines or the indentation.
187 out->Print( "(templatefields" );
188
189 const std::vector<TEMPLATE_FIELDNAME>& source = aScope == SCOPE::GLOBAL ? m_globals : m_project;
190
191 for( const TEMPLATE_FIELDNAME& temp : source )
192 {
193 if( !temp.m_Name.IsEmpty() )
194 temp.Format( out );
195 }
196
197 out->Print( ")" );
198}
199
200
201void TEMPLATES::parse( TEMPLATE_FIELDNAMES_LEXER* in, SCOPE aScope )
202{
203 T tok;
204
205 while( ( tok = in->NextTok() ) != T_RIGHT && tok != T_EOF )
206 {
207 if( tok == T_LEFT )
208 tok = in->NextTok();
209
210 switch( tok )
211 {
212 case T_templatefields: // a token indicating class TEMPLATES.
213
214 // Be flexible regarding the starting point of the TEMPLATE_FIELDNAMES_LEXER
215 // stream. Caller may not have read the first two tokens out of the
216 // stream: T_LEFT and T_templatefields, so ignore them if seen here.
217 break;
218
219 case T_field:
220 {
221 // instantiate on stack, so if exception is thrown,
222 // destructor runs
223 TEMPLATE_FIELDNAME field;
224
225 field.Parse( in );
226
227 // add the field
228 if( !field.m_Name.IsEmpty() )
229 AddTemplateFieldName( field, aScope );
230 }
231 break;
232
233 default:
234 in->Unexpected( in->CurText() );
235 break;
236 }
237 }
238}
239
240
246{
248
249 // Note: order N^2 algorithm. Would need changing if fieldname template sets ever
250 // get large.
251
252 for( const TEMPLATE_FIELDNAME& global : m_globals )
253 {
254 bool overriddenInProject = false;
255
256 for( const TEMPLATE_FIELDNAME& project : m_project )
257 {
258 if( global.m_Name == project.m_Name )
259 {
260 overriddenInProject = true;
261 break;
262 }
263 }
264
265 if( !overriddenInProject )
266 m_resolved.push_back( global );
267 }
268
269 m_resolvedDirty = false;
270}
271
272
274{
275 // Reject any case variant of a mandatory fieldname; the s-expression parser folds those onto
276 // the mandatory field with the matching untranslated name, so they can never become a
277 // distinct user field.
278 for( FIELD_T fieldId : MANDATORY_FIELDS )
279 {
280 if( GetDefaultFieldName( fieldId, UNTRANSLATED ).CmpNoCase( aFieldName.m_Name ) == 0 )
281 return;
282 }
283
284 std::vector<TEMPLATE_FIELDNAME>& target = aScope == SCOPE::GLOBAL ? m_globals : m_project;
285
286 // ensure uniqueness, overwrite any template fieldname by the same name.
287 for( TEMPLATE_FIELDNAME& temp : target )
288 {
289 if( temp.m_Name == aFieldName.m_Name )
290 {
291 temp = aFieldName;
292 m_resolvedDirty = true;
293 return;
294 }
295 }
296
297 // the name is legal and not previously added to the config container, append
298 // it and return its index within the container.
299 target.push_back( aFieldName );
300 m_resolvedDirty = true;
301}
302
303
304void TEMPLATES::AddTemplateFieldNames( const wxString& aSerializedFieldNames, SCOPE aScope )
305{
306 TEMPLATE_FIELDNAMES_LEXER field_lexer( TO_UTF8( aSerializedFieldNames ) );
307
308 try
309 {
310 parse( &field_lexer, aScope );
311 }
312 catch( const IO_ERROR& )
313 {
314 }
315}
316
317
319{
320 if( aScope == SCOPE::GLOBAL )
321 {
322 m_globals.clear();
324 }
325 else
326 {
327 m_project.clear();
329 }
330
331 m_resolvedDirty = false;
332}
333
334
335const std::vector<TEMPLATE_FIELDNAME>& TEMPLATES::GetResolvedTemplateFieldNames()
336{
337 if( m_resolvedDirty )
339
340 return m_resolved;
341}
342
343
344const std::vector<TEMPLATE_FIELDNAME>& TEMPLATES::GetTemplateFieldNames( SCOPE aScope )
345{
346 if( aScope == SCOPE::GLOBAL )
347 return m_globals;
348 else
349 return m_project;
350}
351
352
353const TEMPLATE_FIELDNAME* TEMPLATES::GetFieldName( const wxString& aName )
354{
355 if( m_resolvedDirty )
357
358 for( const TEMPLATE_FIELDNAME& field : m_resolved )
359 {
360 if( field.m_Name == aName )
361 return &field;
362 }
363
364 return nullptr;
365}
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
An interface used to output 8 bit text in a convenient way.
Definition richio.h:294
std::string Quotew(const wxString &aWrapee) const
Definition richio.cpp:505
int PRINTF_FUNC_N Print(int nestLevel, const char *fmt,...)
Format and write text to the output stream.
Definition richio.cpp:432
void AddTemplateFieldName(const TEMPLATE_FIELDNAME &aFieldName, SCOPE aScope)
Insert or append a wanted symbol field name into the field names template.
const std::vector< TEMPLATE_FIELDNAME > & GetResolvedTemplateFieldNames()
Return the resolved project and global template field name list for read only access.
std::vector< TEMPLATE_FIELDNAME > m_resolved
void resolveTemplates()
Flatten project and global templates into a single list.
std::vector< TEMPLATE_FIELDNAME > m_project
void AddTemplateFieldNames(const wxString &aSerializedFieldNames, SCOPE aScope)
Add a serialized list of template field names.
const std::vector< TEMPLATE_FIELDNAME > & GetTemplateFieldNames(SCOPE aScope)
Return a specific list (global or project) for read only access.
const TEMPLATE_FIELDNAME * GetFieldName(const wxString &aName)
Search for aName in the template field name list.
void Format(OUTPUTFORMATTER *out, SCOPE aScope) const
Serialize this object out as text into the given OUTPUTFORMATTER.
void DeleteFieldNameTemplates(SCOPE aScope)
Delete the contents of a scope.
std::vector< TEMPLATE_FIELDNAME > m_globals
void parse(TEMPLATE_FIELDNAMES_LEXER *in, SCOPE aScope)
#define _(s)
wxString From_UTF8(const char *cstring)
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Hold a name of a symbol's field, field value, and default visibility.
void Format(OUTPUTFORMATTER *out) const
Serialize this object out as text into the given OUTPUTFORMATTER.
void Parse(TEMPLATE_FIELDNAMES_LEXER *aSpec)
Fill this object from information in the input stream aSpec, which is a #TEMPLATE_FIELDNAMES_LEXER.
#define INTERSHEET_REFS_UNTRANSLATED
static wxString s_UntranslatedSheetFile(SHEET_FILE_UNTRANSLATED)
static wxString s_UntranslatedFootprint(FOOTPRINT_UNTRANSLATED)
#define DESCRIPTION_UNTRANSLATED
bool FieldNamesAreDuplicates(const wxString &aLhs, const wxString &aRhs, std::initializer_list< FIELD_T > aMandatoryFields)
Test whether two field names should be treated as duplicates for the purposes of field name uniquenes...
#define SHEET_FILE_UNTRANSLATED
#define REFERENCE_UNTRANSLATED
static wxString s_UntranslatedIntersheetRefs(INTERSHEET_REFS_UNTRANSLATED)
static wxString s_UntranslatedValue(VALUE_UNTRANSLATED)
#define VALUE_UNTRANSLATED
static wxString s_UntranslatedSheetName(SHEET_NAME_UNTRANSLATED)
#define SHEET_NAME_UNTRANSLATED
wxString GetUserFieldName(int aFieldNdx, TRANSLATION aTranslation)
static wxString s_UntranslatedDatasheet(DATASHEET_UNTRANSLATED)
static wxString s_UntranslatedDescription(DESCRIPTION_UNTRANSLATED)
#define FOOTPRINT_UNTRANSLATED
#define USER_FIELD_UNTRANSLATED_FORMAT
static wxString s_UntranslatedReference(REFERENCE_UNTRANSLATED)
wxString GetDefaultFieldName(FIELD_T aFieldId, TRANSLATION aTranslation)
Return a default symbol field name for a mandatory field type.
#define DATASHEET_UNTRANSLATED
#define MANDATORY_FIELDS
FIELD_T
The set of all field indices assuming an array like sequence that a SCH_COMPONENT or LIB_PART can hol...
@ INTERSHEET_REFS
Global label cross-reference page numbers.
@ DESCRIPTION
Field Description of part, i.e. "1/4W 1% Metal Film Resistor".
@ 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".
@ UNTRANSLATED
KICOMMON_API wxString GetDefaultFieldName(FIELD_T aFieldId, TRANSLATION aTranslation)
Return a default symbol field name for a mandatory field type.