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_CANONICAL "Reference"
32#define VALUE_CANONICAL "Value"
33#define FOOTPRINT_CANONICAL "Footprint"
34#define DATASHEET_CANONICAL "Datasheet"
35#define DESCRIPTION_CANONICAL "Description"
36#define SHEET_NAME_CANONICAL "Sheetname"
37#define SHEET_FILE_CANONICAL "Sheetfile"
38#define INTERSHEET_REFS_CANONICAL "Intersheetrefs"
39#define USER_FIELD_CANONICAL "Field%d"
40
49
50
51wxString GetDefaultFieldName( FIELD_T aFieldId, bool aTranslateForHI )
52{
53 if( !aTranslateForHI )
54 {
55 switch( aFieldId )
56 {
57 case FIELD_T::REFERENCE: return s_CanonicalReference; // The symbol reference, R1, C1, etc.
58 case FIELD_T::VALUE: return s_CanonicalValue; // The symbol value
59 case FIELD_T::FOOTPRINT: return s_CanonicalFootprint; // The footprint for use with Pcbnew
60 case FIELD_T::DATASHEET: return s_CanonicalDatasheet; // Link to a datasheet for symbol
61 case FIELD_T::DESCRIPTION: return s_CanonicalDescription; // The symbol description
65 default: return GetUserFieldName( 42, aTranslateForHI );
66 }
67 }
68 else
69 {
70 switch( aFieldId )
71 {
72 case FIELD_T::REFERENCE: return _( REFERENCE_CANONICAL ); // The symbol reference, R1, C1, etc.
73 case FIELD_T::VALUE: return _( VALUE_CANONICAL ); // The symbol value
74 case FIELD_T::FOOTPRINT: return _( FOOTPRINT_CANONICAL ); // The footprint for use with Pcbnew
75 case FIELD_T::DATASHEET: return _( DATASHEET_CANONICAL ); // Link to a datasheet for symbol
76 case FIELD_T::DESCRIPTION: return _( DESCRIPTION_CANONICAL ); // The symbol description
80 default: return GetUserFieldName( 42, aTranslateForHI );
81 }
82 }
83}
84
85
86wxString GetUserFieldName( int aFieldNdx, bool aTranslateForHI )
87{
88 if( !aTranslateForHI )
89 return wxString::Format( wxS( USER_FIELD_CANONICAL ), aFieldNdx );
90 else
91 return wxString::Format( _( USER_FIELD_CANONICAL ), 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 // canonical 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 a mandatory canonical name collides with the canonical mandatory field.
108 for( FIELD_T fieldId : aMandatoryFields )
109 {
110 if( aLhs.CmpNoCase( GetCanonicalFieldName( fieldId ) ) == 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, bool aGlobal ) 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 = aGlobal ? 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, bool aGlobal )
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, aGlobal );
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
273void TEMPLATES::AddTemplateFieldName( const TEMPLATE_FIELDNAME& aFieldName, bool aGlobal )
274{
275 // Reject any case variant of a mandatory fieldname; the s-expression parser folds those
276 // onto the canonical mandatory field, so they can never become a distinct user field.
277 for( FIELD_T fieldId : MANDATORY_FIELDS )
278 {
279 if( GetCanonicalFieldName( fieldId ).CmpNoCase( aFieldName.m_Name ) == 0 )
280 return;
281 }
282
283 std::vector<TEMPLATE_FIELDNAME>& target = aGlobal ? m_globals : m_project;
284
285 // ensure uniqueness, overwrite any template fieldname by the same name.
286 for( TEMPLATE_FIELDNAME& temp : target )
287 {
288 if( temp.m_Name == aFieldName.m_Name )
289 {
290 temp = aFieldName;
291 m_resolvedDirty = true;
292 return;
293 }
294 }
295
296 // the name is legal and not previously added to the config container, append
297 // it and return its index within the container.
298 target.push_back( aFieldName );
299 m_resolvedDirty = true;
300}
301
302
303void TEMPLATES::AddTemplateFieldNames( const wxString& aSerializedFieldNames )
304{
305 TEMPLATE_FIELDNAMES_LEXER field_lexer( TO_UTF8( aSerializedFieldNames ) );
306
307 try
308 {
309 parse( &field_lexer, true );
310 }
311 catch( const IO_ERROR& )
312 {
313 }
314}
315
316
318{
319 if( aGlobal )
320 {
321 m_globals.clear();
323 }
324 else
325 {
326 m_project.clear();
328 }
329
330 m_resolvedDirty = false;
331}
332
333
334const std::vector<TEMPLATE_FIELDNAME>& TEMPLATES::GetTemplateFieldNames()
335{
336 if( m_resolvedDirty )
338
339 return m_resolved;
340}
341
342
343const std::vector<TEMPLATE_FIELDNAME>& TEMPLATES::GetTemplateFieldNames( bool aGlobal )
344{
345 if( aGlobal )
346 return m_globals;
347 else
348 return m_project;
349}
350
351
352const TEMPLATE_FIELDNAME* TEMPLATES::GetFieldName( const wxString& aName )
353{
354 if( m_resolvedDirty )
356
357 for( const TEMPLATE_FIELDNAME& field : m_resolved )
358 {
359 if( field.m_Name == aName )
360 return &field;
361 }
362
363 return nullptr;
364}
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:291
std::string Quotew(const wxString &aWrapee) const
Definition richio.cpp:503
int PRINTF_FUNC_N Print(int nestLevel, const char *fmt,...)
Format and write text to the output stream.
Definition richio.cpp:418
void AddTemplateFieldName(const TEMPLATE_FIELDNAME &aFieldName, bool aGlobal)
Insert or append a wanted symbol field name into the field names template.
void AddTemplateFieldNames(const wxString &aSerializedFieldNames)
Add a serialized list of template field names.
const std::vector< TEMPLATE_FIELDNAME > & GetTemplateFieldNames()
Return a 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
const TEMPLATE_FIELDNAME * GetFieldName(const wxString &aName)
Search for aName in the template field name list.
void DeleteAllFieldNameTemplates(bool aGlobal)
Delete the entire contents.
void parse(TEMPLATE_FIELDNAMES_LEXER *in, bool aGlobal)
std::vector< TEMPLATE_FIELDNAME > m_globals
void Format(OUTPUTFORMATTER *out, bool aGlobal) const
Serialize this object out as text into the given OUTPUTFORMATTER.
#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 VALUE_CANONICAL
static wxString s_CanonicalSheetFile(SHEET_FILE_CANONICAL)
#define FOOTPRINT_CANONICAL
#define USER_FIELD_CANONICAL
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 INTERSHEET_REFS_CANONICAL
static wxString s_CanonicalReference(REFERENCE_CANONICAL)
static wxString s_CanonicalValue(VALUE_CANONICAL)
static wxString s_CanonicalFootprint(FOOTPRINT_CANONICAL)
static wxString s_CanonicalDatasheet(DATASHEET_CANONICAL)
#define DATASHEET_CANONICAL
wxString GetUserFieldName(int aFieldNdx, bool aTranslateForHI)
static wxString s_CanonicalIntersheetRefs(INTERSHEET_REFS_CANONICAL)
#define SHEET_NAME_CANONICAL
static wxString s_CanonicalSheetName(SHEET_NAME_CANONICAL)
#define DESCRIPTION_CANONICAL
static wxString s_CanonicalDescription(DESCRIPTION_CANONICAL)
#define REFERENCE_CANONICAL
#define SHEET_FILE_CANONICAL
wxString GetDefaultFieldName(FIELD_T aFieldId, bool aTranslateForHI)
Return a default symbol field name for a mandatory field type.
#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".
wxString GetCanonicalFieldName(FIELD_T aFieldType)