KiCad PCB EDA Suite
Loading...
Searching...
No Matches
component_class_settings.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <json_common.h>
21
23#include <settings/parameters.h>
24
26
27
29 NESTED_SETTINGS( "component_class_settings", componentClassSettingsSchemaVersion, aParent, aPath, false ),
31{
32 m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>(
33 "sheet_component_classes",
34 [&]() -> nlohmann::json
35 {
36 nlohmann::json ret = {};
37
38 ret["enabled"] = m_enableSheetComponentClasses;
39
40 return ret;
41 },
42 [&]( const nlohmann::json& aJson )
43 {
44 if( !aJson.is_object() )
45 return;
46
47 if( !aJson.contains( "enabled" ) )
48 return;
49
50 m_enableSheetComponentClasses = aJson["enabled"].get<bool>();
51 },
52 {} ) );
53
54 m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>(
55 "assignments",
56 [&]() -> nlohmann::json
57 {
58 nlohmann::json ret = nlohmann::json::array();
59
61 ret.push_back( saveAssignment( assignment ) );
62
63 return ret;
64 },
65 [&]( const nlohmann::json& aJson )
66 {
67 if( !aJson.is_array() )
68 return;
69
71
72 for( const nlohmann::json& assignmentJson : aJson )
73 {
74 COMPONENT_CLASS_ASSIGNMENT_DATA assignment = loadAssignment( assignmentJson );
75 m_componentClassAssignments.push_back( assignment );
76 }
77 },
78 {} ) );
79}
80
81
83{
84 // Release early before destroying members
85 if( m_parent )
86 {
87 m_parent->ReleaseNestedSettings( this );
88 m_parent = nullptr;
89 }
90}
91
92
93nlohmann::json
95{
96 nlohmann::json ret;
97
98 const wxString matchOperator =
100 ? wxT( "ALL" )
101 : wxT( "ANY" );
102
103 ret["component_class"] = aAssignment.GetComponentClass().ToUTF8();
104 ret["conditions_operator"] = matchOperator.ToUTF8();
105
106 nlohmann::json conditionsJson;
107
108 for( const auto& [conditionType, primaryData, secondaryData] : aAssignment.GetConditions() )
109 {
110 nlohmann::json conditionJson;
111
112 if( !primaryData.empty() )
113 conditionJson["primary"] = primaryData;
114
115 if( !secondaryData.empty() )
116 conditionJson["secondary"] = secondaryData;
117
118 const wxString conditionName = COMPONENT_CLASS_ASSIGNMENT_DATA::GetConditionName( conditionType );
119 int suffix = 1;
120 wxString uniqueName = conditionName;
121
122 while( conditionsJson.contains( uniqueName ) )
123 uniqueName = wxString::Format( wxT( "%s-%d" ), conditionName, suffix++ );
124
125 conditionsJson[uniqueName] = conditionJson;
126 }
127
128 ret["conditions"] = conditionsJson;
129
130 return ret;
131}
132
133
135COMPONENT_CLASS_SETTINGS::loadAssignment( const nlohmann::json& aJson )
136{
138
139 assignment.SetComponentClass( wxString( aJson["component_class"].get<std::string>().c_str(), wxConvUTF8 ) );
140
141 const wxString matchOperator( aJson["conditions_operator"].get<std::string>().c_str(), wxConvUTF8 );
142
143 if( matchOperator == wxT( "ALL" ) )
145 else
147
148 for( const auto& [conditionTypeStr, conditionData] : aJson["conditions"].items() )
149 {
150 wxString primary, secondary;
151 wxString typeStr( conditionTypeStr );
152
153 typeStr = typeStr.BeforeFirst( '-' );
154
157
158 if( conditionData.contains( "primary" ) )
159 primary = wxString( conditionData["primary"].get<std::string>().c_str(), wxConvUTF8 );
160
161 if( conditionData.contains( "secondary" ) )
162 secondary = wxString( conditionData["secondary"].get<std::string>().c_str(), wxConvUTF8 );
163
164 assignment.AddCondition( conditionType, primary, secondary );
165 }
166
167 return assignment;
168}
169
170
172{
173 // TODO: Implement this
174 throw;
175 //return true;
176}
177
178
179/**************************************************************************************************
180 *
181 * COMPONENT_CLASS_ASSIGNMENT_DATA implementation
182 *
183 *************************************************************************************************/
184
186{
187 switch( aCondition )
188 {
189 case CONDITION_TYPE::REFERENCE: return wxT( "REFERENCE" );
190 case CONDITION_TYPE::FOOTPRINT: return wxT( "FOOTPRINT" );
191 case CONDITION_TYPE::SIDE: return wxT( "SIDE" );
192 case CONDITION_TYPE::ROTATION: return wxT( "ROTATION" );
193 case CONDITION_TYPE::FOOTPRINT_FIELD: return wxT( "FOOTPRINT_FIELD" );
194 case CONDITION_TYPE::CUSTOM: return wxT( "CUSTOM" );
195 case CONDITION_TYPE::SHEET_NAME: return wxT( "SHEET_NAME" );
196 }
197
198 wxASSERT_MSG( false, "Invalid condition type" );
199
200 return wxEmptyString;
201}
202
203
206{
207 if( aCondition == wxT( "REFERENCE" ) )
209 if( aCondition == wxT( "FOOTPRINT" ) )
211 if( aCondition == wxT( "SIDE" ) )
213 if( aCondition == wxT( "ROTATION" ) )
215 if( aCondition == wxT( "FOOTPRINT_FIELD" ) )
217 if( aCondition == wxT( "CUSTOM" ) )
219 if( aCondition == wxT( "SHEET_NAME" ) )
221
222 wxASSERT_MSG( false, "Invalid condition type" );
223
225}
226
227
229{
230 if( m_componentClass.empty() )
231 return wxEmptyString;
232
233 if( m_conditions.empty() )
234 {
235 // A condition which always applies the netclass
236 return wxString::Format( wxT( "(version 1) (assign_component_class \"%s\")" ), m_componentClass );
237 }
238
239 // Lambda to format a comma-separated list of references in to a DRC expression
240 auto getRefExpr =
241 []( wxString aRefs ) -> wxString
242 {
243 aRefs.Trim( true ).Trim( false );
244
245 wxArrayString refs = wxSplit( aRefs, ',' );
246
247 if( refs.empty() )
248 return wxEmptyString;
249
250 std::ranges::transform( refs, refs.begin(),
251 []( const wxString& aRef )
252 {
253 return wxString::Format( wxT( "A.Reference == '%s'" ), aRef );
254 } );
255
256 wxString refsExpr = refs[0];
257
258 if( refs.size() > 1 )
259 {
260 for( auto itr = refs.begin() + 1; itr != refs.end(); ++itr )
261 refsExpr = refsExpr + wxT( " || " ) + *itr;
262 }
263
264 return wxString::Format( wxT( "( %s )" ), refsExpr );
265 };
266
267 // Lambda to format a footprint match DRC expression
268 auto getFootprintExpr =
269 []( wxString aFootprint ) -> wxString
270 {
271 aFootprint.Trim( true ).Trim( false );
272
273 if( aFootprint.empty() )
274 return wxEmptyString;
275
276 return wxString::Format( wxT( "( A.Library_Link == '%s' )" ), aFootprint );
277 };
278
279 // Lambda to format a layer side DRC expression
280 auto getSideExpr =
281 []( const wxString& aSide ) -> wxString
282 {
283 if( aSide == wxT( "Any" ) )
284 return wxEmptyString;
285
286 return wxString::Format( wxT( "( A.Layer == '%s' )" ),
287 aSide == wxT( "Front" ) ? wxT( "F.Cu" ) : wxT( "B.Cu" ) );
288 };
289
290 // Lambda to format a rotation DRC expression
291 auto getRotationExpr =
292 []( wxString aRotation ) -> wxString
293 {
294 aRotation.Trim( true ).Trim( false );
295
296 int dummy;
297
298 if( aRotation.empty() || aRotation == wxT( "Any" ) || !aRotation.ToInt( &dummy ) )
299 return wxEmptyString;
300
301 return wxString::Format( wxT( "( A.Orientation == %s deg )" ), aRotation );
302 };
303
304
305 // Lambda to format a footprint field DRC expression
306 auto getFootprintFieldExpr =
307 []( wxString aFieldName, wxString aFieldMatch ) -> wxString
308 {
309 aFieldName.Trim( true ).Trim( false );
310 aFieldMatch.Trim( true ).Trim( false );
311
312 if( aFieldName.empty() || aFieldMatch.empty() )
313 return wxEmptyString;
314
315 return wxString::Format( wxT( "( A.getField('%s') == '%s' )" ), aFieldName, aFieldMatch );
316 };
317
318 // Lambda to format a custom DRC expression
319 auto getCustomFieldExpr =
320 []( wxString aExpr ) -> wxString
321 {
322 aExpr.Trim( true ).Trim( false );
323
324 if( aExpr.empty() )
325 return wxEmptyString;
326
327 return wxString::Format( wxT( "( %s )" ), aExpr );
328 };
329
330 // Lambda to format a sheet name expression
331 auto getSheetNameExpr =
332 []( wxString aSheetName ) -> wxString
333 {
334 aSheetName.Trim( true ).Trim( false );
335
336 if( aSheetName.empty() )
337 return wxEmptyString;
338
339 return wxString::Format( wxT( "( A.memberOfSheet('%s') )" ), aSheetName );
340 };
341
342 std::vector<wxString> conditionsExprs;
343
344 for( auto& [conditionType, primaryData, secondaryData] : m_conditions )
345 {
346 wxString conditionExpr;
347
348 switch( conditionType )
349 {
351 conditionExpr = getRefExpr( primaryData );
352 break;
354 conditionExpr = getFootprintExpr( primaryData );
355 break;
357 conditionExpr = getSideExpr( primaryData );
358 break;
360 conditionExpr = getRotationExpr( primaryData );
361 break;
363 conditionExpr = getFootprintFieldExpr( primaryData, secondaryData );
364 break;
366 conditionExpr = getCustomFieldExpr( primaryData );
367 break;
369 conditionExpr = getSheetNameExpr( primaryData );
370 break;
371 }
372
373 if( !conditionExpr.empty() )
374 conditionsExprs.push_back( conditionExpr );
375 }
376
377 if( conditionsExprs.empty() )
378 return wxString::Format( wxT( "(version 1) (assign_component_class \"%s\")" ), m_componentClass );
379
380 wxString allConditionsExpr = conditionsExprs[0];
381
382 if( conditionsExprs.size() > 1 )
383 {
384 wxString operatorExpr = m_conditionsOperator == CONDITIONS_OPERATOR::ALL ? wxT( " && " ) : wxT( " || " );
385
386 for( auto itr = conditionsExprs.begin() + 1; itr != conditionsExprs.end(); ++itr )
387 allConditionsExpr = allConditionsExpr + operatorExpr + *itr;
388 }
389
390 return wxString::Format( wxT( "(version 1) (assign_component_class \"%s\" (condition \"%s\" ) )" ),
392 allConditionsExpr );
393}
void AddCondition(const CONDITION_TYPE aCondition, const wxString &aPrimaryData, const wxString &aSecondaryData)
Sets the given condition type with the assocated match data.
wxString GetAssignmentInDRCLanguage() const
Returns the DRC rules language for this component class assignment.
wxString m_componentClass
The name of the component class for this assignment rule.
static CONDITION_TYPE GetConditionType(const wxString &aCondition)
Maps a descriptive string to a CONDITION_TYPE.
void SetConditionsOperation(const CONDITIONS_OPERATOR aOperator)
Sets the boolean operation in use for all conditions.
static wxString GetConditionName(const CONDITION_TYPE aCondition)
Maps a CONDITION_TYPE to a descriptive string.
std::vector< std::tuple< CONDITION_TYPE, wxString, wxString > > m_conditions
Set of conditions with type, primary and secondary data fields for the condition.
const std::vector< std::tuple< CONDITION_TYPE, wxString, wxString > > & GetConditions() const
Gets all conditions.
CONDITIONS_OPERATOR m_conditionsOperator
Whether conditions are applied with AND or OR logic Defaults to ALL.
void SetComponentClass(const wxString &aComponentClass)
Sets the resulting component class for matching footprints.
CONDITIONS_OPERATOR GetConditionsOperator() const
Gets the boolean operation in use for all conditions.
const wxString & GetComponentClass() const
Gets the resulting component class for matching footprints.
COMPONENT_CLASS_SETTINGS(JSON_SETTINGS *aParent, const std::string &aPath)
bool operator==(const COMPONENT_CLASS_SETTINGS &aOther) const
static nlohmann::json saveAssignment(const COMPONENT_CLASS_ASSIGNMENT_DATA &aAssignment)
Saves a dynamic component class assignment to JSON.
void ClearComponentClassAssignments()
Clear all dynamic component class assignments.
std::vector< COMPONENT_CLASS_ASSIGNMENT_DATA > m_componentClassAssignments
All dynamic component class assignment rules.
static COMPONENT_CLASS_ASSIGNMENT_DATA loadAssignment(const nlohmann::json &aJson)
Loads a dynamic component class assignment from JSON.
bool m_enableSheetComponentClasses
Toggle generation of component classes for hierarchical sheets.
std::vector< PARAM_BASE * > m_params
The list of parameters (owned by this object)
JSON_SETTINGS(const wxString &aFilename, SETTINGS_LOC aLocation, int aSchemaVersion)
JSON_SETTINGS * m_parent
A pointer to the parent object to load and store from.
NESTED_SETTINGS(const std::string &aName, int aSchemaVersion, JSON_SETTINGS *aParent, const std::string &aPath, bool aLoadFromFile=true)
Like a normal param, but with custom getter and setter functions.
Definition parameters.h:296
constexpr int componentClassSettingsSchemaVersion
std::vector< FAB_LAYER_COLOR > dummy