KiCad PCB EDA Suite
fp_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-2021 KiCad Developers, see AUTHORS.txt for contributors.
6  * @author Maciej Suminski <maciej.suminski@cern.ch>
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 #include <footprint_edit_frame.h>
28 #include <fp_lib_table.h>
29 #include <footprint_info_impl.h>
30 #include <string_utils.h>
31 #include <board.h>
32 #include <footprint.h>
33 #include <tool/tool_manager.h>
35 #include <wx/settings.h>
36 
37 
38 wxObjectDataPtr<LIB_TREE_MODEL_ADAPTER>
40 {
41  auto* adapter = new FP_TREE_SYNCHRONIZING_ADAPTER( aFrame, aLibs );
42  return wxObjectDataPtr<LIB_TREE_MODEL_ADAPTER>( adapter );
43 }
44 
45 
47  FP_LIB_TABLE* aLibs ) :
48  FP_TREE_MODEL_ADAPTER( aFrame, aLibs ),
49  m_frame( aFrame )
50 {
51 }
52 
53 
55 {
57 }
58 
59 
60 bool FP_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 66
68 
70 {
71  // Process already stored libraries
72  for( auto it = m_tree.m_Children.begin(); it != m_tree.m_Children.end(); )
73  {
74  const wxString& name = it->get()->m_Name;
75 
76  // Remove the library if it no longer exists or it exists in both the global and the
77  // project library but the project library entry is disabled.
78  if( !m_libs->HasLibrary( name, true )
79  || ( m_libs->FindRow( name, true ) != m_libs->FindRow( name, false ) ) )
80  {
81  it = deleteLibrary( it );
82  continue;
83  }
84 
85  updateLibrary( *(LIB_TREE_NODE_LIB*) it->get() );
86  ++it;
87  }
88 
89  // Look for new libraries
90  size_t count = m_libMap.size();
91 
92  for( const auto& libName : m_libs->GetLogicalLibs() )
93  {
94  if( m_libMap.count( libName ) == 0 )
95  {
96  const FP_LIB_TABLE_ROW* library = m_libs->FindRow( libName, true );
97 
98  DoAddLibrary( libName, library->GetDescr(), getFootprints( libName ), true );
99  m_libMap.insert( libName );
100  }
101  }
102 
103  if( m_libMap.size() > count )
105 }
106 
107 
109 {
110  return GFootprintTable.GetCount();
111 }
112 
113 
115 {
116  std::vector<LIB_TREE_ITEM*> footprints = getFootprints( aLibNode.m_Name );
117 
118  // remove the common part from the footprints list
119  for( auto nodeIt = aLibNode.m_Children.begin(); nodeIt != aLibNode.m_Children.end(); )
120  {
121  // Since the list is sorted we can use a binary search to speed up searches within
122  // libraries with lots of footprints.
123  FOOTPRINT_INFO_IMPL dummy( wxEmptyString, (*nodeIt)->m_Name );
124  auto footprintIt = std::lower_bound( footprints.begin(), footprints.end(), &dummy,
125  []( LIB_TREE_ITEM* a, LIB_TREE_ITEM* b )
126  {
127  return StrNumCmp( a->GetName(), b->GetName(), false ) < 0;
128  } );
129 
130  if( footprintIt != footprints.end() && dummy.GetName() == (*footprintIt)->GetName() )
131  {
132  // footprint exists both in the lib tree and the footprint info list; just
133  // update the node data
134  static_cast<LIB_TREE_NODE_LIB_ID*>( nodeIt->get() )->Update( *footprintIt );
135  footprints.erase( footprintIt );
136  ++nodeIt;
137  }
138  else
139  {
140  // node does not exist in the library manager, remove the corresponding node
141  nodeIt = aLibNode.m_Children.erase( nodeIt );
142  }
143  }
144 
145  // now the footprint list contains only new aliases that need to be added to the tree
146  for( auto footprint : footprints )
147  aLibNode.AddItem( footprint );
148 
149  aLibNode.AssignIntrinsicRanks();
150  m_libMap.insert( aLibNode.m_Name );
151 }
152 
153 
154 LIB_TREE_NODE::PTR_VECTOR::iterator FP_TREE_SYNCHRONIZING_ADAPTER::deleteLibrary(
155  LIB_TREE_NODE::PTR_VECTOR::iterator& aLibNodeIt )
156 {
157  LIB_TREE_NODE* node = aLibNodeIt->get();
158  m_libMap.erase( node->m_Name );
159  auto it = m_tree.m_Children.erase( aLibNodeIt );
160  return it;
161 }
162 
163 
164 void FP_TREE_SYNCHRONIZING_ADAPTER::GetValue( wxVariant& aVariant, wxDataViewItem const& aItem,
165  unsigned int aCol ) const
166 {
167  if( IsFrozen() )
168  {
169  aVariant = wxEmptyString;
170  return;
171  }
172 
173  auto node = ToNode( aItem );
174 
175  switch( aCol )
176  {
177  case 0:
178  if( node->m_LibId == m_frame->GetLoadedFPID() && !m_frame->IsCurrentFPFromBoard() )
179  {
180  node->m_Name = m_frame->GetLoadedFPID().GetLibItemName();
181 
182  // mark modified part with an asterisk
184  aVariant = node->m_Name + " *";
185  else
186  aVariant = node->m_Name;
187  }
188  else if( node->m_Pinned )
189  aVariant = GetPinningSymbol() + node->m_Name;
190  else
191  aVariant = node->m_Name;
192  break;
193 
194  case 1:
195  if( node->m_LibId == m_frame->GetLoadedFPID() && !m_frame->IsCurrentFPFromBoard() )
196  {
197  node->m_Desc = m_frame->GetBoard()->GetFirstFootprint()->GetDescription();
198  }
199  else if( node->m_Type == LIB_TREE_NODE::LIB )
200  {
201  try
202  {
203  const FP_LIB_TABLE_ROW* lib =
204  GFootprintTable.FindRow( node->m_LibId.GetLibNickname() );
205 
206  if( lib )
207  node->m_Desc = lib->GetDescr();
208  }
209  catch( IO_ERROR& )
210  {
211  }
212  }
213 
214  aVariant = node->m_Desc;
215  break;
216 
217  default: // column == -1 is used for default Compare function
218  aVariant = node->m_Name;
219  break;
220  }
221 }
222 
223 
224 bool FP_TREE_SYNCHRONIZING_ADAPTER::GetAttr( wxDataViewItem const& aItem, unsigned int aCol,
225  wxDataViewItemAttr& aAttr ) const
226 {
227  if( IsFrozen() )
228  return false;
229 
230  // change attributes only for the name field
231  if( aCol != 0 )
232  return false;
233 
234  // don't link to a board footprint, even if the FPIDs match
236  return false;
237 
238  auto node = ToNode( aItem );
239  wxCHECK( node, false );
240 
241  switch( node->m_Type )
242  {
243  case LIB_TREE_NODE::LIB:
244  if( node->m_Name == m_frame->GetLoadedFPID().GetLibNickname() )
245  {
246 #ifdef __WXGTK__
247  // The native wxGTK+ impl ignores background colour, so set the text colour
248  // instead. Works reasonably well in dark themes, less well in light ones....
249  aAttr.SetColour( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
250 #else
251  aAttr.SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
252  aAttr.SetColour( wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT ) );
253 #endif
254 
255  // mark modified libs with bold font
257  aAttr.SetBold( true );
258  }
259  break;
260 
262  if( node->m_LibId == m_frame->GetLoadedFPID() )
263  {
264 #ifdef __WXGTK__
265  // The native wxGTK+ impl ignores background colour, so set the text colour
266  // instead. Works reasonably well in dark themes, less well in light ones....
267  aAttr.SetColour( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
268 #else
269  aAttr.SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
270  aAttr.SetColour( wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT ) );
271 #endif
272 
273  // mark modified part with bold font
275  aAttr.SetBold( true );
276  }
277  break;
278 
279  default:
280  return false;
281  }
282 
283  return true;
284 }
285 
286 
void GetValue(wxVariant &aVariant, wxDataViewItem const &aItem, unsigned int aCol) const override
Module editor specific tools.
const wxString & GetDescription() const
Definition: footprint.h:197
const UTF8 & GetLibItemName() const
Definition: lib_id.h:104
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library table.
bool IsContentModified() const
Definition: base_screen.h:60
FP_LIB_TABLE GFootprintTable
The global footprint library table.
Definition: cvpcb.cpp:134
Hold a record identifying a library accessed by the appropriate footprint library PLUGIN object in th...
Definition: fp_lib_table.h:40
bool IsContainer(const wxDataViewItem &aItem) const override
wxString GetName() const override
Definition: lib_symbol.h:133
A mix-in to provide polymorphism between items stored in libraries (symbols, aliases and footprints).
Definition: lib_tree_item.h:38
unsigned GetCount() const
Get the number of rows contained in the table.
static wxObjectDataPtr< LIB_TREE_MODEL_ADAPTER > Create(FOOTPRINT_EDIT_FRAME *aFrame, FP_LIB_TABLE *aLibs)
int GetLibrariesCount() const override
Return the number of libraries loaded in the tree.
TOOL_INTERACTIVE * GetContextMenuTool() override
const wxString & GetDescr() const
Return the description of the library referenced by this row.
static LIB_SYMBOL * dummy()
Used to draw a dummy shape when a LIB_SYMBOL is not found in library.
Definition: sch_symbol.cpp:72
std::vector< LIB_TREE_ITEM * > getFootprints(const wxString &aLibName)
LIB_TREE_NODE::PTR_VECTOR::iterator deleteLibrary(LIB_TREE_NODE::PTR_VECTOR::iterator &aLibNodeIt)
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
Definition: board.h:317
LIB_TREE_NODE_LIB_ID & AddItem(LIB_TREE_ITEM *aItem)
Construct a new alias node, add it to this library, and return it.
Node type: library.
static LIB_TREE_NODE * ToNode(wxDataViewItem aItem)
Convert wxDataViewItem -> #SYM_TREE_NODE.
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition: lib_id.h:90
Model class in the component selector Model-View-Adapter (mediated MVC) architecture.
FP_TREE_SYNCHRONIZING_ADAPTER(FOOTPRINT_EDIT_FRAME *aFrame, FP_LIB_TABLE *aLibs)
void updateLibrary(LIB_TREE_NODE_LIB &aLibNode)
const wxString GetPinningSymbol() const
void DoAddLibrary(const wxString &aNodeName, const wxString &aDesc, const std::vector< LIB_TREE_ITEM * > &aItemList, bool presorted)
Add the given list of symbols by alias.
void AssignIntrinsicRanks(bool presorted=false)
Store intrinsic ranks on all children of this node.
const char * name
Definition: DXF_plotter.cpp:56
const FP_LIB_TABLE_ROW * FindRow(const wxString &aNickName, bool aCheckIfEnabled=false)
Return an FP_LIB_TABLE_ROW if aNickName is found in this table or in any chained fall back table frag...
LIB_ID GetLoadedFPID() const
Return the LIB_ID of the part being edited.
enum TYPE m_Type
PCB_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
bool GetAttr(wxDataViewItem const &aItem, unsigned int aCol, wxDataViewItemAttr &aAttr) const override
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:54
int StrNumCmp(const wxString &aString1, const wxString &aString2, bool aIgnoreCase)
Compare two strings with alphanumerical content.
BOARD * GetBoard() const
PTR_VECTOR m_Children
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:75
std::vector< wxString > GetLogicalLibs()
Return the logical library names, all of them that are pertinent to a look up done on this LIB_TABLE.