KiCad PCB EDA Suite
Loading...
Searching...
No Matches
fp_tree_synchronizing_adapter.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) 2017 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Maciej Suminski <[email protected]>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 3
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU 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, you may find one here:
20 * https://www.gnu.org/licenses/gpl-3.0.html
21 * or you may search the http://www.gnu.org website for the version 3 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include <pgm_base.h>
32#include <footprint_info_impl.h>
34#include <project_pcb.h>
35#include <string_utils.h>
36#include <board.h>
37#include <footprint.h>
38#include <tool/tool_manager.h>
40#include <wx/settings.h>
41
42
43wxObjectDataPtr<LIB_TREE_MODEL_ADAPTER>
45{
46 auto* adapter = new FP_TREE_SYNCHRONIZING_ADAPTER( aFrame, aLibs );
47 return wxObjectDataPtr<LIB_TREE_MODEL_ADAPTER>( adapter );
48}
49
50
57
58
63
64
65bool FP_TREE_SYNCHRONIZING_ADAPTER::IsContainer( const wxDataViewItem& aItem ) const
66{
67 const LIB_TREE_NODE* node = ToNode( aItem );
68 return node ? node->m_Type == LIB_TREE_NODE::TYPE::LIBRARY : true;
69}
70
71
72#define PROGRESS_INTERVAL_MILLIS 33 // 30 FPS refresh rate
73
75{
76 m_libs = aLibs;
77
78 // Process already stored libraries
79 for( auto it = m_tree.m_Children.begin(); it != m_tree.m_Children.end(); )
80 {
81 const wxString& name = it->get()->m_Name;
82
83 try
84 {
85 // Remove the library if it no longer exists or it exists in both the global and the
86 // project library but the project library entry is disabled.
87 if( !m_libs->HasLibrary( name, true )
88 || m_libs->HasLibrary( name, true ) != m_libs->HasLibrary( name, false ) )
89 {
90 it = deleteLibrary( it );
91 continue;
92 }
93
94 updateLibrary( *(LIB_TREE_NODE_LIBRARY*) it->get() );
95 }
96 catch( ... )
97 {
98 // If the library isn't found, remove it
99 it = deleteLibrary( it );
100 continue;
101 }
102
103 ++it;
104 }
105
106 // Look for new libraries
108 PROJECT_FILE& project = m_frame->Prj().GetProjectFile();
109 size_t count = m_libMap.size();
110
111 for( const wxString& libName : m_libs->GetLibraryNames() )
112 {
113 if( m_libMap.count( libName ) == 0 )
114 {
115 if( std::optional<wxString> optDesc = PROJECT_PCB::FootprintLibAdapter( &m_frame->Prj() )->
116 GetLibraryDescription( libName ) )
117 {
118 bool pinned = alg::contains( cfg->m_Session.pinned_fp_libs, libName )
119 || alg::contains( project.m_PinnedFootprintLibs, libName );
120
121 DoAddLibrary( libName, *optDesc, getFootprints( libName ), pinned, true );
122 m_libMap.insert( libName );
123 }
124 }
125 }
126
127 if( m_libMap.size() > count )
128 m_tree.AssignIntrinsicRanks( m_shownColumns );
129}
130
131
133{
134 return m_libs->GetLibraryNames().size();
135}
136
137
139{
140 std::vector<LIB_TREE_ITEM*> footprints = getFootprints( aLibNode.m_Name );
141
142 // remove the common part from the footprints list
143 for( auto nodeIt = aLibNode.m_Children.begin(); nodeIt != aLibNode.m_Children.end(); )
144 {
145 // Since the list is sorted we can use a binary search to speed up searches within
146 // libraries with lots of footprints.
147 FOOTPRINT_INFO_IMPL dummy( wxEmptyString, (*nodeIt)->m_Name );
148 auto footprintIt = std::lower_bound( footprints.begin(), footprints.end(), &dummy,
149 []( LIB_TREE_ITEM* a, LIB_TREE_ITEM* b )
150 {
151 return StrNumCmp( a->GetName(), b->GetName(), false ) < 0;
152 } );
153
154 if( footprintIt != footprints.end() && dummy.GetName() == (*footprintIt)->GetName() )
155 {
156 // footprint exists both in the lib tree and the footprint info list; just
157 // update the node data
158 static_cast<LIB_TREE_NODE_ITEM*>( nodeIt->get() )->Update( *footprintIt );
159 footprints.erase( footprintIt );
160 ++nodeIt;
161 }
162 else
163 {
164 // node does not exist in the library manager, remove the corresponding node
165 nodeIt = aLibNode.m_Children.erase( nodeIt );
166 }
167 }
168
169 // now the footprint list contains only new aliases that need to be added to the tree
170 for( LIB_TREE_ITEM* footprint : footprints )
171 aLibNode.AddItem( footprint );
172
174 m_libMap.insert( aLibNode.m_Name );
175}
176
177
178LIB_TREE_NODE::PTR_VECTOR::iterator
179FP_TREE_SYNCHRONIZING_ADAPTER::deleteLibrary( LIB_TREE_NODE::PTR_VECTOR::iterator& aLibNodeIt )
180{
181 LIB_TREE_NODE* node = aLibNodeIt->get();
182 m_libMap.erase( node->m_Name );
183 auto it = m_tree.m_Children.erase( aLibNodeIt );
184 return it;
185}
186
187
189{
190 return FindItem( m_frame->GetLoadedFPID() );
191}
192
193
194void FP_TREE_SYNCHRONIZING_ADAPTER::GetValue( wxVariant& aVariant, wxDataViewItem const& aItem,
195 unsigned int aCol ) const
196{
197 if( IsFrozen() )
198 {
199 aVariant = wxEmptyString;
200 return;
201 }
202
203 LIB_TREE_NODE* node = ToNode( aItem );
204
205 switch( aCol )
206 {
207 case NAME_COL:
208 {
209 if( node->m_LibId == m_frame->GetLoadedFPID() && !m_frame->IsCurrentFPFromBoard() )
210 {
211 // Do not use GetLoadedFPID(); it returns m_footprintNameWhenLoaded.
212 node->m_Name =
213 m_frame->GetBoard()->GetFirstFootprint()->GetFPID().GetUniStringLibItemName();
214
215 // mark modified part with an asterisk
216 if( m_frame->GetScreen()->IsContentModified() )
217 aVariant = node->m_Name + wxT( " *" );
218 else
219 aVariant = node->m_Name;
220 }
221 else if( node->m_Pinned )
222 {
223 aVariant = GetPinningSymbol() + node->m_Name;
224 }
225 else
226 {
227 aVariant = node->m_Name;
228 }
229
230 break;
231 }
232
233 case DESC_COL:
234 {
235 if( node->m_LibId == m_frame->GetLoadedFPID() && !m_frame->IsCurrentFPFromBoard() )
236 {
237 node->m_Desc = m_frame->GetBoard()->GetFirstFootprint()->GetLibDescription();
238 }
239 else if( node->m_Type == LIB_TREE_NODE::TYPE::LIBRARY )
240 {
241 if( std::optional<wxString> optDesc = PROJECT_PCB::FootprintLibAdapter( &m_frame->Prj() )->
242 GetLibraryDescription( node->m_LibId.GetLibNickname() ) )
243 {
244 node->m_Desc = *optDesc;
245 }
246 }
247
248 wxString descStr = UnescapeString( node->m_Desc );
249 descStr.Replace( wxS( "\n" ), wxS( " " ) ); // Clear line breaks
250
251 aVariant = descStr;
252 break;
253 }
254
255 default: // column == -1 is used for default Compare function
256 aVariant = node->m_Name;
257 break;
258 }
259}
260
261
262bool FP_TREE_SYNCHRONIZING_ADAPTER::GetAttr( wxDataViewItem const& aItem, unsigned int aCol,
263 wxDataViewItemAttr& aAttr ) const
264{
265 if( IsFrozen() )
266 return false;
267
268 // change attributes only for the name field
269 if( aCol != 0 )
270 return false;
271
272 // don't link to a board footprint, even if the FPIDs match
273 if( m_frame->IsCurrentFPFromBoard() )
274 return false;
275
276 LIB_TREE_NODE* node = ToNode( aItem );
277 wxCHECK( node, false );
278
279 switch( node->m_Type )
280 {
281 case LIB_TREE_NODE::TYPE::LIBRARY:
282 if( node->m_Name == m_frame->GetLoadedFPID().GetLibNickname().wx_str() )
283 {
284 // mark the current library if it's collapsed
285 if( !m_widget->IsExpanded( ToItem( node ) ) )
286 {
287 aAttr.SetStrikethrough( true ); // LIB_TREE_RENDERER uses strikethrough as a
288 // proxy for "is canvas item"
289 }
290
291 // mark modified libs with bold font
292 if( m_frame->GetScreen()->IsContentModified() && !m_frame->IsCurrentFPFromBoard() )
293 aAttr.SetBold( true );
294 }
295 break;
296
297 case LIB_TREE_NODE::TYPE::ITEM:
298 if( node->m_LibId == m_frame->GetLoadedFPID() )
299 {
300 // mark the current (on-canvas) part
301 aAttr.SetStrikethrough( true ); // LIB_TREE_RENDERER uses strikethrough as a
302 // proxy for "is canvas item"
303
304 // mark modified part with bold font
305 if( m_frame->GetScreen()->IsContentModified() && !m_frame->IsCurrentFPFromBoard() )
306 aAttr.SetBold( true );
307 }
308 break;
309
310 default:
311 return false;
312 }
313
314 return true;
315}
316
317
318bool FP_TREE_SYNCHRONIZING_ADAPTER::HasPreview( const wxDataViewItem& aItem )
319{
320 LIB_TREE_NODE* node = ToNode( aItem );
321 wxCHECK( node, false );
322
323 return node->m_Type == LIB_TREE_NODE::TYPE::ITEM && node->m_LibId != m_frame->GetLoadedFPID();
324}
325
326
327static const wxString c_previewName = wxS( "fpHoverPreview" );
328
329
330void FP_TREE_SYNCHRONIZING_ADAPTER::ShowPreview( wxWindow* aParent, const wxDataViewItem& aItem )
331{
332 LIB_TREE_NODE* node = ToNode( aItem );
333 wxCHECK( node, /* void */ );
334
335 wxWindow* previewWindow = wxWindow::FindWindowByName( c_previewName, aParent );
336 FOOTPRINT_PREVIEW_PANEL* preview = dynamic_cast<FOOTPRINT_PREVIEW_PANEL*>( previewWindow );
337
338 if( !preview )
339 {
340 wxBoxSizer* mainSizer = new wxBoxSizer( wxVERTICAL );
341 aParent->SetSizer( mainSizer );
342
343 preview = FOOTPRINT_PREVIEW_PANEL::New( &m_frame->Kiway(), aParent, m_frame );
344
345 preview->SetName( c_previewName );
346 preview->GetGAL()->SetAxesEnabled( false );
347
348 mainSizer->Add( preview, 1, wxEXPAND | wxALL, 1 );
349 aParent->Layout();
350 }
351
352 preview->DisplayFootprint( node->m_LibId );
353}
354
355
357{
358 wxWindow* previewWindow = wxWindow::FindWindowByName( c_previewName, aParent );
359
360 if( FOOTPRINT_PREVIEW_PANEL* preview = dynamic_cast<FOOTPRINT_PREVIEW_PANEL*>( previewWindow ) )
361 {
362 preview->GetCanvas()->SetEvtHandlerEnabled( false );
363 preview->GetCanvas()->StopDrawing();
364 }
365}
const char * name
KIGFX::GAL * GetGAL() const
Return a pointer to the GAL instance used in the panel.
Module editor specific tools.
An interface to the global shared library manager that is schematic-specific and linked to one projec...
Panel that renders a single footprint via Cairo GAL, meant to be exported through Kiface.
bool DisplayFootprint(const LIB_ID &aFPID) override
Set the currently displayed footprint.
static FOOTPRINT_PREVIEW_PANEL * New(KIWAY *aKiway, wxWindow *aParent, UNITS_PROVIDER *aUnitsProvider)
FOOTPRINT_LIBRARY_ADAPTER * m_libs
FP_TREE_MODEL_ADAPTER(PCB_BASE_FRAME *aParent, FOOTPRINT_LIBRARY_ADAPTER *aLibs)
Constructor; takes a set of libraries to be included in the search.
std::vector< LIB_TREE_ITEM * > getFootprints(const wxString &aLibName)
FP_TREE_SYNCHRONIZING_ADAPTER(FOOTPRINT_EDIT_FRAME *aFrame, FOOTPRINT_LIBRARY_ADAPTER *aLibs)
bool HasPreview(const wxDataViewItem &aItem) override
void Sync(FOOTPRINT_LIBRARY_ADAPTER *aLibs)
bool GetAttr(wxDataViewItem const &aItem, unsigned int aCol, wxDataViewItemAttr &aAttr) const override
void updateLibrary(LIB_TREE_NODE_LIBRARY &aLibNode)
static wxObjectDataPtr< LIB_TREE_MODEL_ADAPTER > Create(FOOTPRINT_EDIT_FRAME *aFrame, FOOTPRINT_LIBRARY_ADAPTER *aLibs)
int GetLibrariesCount() const override
Return the number of libraries loaded in the tree.
void ShutdownPreview(wxWindow *aParent) override
bool IsContainer(const wxDataViewItem &aItem) const override
LIB_TREE_NODE::PTR_VECTOR::iterator deleteLibrary(LIB_TREE_NODE::PTR_VECTOR::iterator &aLibNodeIt)
TOOL_INTERACTIVE * GetContextMenuTool() override
void ShowPreview(wxWindow *aParent, const wxDataViewItem &aItem) override
void GetValue(wxVariant &aVariant, wxDataViewItem const &aItem, unsigned int aCol) const override
void SetAxesEnabled(bool aAxesEnabled)
Enable drawing the axes.
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition lib_id.h:87
A mix-in to provide polymorphism between items stored in libraries (symbols, aliases and footprints).
static LIB_TREE_NODE * ToNode(wxDataViewItem aItem)
Convert wxDataViewItem -> #SYM_TREE_NODE.
static wxDataViewItem ToItem(const LIB_TREE_NODE *aNode)
Convert #SYM_TREE_NODE -> wxDataViewItem.
static const wxString GetPinningSymbol()
@ NAME_COL
Library or library item name column.
@ DESC_COL
Library or library description column.
std::vector< wxString > m_shownColumns
LIB_TREE_NODE_LIBRARY & DoAddLibrary(const wxString &aNodeName, const wxString &aDesc, const std::vector< LIB_TREE_ITEM * > &aItemList, bool pinned, bool presorted)
Add the given list of symbols by alias.
wxDataViewItem FindItem(const LIB_ID &aLibId)
Returns tree item corresponding to part.
Node type: LIB_ID.
void Update(LIB_TREE_ITEM *aItem)
Update the node using data from a LIB_ALIAS object.
Node type: library.
LIB_TREE_NODE_ITEM & AddItem(LIB_TREE_ITEM *aItem)
Construct a new alias node, add it to this library, and return it.
Model class in the component selector Model-View-Adapter (mediated MVC) architecture.
PTR_VECTOR m_Children
void AssignIntrinsicRanks(const std::vector< wxString > &aShownColumns, bool presorted=false)
Store intrinsic ranks on all children of this node.
virtual COMMON_SETTINGS * GetCommonSettings() const
Definition pgm_base.cpp:537
The backing store for a PROJECT, in JSON format.
static FOOTPRINT_LIBRARY_ADAPTER * FootprintLibAdapter(PROJECT *aProject)
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:100
PGM_BASE & Pgm()
The global program "get" accessor.
Definition pgm_base.cpp:946
see class PGM_BASE
std::vector< FAB_LAYER_COLOR > dummy
wxString UnescapeString(const wxString &aSource)
std::vector< wxString > pinned_fp_libs
static const wxString c_previewName