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