KiCad PCB EDA Suite
Loading...
Searching...
No Matches
footprint_info_impl.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) 2011 Jean-Pierre Charras, <[email protected]>
5 * Copyright (C) 2013-2016 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
6 * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software: you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22
23#include <footprint_info_impl.h>
24
26#include <footprint.h>
27#include <footprint_info.h>
28#include <fp_lib_table.h>
29#include <kiway.h>
30#include <locale_io.h>
31#include <lib_id.h>
32#include <progress_reporter.h>
33#include <string_utils.h>
34#include <core/thread_pool.h>
36
37#include <kiplatform/io.h>
38
39#include <wx/textfile.h>
40#include <wx/txtstrm.h>
41#include <wx/wfstream.h>
42
43
45{
46 FP_LIB_TABLE* fptable = m_owner->GetTable();
47
48 wxASSERT( fptable );
49
50 const FOOTPRINT* footprint = fptable->GetEnumeratedFootprint( m_nickname, m_fpname );
51
52 if( footprint == nullptr ) // Should happen only with malformed/broken libraries
53 {
54 m_pad_count = 0;
56 }
57 else
58 {
61 m_keywords = footprint->GetKeywords();
62 m_doc = footprint->GetLibDescription();
63 }
64
65 m_loaded = true;
66}
67
68
70{
71 m_list.clear();
73}
74
75
76bool FOOTPRINT_LIST_IMPL::CatchErrors( const std::function<void()>& aFunc )
77{
78 try
79 {
80 aFunc();
81 }
82 catch( const IO_ERROR& ioe )
83 {
84 m_errors.move_push( std::make_unique<IO_ERROR>( ioe ) );
85 return false;
86 }
87 catch( const std::exception& se )
88 {
89 // This is a round about way to do this, but who knows what THROW_IO_ERROR()
90 // may be tricked out to do someday, keep it in the game.
91 try
92 {
93 THROW_IO_ERROR( se.what() );
94 }
95 catch( const IO_ERROR& ioe )
96 {
97 m_errors.move_push( std::make_unique<IO_ERROR>( ioe ) );
98 }
99
100 return false;
101 }
102
103 return true;
104}
105
106
107bool FOOTPRINT_LIST_IMPL::ReadFootprintFiles( FP_LIB_TABLE* aTable, const wxString* aNickname,
108 PROGRESS_REPORTER* aProgressReporter )
109{
110 long long int generatedTimestamp = 0;
111
112 if( !CatchErrors( [&]()
113 {
114 generatedTimestamp = aTable->GenerateTimestamp( aNickname );
115 } ) )
116 {
117 return false;
118 }
119
120 if( generatedTimestamp == m_list_timestamp )
121 return true;
122
123 // Disable KIID generation: not needed for library parts; sometimes very slow
124 KIID_NIL_SET_RESET reset_kiid;
125
126 m_progress_reporter = aProgressReporter;
127
129 {
131 m_progress_reporter->Report( _( "Fetching footprint libraries..." ) );
132 }
133
134 m_cancelled = false;
135 m_lib_table = aTable;
136
137 // Clear data before reading files
138 m_errors.clear();
139 m_list.clear();
142
143 if( aNickname )
144 {
145 m_queue_in.push( *aNickname );
146 }
147 else
148 {
149 for( const wxString& nickname : aTable->GetLogicalLibs() )
150 m_queue_in.push( nickname );
151 }
152
153
154 loadLibs();
155
156 if( !m_cancelled )
157 {
159 {
162 m_progress_reporter->Report( _( "Loading footprints..." ) );
163 }
164
166
169 }
170
171 if( m_cancelled )
172 m_list_timestamp = 0; // God knows what we got before we were canceled
173 else
174 m_list_timestamp = generatedTimestamp;
175
176 return m_errors.empty();
177}
178
179
181{
183 size_t num_returns = m_queue_in.size();
184 std::vector<std::future<size_t>> returns( num_returns );
185
186 auto loader_job =
187 [this]() -> size_t
188 {
189 wxString nickname;
190 size_t retval = 0;
191
192 if( !m_cancelled && m_queue_in.pop( nickname ) )
193 {
194 if( CatchErrors( [this, &nickname]()
195 {
196 m_lib_table->PrefetchLib( nickname );
197 m_queue_out.push( nickname );
198 } ) && m_progress_reporter )
199 {
201 }
202
203 ++retval;
204 }
205
206 return retval;
207 };
208
209 for( size_t ii = 0; ii < num_returns; ++ii )
210 returns[ii] = tp.submit( loader_job );
211
212 for( const std::future<size_t>& ret : returns )
213 {
214 std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );
215
216 while( status != std::future_status::ready )
217 {
219 m_cancelled = true;
220
221 status = ret.wait_for( std::chrono::milliseconds( 250 ) );
222 }
223 }
224}
225
226
228{
229 LOCALE_IO toggle_locale;
230
231 // Parse the footprints in parallel. WARNING! This requires changing the locale, which is
232 // GLOBAL. It is only thread safe to construct the LOCALE_IO before the threads are created,
233 // destroy it after they finish, and block the main (GUI) thread while they work. Any deviation
234 // from this will cause nasal demons.
235 //
236 // TODO: blast LOCALE_IO into the sun
237
240 size_t num_elements = m_queue_out.size();
241 std::vector<std::future<size_t>> returns( num_elements );
242
243 auto fp_thread =
244 [ this, &queue_parsed ]() -> size_t
245 {
246 wxString nickname;
247
248 if( m_cancelled || !m_queue_out.pop( nickname ) )
249 return 0;
250
251 wxArrayString fpnames;
252
254 [&]()
255 {
256 m_lib_table->FootprintEnumerate( fpnames, nickname, false );
257 } );
258
259 for( wxString fpname : fpnames )
260 {
262 [&]()
263 {
264 auto* fpinfo = new FOOTPRINT_INFO_IMPL( this, nickname, fpname );
265 queue_parsed.move_push( std::unique_ptr<FOOTPRINT_INFO>( fpinfo ) );
266 } );
267
268 if( m_cancelled )
269 return 0;
270 }
271
274
275 return 1;
276 };
277
278 for( size_t ii = 0; ii < num_elements; ++ii )
279 returns[ii] = tp.submit( fp_thread );
280
281 for( const std::future<size_t>& ret : returns )
282 {
283 std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );
284
285 while( status != std::future_status::ready )
286 {
289
290 status = ret.wait_for( std::chrono::milliseconds( 250 ) );
291 }
292 }
293
294 std::unique_ptr<FOOTPRINT_INFO> fpi;
295
296 while( queue_parsed.pop( fpi ) )
297 m_list.push_back( std::move( fpi ) );
298
299 std::sort( m_list.begin(), m_list.end(),
300 []( std::unique_ptr<FOOTPRINT_INFO> const& lhs,
301 std::unique_ptr<FOOTPRINT_INFO> const& rhs ) -> bool
302 {
303 return *lhs < *rhs;
304 } );
305}
306
307
309 m_list_timestamp( 0 ),
310 m_progress_reporter( nullptr ),
311 m_cancelled( false )
312{
313}
314
315
316void FOOTPRINT_LIST_IMPL::WriteCacheToFile( const wxString& aFilePath )
317{
318 wxFileName tmpFileName = wxFileName::CreateTempFileName( aFilePath );
319 wxFFileOutputStream outStream( tmpFileName.GetFullPath() );
320 wxTextOutputStream txtStream( outStream );
321
322 if( !outStream.IsOk() )
323 {
324 return;
325 }
326
327 txtStream << wxString::Format( wxT( "%lld" ), m_list_timestamp ) << endl;
328
329 for( std::unique_ptr<FOOTPRINT_INFO>& fpinfo : m_list )
330 {
331 txtStream << fpinfo->GetLibNickname() << endl;
332 txtStream << fpinfo->GetName() << endl;
333 txtStream << EscapeString( fpinfo->GetDesc(), CTX_LINE ) << endl;
334 txtStream << EscapeString( fpinfo->GetKeywords(), CTX_LINE ) << endl;
335 txtStream << wxString::Format( wxT( "%d" ), fpinfo->GetOrderNum() ) << endl;
336 txtStream << wxString::Format( wxT( "%u" ), fpinfo->GetPadCount() ) << endl;
337 txtStream << wxString::Format( wxT( "%u" ), fpinfo->GetUniquePadCount() ) << endl;
338 }
339
340 txtStream.Flush();
341 outStream.Close();
342
343 // Preserve the permissions of the current file
344 KIPLATFORM::IO::DuplicatePermissions( aFilePath, tmpFileName.GetFullPath() );
345
346 if( !wxRenameFile( tmpFileName.GetFullPath(), aFilePath, true ) )
347 {
348 // cleanup in case rename failed
349 // its also not the end of the world since this is just a cache file
350 wxRemoveFile( tmpFileName.GetFullPath() );
351 }
352}
353
354
355void FOOTPRINT_LIST_IMPL::ReadCacheFromFile( const wxString& aFilePath )
356{
357 wxTextFile cacheFile( aFilePath );
358
360 m_list.clear();
361
362 try
363 {
364 if( cacheFile.Exists() && cacheFile.Open() )
365 {
366 cacheFile.GetFirstLine().ToLongLong( &m_list_timestamp );
367
368 while( cacheFile.GetCurrentLine() + 6 < cacheFile.GetLineCount() )
369 {
370 wxString libNickname = cacheFile.GetNextLine();
371 wxString name = cacheFile.GetNextLine();
372 wxString desc = UnescapeString( cacheFile.GetNextLine() );
373 wxString keywords = UnescapeString( cacheFile.GetNextLine() );
374 int orderNum = wxAtoi( cacheFile.GetNextLine() );
375 unsigned int padCount = (unsigned) wxAtoi( cacheFile.GetNextLine() );
376 unsigned int uniquePadCount = (unsigned) wxAtoi( cacheFile.GetNextLine() );
377
378 FOOTPRINT_INFO_IMPL* fpinfo = new FOOTPRINT_INFO_IMPL( libNickname, name, desc,
379 keywords, orderNum,
380 padCount, uniquePadCount );
381
382 m_list.emplace_back( std::unique_ptr<FOOTPRINT_INFO>( fpinfo ) );
383 }
384 }
385 }
386 catch( ... )
387 {
388 // whatever went wrong, invalidate the cache
390 }
391
392 // Sanity check: an empty list is very unlikely to be correct.
393 if( m_list.size() == 0 )
395
396 if( cacheFile.IsOpened() )
397 cacheFile.Close();
398}
const char * name
Definition: DXF_plotter.cpp:57
virtual void load() override
lazily load stuff not filled in by constructor. This may throw IO_ERRORS.
wxString m_doc
Footprint description.
wxString m_fpname
Module name.
wxString m_keywords
Footprint keywords.
unsigned m_unique_pad_count
Number of unique pads.
unsigned m_pad_count
Number of pads.
FOOTPRINT_LIST * m_owner
provides access to FP_LIB_TABLE
wxString m_nickname
library as known in FP_LIB_TABLE
bool ReadFootprintFiles(FP_LIB_TABLE *aTable, const wxString *aNickname=nullptr, PROGRESS_REPORTER *aProgressReporter=nullptr) override
Read all the footprints provided by the combination of aTable and aNickname.
std::atomic_bool m_cancelled
SYNC_QUEUE< wxString > m_queue_in
bool CatchErrors(const std::function< void()> &aFunc)
Call aFunc, pushing any IO_ERRORs and std::exceptions it throws onto m_errors.
void WriteCacheToFile(const wxString &aFilePath) override
void ReadCacheFromFile(const wxString &aFilePath) override
PROGRESS_REPORTER * m_progress_reporter
SYNC_QUEUE< wxString > m_queue_out
FP_LIB_TABLE * m_lib_table
no ownership
FP_LIB_TABLE * GetTable() const
SYNC_QUEUE< std::unique_ptr< IO_ERROR > > m_errors
some can be PARSE_ERRORs also
std::vector< std::unique_ptr< FOOTPRINT_INFO > > m_list
wxString GetLibDescription() const
Definition: footprint.h:256
unsigned GetPadCount(INCLUDE_NPTH_T aIncludeNPTH=INCLUDE_NPTH_T(INCLUDE_NPTH)) const
Return the number of pads.
Definition: footprint.cpp:1854
unsigned GetUniquePadCount(INCLUDE_NPTH_T aIncludeNPTH=INCLUDE_NPTH_T(INCLUDE_NPTH)) const
Return the number of unique non-blank pads.
Definition: footprint.cpp:1904
wxString GetKeywords() const
Definition: footprint.h:259
void FootprintEnumerate(wxArrayString &aFootprintNames, const wxString &aNickname, bool aBestEfforts)
Return a list of footprint names contained within the library given by aNickname.
const FOOTPRINT * GetEnumeratedFootprint(const wxString &aNickname, const wxString &aFootprintName)
A version of FootprintLoad() for use after FootprintEnumerate() for more efficient cache management.
long long GenerateTimestamp(const wxString *aNickname)
Generate a hashed timestamp representing the last-mod-times of the library indicated by aNickname,...
void PrefetchLib(const wxString &aNickname)
If possible, prefetches the specified library (e.g.
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:77
RAII class to safely set/reset nil KIIDs for use in footprint/symbol loading.
Definition: kiid.h:230
std::vector< wxString > GetLogicalLibs()
Return the logical library names, all of them that are pertinent to a look up done on this LIB_TABLE.
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:49
A progress reporter interface for use in multi-threaded environments.
virtual bool KeepRefreshing(bool aWait=false)=0
Update the UI (if any).
virtual void Report(const wxString &aMessage)=0
Display aMessage in the progress bar dialog.
virtual void AdvancePhase()=0
Use the next available virtual zone of the dialog progress bar.
virtual void AdvanceProgress()=0
Increment the progress bar length (inside the current virtual zone).
virtual void SetMaxProgress(int aMaxProgress)=0
Fix the value that gives the 100 percent progress bar length (inside the current virtual zone).
Synchronized, locking queue.
Definition: sync_queue.h:32
bool pop(T &aReceiver)
Pop a value if the queue into the provided variable.
Definition: sync_queue.h:63
bool empty() const
Return true if the queue is empty.
Definition: sync_queue.h:82
void clear()
Clear the queue.
Definition: sync_queue.h:100
size_t size() const
Return the size of the queue.
Definition: sync_queue.h:91
void push(T const &aValue)
Push a value onto the queue.
Definition: sync_queue.h:41
void move_push(T &&aValue)
Move a value onto the queue.
Definition: sync_queue.h:50
#define _(s)
@ DO_NOT_INCLUDE_NPTH
Definition: footprint.h:63
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:39
bool DuplicatePermissions(const wxString &aSrc, const wxString &aDest)
Duplicates the file security data from one file to another ensuring that they are the same between bo...
Definition: unix/io.cpp:40
wxString UnescapeString(const wxString &aSource)
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
@ CTX_LINE
Definition: string_utils.h:59
static thread_pool * tp
Definition: thread_pool.cpp:30
BS::thread_pool thread_pool
Definition: thread_pool.h:30
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
Definition: thread_pool.cpp:32
Definition of file extensions used in Kicad.