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>
33#include <symbol_lib_table.h>
35#include <project_sch.h>
36#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
62{
64}
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
82 int i = 0, max = GetLibrariesCount();
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( wxGetUTCTimeMillis() > nextUpdate )
90 {
91 aProgressCallback( i, max, name );
92 nextUpdate = wxGetUTCTimeMillis() + PROGRESS_INTERVAL_MILLIS;
93 }
94
95 // There is a bug in SYMBOL_LIBRARY_MANAGER::LibraryExists() that uses the buffered
96 // modified libraries before the symbol library table which prevents the library from
97 // being removed from the tree control.
98 if( !m_libMgr->LibraryExists( name, true )
102 || name == aForceRefresh )
103 {
104 it = deleteLibrary( it );
105 continue;
106 }
107 else
108 {
109 updateLibrary( *(LIB_TREE_NODE_LIBRARY*) it->get() );
110 }
111
112 ++it;
113 ++i;
114 }
115
116 // Look for new libraries
117 //
120
121 for( const wxString& libName : m_libMgr->GetLibraryNames() )
122 {
123 if( m_libHashes.count( libName ) == 0 )
124 {
125 if( wxGetUTCTimeMillis() > nextUpdate )
126 {
127 aProgressCallback( i++, max, libName );
128 nextUpdate = wxGetUTCTimeMillis() + PROGRESS_INTERVAL_MILLIS;
129 }
130
132 bool pinned = alg::contains( cfg->m_Session.pinned_symbol_libs, libName )
133 || alg::contains( project.m_PinnedSymbolLibs, libName );
134
135 LIB_TREE_NODE_LIBRARY& lib_node = DoAddLibraryNode( libName, library->GetDescr(),
136 pinned );
137
138 updateLibrary( lib_node );
139 }
140 }
141
143}
144
145
147{
149
150 for( const wxString& libName : m_libMgr->GetLibraryNames() )
151 {
152 if( m_libHashes.count( libName ) == 0 )
153 ++count;
154 }
155
156 return count;
157}
158
159
161{
162 auto hashIt = m_libHashes.find( aLibNode.m_Name );
163
164 if( hashIt == m_libHashes.end() )
165 {
166 // add a new library
167 for( LIB_SYMBOL* symbol : m_libMgr->EnumerateSymbols( aLibNode.m_Name ) )
168 aLibNode.AddItem( symbol );
169 }
170 else if( hashIt->second != m_libMgr->GetLibraryHash( aLibNode.m_Name ) )
171 {
172 // update an existing library
173 std::list<LIB_SYMBOL*> symbols = m_libMgr->EnumerateSymbols( aLibNode.m_Name );
174
175 // remove the common part from the aliases list
176 for( auto nodeIt = aLibNode.m_Children.begin(); nodeIt != aLibNode.m_Children.end(); )
177 {
178 auto symbolIt = std::find_if( symbols.begin(), symbols.end(),
179 [&] ( const LIB_SYMBOL* a )
180 {
181 return a->GetName() == (*nodeIt)->m_LibId.GetLibItemName().wx_str();
182 } );
183
184 if( symbolIt != symbols.end() )
185 {
186 // alias exists both in the symbol tree and the library manager,
187 // update only the node data.
188 static_cast<LIB_TREE_NODE_ITEM*>( nodeIt->get() )->Update( *symbolIt );
189 symbols.erase( symbolIt );
190 ++nodeIt;
191 }
192 else
193 {
194 // node does not exist in the library manager, remove the corresponding node
195 nodeIt = aLibNode.m_Children.erase( nodeIt );
196 }
197 }
198
199 // now the aliases list contains only new aliases that need to be added to the tree
200 for( LIB_SYMBOL* symbol : symbols )
201 aLibNode.AddItem( symbol );
202 }
203
205 m_libHashes[aLibNode.m_Name] = m_libMgr->GetLibraryHash( aLibNode.m_Name );
206}
207
208
209LIB_TREE_NODE::PTR_VECTOR::iterator
210SYMBOL_TREE_SYNCHRONIZING_ADAPTER::deleteLibrary( LIB_TREE_NODE::PTR_VECTOR::iterator& aLibNodeIt )
211{
212 LIB_TREE_NODE* node = aLibNodeIt->get();
213 m_libHashes.erase( node->m_Name );
214 return m_tree.m_Children.erase( aLibNodeIt );
215}
216
217
219{
220 if( m_frame->GetCurSymbol() )
221 return FindItem( m_frame->GetCurSymbol()->GetLibId() );
222
223 return wxDataViewItem();
224}
225
226
227void SYMBOL_TREE_SYNCHRONIZING_ADAPTER::GetValue( wxVariant& aVariant, wxDataViewItem const& aItem,
228 unsigned int aCol ) const
229{
230 if( IsFrozen() )
231 {
232 aVariant = wxEmptyString;
233 return;
234 }
235
236 LIB_TREE_NODE* node = ToNode( aItem );
237 wxASSERT( node );
238
239 switch( aCol )
240 {
241 case NAME_COL:
242 if( m_frame->GetCurSymbol() && m_frame->GetCurSymbol()->GetLibId() == node->m_LibId )
244
245 if( node->m_Pinned )
246 aVariant = GetPinningSymbol() + UnescapeString( node->m_Name );
247 else
248 aVariant = UnescapeString( node->m_Name );
249
250 // mark modified items with an asterisk
251 if( node->m_Type == LIB_TREE_NODE::TYPE::LIBRARY )
252 {
253 if( m_libMgr->IsLibraryModified( node->m_Name ) )
254 aVariant = aVariant.GetString() + " *";
255 }
256 else if( node->m_Type == LIB_TREE_NODE::TYPE::ITEM )
257 {
258 if( m_libMgr->IsSymbolModified( node->m_Name, node->m_Parent->m_Name ) )
259 aVariant = aVariant.GetString() + " *";
260 }
261
262 break;
263
264 default:
265 if( m_colIdxMap.count( aCol ) )
266 {
267 if( node->m_Type == LIB_TREE_NODE::TYPE::LIBRARY )
268 {
270 SYMBOL_LIB_TABLE_ROW* lib = libMgr.GetLibrary( node->m_LibId.GetLibNickname() );
271
272 if( lib )
273 node->m_Desc = lib->GetDescr();
274
275 if( !m_libMgr->IsLibraryLoaded( node->m_Name ) )
276 aVariant = _( "(failed to load)" ) + wxS( " " ) + aVariant.GetString();
277 else if( m_libMgr->IsLibraryReadOnly( node->m_Name ) )
278 aVariant = _( "(read-only)" ) + wxS( " " ) + aVariant.GetString();
279 }
280
281 const wxString& key = m_colIdxMap.at( aCol );
282
283 if( m_frame->GetCurSymbol() && m_frame->GetCurSymbol()->GetLibId() == node->m_LibId )
284 {
286 }
287
288 wxString valueStr;
289
290 if( key == wxT( "Description" ) )
291 valueStr = node->m_Desc;
292 else if( node->m_Fields.count( key ) )
293 valueStr = node->m_Fields.at( key );
294 else
295 valueStr = wxEmptyString;
296
297 valueStr.Replace( wxS( "\n" ), wxS( " " ) ); // Clear line breaks
298
299 if( !aVariant.GetString().IsEmpty() )
300 {
301 if( !valueStr.IsEmpty() )
302 aVariant = valueStr + wxS( " - " ) + aVariant.GetString();
303 }
304 else
305 {
306 aVariant = valueStr;
307 }
308 }
309 break;
310 }
311}
312
313
314bool SYMBOL_TREE_SYNCHRONIZING_ADAPTER::GetAttr( wxDataViewItem const& aItem, unsigned int aCol,
315 wxDataViewItemAttr& aAttr ) const
316{
317 if( IsFrozen() )
318 return false;
319
320 LIB_TREE_NODE* node = ToNode( aItem );
321 wxCHECK( node, false );
322
323 // Mark both columns of unloaded libraries using grey text color (to look disabled)
324 if( node->m_Type == LIB_TREE_NODE::TYPE::LIBRARY && !m_libMgr->IsLibraryLoaded( node->m_Name ) )
325 {
326 aAttr.SetColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) );
327 return true;
328 }
329
330 // The remaining attributes are only for the name column
331 if( aCol != NAME_COL )
332 return false;
333
334 LIB_SYMBOL* curSymbol = m_frame->GetCurSymbol();
335
336 switch( node->m_Type )
337 {
338 case LIB_TREE_NODE::TYPE::LIBRARY:
339 // mark modified libs with bold font
340 aAttr.SetBold( m_libMgr->IsLibraryModified( node->m_Name ) );
341
342 // mark the current library if it's collapsed
343 if( curSymbol && curSymbol->GetLibId().GetLibNickname() == node->m_LibId.GetLibNickname() )
344 {
345 if( !m_widget->IsExpanded( ToItem( node ) ) )
346 {
347 aAttr.SetStrikethrough( true ); // LIB_TREE_RENDERER uses strikethrough as a
348 // proxy for "is canvas item"
349 }
350 }
351
352 break;
353
354 case LIB_TREE_NODE::TYPE::ITEM:
355 // mark modified part with bold font
356 aAttr.SetBold( m_libMgr->IsSymbolModified( node->m_Name, node->m_Parent->m_Name ) );
357
358 // mark aliases with italic font
359 aAttr.SetItalic( !node->m_IsRoot );
360
361 // mark the current (on-canvas) part
362 if( curSymbol && curSymbol->GetLibId() == node->m_LibId )
363 {
364 aAttr.SetStrikethrough( true ); // LIB_TREE_RENDERER uses strikethrough as a
365 // proxy for "is canvas item"
366 }
367
368 break;
369
370 default:
371 return false;
372 }
373
374 return true;
375}
376
377
378bool SYMBOL_TREE_SYNCHRONIZING_ADAPTER::HasPreview( const wxDataViewItem& aItem )
379{
380 LIB_TREE_NODE* node = ToNode( aItem );
381 wxCHECK( node, false );
382
383 return node->m_Type == LIB_TREE_NODE::TYPE::ITEM && node->m_LibId != m_frame->GetTargetLibId();
384}
385
386
387static const wxString c_previewName = wxS( "symHoverPreview" );
388
389
391 const wxDataViewItem& aItem )
392{
393 LIB_TREE_NODE* node = ToNode( aItem );
394 wxCHECK( node, /* void */ );
395
396 SYMBOL_PREVIEW_WIDGET* preview = dynamic_cast<SYMBOL_PREVIEW_WIDGET*>(
397 wxWindow::FindWindowByName( c_previewName, aParent ) );
398
399 if( !preview )
400 {
401 wxBoxSizer* mainSizer = new wxBoxSizer( wxVERTICAL );
402 aParent->SetSizer( mainSizer );
403
404 WX_PANEL* panel = new WX_PANEL( aParent );
405 panel->SetBorders( true, true, true, true );
407
408 wxBoxSizer* panelSizer = new wxBoxSizer( wxVERTICAL );
409 panel->SetSizer( panelSizer );
410
412 preview = new SYMBOL_PREVIEW_WIDGET( panel, &m_frame->Kiway(), false, backend );
413 preview->SetName( c_previewName );
414 preview->SetLayoutDirection( wxLayout_LeftToRight );
415
416 panelSizer->Add( preview, 1, wxEXPAND | wxALL, 1 );
417 mainSizer->Add( panel, 1, wxEXPAND, 0 );
418 aParent->Layout();
419 }
420
421 preview->DisplaySymbol( node->m_LibId, node->m_Unit );
422}
423
424
426{
427 wxWindow* previewWindow = wxWindow::FindWindowByName( c_previewName, aParent );
428
429 if( SYMBOL_PREVIEW_WIDGET* preview = dynamic_cast<SYMBOL_PREVIEW_WIDGET*>( previewWindow ) )
430 {
431 preview->GetCanvas()->SetEvtHandlerEnabled( false );
432 preview->GetCanvas()->StopDrawing();
433 }
434}
const char * name
Definition: DXF_plotter.cpp:62
GAL_TYPE GetBackend() const
Return the type of backend currently used by GAL canvas.
static const COLOR4D BLACK
Definition: color4d.h:402
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
KIWAY & Kiway() const
Return a reference to the KIWAY that this object has an opportunity to participate in.
Definition: kiway_holder.h:55
const wxString GetUniStringLibItemName() const
Get strings for display messages in dialogs.
Definition: lib_id.h:112
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:85
wxString GetDescription() const override
Definition: lib_symbol.h:170
const LIB_ID & GetLibId() const override
Definition: lib_symbol.h:155
const wxString & GetDescr() const
Return the description of the library referenced by this row.
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library table.
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.
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.
enum TYPE m_Type
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:565
The backing store for a PROJECT, in JSON format.
Definition: project_file.h:68
static SYMBOL_LIB_TABLE * SchSymbolLibTable(PROJECT *aProject)
Accessor for project symbol library table.
virtual PROJECT_FILE & GetProjectFile() const
Definition: project.h:204
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
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_ID GetTargetLibId() const override
Return either the symbol selected in the symbol tree (if context menu is active) or the symbol on the...
LIB_SYMBOL_LIBRARY_MANAGER & GetLibManager()
Class to handle modifications to the symbol libraries.
bool IsLibraryReadOnly(const wxString &aLibrary) const
Return true if the library is stored in a read-only file.
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 &aSymbolName, 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 * > EnumerateSymbols(const wxString &aLibrary) const
Hold a record identifying a symbol library accessed by the appropriate symbol library SCH_IO object i...
SYMBOL_LIB_TABLE_ROW * FindRow(const wxString &aNickName, bool aCheckIfEnabled=false)
Return an SYMBOL_LIB_TABLE_ROW if aNickName is found in this table or in any chained fallBack table f...
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)
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:55
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:902
see class PGM_BASE
wxString UnescapeString(const wxString &aSource)
std::vector< wxString > pinned_symbol_libs
#define PROGRESS_INTERVAL_MILLIS
static const wxString c_previewName