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 <pgm_base.h>
34#include <project_sch.h>
35#include <string_utils.h>
38#include <widgets/wx_panel.h>
39
40
41wxObjectDataPtr<LIB_TREE_MODEL_ADAPTER>
43{
44 auto* adapter = new SYMBOL_TREE_SYNCHRONIZING_ADAPTER( aParent, aLibMgr );
45 return wxObjectDataPtr<LIB_TREE_MODEL_ADAPTER>( adapter );
46}
47
48
50 SYMBOL_LIBRARY_MANAGER* aLibMgr ) :
51 LIB_TREE_MODEL_ADAPTER( aParent, "pinned_symbol_libs",
52 aParent->GetViewerSettingsBase()->m_LibTree ),
53 m_frame( aParent ),
54 m_libMgr( aLibMgr ),
55 m_lastSyncHash( -1 )
56{
57}
58
59
64
65
66bool SYMBOL_TREE_SYNCHRONIZING_ADAPTER::IsContainer( const wxDataViewItem& aItem ) const
67{
68 const LIB_TREE_NODE* node = ToNode( aItem );
69 return node ? node->m_Type == LIB_TREE_NODE::TYPE::LIBRARY : true;
70}
71
72
73#define PROGRESS_INTERVAL_MILLIS 120
74
75void SYMBOL_TREE_SYNCHRONIZING_ADAPTER::Sync( const wxString& aForceRefresh,
76 std::function<void( int, int, const wxString& )> aProgressCallback )
77{
78 wxLongLong nextUpdate = wxGetUTCTimeMillis() + (PROGRESS_INTERVAL_MILLIS / 2);
79
80 m_lastSyncHash = m_libMgr->GetHash();
81 int i = 0, max = GetLibrariesCount();
82
84
85 // Process already stored libraries
86 for( auto it = m_tree.m_Children.begin(); it != m_tree.m_Children.end(); )
87 {
88 const wxString& name = it->get()->m_Name;
89
90 if( wxGetUTCTimeMillis() > nextUpdate )
91 {
92 aProgressCallback( i, max, name );
93 nextUpdate = wxGetUTCTimeMillis() + PROGRESS_INTERVAL_MILLIS;
94 }
95
96 // There is a bug in SYMBOL_LIBRARY_MANAGER::LibraryExists() that uses the buffered
97 // modified libraries before the symbol library table which prevents the library from
98 // being removed from the tree control.
99 if( !m_libMgr->LibraryExists( name, true )
100 || !adapter->HasLibrary( name, true )
101 || ( *adapter->GetRow( name ) )->Hidden()
102 || name == aForceRefresh )
103 {
104 it = deleteLibrary( it );
105 continue;
106 }
107 else
108 {
109 updateLibrary( *static_cast<LIB_TREE_NODE_LIBRARY*>( it->get() ) );
110 }
111
112 ++it;
113 ++i;
114 }
115
116 // Look for new libraries
117 //
119 PROJECT_FILE& project = m_frame->Prj().GetProjectFile();
120
121 for( const auto& [libName, status] : adapter->GetLibraryStatuses() )
122 {
123 if( status.load_status != LOAD_STATUS::LOADED || status.error )
124 continue;
125
126 if( m_libHashes.count( libName ) == 0 )
127 {
128 if( wxGetUTCTimeMillis() > nextUpdate )
129 {
130 aProgressCallback( i++, max, libName );
131 nextUpdate = wxGetUTCTimeMillis() + PROGRESS_INTERVAL_MILLIS;
132 }
133
134 auto optRow = adapter->GetRow( libName );
135 wxCHECK2( optRow.has_value(), continue );
136
137 bool pinned = alg::contains( cfg->m_Session.pinned_symbol_libs, libName )
138 || alg::contains( project.m_PinnedSymbolLibs, libName );
139
140 LIB_TREE_NODE_LIBRARY& lib_node = DoAddLibraryNode( libName, ( *optRow )->Description(), pinned );
141
142 updateLibrary( lib_node );
143 }
144 }
145
146 m_tree.AssignIntrinsicRanks( m_shownColumns );
147}
148
149
151{
153
154 for( const wxString& libName : m_libMgr->GetLibraryNames() )
155 {
156 if( m_libHashes.count( libName ) == 0 )
157 ++count;
158 }
159
160 return count;
161}
162
163
165{
166 auto hashIt = m_libHashes.find( aLibNode.m_Name );
167
168 if( hashIt == m_libHashes.end() )
169 {
170 // add a new library
171 for( LIB_SYMBOL* symbol : m_libMgr->EnumerateSymbols( aLibNode.m_Name ) )
172 aLibNode.AddItem( symbol );
173 }
174 else if( hashIt->second != m_libMgr->GetLibraryHash( aLibNode.m_Name ) )
175 {
176 // update an existing library
177 std::list<LIB_SYMBOL*> symbols = m_libMgr->EnumerateSymbols( aLibNode.m_Name );
178
179 // remove the common part from the aliases list
180 for( auto nodeIt = aLibNode.m_Children.begin(); nodeIt != aLibNode.m_Children.end(); /**/ )
181 {
182 auto symbolIt = std::find_if( symbols.begin(), symbols.end(),
183 [&] ( const LIB_SYMBOL* a )
184 {
185 return a->GetName() == (*nodeIt)->m_LibId.GetLibItemName().wx_str();
186 } );
187
188 if( symbolIt != symbols.end() )
189 {
190 // alias exists both in the symbol tree and the library manager,
191 // update only the node data.
192 static_cast<LIB_TREE_NODE_ITEM*>( nodeIt->get() )->Update( *symbolIt );
193 symbols.erase( symbolIt );
194 ++nodeIt;
195 }
196 else
197 {
198 // node does not exist in the library manager, remove the corresponding node
199 nodeIt = aLibNode.m_Children.erase( nodeIt );
200 }
201 }
202
203 // now the aliases list contains only new aliases that need to be added to the tree
204 for( LIB_SYMBOL* symbol : symbols )
205 aLibNode.AddItem( symbol );
206 }
207
209
210 for( const wxString& column : adapter->GetAvailableExtraFields( aLibNode.m_Name ) )
211 addColumnIfNecessary( column );
212
214 m_libHashes[aLibNode.m_Name] = m_libMgr->GetLibraryHash( aLibNode.m_Name );
215}
216
217
218LIB_TREE_NODE::PTR_VECTOR::iterator
219SYMBOL_TREE_SYNCHRONIZING_ADAPTER::deleteLibrary( LIB_TREE_NODE::PTR_VECTOR::iterator& aLibNodeIt )
220{
221 LIB_TREE_NODE* node = aLibNodeIt->get();
222 m_libHashes.erase( node->m_Name );
223 return m_tree.m_Children.erase( aLibNodeIt );
224}
225
226
228{
229 if( m_frame->GetCurSymbol() )
230 return FindItem( m_frame->GetCurSymbol()->GetLibId() );
231
232 return wxDataViewItem();
233}
234
235
236void SYMBOL_TREE_SYNCHRONIZING_ADAPTER::GetValue( wxVariant& aVariant, wxDataViewItem const& aItem,
237 unsigned int aCol ) const
238{
239 if( IsFrozen() )
240 {
241 aVariant = wxEmptyString;
242 return;
243 }
244
245 LIB_TREE_NODE* node = ToNode( aItem );
246 wxASSERT( node );
247
248 switch( aCol )
249 {
250 case NAME_COL:
251 if( m_frame->GetCurSymbol() && m_frame->GetCurSymbol()->GetLibId() == node->m_LibId )
252 node->m_Name = m_frame->GetCurSymbol()->GetLibId().GetUniStringLibItemName();
253
254 if( node->m_Pinned )
255 aVariant = GetPinningSymbol() + UnescapeString( node->m_Name );
256 else
257 aVariant = UnescapeString( node->m_Name );
258
259 // mark modified items with an asterisk
260 if( node->m_Type == LIB_TREE_NODE::TYPE::LIBRARY )
261 {
262 if( m_libMgr->IsLibraryModified( node->m_Name ) )
263 aVariant = aVariant.GetString() + " *";
264 }
265 else if( node->m_Type == LIB_TREE_NODE::TYPE::ITEM )
266 {
267 if( m_libMgr->IsSymbolModified( node->m_Name, node->m_Parent->m_Name ) )
268 aVariant = aVariant.GetString() + " *";
269 }
270
271 break;
272
273 default:
274 if( m_colIdxMap.count( aCol ) )
275 {
276 if( node->m_Type == LIB_TREE_NODE::TYPE::LIBRARY )
277 {
279 &m_frame->Prj() );
280
281 if( auto optRow = adapter->GetRow( node->m_LibId.GetLibNickname() ) )
282 node->m_Desc = ( *optRow )->Description();
283
284 if( !m_libMgr->IsLibraryLoaded( node->m_Name ) )
285 aVariant = _( "(failed to load)" ) + wxS( " " ) + aVariant.GetString();
286 else if( m_libMgr->IsLibraryReadOnly( node->m_Name ) )
287 aVariant = _( "(read-only)" ) + wxS( " " ) + aVariant.GetString();
288 }
289
290 const wxString& key = m_colIdxMap.at( aCol );
291
292 if( m_frame->GetCurSymbol() && m_frame->GetCurSymbol()->GetLibId() == node->m_LibId )
293 {
294 node->m_Desc = m_frame->GetCurSymbol()->GetShownDescription();
295 }
296
297 wxString valueStr;
298
299 if( key == wxT( "Description" ) )
300 valueStr = node->m_Desc;
301 else if( node->m_Fields.count( key ) )
302 valueStr = node->m_Fields.at( key );
303 else
304 valueStr = wxEmptyString;
305
306 valueStr.Replace( wxS( "\n" ), wxS( " " ) ); // Clear line breaks
307
308 if( !aVariant.GetString().IsEmpty() )
309 {
310 if( !valueStr.IsEmpty() )
311 aVariant = valueStr + wxS( " - " ) + aVariant.GetString();
312 }
313 else
314 {
315 aVariant = valueStr;
316 }
317 }
318 break;
319 }
320}
321
322
323bool SYMBOL_TREE_SYNCHRONIZING_ADAPTER::GetAttr( wxDataViewItem const& aItem, unsigned int aCol,
324 wxDataViewItemAttr& aAttr ) const
325{
326 if( IsFrozen() )
327 return false;
328
329 LIB_TREE_NODE* node = ToNode( aItem );
330 wxCHECK( node, false );
331
332 // Mark both columns of unloaded libraries using grey text color (to look disabled)
333 if( node->m_Type == LIB_TREE_NODE::TYPE::LIBRARY && !m_libMgr->IsLibraryLoaded( node->m_Name ) )
334 {
335 aAttr.SetColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) );
336 return true;
337 }
338
339 // The remaining attributes are only for the name column
340 if( aCol != NAME_COL )
341 return false;
342
343 LIB_SYMBOL* curSymbol = m_frame->GetCurSymbol();
344
345 switch( node->m_Type )
346 {
347 case LIB_TREE_NODE::TYPE::LIBRARY:
348 // mark modified libs with bold font
349 aAttr.SetBold( m_libMgr->IsLibraryModified( node->m_Name ) );
350
351 // mark the current library if it's collapsed
352 if( curSymbol && curSymbol->GetLibId().GetLibNickname() == node->m_LibId.GetLibNickname() )
353 {
354 if( !m_widget->IsExpanded( ToItem( node ) ) )
355 {
356 aAttr.SetStrikethrough( true ); // LIB_TREE_RENDERER uses strikethrough as a
357 // proxy for "is canvas item"
358 }
359 }
360
361 break;
362
363 case LIB_TREE_NODE::TYPE::ITEM:
364 // mark modified part with bold font
365 aAttr.SetBold( m_libMgr->IsSymbolModified( node->m_Name, node->m_Parent->m_Name ) );
366
367 // mark aliases with italic font
368 aAttr.SetItalic( !node->m_IsRoot );
369
370 // mark the current (on-canvas) part
371 if( curSymbol && curSymbol->GetLibId() == node->m_LibId )
372 {
373 aAttr.SetStrikethrough( true ); // LIB_TREE_RENDERER uses strikethrough as a
374 // proxy for "is canvas item"
375 }
376
377 break;
378
379 default:
380 return false;
381 }
382
383 return true;
384}
385
386
387bool SYMBOL_TREE_SYNCHRONIZING_ADAPTER::HasPreview( const wxDataViewItem& aItem )
388{
389 LIB_TREE_NODE* node = ToNode( aItem );
390 wxCHECK( node, false );
391
392 return node->m_Type == LIB_TREE_NODE::TYPE::ITEM && node->m_LibId != m_frame->GetTargetLibId();
393}
394
395
396static const wxString c_previewName = wxS( "symHoverPreview" );
397
398
400 const wxDataViewItem& aItem )
401{
402 LIB_TREE_NODE* node = ToNode( aItem );
403 wxCHECK( node, /* void */ );
404
405 SYMBOL_PREVIEW_WIDGET* preview = dynamic_cast<SYMBOL_PREVIEW_WIDGET*>(
406 wxWindow::FindWindowByName( c_previewName, aParent ) );
407
408 if( !preview )
409 {
410 wxBoxSizer* mainSizer = new wxBoxSizer( wxVERTICAL );
411 aParent->SetSizer( mainSizer );
412
413 WX_PANEL* panel = new WX_PANEL( aParent );
414 panel->SetBorders( true, true, true, true );
416
417 wxBoxSizer* panelSizer = new wxBoxSizer( wxVERTICAL );
418 panel->SetSizer( panelSizer );
419
420 EDA_DRAW_PANEL_GAL::GAL_TYPE backend = m_frame->GetCanvas()->GetBackend();
421 preview = new SYMBOL_PREVIEW_WIDGET( panel, &m_frame->Kiway(), false, backend );
422 preview->SetName( c_previewName );
423 preview->SetLayoutDirection( wxLayout_LeftToRight );
424
425 panelSizer->Add( preview, 1, wxEXPAND | wxALL, 1 );
426 mainSizer->Add( panel, 1, wxEXPAND, 0 );
427 aParent->Layout();
428 }
429
430 preview->DisplaySymbol( node->m_LibId, node->m_Unit );
431}
432
433
435{
436 wxWindow* previewWindow = wxWindow::FindWindowByName( c_previewName, aParent );
437
438 if( SYMBOL_PREVIEW_WIDGET* preview = dynamic_cast<SYMBOL_PREVIEW_WIDGET*>( previewWindow ) )
439 {
440 preview->GetCanvas()->SetEvtHandlerEnabled( false );
441 preview->GetCanvas()->StopDrawing();
442 }
443}
const char * name
static const COLOR4D BLACK
Definition color4d.h:406
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library tables.
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:153
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)
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
#define PROGRESS_INTERVAL_MILLIS
static const wxString c_previewName