KiCad PCB EDA Suite
Loading...
Searching...
No Matches
symbol_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
27
28#include <wx/settings.h>
29
30#include <core/throttle.h>
31#include <pgm_base.h>
35#include <project_sch.h>
36#include <string_utils.h>
39#include <widgets/wx_panel.h>
40
41
42wxObjectDataPtr<LIB_TREE_MODEL_ADAPTER>
44{
45 auto* adapter = new SYMBOL_TREE_SYNCHRONIZING_ADAPTER( aParent, aLibMgr );
46 return wxObjectDataPtr<LIB_TREE_MODEL_ADAPTER>( adapter );
47}
48
49
51 SYMBOL_LIBRARY_MANAGER* aLibMgr ) :
52 LIB_TREE_MODEL_ADAPTER( aParent, "pinned_symbol_libs",
53 aParent->GetViewerSettingsBase()->m_LibTree ),
54 m_frame( aParent ),
55 m_libMgr( aLibMgr ),
56 m_lastSyncHash( -1 )
57{
58}
59
60
65
66
67bool SYMBOL_TREE_SYNCHRONIZING_ADAPTER::IsContainer( const wxDataViewItem& aItem ) const
68{
69 const LIB_TREE_NODE* node = ToNode( aItem );
70 return node ? node->m_Type == LIB_TREE_NODE::TYPE::LIBRARY : true;
71}
72
73
74void SYMBOL_TREE_SYNCHRONIZING_ADAPTER::Sync( const wxString& aForceRefresh,
75 std::function<void( int, int, const wxString& )> aProgressCallback )
76{
77 THROTTLE progressThrottle( std::chrono::milliseconds( 120 ) );
78
79 m_lastSyncHash = m_libMgr->GetHash();
80 int i = 0, max = GetLibrariesCount();
81
83
84 // Process already stored libraries
85 for( auto it = m_tree.m_Children.begin(); it != m_tree.m_Children.end(); )
86 {
87 const wxString& name = it->get()->m_Name;
88
89 if( progressThrottle.Ready() )
90 aProgressCallback( i, max, name );
91
92 // Check the table row directly rather than adapter->HasLibrary(), which requires the
93 // library to be fully loaded. After table reloads (e.g. adding a new library), all
94 // previously loaded libraries are cleared and not yet reloaded, so HasLibrary() would
95 // return false and incorrectly remove them from the tree.
96 //
97 // However, we must still remove nodes for libraries that failed to load (e.g. the
98 // library file was deleted), otherwise stale symbols remain because updateLibrary()
99 // skips re-enumeration when the URI-based hash is unchanged.
100 std::optional<LIBRARY_TABLE_ROW*> optRow = adapter->GetRow( name );
101 std::optional<LIB_STATUS> libStatus = adapter->GetLibraryStatus( name );
102
103 bool loadFailed = libStatus.has_value()
104 && libStatus->load_status == LOAD_STATUS::LOAD_ERROR;
105
106 if( !optRow.has_value()
107 || ( *optRow )->Disabled()
108 || ( *optRow )->Hidden()
109 || loadFailed
110 || name == aForceRefresh )
111 {
112 it = deleteLibrary( it );
113 continue;
114 }
115 else
116 {
117 updateLibrary( *static_cast<LIB_TREE_NODE_LIBRARY*>( it->get() ) );
118 }
119
120 ++it;
121 ++i;
122 }
123
124 // Look for new libraries
125 //
127 PROJECT_FILE& project = m_frame->Prj().GetProjectFile();
128
129 for( const auto& [libName, status] : adapter->GetLibraryStatuses() )
130 {
131 if( status.load_status != LOAD_STATUS::LOADED || status.error )
132 continue;
133
134 if( m_libHashes.count( libName ) == 0 )
135 {
136 if( progressThrottle.Ready() )
137 aProgressCallback( i++, max, libName );
138
139 auto optRow = adapter->GetRow( libName );
140 wxCHECK2( optRow.has_value(), continue );
141
142 bool pinned = alg::contains( cfg->m_Session.pinned_symbol_libs, libName )
143 || alg::contains( project.m_PinnedSymbolLibs, libName );
144
145 LIB_TREE_NODE_LIBRARY& lib_node = DoAddLibraryNode( libName, ( *optRow )->Description(), pinned );
146
147 updateLibrary( lib_node );
148 }
149 }
150
151 m_tree.AssignIntrinsicRanks( m_shownColumns );
152}
153
154
156{
158
159 for( const wxString& libName : m_libMgr->GetLibraryNames() )
160 {
161 if( m_libHashes.count( libName ) == 0 )
162 ++count;
163 }
164
165 return count;
166}
167
168
170{
171 auto hashIt = m_libHashes.find( aLibNode.m_Name );
172
173 if( hashIt == m_libHashes.end() )
174 {
175 // add a new library
176 for( LIB_SYMBOL* symbol : m_libMgr->EnumerateSymbols( aLibNode.m_Name ) )
177 aLibNode.AddItem( symbol );
178 }
179 else if( hashIt->second != m_libMgr->GetLibraryHash( aLibNode.m_Name ) )
180 {
181 // update an existing library
182 std::list<LIB_SYMBOL*> symbols = m_libMgr->EnumerateSymbols( aLibNode.m_Name );
183
184 // remove the common part from the aliases list
185 for( auto nodeIt = aLibNode.m_Children.begin(); nodeIt != aLibNode.m_Children.end(); /**/ )
186 {
187 auto symbolIt = std::find_if( symbols.begin(), symbols.end(),
188 [&] ( const LIB_SYMBOL* a )
189 {
190 return a->GetName() == (*nodeIt)->m_LibId.GetLibItemName().wx_str();
191 } );
192
193 if( symbolIt != symbols.end() )
194 {
195 // alias exists both in the symbol tree and the library manager,
196 // update only the node data.
197 static_cast<LIB_TREE_NODE_ITEM*>( nodeIt->get() )->Update( *symbolIt );
198 symbols.erase( symbolIt );
199 ++nodeIt;
200 }
201 else
202 {
203 // node does not exist in the library manager, remove the corresponding node
204 nodeIt = aLibNode.m_Children.erase( nodeIt );
205 }
206 }
207
208 // now the aliases list contains only new aliases that need to be added to the tree
209 for( LIB_SYMBOL* symbol : symbols )
210 aLibNode.AddItem( symbol );
211 }
212
214
215 for( const wxString& column : adapter->GetAvailableExtraFields( aLibNode.m_Name ) )
216 addColumnIfNecessary( column );
217
219 m_libHashes[aLibNode.m_Name] = m_libMgr->GetLibraryHash( aLibNode.m_Name );
220}
221
222
223LIB_TREE_NODE::PTR_VECTOR::iterator
224SYMBOL_TREE_SYNCHRONIZING_ADAPTER::deleteLibrary( LIB_TREE_NODE::PTR_VECTOR::iterator& aLibNodeIt )
225{
226 LIB_TREE_NODE* node = aLibNodeIt->get();
227 m_libHashes.erase( node->m_Name );
228 return m_tree.m_Children.erase( aLibNodeIt );
229}
230
231
233{
234 if( m_frame->GetCurSymbol() )
235 return FindItem( m_frame->GetCurSymbol()->GetLibId() );
236
237 return wxDataViewItem();
238}
239
240
241void SYMBOL_TREE_SYNCHRONIZING_ADAPTER::GetValue( wxVariant& aVariant, wxDataViewItem const& aItem,
242 unsigned int aCol ) const
243{
244 if( IsFrozen() )
245 {
246 aVariant = wxEmptyString;
247 return;
248 }
249
250 LIB_TREE_NODE* node = ToNode( aItem );
251 wxASSERT( node );
252
253 switch( aCol )
254 {
255 case NAME_COL:
256 if( m_frame->GetCurSymbol() && m_frame->GetCurSymbol()->GetLibId() == node->m_LibId )
257 node->m_Name = m_frame->GetCurSymbol()->GetLibId().GetUniStringLibItemName();
258
259 if( node->m_Pinned )
260 aVariant = GetPinningSymbol() + UnescapeString( node->m_Name );
261 else
262 aVariant = UnescapeString( node->m_Name );
263
264 // mark modified items with an asterisk
265 if( node->m_Type == LIB_TREE_NODE::TYPE::LIBRARY )
266 {
267 if( m_libMgr->IsLibraryModified( node->m_Name ) )
268 aVariant = aVariant.GetString() + " *";
269 }
270 else if( node->m_Type == LIB_TREE_NODE::TYPE::ITEM )
271 {
272 if( m_libMgr->IsSymbolModified( node->m_Name, node->m_Parent->m_Name ) )
273 aVariant = aVariant.GetString() + " *";
274 }
275
276 break;
277
278 default:
279 if( m_colIdxMap.count( aCol ) )
280 {
281 if( node->m_Type == LIB_TREE_NODE::TYPE::LIBRARY )
282 {
284 &m_frame->Prj() );
285
286 if( auto optRow = adapter->GetRow( node->m_LibId.GetLibNickname() ) )
287 node->m_Desc = ( *optRow )->Description();
288
289 if( !m_libMgr->IsLibraryLoaded( node->m_Name ) )
290 aVariant = _( "(failed to load)" ) + wxS( " " ) + aVariant.GetString();
291 else if( m_libMgr->IsLibraryReadOnly( node->m_Name ) )
292 aVariant = _( "(read-only)" ) + wxS( " " ) + aVariant.GetString();
293 }
294
295 const wxString& key = m_colIdxMap.at( aCol );
296
297 if( m_frame->GetCurSymbol() && m_frame->GetCurSymbol()->GetLibId() == node->m_LibId )
298 {
299 node->m_Desc = m_frame->GetCurSymbol()->GetShownDescription();
300 }
301
302 wxString valueStr;
303
304 if( key == wxT( "Description" ) )
305 valueStr = node->m_Desc;
306 else if( node->m_Fields.count( key ) )
307 valueStr = node->m_Fields.at( key );
308 else
309 valueStr = wxEmptyString;
310
311 valueStr.Replace( wxS( "\n" ), wxS( " " ) ); // Clear line breaks
312
313 if( !aVariant.GetString().IsEmpty() )
314 {
315 if( !valueStr.IsEmpty() )
316 aVariant = valueStr + wxS( " - " ) + aVariant.GetString();
317 }
318 else
319 {
320 aVariant = valueStr;
321 }
322 }
323 break;
324 }
325}
326
327
328bool SYMBOL_TREE_SYNCHRONIZING_ADAPTER::GetAttr( wxDataViewItem const& aItem, unsigned int aCol,
329 wxDataViewItemAttr& aAttr ) const
330{
331 if( IsFrozen() )
332 return false;
333
334 LIB_TREE_NODE* node = ToNode( aItem );
335 wxCHECK( node, false );
336
337 // Mark both columns of unloaded libraries using grey text color (to look disabled)
338 if( node->m_Type == LIB_TREE_NODE::TYPE::LIBRARY && !m_libMgr->IsLibraryLoaded( node->m_Name ) )
339 {
340 aAttr.SetColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) );
341 return true;
342 }
343
344 // The remaining attributes are only for the name column
345 if( aCol != NAME_COL )
346 return false;
347
348 LIB_SYMBOL* curSymbol = m_frame->GetCurSymbol();
349
350 switch( node->m_Type )
351 {
352 case LIB_TREE_NODE::TYPE::LIBRARY:
353 // mark modified libs with bold font
354 aAttr.SetBold( m_libMgr->IsLibraryModified( node->m_Name ) );
355
356 // mark the current library if it's collapsed
357 if( curSymbol && curSymbol->GetLibId().GetLibNickname() == node->m_LibId.GetLibNickname() )
358 {
359 if( !m_widget->IsExpanded( ToItem( node ) ) )
360 {
361 aAttr.SetStrikethrough( true ); // LIB_TREE_RENDERER uses strikethrough as a
362 // proxy for "is canvas item"
363 }
364 }
365
366 break;
367
368 case LIB_TREE_NODE::TYPE::ITEM:
369 // mark modified part with bold font
370 aAttr.SetBold( m_libMgr->IsSymbolModified( node->m_Name, node->m_Parent->m_Name ) );
371
372 // mark aliases with italic font
373 aAttr.SetItalic( !node->m_IsRoot );
374
375 // mark the current (on-canvas) part
376 if( curSymbol && curSymbol->GetLibId() == node->m_LibId )
377 {
378 aAttr.SetStrikethrough( true ); // LIB_TREE_RENDERER uses strikethrough as a
379 // proxy for "is canvas item"
380 }
381
382 break;
383
384 default:
385 return false;
386 }
387
388 return true;
389}
390
391
392bool SYMBOL_TREE_SYNCHRONIZING_ADAPTER::HasPreview( const wxDataViewItem& aItem )
393{
394 LIB_TREE_NODE* node = ToNode( aItem );
395 wxCHECK( node, false );
396
397 return node->m_Type == LIB_TREE_NODE::TYPE::ITEM && node->m_LibId != m_frame->GetTargetLibId();
398}
399
400
401static const wxString c_previewName = wxS( "symHoverPreview" );
402
403
405 const wxDataViewItem& aItem )
406{
407 LIB_TREE_NODE* node = ToNode( aItem );
408 wxCHECK( node, /* void */ );
409
410 SYMBOL_PREVIEW_WIDGET* preview = dynamic_cast<SYMBOL_PREVIEW_WIDGET*>(
411 wxWindow::FindWindowByName( c_previewName, aParent ) );
412
413 if( !preview )
414 {
415 wxBoxSizer* mainSizer = new wxBoxSizer( wxVERTICAL );
416 aParent->SetSizer( mainSizer );
417
418 WX_PANEL* panel = new WX_PANEL( aParent );
419 panel->SetBorders( true, true, true, true );
421
422 wxBoxSizer* panelSizer = new wxBoxSizer( wxVERTICAL );
423 panel->SetSizer( panelSizer );
424
425 EDA_DRAW_PANEL_GAL::GAL_TYPE backend = m_frame->GetCanvas()->GetBackend();
426 preview = new SYMBOL_PREVIEW_WIDGET( panel, &m_frame->Kiway(), false, backend );
427 preview->SetName( c_previewName );
428 preview->SetLayoutDirection( wxLayout_LeftToRight );
429
430 panelSizer->Add( preview, 1, wxEXPAND | wxALL, 1 );
431 mainSizer->Add( panel, 1, wxEXPAND, 0 );
432 aParent->Layout();
433 }
434
435 preview->DisplaySymbol( node->m_LibId, node->m_Unit );
436}
437
438
440{
441 wxWindow* previewWindow = wxWindow::FindWindowByName( c_previewName, aParent );
442
443 if( SYMBOL_PREVIEW_WIDGET* preview = dynamic_cast<SYMBOL_PREVIEW_WIDGET*>( previewWindow ) )
444 {
445 preview->GetCanvas()->SetEvtHandlerEnabled( false );
446 preview->GetCanvas()->StopDrawing();
447 }
448}
const char * name
static const COLOR4D BLACK
Definition color4d.h:406
std::optional< LIB_STATUS > GetLibraryStatus(const wxString &aNickname) const
Returns the status of a loaded library, or nullopt if the library hasn't been loaded (yet)
std::optional< LIBRARY_TABLE_ROW * > GetRow(const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH) const
Like LIBRARY_MANAGER::GetRow but filtered to the LIBRARY_TABLE_TYPE of this adapter.
std::vector< std::pair< wxString, LIB_STATUS > > GetLibraryStatuses() const
Returns a list of all library nicknames and their status (even if they failed to load)
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition lib_id.h:87
Define a library symbol object.
Definition lib_symbol.h:83
const LIB_ID & GetLibId() const override
Definition lib_symbol.h:152
LIB_TREE_MODEL_ADAPTER(EDA_BASE_FRAME *aParent, const wxString &aPinnedKey, APP_SETTINGS_BASE::LIB_TREE &aSettingsStruct)
Create the adapter.
void addColumnIfNecessary(const wxString &aHeader)
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.
std::map< unsigned, wxString > m_colIdxMap
virtual int GetLibrariesCount() const
Return the number of libraries loaded in the tree.
std::vector< wxString > m_shownColumns
LIB_TREE_NODE_LIBRARY & DoAddLibraryNode(const wxString &aNodeName, const wxString &aDesc, bool pinned)
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.
std::map< wxString, wxString > m_Fields
List of weighted search terms.
PTR_VECTOR m_Children
LIB_TREE_NODE * m_Parent
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:547
The backing store for a PROJECT, in JSON format.
static SYMBOL_LIBRARY_ADAPTER * SymbolLibAdapter(PROJECT *aProject)
Accessor for project symbol library manager adapter.
Handle actions for the various symbol editor and viewers.
The symbol library editor main window.
An interface to the global shared library manager that is schematic-specific and linked to one projec...
std::vector< wxString > GetAvailableExtraFields(const wxString &aNickname)
Returns a list of additional (non-mandatory) symbol fields present in the given library.
Class to handle modifications to the symbol libraries.
void DisplaySymbol(const LIB_ID &aSymbolID, int aUnit, int aBodyStyle=0)
Set the currently displayed symbol.
LIB_TREE_NODE::PTR_VECTOR::iterator deleteLibrary(LIB_TREE_NODE::PTR_VECTOR::iterator &aLibNodeIt)
void GetValue(wxVariant &aVariant, wxDataViewItem const &aItem, unsigned int aCol) const override
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(SYMBOL_EDIT_FRAME *aParent, SYMBOL_LIBRARY_MANAGER *aLibs)
void ShowPreview(wxWindow *aParent, const wxDataViewItem &aItem) override
int GetLibrariesCount() const override
Return the number of libraries loaded in the tree.
int m_lastSyncHash
SYMBOL_LIBRARY_MANAGER hash value returned in the last synchronization.
void Sync(const wxString &aForceRefresh, std::function< void(int, int, const wxString &)> aProgressCallback)
bool IsContainer(const wxDataViewItem &aItem) const override
bool HasPreview(const wxDataViewItem &aItem) override
std::map< wxString, int > m_libHashes
Hashes to decide whether a library needs an update.
SYMBOL_TREE_SYNCHRONIZING_ADAPTER(SYMBOL_EDIT_FRAME *aParent, SYMBOL_LIBRARY_MANAGER *aLibMgr)
Rate-limiter that fires at most once per interval.
Definition throttle.h:35
bool Ready()
Definition throttle.h:48
void SetBorders(bool aLeft, bool aRight, bool aTop, bool aBottom)
Definition wx_panel.h:39
void SetBorderColor(const KIGFX::COLOR4D &aColor)
Definition wx_panel.h:47
#define _(s)
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.
see class PGM_BASE
wxString UnescapeString(const wxString &aSource)
std::vector< wxString > pinned_symbol_libs
static const wxString c_previewName