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 The 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>
29#include <kiway.h>
30#include <lib_id.h>
31#include <progress_reporter.h>
32#include <string_utils.h>
33#include <thread_pool.h>
35
36#include <kiplatform/io.h>
37
38#include <wx/textfile.h>
39#include <wx/txtstrm.h>
40#include <wx/wfstream.h>
41
42
44{
45 FOOTPRINT_LIBRARY_ADAPTER* adapter = m_owner->GetAdapter();
46 wxCHECK( adapter, /* void */ );
47
48 try
49 {
50 std::unique_ptr<FOOTPRINT> footprint( adapter->LoadFootprint( m_nickname, m_fpname, false ) );
51
52 if( footprint == nullptr ) // Should happen only with malformed/broken libraries
53 {
54 m_pad_count = 0;
56 }
57 else
58 {
59 m_pad_count = footprint->GetPadCount( DO_NOT_INCLUDE_NPTH );
60 m_unique_pad_count = footprint->GetUniquePadCount( DO_NOT_INCLUDE_NPTH );
61 m_keywords = footprint->GetKeywords();
62 m_doc = footprint->GetLibDescription();
63 }
64 }
65 catch( const IO_ERROR& ioe )
66 {
67 // Store error in the owner's error list for later display
68 if( m_owner )
69 m_owner->PushError( std::make_unique<IO_ERROR>( ioe ) );
70
71 m_pad_count = 0;
73 }
74
75 m_loaded = true;
76}
77
78
80{
81 std::unique_lock<std::mutex> lock( m_loadInProgress );
82
83 m_list.clear();
85}
86
87
88bool FOOTPRINT_LIST_IMPL::CatchErrors( const std::function<void()>& aFunc )
89{
90 try
91 {
92 aFunc();
93 }
94 catch( const IO_ERROR& ioe )
95 {
96 m_errors.move_push( std::make_unique<IO_ERROR>( ioe ) );
97 return false;
98 }
99 catch( const std::exception& se )
100 {
101 // This is a round about way to do this, but who knows what THROW_IO_ERROR()
102 // may be tricked out to do someday, keep it in the game.
103 try
104 {
105 THROW_IO_ERROR( se.what() );
106 }
107 catch( const IO_ERROR& ioe )
108 {
109 m_errors.move_push( std::make_unique<IO_ERROR>( ioe ) );
110 }
111
112 return false;
113 }
114
115 return true;
116}
117
118
120 PROGRESS_REPORTER* aProgressReporter )
121{
122 std::unique_lock<std::mutex> lock( m_loadInProgress );
123
124 long long int generatedTimestamp = 0;
125
126 if( !CatchErrors( [&]()
127 {
128 generatedTimestamp = aAdapter->GenerateTimestamp( aNickname );
129 } ) )
130 {
131 return false;
132 }
133
134 if( generatedTimestamp == m_list_timestamp )
135 return true;
136
137 // Disable KIID generation: not needed for library parts; sometimes very slow
138 KIID_NIL_SET_RESET reset_kiid;
139
140 m_progress_reporter = aProgressReporter;
141
142 m_cancelled = false;
143 m_adapter = aAdapter;
144
145 // Clear data before reading files
146 m_errors.clear();
147 m_list.clear();
148 m_queue.clear();
149
150 if( aNickname )
151 {
152 m_queue.push( *aNickname );
153 }
154 else
155 {
156 for( const wxString& nickname : aAdapter->GetLibraryNames() )
157 m_queue.push( nickname );
158 }
159
161 {
162 m_progress_reporter->SetMaxProgress( (int) m_queue.size() );
163 m_progress_reporter->Report( _( "Loading footprints..." ) );
164 }
165
167
169 m_progress_reporter->AdvancePhase();
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{
182 // Parse the footprints in parallel.
183
186 size_t num_elements = m_queue.size();
187 std::vector<std::future<size_t>> returns( num_elements );
188
189 auto fp_thread =
190 [ this, &queue_parsed ]() -> size_t
191 {
192 wxString nickname;
193
194 if( m_cancelled || !m_queue.pop( nickname ) )
195 return 0;
196
197 std::vector<wxString> fpnames;
198
200 [&]()
201 {
202 fpnames = m_adapter->GetFootprintNames( nickname );
203 } );
204
205 for( wxString fpname : fpnames )
206 {
208 [&]()
209 {
210 auto* fpinfo = new FOOTPRINT_INFO_IMPL( this, nickname, fpname );
211 queue_parsed.move_push( std::unique_ptr<FOOTPRINT_INFO>( fpinfo ) );
212 } );
213
214 if( m_cancelled )
215 return 0;
216 }
217
219 m_progress_reporter->AdvanceProgress();
220
221 return 1;
222 };
223
224 for( size_t ii = 0; ii < num_elements; ++ii )
225 returns[ii] = tp.submit_task( fp_thread );
226
227 for( const std::future<size_t>& ret : returns )
228 {
229 std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );
230
231 while( status != std::future_status::ready )
232 {
234 m_progress_reporter->KeepRefreshing();
235
236 status = ret.wait_for( std::chrono::milliseconds( 250 ) );
237 }
238 }
239
240 std::unique_ptr<FOOTPRINT_INFO> fpi;
241
242 while( queue_parsed.pop( fpi ) )
243 m_list.push_back( std::move( fpi ) );
244
245 std::sort( m_list.begin(), m_list.end(),
246 []( std::unique_ptr<FOOTPRINT_INFO> const& lhs,
247 std::unique_ptr<FOOTPRINT_INFO> const& rhs ) -> bool
248 {
249 if( !lhs || !rhs )
250 return false;
251
252 return *lhs < *rhs;
253 } );
254}
255
256
263
264
265void FOOTPRINT_LIST_IMPL::WriteCacheToFile( const wxString& aFilePath )
266{
267 wxFileName tmpFileName = wxFileName::CreateTempFileName( aFilePath );
268 wxFFileOutputStream outStream( tmpFileName.GetFullPath() );
269 wxTextOutputStream txtStream( outStream );
270
271 if( !outStream.IsOk() )
272 {
273 return;
274 }
275
276 txtStream << wxString::Format( wxT( "%lld" ), m_list_timestamp ) << endl;
277
278 for( std::unique_ptr<FOOTPRINT_INFO>& fpinfo : m_list )
279 {
280 txtStream << fpinfo->GetLibNickname() << endl;
281 txtStream << fpinfo->GetName() << endl;
282 txtStream << EscapeString( fpinfo->GetDesc(), CTX_LINE ) << endl;
283 txtStream << EscapeString( fpinfo->GetKeywords(), CTX_LINE ) << endl;
284 txtStream << wxString::Format( wxT( "%d" ), fpinfo->GetOrderNum() ) << endl;
285 txtStream << wxString::Format( wxT( "%u" ), fpinfo->GetPadCount() ) << endl;
286 txtStream << wxString::Format( wxT( "%u" ), fpinfo->GetUniquePadCount() ) << endl;
287 }
288
289 txtStream.Flush();
290 outStream.Close();
291
292 // Preserve the permissions of the current file
293 KIPLATFORM::IO::DuplicatePermissions( aFilePath, tmpFileName.GetFullPath() );
294
295 if( !wxRenameFile( tmpFileName.GetFullPath(), aFilePath, true ) )
296 {
297 // cleanup in case rename failed
298 // its also not the end of the world since this is just a cache file
299 wxRemoveFile( tmpFileName.GetFullPath() );
300 }
301}
302
303
304void FOOTPRINT_LIST_IMPL::ReadCacheFromFile( const wxString& aFilePath )
305{
306 wxTextFile cacheFile( aFilePath );
307
309 m_list.clear();
310
311 try
312 {
313 if( cacheFile.Exists() && cacheFile.Open() )
314 {
315 cacheFile.GetFirstLine().ToLongLong( &m_list_timestamp );
316
317 while( cacheFile.GetCurrentLine() + 6 < cacheFile.GetLineCount() )
318 {
319 wxString libNickname = cacheFile.GetNextLine();
320 wxString name = cacheFile.GetNextLine();
321 wxString desc = UnescapeString( cacheFile.GetNextLine() );
322 wxString keywords = UnescapeString( cacheFile.GetNextLine() );
323 int orderNum = wxAtoi( cacheFile.GetNextLine() );
324 unsigned int padCount = (unsigned) wxAtoi( cacheFile.GetNextLine() );
325 unsigned int uniquePadCount = (unsigned) wxAtoi( cacheFile.GetNextLine() );
326
327 FOOTPRINT_INFO_IMPL* fpinfo = new FOOTPRINT_INFO_IMPL( libNickname, name, desc,
328 keywords, orderNum,
329 padCount, uniquePadCount );
330
331 m_list.emplace_back( std::unique_ptr<FOOTPRINT_INFO>( fpinfo ) );
332 }
333 }
334 }
335 catch( ... )
336 {
337 // whatever went wrong, invalidate the cache
339 }
340
341 // Sanity check: an empty list is very unlikely to be correct.
342 if( m_list.size() == 0 )
344
345 if( cacheFile.IsOpened() )
346 cacheFile.Close();
347}
const char * name
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
An interface to the global shared library manager that is schematic-specific and linked to one projec...
FOOTPRINT * LoadFootprint(const wxString &aNickname, const wxString &aName, bool aKeepUUID)
Load a FOOTPRINT having aName from the library given by aNickname.
long long GenerateTimestamp(const wxString *aNickname)
Generates a filesystem timestamp / hash value for library(ies)
bool ReadFootprintFiles(FOOTPRINT_LIBRARY_ADAPTER *aAdapter, 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
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< std::unique_ptr< IO_ERROR > > m_errors
some can be PARSE_ERRORs also
std::vector< std::unique_ptr< FOOTPRINT_INFO > > m_list
FOOTPRINT_LIBRARY_ADAPTER * m_adapter
no ownership
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
RAII class to safely set/reset nil KIIDs for use in footprint/symbol loading.
Definition kiid.h:230
std::vector< wxString > GetLibraryNames() const
Returns a list of library nicknames that are available (skips any that failed to load)
A progress reporter interface for use in multi-threaded environments.
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
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:71
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
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:47
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
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
static thread_pool * tp
BS::priority_thread_pool thread_pool
Definition thread_pool.h:31
Definition of file extensions used in Kicad.