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 const FOOTPRINT* footprint = adapter->LoadFootprint( m_nickname, m_fpname, false );
49
50 if( footprint == nullptr ) // Should happen only with malformed/broken libraries
51 {
52 m_pad_count = 0;
54 }
55 else
56 {
59 m_keywords = footprint->GetKeywords();
60 m_doc = footprint->GetLibDescription();
61 }
62
63 m_loaded = true;
64}
65
66
68{
69 m_list.clear();
71}
72
73
74bool FOOTPRINT_LIST_IMPL::CatchErrors( const std::function<void()>& aFunc )
75{
76 try
77 {
78 aFunc();
79 }
80 catch( const IO_ERROR& ioe )
81 {
82 m_errors.move_push( std::make_unique<IO_ERROR>( ioe ) );
83 return false;
84 }
85 catch( const std::exception& se )
86 {
87 // This is a round about way to do this, but who knows what THROW_IO_ERROR()
88 // may be tricked out to do someday, keep it in the game.
89 try
90 {
91 THROW_IO_ERROR( se.what() );
92 }
93 catch( const IO_ERROR& ioe )
94 {
95 m_errors.move_push( std::make_unique<IO_ERROR>( ioe ) );
96 }
97
98 return false;
99 }
100
101 return true;
102}
103
104
106 PROGRESS_REPORTER* aProgressReporter )
107{
108 std::unique_lock<std::mutex> lock( m_loadInProgress );
109
110 long long int generatedTimestamp = 0;
111
112 if( !CatchErrors( [&]()
113 {
114 generatedTimestamp = aAdapter->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
128 m_cancelled = false;
129 m_adapter = aAdapter;
130
131 // Clear data before reading files
132 m_errors.clear();
133 m_list.clear();
134 m_queue.clear();
135
136 if( aNickname )
137 {
138 m_queue.push( *aNickname );
139 }
140 else
141 {
142 for( const wxString& nickname : aAdapter->GetLibraryNames() )
143 m_queue.push( nickname );
144 }
145
147 {
148 m_progress_reporter->SetMaxProgress( (int) m_queue.size() );
149 m_progress_reporter->Report( _( "Loading footprints..." ) );
150 }
151
153
155 m_progress_reporter->AdvancePhase();
156
157 if( m_cancelled )
158 m_list_timestamp = 0; // God knows what we got before we were canceled
159 else
160 m_list_timestamp = generatedTimestamp;
161
162 return m_errors.empty();
163}
164
165
167{
168 // Parse the footprints in parallel.
169
172 size_t num_elements = m_queue.size();
173 std::vector<std::future<size_t>> returns( num_elements );
174
175 auto fp_thread =
176 [ this, &queue_parsed ]() -> size_t
177 {
178 wxString nickname;
179
180 if( m_cancelled || !m_queue.pop( nickname ) )
181 return 0;
182
183 std::vector<wxString> fpnames;
184
186 [&]()
187 {
188 fpnames = m_adapter->GetFootprintNames( nickname );
189 } );
190
191 for( wxString fpname : fpnames )
192 {
194 [&]()
195 {
196 auto* fpinfo = new FOOTPRINT_INFO_IMPL( this, nickname, fpname );
197 queue_parsed.move_push( std::unique_ptr<FOOTPRINT_INFO>( fpinfo ) );
198 } );
199
200 if( m_cancelled )
201 return 0;
202 }
203
205 m_progress_reporter->AdvanceProgress();
206
207 return 1;
208 };
209
210 for( size_t ii = 0; ii < num_elements; ++ii )
211 returns[ii] = tp.submit_task( fp_thread );
212
213 for( const std::future<size_t>& ret : returns )
214 {
215 std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );
216
217 while( status != std::future_status::ready )
218 {
220 m_progress_reporter->KeepRefreshing();
221
222 status = ret.wait_for( std::chrono::milliseconds( 250 ) );
223 }
224 }
225
226 std::unique_ptr<FOOTPRINT_INFO> fpi;
227
228 while( queue_parsed.pop( fpi ) )
229 m_list.push_back( std::move( fpi ) );
230
231 std::sort( m_list.begin(), m_list.end(),
232 []( std::unique_ptr<FOOTPRINT_INFO> const& lhs,
233 std::unique_ptr<FOOTPRINT_INFO> const& rhs ) -> bool
234 {
235 if( !lhs || !rhs )
236 return false;
237
238 return *lhs < *rhs;
239 } );
240}
241
242
249
250
251void FOOTPRINT_LIST_IMPL::WriteCacheToFile( const wxString& aFilePath )
252{
253 wxFileName tmpFileName = wxFileName::CreateTempFileName( aFilePath );
254 wxFFileOutputStream outStream( tmpFileName.GetFullPath() );
255 wxTextOutputStream txtStream( outStream );
256
257 if( !outStream.IsOk() )
258 {
259 return;
260 }
261
262 txtStream << wxString::Format( wxT( "%lld" ), m_list_timestamp ) << endl;
263
264 for( std::unique_ptr<FOOTPRINT_INFO>& fpinfo : m_list )
265 {
266 txtStream << fpinfo->GetLibNickname() << endl;
267 txtStream << fpinfo->GetName() << endl;
268 txtStream << EscapeString( fpinfo->GetDesc(), CTX_LINE ) << endl;
269 txtStream << EscapeString( fpinfo->GetKeywords(), CTX_LINE ) << endl;
270 txtStream << wxString::Format( wxT( "%d" ), fpinfo->GetOrderNum() ) << endl;
271 txtStream << wxString::Format( wxT( "%u" ), fpinfo->GetPadCount() ) << endl;
272 txtStream << wxString::Format( wxT( "%u" ), fpinfo->GetUniquePadCount() ) << endl;
273 }
274
275 txtStream.Flush();
276 outStream.Close();
277
278 // Preserve the permissions of the current file
279 KIPLATFORM::IO::DuplicatePermissions( aFilePath, tmpFileName.GetFullPath() );
280
281 if( !wxRenameFile( tmpFileName.GetFullPath(), aFilePath, true ) )
282 {
283 // cleanup in case rename failed
284 // its also not the end of the world since this is just a cache file
285 wxRemoveFile( tmpFileName.GetFullPath() );
286 }
287}
288
289
290void FOOTPRINT_LIST_IMPL::ReadCacheFromFile( const wxString& aFilePath )
291{
292 wxTextFile cacheFile( aFilePath );
293
295 m_list.clear();
296
297 try
298 {
299 if( cacheFile.Exists() && cacheFile.Open() )
300 {
301 cacheFile.GetFirstLine().ToLongLong( &m_list_timestamp );
302
303 while( cacheFile.GetCurrentLine() + 6 < cacheFile.GetLineCount() )
304 {
305 wxString libNickname = cacheFile.GetNextLine();
306 wxString name = cacheFile.GetNextLine();
307 wxString desc = UnescapeString( cacheFile.GetNextLine() );
308 wxString keywords = UnescapeString( cacheFile.GetNextLine() );
309 int orderNum = wxAtoi( cacheFile.GetNextLine() );
310 unsigned int padCount = (unsigned) wxAtoi( cacheFile.GetNextLine() );
311 unsigned int uniquePadCount = (unsigned) wxAtoi( cacheFile.GetNextLine() );
312
313 FOOTPRINT_INFO_IMPL* fpinfo = new FOOTPRINT_INFO_IMPL( libNickname, name, desc,
314 keywords, orderNum,
315 padCount, uniquePadCount );
316
317 m_list.emplace_back( std::unique_ptr<FOOTPRINT_INFO>( fpinfo ) );
318 }
319 }
320 }
321 catch( ... )
322 {
323 // whatever went wrong, invalidate the cache
325 }
326
327 // Sanity check: an empty list is very unlikely to be correct.
328 if( m_list.size() == 0 )
330
331 if( cacheFile.IsOpened() )
332 cacheFile.Close();
333}
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
wxString GetLibDescription() const
Definition footprint.h:278
unsigned GetPadCount(INCLUDE_NPTH_T aIncludeNPTH=INCLUDE_NPTH_T(INCLUDE_NPTH)) const
Return the number of pads.
unsigned GetUniquePadCount(INCLUDE_NPTH_T aIncludeNPTH=INCLUDE_NPTH_T(INCLUDE_NPTH)) const
Return the number of unique non-blank pads.
wxString GetKeywords() const
Definition footprint.h:281
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:70
#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.