KiCad PCB EDA Suite
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 (C) 2019-2022 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>
30#include <symbol_lib_table.h>
32#include <string_utils.h>
33
34
35wxObjectDataPtr<LIB_TREE_MODEL_ADAPTER>
37 SYMBOL_LIBRARY_MANAGER* aLibMgr )
38{
39 auto* adapter = new SYMBOL_TREE_SYNCHRONIZING_ADAPTER( aParent, aLibMgr );
40 return wxObjectDataPtr<LIB_TREE_MODEL_ADAPTER>( adapter );
41}
42
43
45 SYMBOL_LIBRARY_MANAGER* aLibMgr ) :
46 LIB_TREE_MODEL_ADAPTER( aParent, "pinned_symbol_libs" ),
47 m_frame( aParent ),
48 m_libMgr( aLibMgr ),
49 m_lastSyncHash( -1 )
50{
51}
52
53
55{
57}
58
59
60bool SYMBOL_TREE_SYNCHRONIZING_ADAPTER::IsContainer( const wxDataViewItem& aItem ) const
61{
62 const LIB_TREE_NODE* node = ToNode( aItem );
63 return node ? node->m_Type == LIB_TREE_NODE::LIB : true;
64}
65
66
67#define PROGRESS_INTERVAL_MILLIS 120
68
69void SYMBOL_TREE_SYNCHRONIZING_ADAPTER::Sync( const wxString& aForceRefresh,
70 std::function<void( int, int, const wxString& )> aProgressCallback )
71{
72 wxLongLong nextUpdate = wxGetUTCTimeMillis() + (PROGRESS_INTERVAL_MILLIS / 2);
73
75 int i = 0, max = GetLibrariesCount();
76
77 // Process already stored libraries
78 for( auto it = m_tree.m_Children.begin(); it != m_tree.m_Children.end(); /* iteration inside */ )
79 {
80 const wxString& name = it->get()->m_Name;
81
82 if( wxGetUTCTimeMillis() > nextUpdate )
83 {
84 aProgressCallback( i, max, name );
85 nextUpdate = wxGetUTCTimeMillis() + PROGRESS_INTERVAL_MILLIS;
86 }
87
88 // There is a bug in SYMBOL_LIBRARY_MANAGER::LibraryExists() that uses the buffered
89 // modified libraries before the symbol library table which prevents the library from
90 // being removed from the tree control.
91 if( !m_libMgr->LibraryExists( name, true )
92 || !m_frame->Prj().SchSymbolLibTable()->HasLibrary( name, true )
93 || m_frame->Prj().SchSymbolLibTable()->FindRow( name, true ) !=
94 m_frame->Prj().SchSymbolLibTable()->FindRow( name, false )
95 || name == aForceRefresh )
96 {
97 it = deleteLibrary( it );
98 continue;
99 }
100 else
101 {
102 updateLibrary( *(LIB_TREE_NODE_LIB*) it->get() );
103 }
104
105 ++it;
106 ++i;
107 }
108
109 // Look for new libraries
110 //
111 COMMON_SETTINGS* cfg = Pgm().GetCommonSettings();
113
114 for( const wxString& libName : m_libMgr->GetLibraryNames() )
115 {
116 if( m_libHashes.count( libName ) == 0 )
117 {
118 if( wxGetUTCTimeMillis() > nextUpdate )
119 {
120 aProgressCallback( i++, max, libName );
121 nextUpdate = wxGetUTCTimeMillis() + PROGRESS_INTERVAL_MILLIS;
122 }
123
125 bool pinned = alg::contains( cfg->m_Session.pinned_symbol_libs, libName )
126 || alg::contains( project.m_PinnedSymbolLibs, libName );
127
128 LIB_TREE_NODE_LIB& lib_node = DoAddLibraryNode( libName, library->GetDescr(), pinned );
129
130 updateLibrary( lib_node );
131 }
132 }
133
135}
136
137
139{
141
142 for( const wxString& libName : m_libMgr->GetLibraryNames() )
143 {
144 if( m_libHashes.count( libName ) == 0 )
145 ++count;
146 }
147
148 return count;
149}
150
151
153{
154 auto hashIt = m_libHashes.find( aLibNode.m_Name );
155
156 if( hashIt == m_libHashes.end() )
157 {
158 // add a new library
159 for( LIB_SYMBOL* alias : m_libMgr->GetAliases( aLibNode.m_Name ) )
160 aLibNode.AddItem( alias );
161 }
162 else if( hashIt->second != m_libMgr->GetLibraryHash( aLibNode.m_Name ) )
163 {
164 // update an existing library
165 std::list<LIB_SYMBOL*> aliases = m_libMgr->GetAliases( aLibNode.m_Name );
166
167 // remove the common part from the aliases list
168 for( auto nodeIt = aLibNode.m_Children.begin(); nodeIt != aLibNode.m_Children.end(); )
169 {
170 auto aliasIt = std::find_if( aliases.begin(), aliases.end(),
171 [&] ( const LIB_SYMBOL* a )
172 {
173 return a->GetName() == (*nodeIt)->m_LibId.GetLibItemName();
174 } );
175
176 if( aliasIt != aliases.end() )
177 {
178 // alias exists both in the symbol tree and the library manager,
179 // update only the node data.
180 static_cast<LIB_TREE_NODE_LIB_ID*>( nodeIt->get() )->Update( *aliasIt );
181 aliases.erase( aliasIt );
182 ++nodeIt;
183 }
184 else
185 {
186 // node does not exist in the library manager, remove the corresponding node
187 nodeIt = aLibNode.m_Children.erase( nodeIt );
188 }
189 }
190
191 // now the aliases list contains only new aliases that need to be added to the tree
192 for( LIB_SYMBOL* alias : aliases )
193 aLibNode.AddItem( alias );
194 }
195
196 aLibNode.AssignIntrinsicRanks();
197 m_libHashes[aLibNode.m_Name] = m_libMgr->GetLibraryHash( aLibNode.m_Name );
198}
199
200
201LIB_TREE_NODE::PTR_VECTOR::iterator
202SYMBOL_TREE_SYNCHRONIZING_ADAPTER::deleteLibrary( LIB_TREE_NODE::PTR_VECTOR::iterator& aLibNodeIt )
203{
204 LIB_TREE_NODE* node = aLibNodeIt->get();
205 m_libHashes.erase( node->m_Name );
206 auto it = m_tree.m_Children.erase( aLibNodeIt );
207 return it;
208}
209
210
211void SYMBOL_TREE_SYNCHRONIZING_ADAPTER::GetValue( wxVariant& aVariant, wxDataViewItem const& aItem,
212 unsigned int aCol ) const
213{
214 if( IsFrozen() )
215 {
216 aVariant = wxEmptyString;
217 return;
218 }
219
220 LIB_TREE_NODE* node = ToNode( aItem );
221 wxASSERT( node );
222
223 switch( aCol )
224 {
225 case NAME_COL:
226 if( m_frame->GetCurSymbol() && m_frame->GetCurSymbol()->GetLibId() == node->m_LibId )
228
229 if( node->m_Pinned )
230 aVariant = GetPinningSymbol() + UnescapeString( node->m_Name );
231 else
232 aVariant = UnescapeString( node->m_Name );
233
234 // mark modified items with an asterisk
235 if( node->m_Type == LIB_TREE_NODE::LIB )
236 {
237 if( m_libMgr->IsLibraryModified( node->m_Name ) )
238 aVariant = aVariant.GetString() + " *";
239 }
240 else if( node->m_Type == LIB_TREE_NODE::LIBID )
241 {
242 if( m_libMgr->IsSymbolModified( node->m_Name, node->m_Parent->m_Name ) )
243 aVariant = aVariant.GetString() + " *";
244 }
245
246 break;
247
248 case DESC_COL:
249 if( m_frame->GetCurSymbol() && m_frame->GetCurSymbol()->GetLibId() == node->m_LibId )
250 {
252 }
253 else if( node->m_Type == LIB_TREE_NODE::LIB )
254 {
256 SYMBOL_LIB_TABLE_ROW* lib = libMgr.GetLibrary( node->m_LibId.GetLibNickname() );
257
258 if( lib )
259 node->m_Desc = lib->GetDescr();
260 }
261
262 aVariant = node->m_Desc;
263
264 // Annotate that the library failed to load in the description column
265 if( node->m_Type == LIB_TREE_NODE::LIB )
266 {
267 if( !m_libMgr->IsLibraryLoaded( node->m_Name ) )
268 aVariant = _( "(failed to load)" ) + wxS( " " ) + aVariant.GetString();
269 }
270
271 break;
272
273 default: // column == -1 is used for default Compare function
274 aVariant = node->m_Name;
275 break;
276 }
277}
278
279
280bool SYMBOL_TREE_SYNCHRONIZING_ADAPTER::GetAttr( wxDataViewItem const& aItem, unsigned int aCol,
281 wxDataViewItemAttr& aAttr ) const
282{
283 if( IsFrozen() )
284 return false;
285
286 LIB_TREE_NODE* node = ToNode( aItem );
287 wxCHECK( node, false );
288
289 // Mark both columns of unloaded libraries using grey text color (to look disabled)
290 if( node->m_Type == LIB_TREE_NODE::LIB && !m_libMgr->IsLibraryLoaded( node->m_Name ) )
291 {
292 aAttr.SetColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) );
293 return true;
294 }
295
296 // The remaining attributes are only for the name column
297 if( aCol != NAME_COL )
298 return false;
299
300 LIB_SYMBOL* curSymbol = m_frame->GetCurSymbol();
301
302 switch( node->m_Type )
303 {
305 // mark modified libs with bold font
306 aAttr.SetBold( m_libMgr->IsLibraryModified( node->m_Name ) );
307
308 // mark the current library with background color
309 if( curSymbol && curSymbol->GetLibId().GetLibNickname() == node->m_LibId.GetLibNickname() )
310 {
311#ifdef __WXGTK__
312 // The native wxGTK+ impl ignores background colour, so set the text colour instead.
313 // This works reasonably well in dark themes, and quite poorly in light ones....
314 aAttr.SetColour( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
315#else
316 aAttr.SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
317 aAttr.SetColour( wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT ) );
318#endif
319 }
320 break;
321
323 // mark modified part with bold font
324 aAttr.SetBold( m_libMgr->IsSymbolModified( node->m_Name, node->m_Parent->m_Name ) );
325
326 // mark aliases with italic font
327 aAttr.SetItalic( !node->m_IsRoot );
328
329 // mark the current part with background color
330 if( curSymbol && curSymbol->GetLibId() == node->m_LibId )
331 {
332#ifdef __WXGTK__
333 // The native wxGTK+ impl ignores background colour, so set the text colour instead.
334 // This works reasonably well in dark themes, and quite poorly in light ones....
335 aAttr.SetColour( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
336#else
337 aAttr.SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
338 aAttr.SetColour( wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT ) );
339#endif
340 }
341 break;
342
343 default:
344 return false;
345 }
346
347 return true;
348}
const char * name
Definition: DXF_plotter.cpp:56
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
const UTF8 & GetLibItemName() const
Definition: lib_id.h:101
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition: lib_id.h:87
Symbol library management helper that is specific to the symbol library editor frame.
Define a library symbol object.
Definition: lib_symbol.h:98
LIB_ID GetLibId() const override
Definition: lib_symbol.h:139
wxString GetDescription() override
Definition: lib_symbol.h:146
const wxString & GetDescr() const
Return the description of the library referenced by this row.
LIB_TREE_NODE_LIB & DoAddLibraryNode(const wxString &aNodeName, const wxString &aDesc, bool pinned)
static LIB_TREE_NODE * ToNode(wxDataViewItem aItem)
Convert wxDataViewItem -> #SYM_TREE_NODE.
static const wxString GetPinningSymbol()
@ NAME_COL
Library or library item name column.
@ DESC_COL
Library or library description column.
virtual int GetLibrariesCount() const
Return the number of libraries loaded in the tree.
Node type: LIB_ID.
Node type: library.
LIB_TREE_NODE_LIB_ID & 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.
enum TYPE m_Type
PTR_VECTOR m_Children
LIB_TREE_NODE * m_Parent
void AssignIntrinsicRanks(bool presorted=false)
Store intrinsic ranks on all children of this node.
The backing store for a PROJECT, in JSON format.
Definition: project_file.h:65
virtual PROJECT_FILE & GetProjectFile() const
Definition: project.h:148
Handle actions for the various symbol editor and viewers.
The symbol library editor main window.
LIB_SYMBOL * GetCurSymbol() const
Return the current symbol being edited or NULL if none selected.
LIB_SYMBOL_LIBRARY_MANAGER & GetLibManager()
Class to handle modifications to the symbol libraries.
bool LibraryExists(const wxString &aLibrary, bool aCheckEnabled=false) const
Return true if library exists.
bool IsLibraryModified(const wxString &aLibrary) const
Return true if library has unsaved modifications.
wxArrayString GetLibraryNames() const
Return the array of library names.
bool IsSymbolModified(const wxString &aAlias, const wxString &aLibrary) const
Return true if symbol has unsaved modifications.
bool IsLibraryLoaded(const wxString &aLibrary) const
Return true if the library was successfully loaded.
int GetLibraryHash(const wxString &aLibrary) const
Return a library hash value to determine if it has changed.
SYMBOL_LIB_TABLE_ROW * GetLibrary(const wxString &aLibrary) const
Find a single library within the (aggregate) library table.
std::list< LIB_SYMBOL * > GetAliases(const wxString &aLibrary) const
Hold a record identifying a symbol library accessed by the appropriate symbol library SCH_PLUGIN obje...
LIB_TREE_NODE::PTR_VECTOR::iterator deleteLibrary(LIB_TREE_NODE::PTR_VECTOR::iterator &aLibNodeIt)
SYMBOL_LIBRARY_MANAGER * m_libMgr
Hashes to decide whether a library needs an update.
void GetValue(wxVariant &aVariant, wxDataViewItem const &aItem, unsigned int aCol) const override
bool GetAttr(wxDataViewItem const &aItem, unsigned int aCol, wxDataViewItemAttr &aAttr) const override
static wxObjectDataPtr< LIB_TREE_MODEL_ADAPTER > Create(SYMBOL_EDIT_FRAME *aParent, SYMBOL_LIBRARY_MANAGER *aLibs)
int GetLibrariesCount() const override
Return the number of libraries loaded in the tree.
void Sync(const wxString &aForceRefresh, std::function< void(int, int, const wxString &)> aProgressCallback)
bool IsContainer(const wxDataViewItem &aItem) const override
std::map< wxString, int > m_libHashes
SYMBOL_LIBRARY_MANAGER hash value returned in the last synchronization.
SYMBOL_TREE_SYNCHRONIZING_ADAPTER(SYMBOL_EDIT_FRAME *aParent, SYMBOL_LIBRARY_MANAGER *aLibMgr)
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:54
#define _(s)
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition: kicad_algo.h:99
see class PGM_BASE
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:111
wxString UnescapeString(const wxString &aSource)
std::vector< wxString > pinned_symbol_libs
#define PROGRESS_INTERVAL_MILLIS