KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_http_lib_plugin.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) 2023 Andre F. K. Iwers <[email protected]>
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
21#include <wx/log.h>
22
23#include <fmt.h>
24#include <lib_symbol.h>
25#include <symbol_lib_table.h>
26
28#include "sch_http_lib_plugin.h"
29
30
32 m_libTable( nullptr )
33{
34}
35
36
38{
39}
40
41
42void SCH_HTTP_LIB_PLUGIN::EnumerateSymbolLib( wxArrayString& aSymbolNameList,
43 const wxString& aLibraryPath,
44 const STRING_UTF8_MAP* aProperties )
45{
46 std::vector<LIB_SYMBOL*> symbols;
47 EnumerateSymbolLib( symbols, aLibraryPath, aProperties );
48
49 for( LIB_SYMBOL* symbol : symbols )
50 aSymbolNameList.Add( symbol->GetName() );
51}
52
53
54void SCH_HTTP_LIB_PLUGIN::EnumerateSymbolLib( std::vector<LIB_SYMBOL*>& aSymbolList,
55 const wxString& aLibraryPath,
56 const STRING_UTF8_MAP* aProperties )
57{
58 wxCHECK_RET( m_libTable, _("httplib plugin missing library table handle!") );
59 ensureSettings( aLibraryPath );
61
62 if( !m_conn)
63 {
65 return;
66 }
67
68 bool powerSymbolsOnly =
69 ( aProperties
70 && aProperties->find( SYMBOL_LIB_TABLE::PropPowerSymsOnly ) != aProperties->end() );
71
72 // clear buffer
73 m_cachedParts.clear();
74
75 for(const HTTP_LIB_CATEGORY& category : m_conn->getCategories() )
76 {
77 std::vector<HTTP_LIB_PART> found_parts;
78
79 if( !m_conn->SelectAll( category, found_parts ) )
80 {
81 if( !m_conn->GetLastError().empty() )
82 {
83 wxString msg = wxString::Format( _( "Error retriving data from HTTP library %s: %s" ),
84 category.name, m_conn->GetLastError() );
85 THROW_IO_ERROR( msg );
86 }
87
88 continue;
89 }
90
91 // cache information for later use in LoadSymbol()
92 m_cachedParts.emplace( category.id, found_parts );
93
94 for( const HTTP_LIB_PART& part : found_parts )
95 {
96 wxString libIDString( part.name );
97
98 LIB_SYMBOL* symbol = loadSymbolFromPart( libIDString, category, part );
99
100 if( symbol && ( !powerSymbolsOnly || symbol->IsPower() ) )
101 aSymbolList.emplace_back( symbol );
102
103 }
104 }
105}
106
107
108LIB_SYMBOL* SCH_HTTP_LIB_PLUGIN::LoadSymbol( const wxString& aLibraryPath,
109 const wxString& aAliasName,
110 const STRING_UTF8_MAP* aProperties )
111{
112 wxCHECK( m_libTable, nullptr );
113 ensureSettings( aLibraryPath );
115
116 if( !m_conn )
118
119 std::string part_id = "";
120
121 std::string partName( aAliasName.ToUTF8() );
122
123 const HTTP_LIB_CATEGORY* foundCategory = nullptr;
124 HTTP_LIB_PART result;
125
126 std::vector<HTTP_LIB_CATEGORY> categories = m_conn->getCategories();
127
128 std::tuple relations = m_conn->getCachedParts()[partName];
129
130 // get the matching category
131 for( const HTTP_LIB_CATEGORY& categoryIter : categories )
132 {
133 std::string associatedCatID = std::get<1>( relations );
134
135 if( categoryIter.id == associatedCatID )
136 {
137 foundCategory = &categoryIter;
138 break;
139 }
140 }
141
142 // return Null if no category was found. This should never happen
143 if( foundCategory == nullptr )
144 {
145 wxLogTrace( traceHTTPLib, wxT( "loadSymbol: no category found for %s" ), partName );
146 return nullptr;
147 }
148
149 // get the matching query ID
150 for( const HTTP_LIB_PART& part : m_cachedParts[foundCategory->id] )
151 {
152 if( part.id == std::get<0>( relations ) )
153 {
154 part_id = part.id;
155 break;
156 }
157 }
158
159 if( m_conn->SelectOne( part_id, result ) )
160 {
161 wxLogTrace( traceHTTPLib, wxT( "loadSymbol: SelectOne (%s) found in %s" ), part_id,
162 foundCategory->name );
163 }
164 else
165 {
166 wxLogTrace( traceHTTPLib, wxT( "loadSymbol: SelectOne (%s) failed for category %s" ),
167 part_id, foundCategory->name );
168
170 }
171
172 wxCHECK( foundCategory, nullptr );
173
174 return loadSymbolFromPart( aAliasName, *foundCategory, result );
175}
176
177
178void SCH_HTTP_LIB_PLUGIN::GetSubLibraryNames( std::vector<wxString>& aNames )
179{
180 ensureSettings( wxEmptyString );
181
182 aNames.clear();
183
184 std::set<wxString> categoryNames;
185
186 for( const HTTP_LIB_CATEGORY& categoryIter : m_conn->getCategories() )
187 {
188 if( categoryNames.count( categoryIter.name ) )
189 continue;
190
191 aNames.emplace_back( categoryIter.name );
192 categoryNames.insert( categoryIter.name );
193 }
194}
195
196
197void SCH_HTTP_LIB_PLUGIN::GetAvailableSymbolFields( std::vector<wxString>& aNames )
198{
199 // TODO: Implement this sometime; This is currently broken...
200 std::copy( m_customFields.begin(), m_customFields.end(), std::back_inserter( aNames ) );
201}
202
203
204void SCH_HTTP_LIB_PLUGIN::GetDefaultSymbolFields( std::vector<wxString>& aNames )
205{
206 std::copy( m_defaultShownFields.begin(), m_defaultShownFields.end(),
207 std::back_inserter( aNames ) );
208}
209
210
211void SCH_HTTP_LIB_PLUGIN::ensureSettings( const wxString& aSettingsPath )
212{
213
214 auto tryLoad = [&]()
215 {
216 if( !m_settings->LoadFromFile() )
217 {
218 wxString msg = wxString::Format( _( "HTTP library settings file %s missing or invalid" ),
219 aSettingsPath );
220
221 THROW_IO_ERROR( msg );
222 }
223
224 if( m_settings->m_Source.api_version.empty() )
225 {
226 wxString msg = wxString::Format(
227 _( "HTTP library settings file %s is missing the API version number!" ),
228 aSettingsPath );
229
230 THROW_IO_ERROR( msg );
231 }
232
233 if( m_settings->getSupportedAPIVersion() != m_settings->m_Source.api_version )
234 {
235 wxString msg = wxString::Format(
236 _( "HTTP library settings file %s uses API version %s, but KiCad requires version %s" ),
237 aSettingsPath,
238 m_settings->m_Source.api_version,
239 m_settings->getSupportedAPIVersion() );
240
241 THROW_IO_ERROR( msg );
242 }
243
244 if( m_settings->m_Source.root_url.empty() )
245 {
246 wxString msg = wxString::Format(
247 _( "HTTP library settings file %s is missing the root URL!" ),
248 aSettingsPath );
249
250 THROW_IO_ERROR( msg );
251 }
252
253 // map lib source type
254 m_settings->m_Source.type = m_settings->get_HTTP_LIB_SOURCE_TYPE();
255
256 if( m_settings->m_Source.type == HTTP_LIB_SOURCE_TYPE::INVALID )
257 {
258 wxString msg = wxString::Format(
259 _( "HTTP library settings file %s has an invalid library type" ),
260 aSettingsPath );
261
262 THROW_IO_ERROR( msg );
263 }
264
265 // make sure that the root url finishes with a forward slash
266 if( m_settings->m_Source.root_url.at( m_settings->m_Source.root_url.length() - 1 ) != '/' )
267 {
268 m_settings->m_Source.root_url += "/";
269 }
270
271 // Append api version to root URL
272 m_settings->m_Source.root_url += m_settings->m_Source.api_version + "/";
273
274 };
275
276 if( !m_settings && !aSettingsPath.IsEmpty() )
277 {
278 std::string path( aSettingsPath.ToUTF8() );
279 m_settings = std::make_unique<HTTP_LIB_SETTINGS>( path );
280
281 m_settings->SetReadOnly( true );
282
283 tryLoad();
284 }
285 else if( m_settings )
286 {
287 // If we have valid settings but no connection yet; reload settings in case user is editing
288 tryLoad();
289 }
290 else if( !m_settings )
291 {
292 wxLogTrace( traceHTTPLib, wxT( "ensureSettings: no settings available!" ) );
293 }
294}
295
296
298{
299 wxCHECK_RET( m_settings, "Call ensureSettings before ensureConnection!" );
300
301 connect();
302
303 if( !m_conn || !m_conn->IsValidEndpoint() )
304 {
305 wxString msg = wxString::Format(
306 _( "Could not connect to %s. Errors: %s" ),
307 m_settings->m_Source.root_url, m_lastError );
308
309 THROW_IO_ERROR( msg );
310 }
311}
312
313
315{
316 wxCHECK_RET( m_settings, "Call ensureSettings before connect()!" );
317
318 if( !m_conn )
319 {
320 m_conn = std::make_unique<HTTP_LIB_CONNECTION>( m_settings->m_Source, true );
321
322 if( !m_conn->IsValidEndpoint() )
323 {
324 m_lastError = m_conn->GetLastError();
325 return;
326 }
327 }
328}
329
330
332 const HTTP_LIB_CATEGORY& aCategory,
333 const HTTP_LIB_PART& aPart )
334{
335 LIB_SYMBOL* symbol = nullptr;
336 LIB_SYMBOL* originalSymbol = nullptr;
337 LIB_ID symbolId;
338
339 std::string symbolIdStr = aPart.symbolIdStr;
340
341 // Get or Create the symbol using the found symbol
342 if( !symbolIdStr.empty() )
343 {
344 symbolId.Parse( symbolIdStr );
345
346 if( symbolId.IsValid() )
347 {
348 originalSymbol = m_libTable->LoadSymbol( symbolId );
349 }
350
351 if( originalSymbol )
352 {
353 wxLogTrace( traceHTTPLib, wxT( "loadSymbolFromPart: found original symbol '%s'" ),
354 symbolIdStr );
355
356 symbol = originalSymbol->Duplicate();
357 symbol->SetSourceLibId( symbolId );
358
359 symbol->LibId().SetSubLibraryName( aCategory.name );
360 }
361 else if( !symbolId.IsValid() )
362 {
363 wxLogTrace( traceHTTPLib,
364 wxT( "loadSymbolFromPart: source symbol id '%s' is invalid, "
365 "will create empty symbol" ),
366 symbolIdStr );
367 }
368 else
369 {
370 wxLogTrace( traceHTTPLib,
371 wxT( "loadSymbolFromPart: source symbol '%s' not found, "
372 "will create empty symbol" ),
373 symbolIdStr );
374 }
375 }
376
377 if( !symbol )
378 {
379 // Actual symbol not found: return metadata only; error will be
380 // indicated in the symbol chooser
381 symbol = new LIB_SYMBOL( aSymbolName );
382 symbol->LibId().SetSubLibraryName( aCategory.name );
383 }
384
385 symbol->SetExcludedFromBOM( aPart.exclude_from_bom );
387 symbol->SetExcludedFromSim( aPart.exclude_from_sim );
388
389 LIB_FIELD* field;
390
391 for( auto& _field : aPart.fields )
392 {
393 wxString fieldName = wxString( _field.first );
394 std::tuple fieldProperties = _field.second;
395
396 if( fieldName.Lower() == footprint_field )
397 {
398 field = &symbol->GetFootprintField();
399 field->SetText( std::get<0>( fieldProperties ) );
400 field->SetVisible( std::get<1>( fieldProperties ) );
401 }
402 else if( fieldName.Lower() == description_field )
403 {
404 field = &symbol->GetDescriptionField();
405 field->SetText( std::get<0>( fieldProperties ) );
406 field->SetVisible( std::get<1>( fieldProperties ) );
407 }
408 else if( fieldName.Lower() == value_field )
409 {
410 field = &symbol->GetValueField();
411 field->SetText( std::get<0>( fieldProperties ) );
412 field->SetVisible( std::get<1>( fieldProperties ) );
413 }
414 else if( fieldName.Lower() == datasheet_field )
415 {
416 field = &symbol->GetDatasheetField();
417 field->SetText( std::get<0>( fieldProperties ) );
418 field->SetVisible( std::get<1>( fieldProperties ) );
419 }
420 else if( fieldName.Lower() == reference_field )
421 {
422 field = &symbol->GetReferenceField();
423 field->SetText( std::get<0>( fieldProperties ) );
424 field->SetVisible( std::get<1>( fieldProperties ) );
425 }
426 else if( fieldName.Lower() == keywords_field )
427 {
428 symbol->SetKeyWords( std::get<0>( fieldProperties ) );
429 }
430 else
431 {
432 // Generic fields
433 field = new LIB_FIELD( symbol->GetNextAvailableFieldId() );
434 field->SetName( fieldName );
435
436 field->SetText( std::get<0>( fieldProperties ) );
437 field->SetVisible( std::get<1>( fieldProperties ) );
438 symbol->AddField( field );
439
440 m_customFields.insert( fieldName );
441 }
442 }
443
444 return symbol;
445}
446
447void SCH_HTTP_LIB_PLUGIN::SaveSymbol( const wxString& aLibraryPath, const LIB_SYMBOL* aSymbol,
448 const STRING_UTF8_MAP* aProperties )
449{
450 // TODO: Implement this sometime;
451}
virtual void SetVisible(bool aVisible)
Definition: eda_text.cpp:229
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:183
Field object used in symbol libraries.
Definition: lib_field.h:62
void SetName(const wxString &aName)
Set a user definable field name to aName.
Definition: lib_field.cpp:507
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:49
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition: lib_id.cpp:51
bool IsValid() const
Check if this LID_ID is valid.
Definition: lib_id.h:172
void SetSubLibraryName(const UTF8 &aName)
Definition: lib_id.h:131
Define a library symbol object.
Definition: lib_symbol.h:99
void SetSourceLibId(const LIB_ID &aLibId)
Definition: lib_symbol.h:167
LIB_FIELD & GetReferenceField()
Return reference to the reference designator field.
int GetNextAvailableFieldId() const
virtual LIB_SYMBOL * Duplicate() const
Create a copy of a LIB_SYMBOL and assigns unique KIIDs to the copy and its children.
Definition: lib_symbol.h:115
bool IsPower() const
Definition: lib_symbol.cpp:704
LIB_FIELD & GetFootprintField()
Return reference to the footprint field.
LIB_FIELD & GetDescriptionField()
Return reference to the description field.
void SetKeyWords(const wxString &aKeyWords)
Definition: lib_symbol.h:189
void SetExcludedFromBOM(bool aExcludeFromBOM)
Set or clear the exclude from schematic bill of materials flag.
Definition: lib_symbol.h:656
void SetExcludedFromBoard(bool aExcludeFromBoard)
Set or clear exclude from board netlist flag.
Definition: lib_symbol.h:664
LIB_FIELD & GetValueField()
Return reference to the value field.
void AddField(LIB_FIELD *aField)
Add a field.
LIB_ID & LibId()
Definition: lib_symbol.h:162
LIB_FIELD & GetDatasheetField()
Return reference to the datasheet field.
void SetExcludedFromSim(bool aExcludeFromSim)
Set or clear the exclude from simulation flag.
Definition: lib_symbol.h:648
void EnumerateSymbolLib(wxArrayString &aSymbolNameList, const wxString &aLibraryPath, const STRING_UTF8_MAP *aProperties=nullptr) override
Populate a list of LIB_SYMBOL alias names contained within the library aLibraryPath.
void GetAvailableSymbolFields(std::vector< wxString > &aNames) override
Retrieves a list of (custom) field names that are present on symbols in this library.
void GetDefaultSymbolFields(std::vector< wxString > &aNames) override
Retrieves a list of (custom) field names that should be shown by default for this library in the symb...
std::set< wxString > m_defaultShownFields
void SaveSymbol(const wxString &aLibraryPath, const LIB_SYMBOL *aSymbol, const STRING_UTF8_MAP *aProperties=nullptr) override
Write aSymbol to an existing library located at aLibraryPath.
LIB_SYMBOL * LoadSymbol(const wxString &aLibraryPath, const wxString &aAliasName, const STRING_UTF8_MAP *aProperties=nullptr) override
Load a LIB_SYMBOL object having aPartName from the aLibraryPath containing a library format that this...
std::unique_ptr< HTTP_LIB_SETTINGS > m_settings
std::unique_ptr< HTTP_LIB_CONNECTION > m_conn
Generally will be null if no valid connection is established.
LIB_SYMBOL * loadSymbolFromPart(const wxString &aSymbolName, const HTTP_LIB_CATEGORY &aCategory, const HTTP_LIB_PART &aPart)
std::set< wxString > m_customFields
std::map< std::string, std::vector< HTTP_LIB_PART > > m_cachedParts
SYMBOL_LIB_TABLE * m_libTable
void ensureSettings(const wxString &aSettingsPath)
void GetSubLibraryNames(std::vector< wxString > &aNames) override
Retrieves a list of sub-libraries in this library.
A name/value tuple with unique names and optional values.
static const char * PropPowerSymsOnly
LIB_SYMBOL * LoadSymbol(const wxString &aNickname, const wxString &aName)
Load a LIB_SYMBOL having aName from the library given by aNickname.
#define _(s)
const char *const traceHTTPLib
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:39
std::string id
id of category
std::string name
name of category
std::string symbolIdStr
std::map< std::string, std::tuple< std::string, bool > > fields
additional generic fields