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.

292 lines
9.0 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 <symbol_tree_synchronizing_adapter.h>
  25. #include <lib_manager.h>
  26. #include <symbol_lib_table.h>
  27. #include <class_libentry.h>
  28. LIB_TREE_MODEL_ADAPTER::PTR SYMBOL_TREE_SYNCHRONIZING_ADAPTER::Create( LIB_MANAGER* aLibMgr )
  29. {
  30. return PTR( new SYMBOL_TREE_SYNCHRONIZING_ADAPTER( aLibMgr ) );
  31. }
  32. SYMBOL_TREE_SYNCHRONIZING_ADAPTER::SYMBOL_TREE_SYNCHRONIZING_ADAPTER( LIB_MANAGER* aLibMgr )
  33. : m_libMgr( aLibMgr ),
  34. m_lastSyncHash( -1 )
  35. {
  36. }
  37. bool SYMBOL_TREE_SYNCHRONIZING_ADAPTER::IsContainer( const wxDataViewItem& aItem ) const
  38. {
  39. const LIB_TREE_NODE* node = ToNode( aItem );
  40. return node ? node->Type == LIB_TREE_NODE::LIB : true;
  41. }
  42. #define PROGRESS_INTERVAL_MILLIS 120
  43. void SYMBOL_TREE_SYNCHRONIZING_ADAPTER::Sync( bool aForce, std::function<void(int, int, const wxString&)> aProgressCallback )
  44. {
  45. wxLongLong nextUpdate = wxGetUTCTimeMillis() + (PROGRESS_INTERVAL_MILLIS / 2);
  46. int libMgrHash = m_libMgr->GetHash();
  47. if( !aForce && m_lastSyncHash == libMgrHash )
  48. return;
  49. m_lastSyncHash = libMgrHash;
  50. int i = 0, max = GetLibrariesCount();
  51. // Process already stored libraries
  52. for( auto it = m_tree.Children.begin(); it != m_tree.Children.end(); /* iteration inside */ )
  53. {
  54. const wxString& name = it->get()->Name;
  55. if( wxGetUTCTimeMillis() > nextUpdate )
  56. {
  57. aProgressCallback( i, max, name );
  58. nextUpdate = wxGetUTCTimeMillis() + PROGRESS_INTERVAL_MILLIS;
  59. }
  60. if( !m_libMgr->LibraryExists( name, true ) )
  61. {
  62. it = deleteLibrary( it );
  63. continue;
  64. }
  65. else if( m_libMgr->GetLibraryHash( name ) != m_libHashes[name] )
  66. {
  67. updateLibrary( *(LIB_TREE_NODE_LIB*) it->get() );
  68. }
  69. ++it;
  70. ++i;
  71. }
  72. // Look for new libraries
  73. for( const auto& libName : m_libMgr->GetLibraryNames() )
  74. {
  75. if( m_libHashes.count( libName ) == 0 )
  76. {
  77. if( wxGetUTCTimeMillis() > nextUpdate )
  78. {
  79. aProgressCallback( i++, max, libName );
  80. nextUpdate = wxGetUTCTimeMillis() + PROGRESS_INTERVAL_MILLIS;
  81. }
  82. SYMBOL_LIB_TABLE_ROW* library = m_libMgr->GetLibrary( libName );
  83. auto& lib_node = m_tree.AddLib( libName, library->GetDescr() );
  84. updateLibrary( lib_node );
  85. }
  86. }
  87. m_tree.AssignIntrinsicRanks();
  88. }
  89. int SYMBOL_TREE_SYNCHRONIZING_ADAPTER::GetLibrariesCount() const
  90. {
  91. int count = LIB_TREE_MODEL_ADAPTER::GetLibrariesCount();
  92. for( const auto& libName : m_libMgr->GetLibraryNames() )
  93. {
  94. if( m_libHashes.count( libName ) == 0 )
  95. ++count;
  96. }
  97. return count;
  98. }
  99. void SYMBOL_TREE_SYNCHRONIZING_ADAPTER::updateLibrary( LIB_TREE_NODE_LIB& aLibNode )
  100. {
  101. auto hashIt = m_libHashes.find( aLibNode.Name );
  102. if( hashIt == m_libHashes.end() )
  103. {
  104. // add a new library
  105. for( auto alias : m_libMgr->GetAliases( aLibNode.Name ) )
  106. aLibNode.AddItem( alias );
  107. }
  108. else if( hashIt->second != m_libMgr->GetLibraryHash( aLibNode.Name ) )
  109. {
  110. // update an existing libary
  111. std::list<LIB_ALIAS*> aliases = m_libMgr->GetAliases( aLibNode.Name );
  112. // remove the common part from the aliases list
  113. for( auto nodeIt = aLibNode.Children.begin(); nodeIt != aLibNode.Children.end(); /**/ )
  114. {
  115. auto aliasIt = std::find_if( aliases.begin(), aliases.end(),
  116. [&] ( const LIB_ALIAS* a ) {
  117. return a->GetName() == (*nodeIt)->Name;
  118. } );
  119. if( aliasIt != aliases.end() )
  120. {
  121. // alias exists both in the component tree and the library manager,
  122. // update only the node data
  123. static_cast<LIB_TREE_NODE_LIB_ID*>( nodeIt->get() )->Update( *aliasIt );
  124. aliases.erase( aliasIt );
  125. ++nodeIt;
  126. }
  127. else
  128. {
  129. // node does not exist in the library manager, remove the corresponding node
  130. nodeIt = aLibNode.Children.erase( nodeIt );
  131. }
  132. }
  133. // now the aliases list contains only new aliases that need to be added to the tree
  134. for( auto alias : aliases )
  135. aLibNode.AddItem( alias );
  136. }
  137. aLibNode.AssignIntrinsicRanks();
  138. m_libHashes[aLibNode.Name] = m_libMgr->GetLibraryHash( aLibNode.Name );
  139. }
  140. LIB_TREE_NODE::PTR_VECTOR::iterator SYMBOL_TREE_SYNCHRONIZING_ADAPTER::deleteLibrary(
  141. LIB_TREE_NODE::PTR_VECTOR::iterator& aLibNodeIt )
  142. {
  143. LIB_TREE_NODE* node = aLibNodeIt->get();
  144. m_libHashes.erase( node->Name );
  145. auto it = m_tree.Children.erase( aLibNodeIt );
  146. return it;
  147. }
  148. LIB_TREE_NODE* SYMBOL_TREE_SYNCHRONIZING_ADAPTER::findLibrary( const wxString& aLibNickName )
  149. {
  150. for( auto& lib : m_tree.Children )
  151. {
  152. if( lib->Name == aLibNickName )
  153. return lib.get();
  154. }
  155. return nullptr;
  156. }
  157. void SYMBOL_TREE_SYNCHRONIZING_ADAPTER::GetValue( wxVariant& aVariant, wxDataViewItem const& aItem,
  158. unsigned int aCol ) const
  159. {
  160. if( IsFrozen() )
  161. {
  162. aVariant = wxEmptyString;
  163. return;
  164. }
  165. auto node = ToNode( aItem );
  166. wxASSERT( node );
  167. switch( aCol )
  168. {
  169. case 0:
  170. aVariant = node->Name;
  171. // mark modified libs with an asterix
  172. if( node->Type == LIB_TREE_NODE::LIB && m_libMgr->IsLibraryModified( node->Name ) )
  173. aVariant = node->Name + " *";
  174. // mark modified parts with an asterix
  175. if( node->Type == LIB_TREE_NODE::LIBID
  176. && m_libMgr->IsPartModified( node->Name, node->Parent->Name ) )
  177. aVariant = node->Name + " *";
  178. break;
  179. case 1:
  180. aVariant = node->Desc;
  181. break;
  182. default: // column == -1 is used for default Compare function
  183. aVariant = node->Name;
  184. break;
  185. }
  186. }
  187. bool SYMBOL_TREE_SYNCHRONIZING_ADAPTER::GetAttr( wxDataViewItem const& aItem, unsigned int aCol,
  188. wxDataViewItemAttr& aAttr ) const
  189. {
  190. if( IsFrozen() )
  191. return false;
  192. // change attributes only for the name field
  193. if( aCol != 0 )
  194. return false;
  195. auto node = ToNode( aItem );
  196. wxCHECK( node, false );
  197. switch( node->Type )
  198. {
  199. case LIB_TREE_NODE::LIB:
  200. // mark modified libs with bold font
  201. aAttr.SetBold( m_libMgr->IsLibraryModified( node->Name ) );
  202. #ifdef __WXGTK__
  203. // The native wxGTK+ impl ignores background colour, so set the text colour instead.
  204. // This works reasonably well in dark themes, and quite poorly in light ones....
  205. if( node->Name == m_libMgr->GetCurrentLib() )
  206. aAttr.SetColour( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
  207. #else
  208. // mark the current library with background color
  209. if( node->Name == m_libMgr->GetCurrentLib() )
  210. aAttr.SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
  211. #endif
  212. break;
  213. case LIB_TREE_NODE::LIBID:
  214. // mark modified part with bold font
  215. aAttr.SetBold( m_libMgr->IsPartModified( node->Name, node->Parent->Name ) );
  216. // mark aliases with italic font
  217. aAttr.SetItalic( !node->IsRoot );
  218. #ifdef __WXGTK__
  219. // The native wxGTK+ impl ignores background colour, so set the text colour instead.
  220. // This works reasonably well in dark themes, and quite poorly in light ones....
  221. if( node->LibId == m_libMgr->GetCurrentLibId() )
  222. aAttr.SetColour( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
  223. #else
  224. // mark the current part with background color
  225. if( node->LibId == m_libMgr->GetCurrentLibId() )
  226. aAttr.SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
  227. #endif
  228. break;
  229. default:
  230. return false;
  231. }
  232. return true;
  233. }