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.

1333 lines
38 KiB

3 years ago
  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-2022 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. #include <symbol_library_manager.h>
  26. #include <symbol_library.h>
  27. #include <dialogs/html_message_box.h>
  28. #include <symbol_edit_frame.h>
  29. #include <env_paths.h>
  30. #include <pgm_base.h>
  31. #include <kiway.h>
  32. #include <profile.h>
  33. #include <wx_filename.h>
  34. #include <sch_io_mgr.h>
  35. #include <sch_plugins/legacy/sch_legacy_plugin.h>
  36. #include <symbol_lib_table.h>
  37. #include <symbol_async_loader.h>
  38. #include <progress_reporter.h>
  39. #include <list>
  40. #include <locale_io.h>
  41. #include <wx/log.h>
  42. #include <string_utils.h>
  43. #include "lib_logger.h"
  44. SYMBOL_LIBRARY_MANAGER::SYMBOL_LIBRARY_MANAGER( SCH_BASE_FRAME& aFrame ) :
  45. m_frame( aFrame )
  46. {
  47. m_logger = new LIB_LOGGER();
  48. }
  49. SYMBOL_LIBRARY_MANAGER::~SYMBOL_LIBRARY_MANAGER()
  50. {
  51. delete m_logger;
  52. }
  53. void SYMBOL_LIBRARY_MANAGER::Preload( PROGRESS_REPORTER& aReporter )
  54. {
  55. SYMBOL_ASYNC_LOADER loader( symTable()->GetLogicalLibs(), symTable(), false, nullptr,
  56. &aReporter );
  57. LOCALE_IO toggle;
  58. loader.Start();
  59. while( !loader.Done() )
  60. {
  61. if( !aReporter.KeepRefreshing() )
  62. break;
  63. wxMilliSleep( 33 /* 30 FPS refresh rate */ );
  64. }
  65. loader.Join();
  66. if( !loader.GetErrors().IsEmpty() )
  67. {
  68. HTML_MESSAGE_BOX dlg( &m_frame, _( "Load Error" ) );
  69. dlg.MessageSet( _( "Errors loading symbols:" ) );
  70. wxString msg = loader.GetErrors();
  71. msg.Replace( "\n", "<BR>" );
  72. dlg.AddHTML_Text( msg );
  73. dlg.ShowModal();
  74. }
  75. }
  76. bool SYMBOL_LIBRARY_MANAGER::HasModifications() const
  77. {
  78. for( const std::pair<const wxString, LIB_BUFFER>& lib : m_libs )
  79. {
  80. if( lib.second.IsModified() )
  81. return true;
  82. }
  83. return false;
  84. }
  85. int SYMBOL_LIBRARY_MANAGER::GetHash() const
  86. {
  87. int hash = symTable()->GetModifyHash();
  88. for( const std::pair<const wxString, LIB_BUFFER>& lib : m_libs )
  89. hash += lib.second.GetHash();
  90. return hash;
  91. }
  92. int SYMBOL_LIBRARY_MANAGER::GetLibraryHash( const wxString& aLibrary ) const
  93. {
  94. const auto libBufIt = m_libs.find( aLibrary );
  95. if( libBufIt != m_libs.end() )
  96. return libBufIt->second.GetHash();
  97. SYMBOL_LIB_TABLE_ROW* row = GetLibrary( aLibrary );
  98. // return -1 if library does not exist or 0 if not modified
  99. return row ? std::hash<std::string>{}( aLibrary.ToStdString() +
  100. row->GetFullURI( true ).ToStdString() ) : -1;
  101. }
  102. wxArrayString SYMBOL_LIBRARY_MANAGER::GetLibraryNames() const
  103. {
  104. wxArrayString res;
  105. for( const wxString& libName : symTable()->GetLogicalLibs() )
  106. res.Add( libName );
  107. return res;
  108. }
  109. SYMBOL_LIB_TABLE_ROW* SYMBOL_LIBRARY_MANAGER::GetLibrary( const wxString& aLibrary ) const
  110. {
  111. SYMBOL_LIB_TABLE_ROW* row = nullptr;
  112. try
  113. {
  114. row = symTable()->FindRow( aLibrary, true );
  115. }
  116. catch( const IO_ERROR& e )
  117. {
  118. wxLogMessage( _( "Library '%s' not found in the Symbol Library Table." ) + e.What(),
  119. aLibrary );
  120. }
  121. return row;
  122. }
  123. bool SYMBOL_LIBRARY_MANAGER::SaveLibrary( const wxString& aLibrary, const wxString& aFileName,
  124. SCH_IO_MGR::SCH_FILE_T aFileType )
  125. {
  126. wxCHECK( aFileType != SCH_IO_MGR::SCH_FILE_T::SCH_LEGACY && LibraryExists( aLibrary ), false );
  127. wxFileName fn( aFileName );
  128. wxCHECK( !fn.FileExists() || fn.IsFileWritable(), false );
  129. SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( aFileType ) );
  130. bool res = true; // assume all libraries are successfully saved
  131. STRING_UTF8_MAP properties;
  132. properties.emplace( SCH_LEGACY_PLUGIN::PropBuffering, "" );
  133. auto it = m_libs.find( aLibrary );
  134. if( it != m_libs.end() )
  135. {
  136. // Handle buffered library
  137. LIB_BUFFER& libBuf = it->second;
  138. const auto& symbolBuffers = libBuf.GetBuffers();
  139. for( const auto& symbolBuf : symbolBuffers )
  140. {
  141. if( !libBuf.SaveBuffer( symbolBuf, aFileName, &*pi, true ) )
  142. {
  143. // Something went wrong, but try to save other libraries
  144. res = false;
  145. }
  146. }
  147. // clear the deleted symbols buffer only if data is saved to the original file
  148. wxFileName original, destination( aFileName );
  149. SYMBOL_LIB_TABLE_ROW* row = GetLibrary( aLibrary );
  150. if( row )
  151. {
  152. original = row->GetFullURI();
  153. original.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS );
  154. }
  155. destination.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS );
  156. if( res && original == destination )
  157. libBuf.ClearDeletedBuffer();
  158. }
  159. else
  160. {
  161. // Handle original library
  162. for( LIB_SYMBOL* symbol : getOriginalSymbols( aLibrary ) )
  163. {
  164. LIB_SYMBOL* newSymbol;
  165. try
  166. {
  167. if( symbol->IsAlias() )
  168. {
  169. std::shared_ptr< LIB_SYMBOL > oldParent = symbol->GetParent().lock();
  170. wxCHECK_MSG( oldParent, false,
  171. wxString::Format( wxT( "Derived symbol '%s' found with undefined parent." ),
  172. symbol->GetName() ) );
  173. LIB_SYMBOL* libParent = pi->LoadSymbol( aLibrary, oldParent->GetName(),
  174. &properties );
  175. if( !libParent )
  176. {
  177. libParent = new LIB_SYMBOL( *oldParent.get() );
  178. pi->SaveSymbol( aLibrary, libParent, &properties );
  179. }
  180. newSymbol = new LIB_SYMBOL( *symbol );
  181. newSymbol->SetParent( libParent );
  182. pi->SaveSymbol( aLibrary, newSymbol, &properties );
  183. }
  184. else if( !pi->LoadSymbol( aLibrary, symbol->GetName(), &properties ) )
  185. {
  186. pi->SaveSymbol( aLibrary, new LIB_SYMBOL( *symbol ), &properties );
  187. }
  188. }
  189. catch( ... )
  190. {
  191. res = false;
  192. break;
  193. }
  194. }
  195. }
  196. try
  197. {
  198. pi->SaveLibrary( aFileName );
  199. }
  200. catch( ... )
  201. {
  202. // return false because something happens.
  203. // The library is not successfully saved
  204. res = false;
  205. }
  206. return res;
  207. }
  208. bool SYMBOL_LIBRARY_MANAGER::IsLibraryModified( const wxString& aLibrary ) const
  209. {
  210. auto it = m_libs.find( aLibrary );
  211. return it != m_libs.end() ? it->second.IsModified() : false;
  212. }
  213. bool SYMBOL_LIBRARY_MANAGER::IsSymbolModified( const wxString& aAlias,
  214. const wxString& aLibrary ) const
  215. {
  216. auto libIt = m_libs.find( aLibrary );
  217. if( libIt == m_libs.end() )
  218. return false;
  219. const LIB_BUFFER& buf = libIt->second;
  220. const std::shared_ptr<SYMBOL_LIBRARY_MANAGER::SYMBOL_BUFFER> symbolBuf = buf.GetBuffer( aAlias );
  221. return symbolBuf ? symbolBuf->IsModified() : false;
  222. }
  223. void SYMBOL_LIBRARY_MANAGER::SetSymbolModified( const wxString& aAlias,
  224. const wxString& aLibrary )
  225. {
  226. auto libIt = m_libs.find( aLibrary );
  227. if( libIt == m_libs.end() )
  228. return;
  229. const LIB_BUFFER& buf = libIt->second;
  230. std::shared_ptr<SYMBOL_LIBRARY_MANAGER::SYMBOL_BUFFER> symbolBuf = buf.GetBuffer( aAlias );
  231. wxCHECK( symbolBuf, /* void */ );
  232. symbolBuf->GetScreen()->SetContentModified();
  233. }
  234. bool SYMBOL_LIBRARY_MANAGER::ClearLibraryModified( const wxString& aLibrary ) const
  235. {
  236. auto libIt = m_libs.find( aLibrary );
  237. if( libIt == m_libs.end() )
  238. return false;
  239. for( auto& symbolBuf : libIt->second.GetBuffers() )
  240. {
  241. SCH_SCREEN* screen = symbolBuf->GetScreen();
  242. if( screen )
  243. screen->SetContentModified( false );
  244. }
  245. return true;
  246. }
  247. bool SYMBOL_LIBRARY_MANAGER::ClearSymbolModified( const wxString& aAlias,
  248. const wxString& aLibrary ) const
  249. {
  250. auto libI = m_libs.find( aLibrary );
  251. if( libI == m_libs.end() )
  252. return false;
  253. auto symbolBuf = libI->second.GetBuffer( aAlias );
  254. wxCHECK( symbolBuf, false );
  255. symbolBuf->GetScreen()->SetContentModified( false );
  256. return true;
  257. }
  258. bool SYMBOL_LIBRARY_MANAGER::IsLibraryReadOnly( const wxString& aLibrary ) const
  259. {
  260. wxCHECK( LibraryExists( aLibrary ), true );
  261. return !symTable()->IsSymbolLibWritable( aLibrary );
  262. }
  263. bool SYMBOL_LIBRARY_MANAGER::IsLibraryLoaded( const wxString& aLibrary ) const
  264. {
  265. wxCHECK( LibraryExists( aLibrary ), false );
  266. return symTable()->IsSymbolLibLoaded( aLibrary );
  267. }
  268. std::list<LIB_SYMBOL*> SYMBOL_LIBRARY_MANAGER::GetAliases( const wxString& aLibrary ) const
  269. {
  270. std::list<LIB_SYMBOL*> ret;
  271. wxCHECK( LibraryExists( aLibrary ), ret );
  272. auto libIt = m_libs.find( aLibrary );
  273. if( libIt != m_libs.end() )
  274. {
  275. for( auto& symbolBuf : libIt->second.GetBuffers() )
  276. {
  277. ret.push_back( symbolBuf->GetSymbol() );
  278. }
  279. }
  280. else
  281. {
  282. std::vector<LIB_SYMBOL*> aliases;
  283. try
  284. {
  285. symTable()->LoadSymbolLib( aliases, aLibrary );
  286. }
  287. catch( const IO_ERROR& e )
  288. {
  289. wxLogWarning( e.Problem() );
  290. }
  291. std::copy( aliases.begin(), aliases.end(), std::back_inserter( ret ) );
  292. }
  293. return ret;
  294. }
  295. LIB_SYMBOL* SYMBOL_LIBRARY_MANAGER::GetBufferedSymbol( const wxString& aAlias,
  296. const wxString& aLibrary )
  297. {
  298. wxCHECK( LibraryExists( aLibrary ), nullptr );
  299. // try the library buffers first
  300. LIB_BUFFER& libBuf = getLibraryBuffer( aLibrary );
  301. LIB_SYMBOL* bufferedSymbol = libBuf.GetSymbol( aAlias );
  302. if( !bufferedSymbol ) // no buffer symbol found
  303. {
  304. // create a copy of the symbol
  305. try
  306. {
  307. LIB_SYMBOL* symbol = symTable()->LoadSymbol( aLibrary, aAlias );
  308. if( symbol == nullptr )
  309. THROW_IO_ERROR( _( "Symbol not found." ) );
  310. LIB_SYMBOL* bufferedParent = nullptr;
  311. // Create parent symbols on demand so parent symbol can be set.
  312. if( symbol->IsAlias() )
  313. {
  314. std::shared_ptr< LIB_SYMBOL > parent = symbol->GetParent().lock();
  315. wxCHECK_MSG( parent, nullptr,
  316. wxString::Format( "Derived symbol '%s' found with undefined parent.",
  317. symbol->GetName() ) );
  318. // Check if the parent symbol buffer has already be created.
  319. bufferedParent = libBuf.GetSymbol( parent->GetName() );
  320. if( !bufferedParent )
  321. {
  322. bufferedParent = new LIB_SYMBOL( *parent.get() );
  323. libBuf.CreateBuffer( bufferedParent, new SCH_SCREEN );
  324. }
  325. }
  326. bufferedSymbol = new LIB_SYMBOL( *symbol );
  327. if( bufferedParent )
  328. bufferedSymbol->SetParent( bufferedParent );
  329. libBuf.CreateBuffer( bufferedSymbol, new SCH_SCREEN );
  330. }
  331. catch( const IO_ERROR& e )
  332. {
  333. wxLogMessage( _( "Error loading symbol %s from library '%s'. (%s)" ),
  334. aAlias, aLibrary, e.What() );
  335. bufferedSymbol = nullptr;
  336. }
  337. }
  338. return bufferedSymbol;
  339. }
  340. SCH_SCREEN* SYMBOL_LIBRARY_MANAGER::GetScreen( const wxString& aAlias, const wxString& aLibrary )
  341. {
  342. wxCHECK( LibraryExists( aLibrary ), nullptr );
  343. wxCHECK( !aAlias.IsEmpty(), nullptr );
  344. auto it = m_libs.find( aLibrary );
  345. wxCHECK( it != m_libs.end(), nullptr );
  346. LIB_BUFFER& buf = it->second;
  347. auto symbolBuf = buf.GetBuffer( aAlias );
  348. return symbolBuf ? symbolBuf->GetScreen() : nullptr;
  349. }
  350. bool SYMBOL_LIBRARY_MANAGER::UpdateSymbol( LIB_SYMBOL* aSymbol, const wxString& aLibrary )
  351. {
  352. wxCHECK( LibraryExists( aLibrary ), false );
  353. wxCHECK( aSymbol, false );
  354. LIB_BUFFER& libBuf = getLibraryBuffer( aLibrary );
  355. auto symbolBuf = libBuf.GetBuffer( aSymbol->GetName() );
  356. if( symbolBuf ) // Existing symbol.
  357. {
  358. LIB_SYMBOL* bufferedSymbol = const_cast< LIB_SYMBOL* >( symbolBuf->GetSymbol() );
  359. wxCHECK( bufferedSymbol, false );
  360. *bufferedSymbol = *aSymbol;
  361. symbolBuf->GetScreen()->SetContentModified();
  362. }
  363. else // New symbol
  364. {
  365. LIB_SYMBOL* symbolCopy = new LIB_SYMBOL( *aSymbol, nullptr );
  366. symbolCopy->SetLibId( LIB_ID( aLibrary, aSymbol->GetLibId().GetLibItemName() ) );
  367. SCH_SCREEN* screen = new SCH_SCREEN;
  368. libBuf.CreateBuffer( symbolCopy, screen );
  369. screen->SetContentModified();
  370. }
  371. return true;
  372. }
  373. bool SYMBOL_LIBRARY_MANAGER::UpdateSymbolAfterRename( LIB_SYMBOL* aSymbol, const wxString& aOldName,
  374. const wxString& aLibrary )
  375. {
  376. LIB_BUFFER& libBuf = getLibraryBuffer( aLibrary );
  377. auto symbolBuf = libBuf.GetBuffer( aOldName );
  378. wxCHECK( symbolBuf, false );
  379. libBuf.UpdateBuffer( symbolBuf, aSymbol );
  380. OnDataChanged();
  381. return true;
  382. }
  383. bool SYMBOL_LIBRARY_MANAGER::FlushSymbol( const wxString& aAlias, const wxString& aLibrary )
  384. {
  385. auto it = m_libs.find( aLibrary );
  386. if( it == m_libs.end() ) // no items to flush
  387. return true;
  388. auto symbolBuf = it->second.GetBuffer( aAlias );
  389. wxCHECK( symbolBuf, false );
  390. return it->second.SaveBuffer( symbolBuf, symTable() );
  391. }
  392. LIB_ID SYMBOL_LIBRARY_MANAGER::RevertSymbol( const wxString& aAlias, const wxString& aLibrary )
  393. {
  394. auto it = m_libs.find( aLibrary );
  395. if( it == m_libs.end() ) // no items to flush
  396. return LIB_ID( aLibrary, aAlias );
  397. auto symbolBuf = it->second.GetBuffer( aAlias );
  398. wxCHECK( symbolBuf, LIB_ID( aLibrary, aAlias ) );
  399. LIB_SYMBOL original( *symbolBuf->GetOriginal() );
  400. if( original.GetName() != aAlias )
  401. {
  402. UpdateSymbolAfterRename( &original, aAlias, aLibrary );
  403. }
  404. else
  405. {
  406. // copy the initial data to the current symbol to restore
  407. *symbolBuf->GetSymbol() = original;
  408. OnDataChanged();
  409. }
  410. return LIB_ID( aLibrary, original.GetName() );
  411. }
  412. bool SYMBOL_LIBRARY_MANAGER::RevertLibrary( const wxString& aLibrary )
  413. {
  414. auto it = m_libs.find( aLibrary );
  415. if( it == m_libs.end() ) // nothing to reverse
  416. return false;
  417. m_libs.erase( it );
  418. OnDataChanged();
  419. return true;
  420. }
  421. bool SYMBOL_LIBRARY_MANAGER::RevertAll()
  422. {
  423. bool retv = true;
  424. // Nothing to revert.
  425. if( GetHash() == 0 )
  426. return true;
  427. for( const auto& lib : m_libs )
  428. {
  429. if( !lib.second.IsModified() )
  430. continue;
  431. for( const auto& buffer : lib.second.GetBuffers() )
  432. {
  433. if( !buffer->IsModified() )
  434. continue;
  435. RevertSymbol( lib.first, buffer->GetOriginal()->GetName() );
  436. }
  437. }
  438. return retv;
  439. }
  440. bool SYMBOL_LIBRARY_MANAGER::RemoveSymbol( const wxString& aAlias, const wxString& aLibrary )
  441. {
  442. LIB_BUFFER& libBuf = getLibraryBuffer( aLibrary );
  443. auto symbolBuf = libBuf.GetBuffer( aAlias );
  444. wxCHECK( symbolBuf, false );
  445. bool retv = true;
  446. retv &= libBuf.DeleteBuffer( symbolBuf );
  447. OnDataChanged();
  448. return retv;
  449. }
  450. LIB_SYMBOL* SYMBOL_LIBRARY_MANAGER::GetAlias( const wxString& aAlias,
  451. const wxString& aLibrary ) const
  452. {
  453. // Try the library buffers first
  454. auto libIt = m_libs.find( aLibrary );
  455. if( libIt != m_libs.end() )
  456. {
  457. LIB_SYMBOL* symbol = libIt->second.GetSymbol( aAlias );
  458. if( symbol )
  459. return symbol;
  460. }
  461. // Get the original symbol
  462. LIB_SYMBOL* alias = nullptr;
  463. try
  464. {
  465. alias = symTable()->LoadSymbol( aLibrary, aAlias );
  466. }
  467. catch( const IO_ERROR& e )
  468. {
  469. wxLogMessage( _( "Cannot load symbol '%s' from library '%s'." ) + e.What(),
  470. aAlias,
  471. aLibrary );
  472. }
  473. return alias;
  474. }
  475. bool SYMBOL_LIBRARY_MANAGER::SymbolExists( const wxString& aAlias, const wxString& aLibrary ) const
  476. {
  477. auto libBufIt = m_libs.find( aLibrary );
  478. LIB_SYMBOL* alias = nullptr;
  479. if( libBufIt != m_libs.end() )
  480. return !!libBufIt->second.GetBuffer( aAlias );
  481. try
  482. {
  483. alias = symTable()->LoadSymbol( aLibrary, aAlias );
  484. }
  485. catch( IO_ERROR& )
  486. {
  487. // checking if certain symbol exists, so its absence is perfectly fine
  488. }
  489. return alias != nullptr;
  490. }
  491. bool SYMBOL_LIBRARY_MANAGER::LibraryExists( const wxString& aLibrary, bool aCheckEnabled ) const
  492. {
  493. if( aLibrary.IsEmpty() )
  494. return false;
  495. if( m_libs.count( aLibrary ) > 0 )
  496. return true;
  497. return symTable()->HasLibrary( aLibrary, aCheckEnabled );
  498. }
  499. wxString SYMBOL_LIBRARY_MANAGER::GetUniqueLibraryName() const
  500. {
  501. wxString name = "New_Library";
  502. if( !LibraryExists( name ) )
  503. return name;
  504. name += "_";
  505. for( unsigned int i = 0; i < std::numeric_limits<unsigned int>::max(); ++i )
  506. {
  507. if( !LibraryExists( name + wxString::Format( "%u", i ) ) )
  508. return name + wxString::Format( "%u", i );
  509. }
  510. wxFAIL;
  511. return wxEmptyString;
  512. }
  513. void SYMBOL_LIBRARY_MANAGER::GetRootSymbolNames( const wxString& aLibraryName,
  514. wxArrayString& aRootSymbolNames )
  515. {
  516. LIB_BUFFER& libBuf = getLibraryBuffer( aLibraryName );
  517. libBuf.GetRootSymbolNames( aRootSymbolNames );
  518. }
  519. bool SYMBOL_LIBRARY_MANAGER:: HasDerivedSymbols( const wxString& aSymbolName,
  520. const wxString& aLibraryName )
  521. {
  522. LIB_BUFFER& libBuf = getLibraryBuffer( aLibraryName );
  523. return libBuf.HasDerivedSymbols( aSymbolName );
  524. }
  525. size_t SYMBOL_LIBRARY_MANAGER::GetLibraryCount() const
  526. {
  527. return symTable()->GetLogicalLibs().size();
  528. }
  529. wxString SYMBOL_LIBRARY_MANAGER::getLibraryName( const wxString& aFilePath )
  530. {
  531. wxFileName fn( aFilePath );
  532. return fn.GetName();
  533. }
  534. bool SYMBOL_LIBRARY_MANAGER::addLibrary( const wxString& aFilePath, bool aCreate,
  535. SYMBOL_LIB_TABLE* aTable )
  536. {
  537. wxCHECK( aTable, false );
  538. wxString libName = getLibraryName( aFilePath );
  539. wxCHECK( !LibraryExists( libName ), false ); // either create or add an existing one
  540. // try to use path normalized to an environmental variable or project path
  541. wxString relPath = NormalizePath( aFilePath, &Pgm().GetLocalEnvVariables(), &m_frame.Prj() );
  542. SCH_IO_MGR::SCH_FILE_T schFileType = SCH_IO_MGR::GuessPluginTypeFromLibPath( aFilePath );
  543. wxString typeName = SCH_IO_MGR::ShowType( schFileType );
  544. SYMBOL_LIB_TABLE_ROW* libRow = new SYMBOL_LIB_TABLE_ROW( libName, relPath, typeName );
  545. aTable->InsertRow( libRow );
  546. if( aCreate )
  547. {
  548. wxCHECK( schFileType != SCH_IO_MGR::SCH_FILE_T::SCH_LEGACY, false );
  549. try
  550. {
  551. aTable->CreateSymbolLib( libName );
  552. }
  553. catch( const IO_ERROR& )
  554. {
  555. aTable->RemoveRow( libRow );
  556. return false;
  557. }
  558. }
  559. OnDataChanged();
  560. return true;
  561. }
  562. SYMBOL_LIB_TABLE* SYMBOL_LIBRARY_MANAGER::symTable() const
  563. {
  564. return m_frame.Prj().SchSymbolLibTable();
  565. }
  566. std::set<LIB_SYMBOL*> SYMBOL_LIBRARY_MANAGER::getOriginalSymbols( const wxString& aLibrary )
  567. {
  568. std::set<LIB_SYMBOL*> symbols;
  569. wxCHECK( LibraryExists( aLibrary ), symbols );
  570. try
  571. {
  572. wxArrayString aliases;
  573. symTable()->EnumerateSymbolLib( aLibrary, aliases );
  574. for( const auto& aliasName : aliases )
  575. {
  576. LIB_SYMBOL* alias = symTable()->LoadSymbol( aLibrary, aliasName );
  577. symbols.insert( alias );
  578. }
  579. }
  580. catch( const IO_ERROR& e )
  581. {
  582. wxLogMessage( _( "Cannot enumerate library '%s'." ) + e.What(), aLibrary );
  583. }
  584. return symbols;
  585. }
  586. SYMBOL_LIBRARY_MANAGER::LIB_BUFFER& SYMBOL_LIBRARY_MANAGER::getLibraryBuffer(
  587. const wxString& aLibrary )
  588. {
  589. auto it = m_libs.find( aLibrary );
  590. if( it != m_libs.end() )
  591. return it->second;
  592. // The requested buffer does not exist yet, so create one
  593. auto ret = m_libs.emplace( aLibrary, LIB_BUFFER( aLibrary ) );
  594. LIB_BUFFER& buf = ret.first->second;
  595. for( auto symbol : getOriginalSymbols( aLibrary ) )
  596. {
  597. LIB_SYMBOL* newSymbol;
  598. if( symbol->IsAlias() )
  599. {
  600. std::shared_ptr< LIB_SYMBOL > oldParent = symbol->GetParent().lock();
  601. wxCHECK_MSG( oldParent, buf,
  602. wxString::Format( "Derived symbol '%s' found with undefined parent.",
  603. symbol->GetName() ) );
  604. LIB_SYMBOL* libParent = buf.GetSymbol( oldParent->GetName() );
  605. if( !libParent )
  606. {
  607. libParent = new LIB_SYMBOL( *oldParent.get() );
  608. buf.CreateBuffer( libParent, new SCH_SCREEN );
  609. }
  610. newSymbol = new LIB_SYMBOL( *symbol );
  611. newSymbol->SetParent( libParent );
  612. buf.CreateBuffer( newSymbol, new SCH_SCREEN );
  613. }
  614. else if( !buf.GetSymbol( symbol->GetName() ) )
  615. {
  616. buf.CreateBuffer( new LIB_SYMBOL( *symbol ), new SCH_SCREEN );
  617. }
  618. }
  619. return buf;
  620. }
  621. SYMBOL_LIBRARY_MANAGER::SYMBOL_BUFFER::SYMBOL_BUFFER( LIB_SYMBOL* aSymbol,
  622. std::unique_ptr<SCH_SCREEN> aScreen ) :
  623. m_screen( std::move( aScreen ) ),
  624. m_symbol( aSymbol )
  625. {
  626. m_original = new LIB_SYMBOL( *aSymbol );
  627. }
  628. SYMBOL_LIBRARY_MANAGER::SYMBOL_BUFFER::~SYMBOL_BUFFER()
  629. {
  630. delete m_symbol;
  631. delete m_original;
  632. }
  633. void SYMBOL_LIBRARY_MANAGER::SYMBOL_BUFFER::SetSymbol( LIB_SYMBOL* aSymbol )
  634. {
  635. wxCHECK( m_symbol != aSymbol, /* void */ );
  636. wxASSERT( aSymbol );
  637. delete m_symbol;
  638. m_symbol = aSymbol;
  639. // If the symbol moves libraries then the original moves with it
  640. if( m_original->GetLibId().GetLibNickname() != m_symbol->GetLibId().GetLibNickname() )
  641. {
  642. m_original->SetLibId( LIB_ID( m_symbol->GetLibId().GetLibNickname(),
  643. m_original->GetLibId().GetLibItemName() ) );
  644. }
  645. }
  646. void SYMBOL_LIBRARY_MANAGER::SYMBOL_BUFFER::SetOriginal( LIB_SYMBOL* aSymbol )
  647. {
  648. wxCHECK( m_original != aSymbol, /* void */ );
  649. wxASSERT( aSymbol );
  650. delete m_original;
  651. m_original = aSymbol;
  652. // The original is not allowed to have a different library than its symbol
  653. if( m_original->GetLibId().GetLibNickname() != m_symbol->GetLibId().GetLibNickname() )
  654. {
  655. m_original->SetLibId( LIB_ID( m_symbol->GetLibId().GetLibNickname(),
  656. m_original->GetLibId().GetLibItemName() ) );
  657. }
  658. }
  659. bool SYMBOL_LIBRARY_MANAGER::SYMBOL_BUFFER::IsModified() const
  660. {
  661. return m_screen && m_screen->IsContentModified();
  662. }
  663. LIB_SYMBOL* SYMBOL_LIBRARY_MANAGER::LIB_BUFFER::GetSymbol( const wxString& aAlias ) const
  664. {
  665. auto buf = GetBuffer( aAlias );
  666. if( !buf )
  667. return nullptr;
  668. LIB_SYMBOL* symbol = buf->GetSymbol();
  669. wxCHECK( symbol, nullptr );
  670. return symbol;
  671. }
  672. bool SYMBOL_LIBRARY_MANAGER::LIB_BUFFER::CreateBuffer( LIB_SYMBOL* aCopy, SCH_SCREEN* aScreen )
  673. {
  674. wxASSERT( aCopy );
  675. wxASSERT( aCopy->GetLib() == nullptr );
  676. std::unique_ptr<SCH_SCREEN> screen( aScreen );
  677. auto symbolBuf = std::make_shared<SYMBOL_BUFFER>( aCopy, std::move( screen ) );
  678. m_symbols.push_back( symbolBuf );
  679. // Set the parent library name,
  680. // otherwise it is empty as no library has been given as the owner during object construction
  681. LIB_ID libId = aCopy->GetLibId();
  682. libId.SetLibNickname( m_libName );
  683. aCopy->SetLibId( libId );
  684. ++m_hash;
  685. return true;
  686. }
  687. bool SYMBOL_LIBRARY_MANAGER::LIB_BUFFER::UpdateBuffer( std::shared_ptr<SYMBOL_BUFFER> aSymbolBuf,
  688. LIB_SYMBOL* aCopy )
  689. {
  690. wxCHECK( aCopy && aSymbolBuf, false );
  691. LIB_SYMBOL* bufferedSymbol = aSymbolBuf->GetSymbol();
  692. wxCHECK( bufferedSymbol, false );
  693. *bufferedSymbol = *aCopy;
  694. ++m_hash;
  695. return true;
  696. }
  697. bool SYMBOL_LIBRARY_MANAGER::LIB_BUFFER::DeleteBuffer( std::shared_ptr<SYMBOL_BUFFER> aSymbolBuf )
  698. {
  699. auto symbolBufIt = std::find( m_symbols.begin(), m_symbols.end(), aSymbolBuf );
  700. wxCHECK( symbolBufIt != m_symbols.end(), false );
  701. bool retv = true;
  702. // Remove all derived symbols to prevent broken inheritance.
  703. if( aSymbolBuf->GetSymbol()->IsRoot() && HasDerivedSymbols( aSymbolBuf->GetSymbol()->GetName() )
  704. && removeChildSymbols( aSymbolBuf ) == 0 )
  705. {
  706. retv = false;
  707. }
  708. m_deleted.emplace_back( *symbolBufIt );
  709. m_symbols.erase( symbolBufIt );
  710. ++m_hash;
  711. return retv;
  712. }
  713. bool SYMBOL_LIBRARY_MANAGER::LIB_BUFFER::SaveBuffer( std::shared_ptr<SYMBOL_BUFFER> aSymbolBuf,
  714. SYMBOL_LIB_TABLE* aLibTable )
  715. {
  716. wxCHECK( aSymbolBuf, false );
  717. LIB_SYMBOL* libSymbol = aSymbolBuf->GetSymbol();
  718. LIB_SYMBOL* originalSymbol = aSymbolBuf->GetOriginal();
  719. wxCHECK( libSymbol && originalSymbol, false );
  720. SYMBOL_LIB_TABLE::SAVE_T result;
  721. STRING_UTF8_MAP properties;
  722. properties.emplace( SCH_LEGACY_PLUGIN::PropBuffering, "" );
  723. wxString errorMsg = _( "Error saving symbol %s to library '%s'." ) + wxS( "\n%s" );
  724. // Delete the original symbol if the symbol name has been changed.
  725. if( libSymbol->GetName() != originalSymbol->GetName() )
  726. {
  727. // DeleteSymbol may throw
  728. try
  729. {
  730. if( aLibTable->LoadSymbol( m_libName, originalSymbol->GetName() ) )
  731. aLibTable->DeleteSymbol( m_libName, originalSymbol->GetName() );
  732. }
  733. catch( const IO_ERROR& ioe )
  734. {
  735. wxLogError( errorMsg, UnescapeString( originalSymbol->GetName() ), m_libName,
  736. ioe.What() );
  737. return false;
  738. }
  739. }
  740. if( libSymbol->IsAlias() )
  741. {
  742. LIB_SYMBOL* newCachedSymbol = new LIB_SYMBOL( *libSymbol );
  743. std::shared_ptr< LIB_SYMBOL > bufferedParent = libSymbol->GetParent().lock();
  744. wxCHECK( bufferedParent, false );
  745. LIB_SYMBOL* cachedParent = aLibTable->LoadSymbol( m_libName, bufferedParent->GetName() );
  746. if( !cachedParent )
  747. {
  748. cachedParent = new LIB_SYMBOL( *bufferedParent.get() );
  749. newCachedSymbol->SetParent( cachedParent );
  750. result = aLibTable->SaveSymbol( m_libName, cachedParent );
  751. wxCHECK( result == SYMBOL_LIB_TABLE::SAVE_OK, false );
  752. result = aLibTable->SaveSymbol( m_libName, newCachedSymbol );
  753. wxCHECK( result == SYMBOL_LIB_TABLE::SAVE_OK, false );
  754. LIB_SYMBOL* originalParent = new LIB_SYMBOL( *bufferedParent.get() );
  755. aSymbolBuf->SetOriginal( originalParent );
  756. originalSymbol = new LIB_SYMBOL( *libSymbol );
  757. originalSymbol->SetParent( originalParent );
  758. aSymbolBuf->SetOriginal( originalSymbol );
  759. }
  760. else
  761. {
  762. newCachedSymbol->SetParent( cachedParent );
  763. result = aLibTable->SaveSymbol( m_libName, newCachedSymbol );
  764. wxCHECK( result == SYMBOL_LIB_TABLE::SAVE_OK, false );
  765. auto originalBufferedParent = GetBuffer( bufferedParent->GetName() );
  766. wxCHECK( originalBufferedParent, false );
  767. originalSymbol = new LIB_SYMBOL( *libSymbol );
  768. originalSymbol->SetParent( originalBufferedParent->GetSymbol() );
  769. aSymbolBuf->SetOriginal( originalSymbol );
  770. }
  771. }
  772. else
  773. {
  774. wxArrayString derivedSymbols;
  775. if( GetDerivedSymbolNames( libSymbol->GetName(), derivedSymbols ) == 0 )
  776. {
  777. result = aLibTable->SaveSymbol( m_libName, new LIB_SYMBOL( *libSymbol ) );
  778. wxCHECK( result == SYMBOL_LIB_TABLE::SAVE_OK, false );
  779. aSymbolBuf->SetOriginal( new LIB_SYMBOL( *libSymbol ) );
  780. }
  781. else
  782. {
  783. LIB_SYMBOL* parentSymbol = new LIB_SYMBOL( *libSymbol );
  784. aLibTable->SaveSymbol( m_libName, parentSymbol );
  785. for( auto& entry : derivedSymbols )
  786. {
  787. std::shared_ptr<SYMBOL_BUFFER> symbol = GetBuffer( entry );
  788. wxCHECK2( symbol, continue );
  789. LIB_SYMBOL* derivedSymbol = new LIB_SYMBOL( *symbol->GetSymbol() );
  790. derivedSymbol->SetParent( parentSymbol );
  791. result = aLibTable->SaveSymbol( m_libName, derivedSymbol );
  792. wxCHECK( result == SYMBOL_LIB_TABLE::SAVE_OK, false );
  793. }
  794. }
  795. }
  796. ++m_hash;
  797. return true;
  798. }
  799. bool SYMBOL_LIBRARY_MANAGER::LIB_BUFFER::SaveBuffer( std::shared_ptr<SYMBOL_BUFFER> aSymbolBuf,
  800. const wxString& aFileName,
  801. SCH_PLUGIN* aPlugin, bool aBuffer )
  802. {
  803. wxCHECK( aSymbolBuf, false );
  804. LIB_SYMBOL* libSymbol = aSymbolBuf->GetSymbol();
  805. LIB_SYMBOL* originalSymbol = aSymbolBuf->GetOriginal();
  806. wxCHECK( libSymbol && originalSymbol, false );
  807. wxCHECK( !aFileName.IsEmpty(), false );
  808. wxString errorMsg = _( "Error saving symbol %s to library '%s'." ) + wxS( "\n%s" );
  809. // set properties to prevent save file on every symbol save
  810. STRING_UTF8_MAP properties;
  811. properties.emplace( SCH_LEGACY_PLUGIN::PropBuffering, "" );
  812. // Delete the original symbol if the symbol name has been changed.
  813. if( libSymbol->GetName() != originalSymbol->GetName() )
  814. {
  815. try
  816. {
  817. if( aPlugin->LoadSymbol( aFileName, originalSymbol->GetName() ) )
  818. aPlugin->DeleteSymbol( aFileName, originalSymbol->GetName(), &properties );
  819. }
  820. catch( const IO_ERROR& ioe )
  821. {
  822. wxLogError( errorMsg, UnescapeString( originalSymbol->GetName() ), aFileName,
  823. ioe.What() );
  824. return false;
  825. }
  826. }
  827. if( libSymbol->IsAlias() )
  828. {
  829. LIB_SYMBOL* newCachedSymbol = new LIB_SYMBOL( *libSymbol );
  830. std::shared_ptr< LIB_SYMBOL > bufferedParent = libSymbol->GetParent().lock();
  831. wxCHECK( bufferedParent, false );
  832. LIB_SYMBOL* cachedParent = nullptr;
  833. try
  834. {
  835. cachedParent = aPlugin->LoadSymbol( aFileName, bufferedParent->GetName() );
  836. }
  837. catch( const IO_ERROR& )
  838. {
  839. return false;
  840. }
  841. if( !cachedParent )
  842. {
  843. cachedParent = new LIB_SYMBOL( *bufferedParent.get() );
  844. newCachedSymbol->SetParent( cachedParent );
  845. try
  846. {
  847. aPlugin->SaveSymbol( aFileName, cachedParent, aBuffer ? &properties : nullptr );
  848. }
  849. catch( const IO_ERROR& ioe )
  850. {
  851. wxLogError( errorMsg, UnescapeString( cachedParent->GetName() ), aFileName,
  852. ioe.What() );
  853. return false;
  854. }
  855. try
  856. {
  857. aPlugin->SaveSymbol( aFileName, newCachedSymbol, aBuffer ? &properties : nullptr );
  858. }
  859. catch( const IO_ERROR& ioe )
  860. {
  861. wxLogError( errorMsg, UnescapeString( newCachedSymbol->GetName() ), aFileName,
  862. ioe.What() );
  863. return false;
  864. }
  865. LIB_SYMBOL* originalParent = new LIB_SYMBOL( *bufferedParent.get() );
  866. aSymbolBuf->SetOriginal( originalParent );
  867. originalSymbol = new LIB_SYMBOL( *libSymbol );
  868. originalSymbol->SetParent( originalParent );
  869. aSymbolBuf->SetOriginal( originalSymbol );
  870. }
  871. else
  872. {
  873. newCachedSymbol->SetParent( cachedParent );
  874. try
  875. {
  876. aPlugin->SaveSymbol( aFileName, newCachedSymbol, aBuffer ? &properties : nullptr );
  877. }
  878. catch( const IO_ERROR& ioe )
  879. {
  880. wxLogError( errorMsg, UnescapeString( newCachedSymbol->GetName() ), aFileName,
  881. ioe.What() );
  882. return false;
  883. }
  884. auto originalBufferedParent = GetBuffer( bufferedParent->GetName() );
  885. wxCHECK( originalBufferedParent, false );
  886. originalSymbol = new LIB_SYMBOL( *libSymbol );
  887. originalSymbol->SetParent( originalBufferedParent->GetSymbol() );
  888. aSymbolBuf->SetOriginal( originalSymbol );
  889. }
  890. }
  891. else
  892. {
  893. wxArrayString derivedSymbols;
  894. if( GetDerivedSymbolNames( libSymbol->GetName(), derivedSymbols ) == 0 )
  895. {
  896. try
  897. {
  898. aPlugin->SaveSymbol( aFileName, new LIB_SYMBOL( *libSymbol ),
  899. aBuffer ? &properties : nullptr );
  900. }
  901. catch( const IO_ERROR& ioe )
  902. {
  903. wxLogError( errorMsg, UnescapeString( libSymbol->GetName() ), aFileName,
  904. ioe.What() );
  905. return false;
  906. }
  907. aSymbolBuf->SetOriginal( new LIB_SYMBOL( *libSymbol ) );
  908. }
  909. else
  910. {
  911. LIB_SYMBOL* parentSymbol = new LIB_SYMBOL( *libSymbol );
  912. // Save the modified root symbol.
  913. try
  914. {
  915. aPlugin->SaveSymbol( aFileName, parentSymbol, aBuffer ? &properties : nullptr );
  916. }
  917. catch( const IO_ERROR& ioe )
  918. {
  919. wxLogError( errorMsg, UnescapeString( libSymbol->GetName() ), aFileName,
  920. ioe.What() );
  921. return false;
  922. }
  923. aSymbolBuf->SetOriginal( new LIB_SYMBOL( *libSymbol ) );
  924. // Save the derived symbols.
  925. for( const wxString& entry : derivedSymbols )
  926. {
  927. std::shared_ptr<SYMBOL_BUFFER> symbol = GetBuffer( entry );
  928. wxCHECK2( symbol, continue );
  929. LIB_SYMBOL* derivedSymbol = new LIB_SYMBOL( *symbol->GetSymbol() );
  930. derivedSymbol->SetParent( parentSymbol );
  931. try
  932. {
  933. aPlugin->SaveSymbol( aFileName, new LIB_SYMBOL( *derivedSymbol ),
  934. aBuffer ? &properties : nullptr );
  935. }
  936. catch( const IO_ERROR& ioe )
  937. {
  938. wxLogError( errorMsg, UnescapeString( derivedSymbol->GetName() ), aFileName,
  939. ioe.What() );
  940. return false;
  941. }
  942. }
  943. }
  944. }
  945. ++m_hash;
  946. return true;
  947. }
  948. std::shared_ptr<SYMBOL_LIBRARY_MANAGER::SYMBOL_BUFFER>
  949. SYMBOL_LIBRARY_MANAGER::LIB_BUFFER::GetBuffer( const wxString& aAlias ) const
  950. {
  951. for( std::shared_ptr<SYMBOL_LIBRARY_MANAGER::SYMBOL_BUFFER> entry : m_symbols )
  952. {
  953. if( entry->GetSymbol()->GetName() == aAlias )
  954. return entry;
  955. }
  956. return std::shared_ptr<SYMBOL_BUFFER>( nullptr );
  957. }
  958. bool SYMBOL_LIBRARY_MANAGER::LIB_BUFFER::HasDerivedSymbols( const wxString& aParentName ) const
  959. {
  960. for( auto& entry : m_symbols )
  961. {
  962. if( entry->GetSymbol()->IsAlias() )
  963. {
  964. LIB_SYMBOL_SPTR parent = entry->GetSymbol()->GetParent().lock();
  965. // Check for inherited symbol without a valid parent.
  966. wxCHECK( parent, false );
  967. if( parent->GetName() == aParentName )
  968. return true;
  969. }
  970. }
  971. return false;
  972. }
  973. void SYMBOL_LIBRARY_MANAGER::LIB_BUFFER::GetRootSymbolNames( wxArrayString& aRootSymbolNames )
  974. {
  975. for( auto& entry : m_symbols )
  976. {
  977. if( entry->GetSymbol()->IsAlias() )
  978. continue;
  979. aRootSymbolNames.Add( UnescapeString( entry->GetSymbol()->GetName() ) );
  980. }
  981. }
  982. size_t SYMBOL_LIBRARY_MANAGER::LIB_BUFFER::GetDerivedSymbolNames( const wxString& aSymbolName,
  983. wxArrayString& aList )
  984. {
  985. wxCHECK( !aSymbolName.IsEmpty(), 0 );
  986. for( auto& entry : m_symbols )
  987. {
  988. if( entry->GetSymbol()->IsAlias() )
  989. {
  990. LIB_SYMBOL_SPTR parent = entry->GetSymbol()->GetParent().lock();
  991. // Check for inherited symbol without a valid parent.
  992. wxCHECK( parent, false );
  993. if( parent->GetName() == aSymbolName )
  994. aList.Add( entry->GetSymbol()->GetName() );
  995. }
  996. }
  997. return aList.GetCount();
  998. }
  999. int SYMBOL_LIBRARY_MANAGER::LIB_BUFFER::removeChildSymbols( std::shared_ptr<SYMBOL_BUFFER> aSymbolBuf )
  1000. {
  1001. wxCHECK( aSymbolBuf && aSymbolBuf->GetSymbol()->IsRoot(), 0 );
  1002. int cnt = 0;
  1003. std::deque< std::shared_ptr<SYMBOL_BUFFER> >::iterator it = m_symbols.begin();
  1004. while( it != m_symbols.end() )
  1005. {
  1006. if( (*it)->GetSymbol()->IsRoot() )
  1007. {
  1008. ++it;
  1009. }
  1010. else
  1011. {
  1012. LIB_SYMBOL_SPTR parent = (*it)->GetSymbol()->GetParent().lock();
  1013. wxCHECK2( parent, ++it; continue );
  1014. if( parent->GetName() == aSymbolBuf->GetSymbol()->GetName() )
  1015. {
  1016. wxCHECK2( parent == aSymbolBuf->GetSymbol()->SharedPtr(), ++it; continue );
  1017. m_deleted.emplace_back( *it );
  1018. it = m_symbols.erase( it );
  1019. cnt++;
  1020. }
  1021. else
  1022. {
  1023. ++it;
  1024. }
  1025. }
  1026. }
  1027. return cnt;
  1028. }