You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

243 lines
7.8 KiB

  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. #include <fp_tree_synchronizing_adapter.h>
  25. #include <footprint_edit_frame.h>
  26. #include <fp_lib_table.h>
  27. #include <footprint_info_impl.h>
  28. LIB_TREE_MODEL_ADAPTER::PTR FP_TREE_SYNCHRONIZING_ADAPTER::Create( FOOTPRINT_EDIT_FRAME* aFrame,
  29. FP_LIB_TABLE* aLibs )
  30. {
  31. return PTR( new FP_TREE_SYNCHRONIZING_ADAPTER( aFrame, aLibs ) );
  32. }
  33. FP_TREE_SYNCHRONIZING_ADAPTER::FP_TREE_SYNCHRONIZING_ADAPTER( FOOTPRINT_EDIT_FRAME* aFrame,
  34. FP_LIB_TABLE* aLibs ) :
  35. FP_TREE_MODEL_ADAPTER( aLibs ),
  36. m_frame( aFrame )
  37. {
  38. }
  39. bool FP_TREE_SYNCHRONIZING_ADAPTER::IsContainer( const wxDataViewItem& aItem ) const
  40. {
  41. const LIB_TREE_NODE* node = ToNode( aItem );
  42. return node ? node->Type == LIB_TREE_NODE::LIB : true;
  43. }
  44. #define PROGRESS_INTERVAL_MILLIS 66
  45. void FP_TREE_SYNCHRONIZING_ADAPTER::Sync()
  46. {
  47. // Process already stored libraries
  48. for( auto it = m_tree.Children.begin(); it != m_tree.Children.end(); )
  49. {
  50. const wxString& name = it->get()->Name;
  51. if( !m_libs->HasLibrary( name, true ) )
  52. {
  53. it = deleteLibrary( it );
  54. continue;
  55. }
  56. updateLibrary( *(LIB_TREE_NODE_LIB*) it->get() );
  57. ++it;
  58. }
  59. // Look for new libraries
  60. size_t count = m_libMap.size();
  61. for( const auto& libName : m_libs->GetLogicalLibs() )
  62. {
  63. if( m_libMap.count( libName ) == 0 )
  64. {
  65. const FP_LIB_TABLE_ROW* library = m_libs->FindRow( libName );
  66. DoAddLibrary( libName, library->GetDescr(), getFootprints( libName ), true );
  67. m_libMap.insert( libName );
  68. }
  69. }
  70. if( m_libMap.size() > count )
  71. m_tree.AssignIntrinsicRanks();
  72. }
  73. int FP_TREE_SYNCHRONIZING_ADAPTER::GetLibrariesCount() const
  74. {
  75. return GFootprintTable.GetCount();
  76. }
  77. void FP_TREE_SYNCHRONIZING_ADAPTER::updateLibrary( LIB_TREE_NODE_LIB& aLibNode )
  78. {
  79. std::vector<LIB_TREE_ITEM*> footprints = getFootprints( aLibNode.Name );
  80. // remove the common part from the footprints list
  81. for( auto nodeIt = aLibNode.Children.begin(); nodeIt != aLibNode.Children.end(); )
  82. {
  83. // Since the list is sorted we can use a binary search to speed up searches within
  84. // libraries with lots of footprints.
  85. FOOTPRINT_INFO_IMPL dummy( wxEmptyString, (*nodeIt)->Name );
  86. auto footprintIt = std::lower_bound( footprints.begin(), footprints.end(), &dummy,
  87. []( LIB_TREE_ITEM* a, LIB_TREE_ITEM* b )
  88. {
  89. return StrNumCmp( a->GetName(), b->GetName(), INT_MAX, true ) < 0;
  90. } );
  91. if( footprintIt != footprints.end() && dummy.GetName() == (*footprintIt)->GetName() )
  92. {
  93. // footprint exists both in the lib tree and the footprint info list; just
  94. // update the node data
  95. static_cast<LIB_TREE_NODE_LIB_ID*>( nodeIt->get() )->Update( *footprintIt );
  96. footprints.erase( footprintIt );
  97. ++nodeIt;
  98. }
  99. else
  100. {
  101. // node does not exist in the library manager, remove the corresponding node
  102. nodeIt = aLibNode.Children.erase( nodeIt );
  103. }
  104. }
  105. // now the footprint list contains only new aliases that need to be added to the tree
  106. for( auto footprint : footprints )
  107. aLibNode.AddItem( footprint );
  108. aLibNode.AssignIntrinsicRanks();
  109. m_libMap.insert( aLibNode.Name );
  110. }
  111. LIB_TREE_NODE::PTR_VECTOR::iterator FP_TREE_SYNCHRONIZING_ADAPTER::deleteLibrary(
  112. LIB_TREE_NODE::PTR_VECTOR::iterator& aLibNodeIt )
  113. {
  114. LIB_TREE_NODE* node = aLibNodeIt->get();
  115. m_libMap.erase( node->Name );
  116. auto it = m_tree.Children.erase( aLibNodeIt );
  117. return it;
  118. }
  119. void FP_TREE_SYNCHRONIZING_ADAPTER::GetValue( wxVariant& aVariant, wxDataViewItem const& aItem,
  120. unsigned int aCol ) const
  121. {
  122. if( IsFrozen() )
  123. {
  124. aVariant = wxEmptyString;
  125. return;
  126. }
  127. auto node = ToNode( aItem );
  128. wxASSERT( node );
  129. switch( aCol )
  130. {
  131. case 0:
  132. // mark modified part with an asterix
  133. if( node->LibId == m_frame->GetCurrentLibId() && m_frame->GetScreen()->IsModify() )
  134. aVariant = node->Name + " *";
  135. else
  136. aVariant = node->Name;
  137. break;
  138. case 1:
  139. aVariant = node->Desc;
  140. break;
  141. default: // column == -1 is used for default Compare function
  142. aVariant = node->Name;
  143. break;
  144. }
  145. }
  146. bool FP_TREE_SYNCHRONIZING_ADAPTER::GetAttr( wxDataViewItem const& aItem, unsigned int aCol,
  147. wxDataViewItemAttr& aAttr ) const
  148. {
  149. if( IsFrozen() )
  150. return false;
  151. // change attributes only for the name field
  152. if( aCol != 0 )
  153. return false;
  154. auto node = ToNode( aItem );
  155. wxCHECK( node, false );
  156. switch( node->Type )
  157. {
  158. case LIB_TREE_NODE::LIB:
  159. #ifdef __WXGTK__
  160. // The native wxGTK+ impl ignores background colour, so set the text colour instead.
  161. // This works reasonably well in dark themes, and quite poorly in light ones....
  162. if( node->Name == m_frame->GetCurrentLibId().GetLibNickname() )
  163. {
  164. aAttr.SetColour( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
  165. // mark modified libs with bold font
  166. aAttr.SetBold( m_frame->GetScreen()->IsModified() );
  167. }
  168. #else
  169. // mark the current library with background color
  170. if( node->Name == m_frame->GetCurrentLibId().GetLibNickname() )
  171. {
  172. aAttr.SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
  173. // mark modified libs with bold font
  174. aAttr.SetBold( m_frame->GetScreen()->IsModify() );
  175. }
  176. #endif
  177. break;
  178. case LIB_TREE_NODE::LIBID:
  179. #ifdef __WXGTK__
  180. // The native wxGTK+ impl ignores background colour, so set the text colour instead.
  181. // This works reasonably well in dark themes, and quite poorly in light ones....
  182. if( node->LibId == m_frame->GetCurrentLibId() )
  183. {
  184. aAttr.SetColour( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
  185. // mark modified part with bold font
  186. aAttr.SetBold( m_frame->GetScreen()->IsModified() );
  187. }
  188. #else
  189. // mark the current part with background color
  190. if( node->LibId == m_frame->GetCurrentLibId() )
  191. {
  192. aAttr.SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
  193. // mark modified part with bold font
  194. aAttr.SetBold( m_frame->GetScreen()->IsModify() );
  195. }
  196. #endif
  197. break;
  198. default:
  199. return false;
  200. }
  201. return true;
  202. }