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
19 * along with this program. If not, see <https://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>
34
35
37{
38 FOOTPRINT_LIBRARY_ADAPTER* adapter = m_owner->GetAdapter();
39 wxCHECK( adapter, /* void */ );
40
41 try
42 {
43 std::unique_ptr<FOOTPRINT> footprint( adapter->LoadFootprint( m_nickname, m_fpname, false ) );
44
45 if( footprint == nullptr ) // Should happen only with malformed/broken libraries
46 {
48 }
49 else
50 {
51 m_numbered_pad_count = footprint->GetNumberedPadCount();
52 m_keywords = footprint->GetKeywords();
53 m_doc = footprint->GetLibDescription();
54 }
55 }
56 catch( const IO_ERROR& ioe )
57 {
58 // Store error in the owner's error list for later display
59 if( m_owner )
60 m_owner->PushError( std::make_unique<IO_ERROR>( ioe ) );
61
63 }
64
65 m_loaded = true;
66}
67
68
70{
71 std::unique_lock<std::mutex> lock( m_loadInProgress );
72
73 m_list.clear();
75}
76
77
79 const wxString& aLibName,
80 const std::function<void( const std::vector<LIB_TREE_ITEM*>& )>& aCallback )
81{
82 std::unique_lock<std::mutex> lock( m_loadInProgress );
83
84 std::vector<LIB_TREE_ITEM*> libList;
85 const auto& fullList = GetList();
86
87 FOOTPRINT_INFO_IMPL dummy( aLibName, wxEmptyString );
88 std::unique_ptr<FOOTPRINT_INFO> dummyPtr( &dummy );
89
90 auto libBounds = std::equal_range( fullList.begin(), fullList.end(), dummyPtr,
91 []( const std::unique_ptr<FOOTPRINT_INFO>& a, const std::unique_ptr<FOOTPRINT_INFO>& b )
92 {
93 if( !a || !b )
94 return false;
95
96 return StrNumCmp( a->GetLibNickname(), b->GetLibNickname(), false ) < 0;
97 } );
98
99 dummyPtr.release();
100
101 for( auto i = libBounds.first; i != libBounds.second; ++i )
102 {
103 if( *i )
104 libList.push_back( i->get() );
105 }
106
107 aCallback( libList );
108}
109
110
111bool FOOTPRINT_LIST_IMPL::CatchErrors( const std::function<void()>& aFunc )
112{
113 try
114 {
115 aFunc();
116 }
117 catch( const IO_ERROR& ioe )
118 {
119 m_errors.move_push( std::make_unique<IO_ERROR>( ioe ) );
120 return false;
121 }
122 catch( const std::exception& se )
123 {
124 // This is a round about way to do this, but who knows what THROW_IO_ERROR()
125 // may be tricked out to do someday, keep it in the game.
126 try
127 {
128 THROW_IO_ERROR( se.what() );
129 }
130 catch( const IO_ERROR& ioe )
131 {
132 m_errors.move_push( std::make_unique<IO_ERROR>( ioe ) );
133 }
134
135 return false;
136 }
137
138 return true;
139}
140
141
143 PROGRESS_REPORTER* aProgressReporter )
144{
145 std::unique_lock<std::mutex> lock( m_loadInProgress );
146
147 m_adapter = aAdapter;
148
149 // AsyncLoad() must be called before BlockUntilLoaded() to ensure library loading is started.
150 // This is necessary when the footprint chooser is opened from contexts that don't preload
151 // footprint libraries (e.g., eeschema).
152 m_adapter->AsyncLoad();
153 m_adapter->BlockUntilLoaded();
154
155 long long int generatedTimestamp = 0;
156
157 if( !CatchErrors( [&]()
158 {
159 generatedTimestamp = aAdapter->GenerateTimestamp( aNickname );
160 } ) )
161 {
162 return false;
163 }
164
165 if( generatedTimestamp == m_list_timestamp )
166 return true;
167
168 // Disable KIID generation: not needed for library parts; sometimes very slow
169 KIID_NIL_SET_RESET reset_kiid;
170
171 m_progress_reporter = aProgressReporter;
172
173 m_cancelled = false;
174
175 // Clear data before reading files
176 m_errors.clear();
177 m_list.clear();
178 m_queue.clear();
179
180 if( aNickname )
181 {
182 m_queue.push( *aNickname );
183 }
184 else
185 {
186 for( const wxString& nickname : aAdapter->GetLibraryNames() )
187 m_queue.push( nickname );
188 }
189
191 {
192 m_progress_reporter->SetMaxProgress( (int) m_queue.size() );
193 m_progress_reporter->Report( _( "Loading footprints..." ) );
194 }
195
197
199 m_progress_reporter->AdvancePhase();
200
201 if( m_cancelled )
202 m_list_timestamp = 0; // God knows what we got before we were canceled
203 else
204 m_list_timestamp = generatedTimestamp;
205
206 return m_errors.empty();
207}
208
209
211{
212 // Parse the footprints in parallel.
213
216 size_t num_elements = m_queue.size();
217 std::vector<std::future<size_t>> returns( num_elements );
218
219 auto fp_thread =
220 [ this, &queue_parsed ]() -> size_t
221 {
222 // Each thread pool worker needs its own KIID_NIL_SET_RESET since g_createNilUuids
223 // is thread_local. This prevents generating real UUIDs for temporary footprint data.
224 KIID_NIL_SET_RESET reset_kiid;
225
226 wxString nickname;
227
228 if( m_cancelled || !m_queue.pop( nickname ) )
229 return 0;
230
231 std::vector<wxString> fpnames;
232
234 [&]()
235 {
236 fpnames = m_adapter->GetFootprintNames( nickname );
237 } );
238
239 for( wxString fpname : fpnames )
240 {
242 [&]()
243 {
244 auto* fpinfo = new FOOTPRINT_INFO_IMPL( this, nickname, fpname );
245 queue_parsed.move_push( std::unique_ptr<FOOTPRINT_INFO>( fpinfo ) );
246 } );
247
248 if( m_cancelled )
249 return 0;
250 }
251
253 m_progress_reporter->AdvanceProgress();
254
255 return 1;
256 };
257
258 for( size_t ii = 0; ii < num_elements; ++ii )
259 returns[ii] = tp.submit_task( fp_thread );
260
261 for( const std::future<size_t>& ret : returns )
262 {
263 std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );
264
265 while( status != std::future_status::ready )
266 {
268 m_progress_reporter->KeepRefreshing();
269
270 status = ret.wait_for( std::chrono::milliseconds( 250 ) );
271 }
272 }
273
274 std::unique_ptr<FOOTPRINT_INFO> fpi;
275
276 while( queue_parsed.pop( fpi ) )
277 m_list.push_back( std::move( fpi ) );
278
279 std::sort( m_list.begin(), m_list.end(),
280 []( std::unique_ptr<FOOTPRINT_INFO> const& lhs,
281 std::unique_ptr<FOOTPRINT_INFO> const& rhs ) -> bool
282 {
283 if( !lhs || !rhs )
284 return false;
285
286 return *lhs < *rhs;
287 } );
288}
289
290
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_numbered_pad_count
Number of unique electrical pads (numeric or BGA-style numbers)
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.
void WithFootprintsForLibrary(const wxString &aLibName, const std::function< void(const std::vector< LIB_TREE_ITEM * > &)> &aCallback)
Execute a callback with thread-safe access to the footprints for a library.
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.
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
const std::vector< std::unique_ptr< FOOTPRINT_INFO > > & GetList() const
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:267
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)
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
std::vector< FAB_LAYER_COLOR > dummy
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:27