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  * @author Maciej Suminski <maciej.suminski@cern.ch>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * https://www.gnu.org/licenses/gpl-3.0.html
20  * or you may search the http://www.gnu.org website for the version 3 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
26 #include <lib_manager.h>
27 #include <symbol_lib_table.h>
28 #include <class_libentry.h>
29 
30 
32 {
33  return PTR( new SYMBOL_TREE_SYNCHRONIZING_ADAPTER( aLibMgr ) );
34 }
35 
36 
38  : m_libMgr( aLibMgr ),
39  m_lastSyncHash( -1 )
40 {
41 }
42 
43 
44 bool SYMBOL_TREE_SYNCHRONIZING_ADAPTER::IsContainer( const wxDataViewItem& aItem ) const
45 {
46  const LIB_TREE_NODE* node = ToNode( aItem );
47  return node ? node->Type == LIB_TREE_NODE::LIB : true;
48 }
49 
50 
51 #define PROGRESS_INTERVAL_MILLIS 120
52 
53 void SYMBOL_TREE_SYNCHRONIZING_ADAPTER::Sync( bool aForce, std::function<void(int, int, const wxString&)> aProgressCallback )
54 {
55  wxLongLong nextUpdate = wxGetUTCTimeMillis() + (PROGRESS_INTERVAL_MILLIS / 2);
56 
57  int libMgrHash = m_libMgr->GetHash();
58 
59  if( !aForce && m_lastSyncHash == libMgrHash )
60  return;
61 
62  m_lastSyncHash = libMgrHash;
63  int i = 0, max = GetLibrariesCount();
64 
65  // Process already stored libraries
66  for( auto it = m_tree.Children.begin(); it != m_tree.Children.end(); /* iteration inside */ )
67  {
68  const wxString& name = it->get()->Name;
69 
70  if( wxGetUTCTimeMillis() > nextUpdate )
71  {
72  aProgressCallback( i, max, name );
73  nextUpdate = wxGetUTCTimeMillis() + PROGRESS_INTERVAL_MILLIS;
74  }
75 
76  if( !m_libMgr->LibraryExists( name, true ) )
77  {
78  it = deleteLibrary( it );
79  continue;
80  }
81  else if( m_libMgr->GetLibraryHash( name ) != m_libHashes[name] )
82  {
83  updateLibrary( *(LIB_TREE_NODE_LIB*) it->get() );
84  }
85 
86  ++it;
87  ++i;
88  }
89 
90  // Look for new libraries
91  for( const auto& libName : m_libMgr->GetLibraryNames() )
92  {
93  if( m_libHashes.count( libName ) == 0 )
94  {
95  if( wxGetUTCTimeMillis() > nextUpdate )
96  {
97  aProgressCallback( i++, max, libName );
98  nextUpdate = wxGetUTCTimeMillis() + PROGRESS_INTERVAL_MILLIS;
99  }
100 
101  SYMBOL_LIB_TABLE_ROW* library = m_libMgr->GetLibrary( libName );
102 
103  auto& lib_node = m_tree.AddLib( libName, library->GetDescr() );
104  updateLibrary( lib_node );
105  }
106  }
107 
109 }
110 
111 
113 {
115 
116  for( const auto& libName : m_libMgr->GetLibraryNames() )
117  {
118  if( m_libHashes.count( libName ) == 0 )
119  ++count;
120  }
121 
122  return count;
123 }
124 
125 
127 {
128  auto hashIt = m_libHashes.find( aLibNode.Name );
129 
130  if( hashIt == m_libHashes.end() )
131  {
132  // add a new library
133  for( auto alias : m_libMgr->GetAliases( aLibNode.Name ) )
134  aLibNode.AddItem( alias );
135  }
136  else if( hashIt->second != m_libMgr->GetLibraryHash( aLibNode.Name ) )
137  {
138  // update an existing libary
139  std::list<LIB_ALIAS*> aliases = m_libMgr->GetAliases( aLibNode.Name );
140 
141  // remove the common part from the aliases list
142  for( auto nodeIt = aLibNode.Children.begin(); nodeIt != aLibNode.Children.end(); )
143  {
144  auto aliasIt = std::find_if( aliases.begin(), aliases.end(),
145  [&] ( const LIB_ALIAS* a ) {
146  return a->GetName() == (*nodeIt)->Name;
147  } );
148 
149  if( aliasIt != aliases.end() )
150  {
151  // alias exists both in the component tree and the library manager,
152  // update only the node data
153  static_cast<LIB_TREE_NODE_LIB_ID*>( nodeIt->get() )->Update( *aliasIt );
154  aliases.erase( aliasIt );
155  ++nodeIt;
156  }
157  else
158  {
159  // node does not exist in the library manager, remove the corresponding node
160  nodeIt = aLibNode.Children.erase( nodeIt );
161  }
162  }
163 
164  // now the aliases list contains only new aliases that need to be added to the tree
165  for( auto alias : aliases )
166  aLibNode.AddItem( alias );
167  }
168 
169  aLibNode.AssignIntrinsicRanks();
170  m_libHashes[aLibNode.Name] = m_libMgr->GetLibraryHash( aLibNode.Name );
171 }
172 
173 
174 LIB_TREE_NODE::PTR_VECTOR::iterator SYMBOL_TREE_SYNCHRONIZING_ADAPTER::deleteLibrary(
175  LIB_TREE_NODE::PTR_VECTOR::iterator& aLibNodeIt )
176 {
177  LIB_TREE_NODE* node = aLibNodeIt->get();
178  m_libHashes.erase( node->Name );
179  auto it = m_tree.Children.erase( aLibNodeIt );
180  return it;
181 }
182 
183 
185 {
186  for( auto& lib : m_tree.Children )
187  {
188  if( lib->Name == aLibNickName )
189  return lib.get();
190  }
191 
192  return nullptr;
193 }
194 
195 
196 void SYMBOL_TREE_SYNCHRONIZING_ADAPTER::GetValue( wxVariant& aVariant, wxDataViewItem const& aItem,
197  unsigned int aCol ) const
198 {
199  if( IsFrozen() )
200  {
201  aVariant = wxEmptyString;
202  return;
203  }
204 
205  auto node = ToNode( aItem );
206  wxASSERT( node );
207 
208  switch( aCol )
209  {
210  case 0:
211  aVariant = node->Name;
212 
213  // mark modified libs with an asterix
214  if( node->Type == LIB_TREE_NODE::LIB && m_libMgr->IsLibraryModified( node->Name ) )
215  aVariant = node->Name + " *";
216 
217  // mark modified parts with an asterix
218  if( node->Type == LIB_TREE_NODE::LIBID
219  && m_libMgr->IsPartModified( node->Name, node->Parent->Name ) )
220  aVariant = node->Name + " *";
221 
222  break;
223 
224  case 1:
225  aVariant = node->Desc;
226  break;
227 
228  default: // column == -1 is used for default Compare function
229  aVariant = node->Name;
230  break;
231  }
232 }
233 
234 
235 bool SYMBOL_TREE_SYNCHRONIZING_ADAPTER::GetAttr( wxDataViewItem const& aItem, unsigned int aCol,
236  wxDataViewItemAttr& aAttr ) const
237 {
238  if( IsFrozen() )
239  return false;
240 
241  // change attributes only for the name field
242  if( aCol != 0 )
243  return false;
244 
245  auto node = ToNode( aItem );
246  wxCHECK( node, false );
247 
248  switch( node->Type )
249  {
250  case LIB_TREE_NODE::LIB:
251  // mark modified libs with bold font
252  aAttr.SetBold( m_libMgr->IsLibraryModified( node->Name ) );
253 
254 #ifdef __WXGTK__
255  // The native wxGTK+ impl ignores background colour, so set the text colour instead.
256  // This works reasonably well in dark themes, and quite poorly in light ones....
257  if( node->Name == m_libMgr->GetCurrentLib() )
258  aAttr.SetColour( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
259 #else
260  // mark the current library with background color
261  if( node->Name == m_libMgr->GetCurrentLib() )
262  aAttr.SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
263 #endif
264  break;
265 
267  // mark modified part with bold font
268  aAttr.SetBold( m_libMgr->IsPartModified( node->Name, node->Parent->Name ) );
269 
270  // mark aliases with italic font
271  aAttr.SetItalic( !node->IsRoot );
272 
273 #ifdef __WXGTK__
274  // The native wxGTK+ impl ignores background colour, so set the text colour instead.
275  // This works reasonably well in dark themes, and quite poorly in light ones....
276  if( node->LibId == m_libMgr->GetCurrentLibId() )
277  aAttr.SetColour( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
278 #else
279  // mark the current part with background color
280  if( node->LibId == m_libMgr->GetCurrentLibId() )
281  aAttr.SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
282 #endif
283  break;
284 
285  default:
286  return false;
287  }
288 
289  return true;
290 }
291 
292 
int m_lastSyncHash
LIB_MANAGER hash value returned in the last synchronization
Part library alias object definition.
Hold a record identifying a symbol library accessed by the appropriate symbol library SCH_PLUGIN obje...
PTR_VECTOR Children
List of child nodes.
enum TYPE Type
Node type.
bool IsContainer(const wxDataViewItem &aItem) const override
Check whether an item can have children.
LIB_TREE_NODE * findLibrary(const wxString &aLibNickName)
LIB_ID GetCurrentLibId() const
Returns the current library and part name as LIB_ID.
Definition: lib_manager.h:272
Node type: LIB_ID.
int GetHash() const
Definition: lib_manager.cpp:59
std::map< wxString, int > m_libHashes
Hashes to decide whether a library needs an update
int GetLibrariesCount() const override
Return the number of libraries loaded in the tree.
std::list< LIB_ALIAS * > GetAliases(const wxString &aLibrary) const
#define PROGRESS_INTERVAL_MILLIS
LIB_TREE_NODE_LIB_ID & AddItem(LIB_TREE_ITEM *aItem)
Construct a new alias node, add it to this library, and return it.
SYMBOL_LIB_TABLE_ROW * GetLibrary(const wxString &aLibrary) const
Finds a single library within the (aggregate) library table.
Definition: lib_manager.cpp:95
Class LIB_ITEM definition.
Node type: library.
static LIB_TREE_NODE const * ToNode(wxDataViewItem aItem)
Convert wxDataViewItem -> CMP_TREE_NODE.
bool IsLibraryModified(const wxString &aLibrary) const
Returns true if library has unsaved modifications.
bool GetAttr(wxDataViewItem const &aItem, unsigned int aCol, wxDataViewItemAttr &aAttr) const override
Get any formatting for an item.
Model class in the component selector Model-View-Adapter (mediated MVC) architecture.
const wxString & GetDescr() const
Return the description of the library referenced by this row.
LIB_TREE_NODE_LIB & AddLib(wxString const &aName, wxString const &aDesc)
Construct an empty library node, add it to the root, and return it.
int GetLibraryHash(const wxString &aLibrary) const
Retruns a library hash value to determine if it has changed.
Definition: lib_manager.cpp:70
Class to handle modifications to the symbol libraries.
Definition: lib_manager.h:49
wxString Name
Actual name of the part.
LIB_TREE_NODE::PTR_VECTOR::iterator deleteLibrary(LIB_TREE_NODE::PTR_VECTOR::iterator &aLibNodeIt)
void AssignIntrinsicRanks(bool presorted=false)
Store intrinsic ranks on all children of this node.
wxArrayString GetLibraryNames() const
Returns the array of library names.
Definition: lib_manager.cpp:84
const char * name
Definition: DXF_plotter.cpp:61
#define max(a, b)
Definition: auxiliary.h:86
size_t i
Definition: json11.cpp:597
void GetValue(wxVariant &aVariant, wxDataViewItem const &aItem, unsigned int aCol) const override
Get the value of an item.
bool LibraryExists(const wxString &aLibrary, bool aCheckEnabled=false) const
Returns true if library exists.
bool IsPartModified(const wxString &aAlias, const wxString &aLibrary) const
Returns true if part has unsaved modifications.
wxObjectDataPtr< LIB_TREE_MODEL_ADAPTER > PTR
Reference-counting container for a pointer to CMP_TREE_MODEL_ADAPTER_BASE.
void Sync(bool aForce=false, std::function< void(int, int, const wxString &)> aProgressCallback=[](int, int, const wxString &){})
const wxString & GetCurrentLib() const
Returns the currently modified library name.
Definition: lib_manager.h:240
virtual int GetLibrariesCount() const
Return the number of libraries loaded in the tree.