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.

586 lines
19 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2010-2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
  5. * Copyright (C) 2012 Wayne Stambaugh <stambaughw@gmail.com>
  6. * Copyright (C) 2012-2021 KiCad Developers, see change_log.txt for contributors.
  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 2
  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. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  21. * or you may search the http://www.gnu.org website for the version 2 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. #ifndef _LIB_TABLE_BASE_H_
  26. #define _LIB_TABLE_BASE_H_
  27. #include <map>
  28. #include <boost/noncopyable.hpp>
  29. #include <boost/ptr_container/ptr_vector.hpp>
  30. #include <memory>
  31. #include <mutex>
  32. #include <project.h>
  33. #include <string_utf8_map.h>
  34. #include <richio.h>
  35. class OUTPUTFORMATTER;
  36. class LIB_TABLE_LEXER;
  37. class LIB_ID;
  38. class LIB_TABLE_ROW;
  39. class LIB_TABLE_GRID;
  40. class LIB_TABLE;
  41. class IO_ERROR;
  42. typedef boost::ptr_vector< LIB_TABLE_ROW > LIB_TABLE_ROWS;
  43. typedef LIB_TABLE_ROWS::iterator LIB_TABLE_ROWS_ITER;
  44. typedef LIB_TABLE_ROWS::const_iterator LIB_TABLE_ROWS_CITER;
  45. /**
  46. * Allows boost pointer containers to make clones of the data stored in them. Since they
  47. * store pointers the data is cloned. Copying and assigning pointers would cause ownership
  48. * issues if the standard C++ containers were used.
  49. */
  50. LIB_TABLE_ROW* new_clone( const LIB_TABLE_ROW& aRow );
  51. /**
  52. * Hold a record identifying a library accessed by the appropriate plug in object in the
  53. * #LIB_TABLE. This is an abstract base class from which to derive library specific rows.
  54. */
  55. class LIB_TABLE_ROW : boost::noncopyable
  56. {
  57. public:
  58. LIB_TABLE_ROW() :
  59. enabled( true ),
  60. visible( true ),
  61. m_loaded( false ),
  62. m_parent( nullptr )
  63. {
  64. }
  65. virtual ~LIB_TABLE_ROW()
  66. {
  67. }
  68. LIB_TABLE_ROW( const wxString& aNick, const wxString& aURI, const wxString& aOptions,
  69. const wxString& aDescr = wxEmptyString, LIB_TABLE* aParent = nullptr ) :
  70. nickName( aNick ),
  71. description( aDescr ),
  72. enabled( true ),
  73. visible( true ),
  74. m_loaded( false ),
  75. m_parent( aParent )
  76. {
  77. properties.reset();
  78. SetOptions( aOptions );
  79. SetFullURI( aURI );
  80. }
  81. bool operator==( const LIB_TABLE_ROW& r ) const;
  82. bool operator!=( const LIB_TABLE_ROW& r ) const { return !( *this == r ); }
  83. /**
  84. * @return the logical name of this library table row.
  85. */
  86. const wxString& GetNickName() const { return nickName; }
  87. /**
  88. * Change the logical name of this library, useful for an editor.
  89. */
  90. void SetNickName( const wxString& aNickName ) { nickName = aNickName; }
  91. /**
  92. * @return true if the library was loaded without error
  93. */
  94. bool GetIsLoaded() const { return m_loaded; }
  95. /**
  96. * Mark the row as being a loaded library
  97. */
  98. void SetLoaded( bool aLoaded ) { m_loaded = aLoaded; };
  99. /**
  100. * @return the enabled status of this library row
  101. */
  102. bool GetIsEnabled() const { return enabled; }
  103. /**
  104. * Change the enabled status of this library
  105. */
  106. void SetEnabled( bool aEnabled = true ) { enabled = aEnabled; }
  107. bool GetIsVisible() const { return visible; }
  108. void SetVisible( bool aVisible = true ) { visible = aVisible; }
  109. /**
  110. * Return the type of library represented by this row.
  111. */
  112. virtual const wxString GetType() const = 0;
  113. /**
  114. * Change the type of library represented by this row that must be implemented in the
  115. * derived object to provide the library table row type.
  116. */
  117. virtual void SetType( const wxString& aType ) = 0;
  118. /**
  119. * Return the full location specifying URI for the LIB, either in original UI form or
  120. * in environment variable expanded form.
  121. *
  122. * @param aSubstituted Tells if caller wanted the substituted form, else not.
  123. */
  124. const wxString GetFullURI( bool aSubstituted = false ) const;
  125. /**
  126. * Change the full URI for the library.
  127. */
  128. void SetFullURI( const wxString& aFullURI );
  129. /**
  130. * Return the options string, which may hold a password or anything else needed to
  131. * instantiate the underlying library plugin.
  132. */
  133. const wxString& GetOptions() const { return options; }
  134. /**
  135. * Change the library options strings.
  136. */
  137. void SetOptions( const wxString& aOptions );
  138. /**
  139. * Return the description of the library referenced by this row.
  140. */
  141. const wxString& GetDescr() const { return description; }
  142. /**
  143. * Change the description of the library referenced by this row.
  144. */
  145. void SetDescr( const wxString& aDescr ) { description = aDescr; }
  146. LIB_TABLE* GetParent() const { return m_parent; }
  147. void SetParent( LIB_TABLE* aParent ) { m_parent = aParent; }
  148. std::mutex& GetMutex() { return m_loadMutex; }
  149. /**
  150. * Return the constant #PROPERTIES for this library (#LIB_TABLE_ROW). These are
  151. * the "options" in a table.
  152. */
  153. const STRING_UTF8_MAP* GetProperties() const { return properties.get(); }
  154. /**
  155. * Serialize this object as utf8 text to an #OUTPUTFORMATTER, and tries to
  156. * make it look good using multiple lines and indentation.
  157. *
  158. * @param out is an #OUTPUTFORMATTER
  159. * @param nestLevel is the indentation level to base all lines of the output.
  160. * Actual indentation will be 2 spaces for each nestLevel.
  161. */
  162. void Format( OUTPUTFORMATTER* out, int nestLevel ) const;
  163. LIB_TABLE_ROW* clone() const
  164. {
  165. return do_clone();
  166. }
  167. protected:
  168. LIB_TABLE_ROW( const LIB_TABLE_ROW& aRow ) :
  169. nickName( aRow.nickName ),
  170. uri_user( aRow.uri_user ),
  171. options( aRow.options ),
  172. description( aRow.description ),
  173. enabled( aRow.enabled ),
  174. visible( aRow.visible ),
  175. m_loaded( aRow.m_loaded ),
  176. m_parent( aRow.m_parent )
  177. {
  178. if( aRow.properties )
  179. properties = std::make_unique<STRING_UTF8_MAP>( *aRow.properties.get() );
  180. else
  181. properties.reset();
  182. }
  183. void operator=( const LIB_TABLE_ROW& aRow );
  184. private:
  185. virtual LIB_TABLE_ROW* do_clone() const = 0;
  186. void setProperties( STRING_UTF8_MAP* aProperties );
  187. wxString nickName;
  188. wxString uri_user; ///< what user entered from UI or loaded from disk
  189. wxString options;
  190. wxString description;
  191. bool enabled = true; ///< Whether the LIB_TABLE_ROW is enabled
  192. bool visible = true; ///< Whether the LIB_TABLE_ROW is visible in choosers
  193. bool m_loaded = false; ///< Whether the LIB_TABLE_ROW is loaded
  194. LIB_TABLE* m_parent; ///< Pointer to the table this row lives in (maybe null)
  195. std::unique_ptr<STRING_UTF8_MAP> properties;
  196. std::mutex m_loadMutex;
  197. };
  198. /**
  199. * Manage #LIB_TABLE_ROW records (rows), and can be searched based on library nickname.
  200. *
  201. * <p>
  202. * This class owns the <b>library table</b>, which is like fstab in concept and maps
  203. * logical library name to the library URI, type, and options. It is heavily based on
  204. * the SWEET parser work done by Dick Hollenbeck and can be seen in new/sch_lib_table.h.
  205. * A library table has the following columns:
  206. * <ul>
  207. * <li> Logical Library Name (Nickname)
  208. * <li> Library Type, used to determine which plugin to load to access the library.
  209. * <li> Library URI. The full URI to the library source, form dependent on Type.
  210. * <li> Options, used for as yet to be defined information such as user names or passwords
  211. * </ul>
  212. * </p>
  213. * <p>
  214. * The Library Type can be one of:
  215. * <ul>
  216. * <li> "file"
  217. * <li> "ftp"
  218. * <li> "http"
  219. * </ul>
  220. * </p>
  221. * <p>
  222. * For now, the Library URI types needed to support the various types can be one of those
  223. * shown below, which are typical of each type:
  224. * <ul>
  225. * <li> "file://C:/mylibdir"
  226. * <li> "ftp://kicad.org/partlib/trunk"
  227. * <li> "http://kicad.org/partlib"
  228. * </ul>
  229. * </p>
  230. * <p>
  231. * The library table is built up from several additive entries (table fragments), and the
  232. * final table is a (conceptual) merging of the table fragments. Two anticipated sources
  233. * of the entries are a personal table saved in the KiCad configuration and a project
  234. * resident table that resides in project file. The project footprint table entries are
  235. * considered a higher priority in the final dynamically assembled library table. An row
  236. * in the project file contribution to the library table takes precedence over the personal
  237. * table if there is a collision of logical library names. Otherwise, the entries simply
  238. * combine without issue to make up the applicable library table.
  239. * </p>
  240. *
  241. * @author Wayne Stambaugh
  242. */
  243. class LIB_TABLE : public PROJECT::_ELEM
  244. {
  245. public:
  246. /**
  247. * Parse the #LIB_TABLE_LEXER s-expression library table format into the appropriate
  248. * #LIB_TABLE_ROW objects.
  249. *
  250. * @param aLexer is the lexer to parse.
  251. *
  252. * @throw IO_ERROR if an I/O error occurs during parsing.
  253. * @throw PARSER_ERROR if the lexer format to parse is invalid.
  254. * @throw boost::bad_pointer if an any attempt to add an invalid pointer to the
  255. * boost::ptr_vector.
  256. * @throw boost::bad_index if an index outside the row table bounds is accessed.
  257. */
  258. virtual void Parse( LIB_TABLE_LEXER* aLexer ) = 0;
  259. /**
  260. * Generate the table in s-expression format to \a aOutput with an indentation level
  261. * of \a aIndentLevel.
  262. *
  263. * @param aOutput is the #OUTPUTFORMATTER to format the table into.
  264. * @param aIndentLevel is the indentation level (2 spaces) to indent.
  265. *
  266. * @throw IO_ERROR if an I/O error occurs during output.
  267. * @throw boost::interprocess::lock_except if separate process attempt to access the table.
  268. */
  269. virtual void Format( OUTPUTFORMATTER* aOutput, int aIndentLevel ) const = 0;
  270. /**
  271. * Build a library table by pre-pending this table fragment in front of \a aFallBackTable.
  272. * Loading of this table fragment is done by using Parse().
  273. *
  274. * @param aFallBackTable is another LIB_TABLE which is searched only when
  275. * a row is not found in this table. No ownership is
  276. * taken of aFallBackTable.
  277. */
  278. LIB_TABLE( LIB_TABLE* aFallBackTable = nullptr );
  279. virtual ~LIB_TABLE();
  280. /// Delete all rows.
  281. void Clear()
  282. {
  283. std::lock_guard<std::mutex> lock( m_nickIndexMutex );
  284. m_rows.clear();
  285. m_nickIndex.clear();
  286. }
  287. /**
  288. * Compares this table against another.
  289. *
  290. * This compares the row *contents* against each other.
  291. * Any fallback tables are not checked.
  292. */
  293. bool operator==( const LIB_TABLE& r ) const
  294. {
  295. if( m_rows.size() == r.m_rows.size() )
  296. {
  297. unsigned i;
  298. for( i = 0; i < m_rows.size() && m_rows[i] == r.m_rows[i]; ++i )
  299. ;
  300. if( i == m_rows.size() )
  301. return true;
  302. }
  303. return false;
  304. }
  305. bool operator!=( const LIB_TABLE& r ) const { return !( *this == r ); }
  306. /**
  307. * Get the number of rows contained in the table
  308. */
  309. unsigned GetCount() const
  310. {
  311. return m_rows.size();
  312. }
  313. /**
  314. * Get the 'n'th #LIB_TABLE_ROW object
  315. * @param aIndex index of row (must exist: from 0 to GetCount() - 1)
  316. * @return reference to the row
  317. */
  318. LIB_TABLE_ROW& At( unsigned aIndex )
  319. {
  320. return m_rows[aIndex];
  321. }
  322. /**
  323. * @copydoc At()
  324. */
  325. const LIB_TABLE_ROW& At( unsigned aIndex ) const
  326. {
  327. return m_rows[aIndex];
  328. }
  329. /**
  330. * Return true if the table is empty.
  331. *
  332. * @param aIncludeFallback is used to determine if the fallback table should be
  333. * included in the test.
  334. *
  335. * @return true if the footprint library table is empty.
  336. */
  337. bool IsEmpty( bool aIncludeFallback = true );
  338. /**
  339. * @return the library description from @a aNickname, or an empty string
  340. * if @a aNickname does not exist.
  341. */
  342. const wxString GetDescription( const wxString& aNickname );
  343. /**
  344. * Test for the existence of \a aNickname in the library table.
  345. *
  346. * @param aCheckEnabled if true will only return true for enabled libraries
  347. * @return true if a library \a aNickname exists in the table.
  348. */
  349. bool HasLibrary( const wxString& aNickname, bool aCheckEnabled = false ) const;
  350. /**
  351. * Test for the existence of \a aPath in the library table.
  352. *
  353. * @param aCheckEnabled if true will only return true for enabled libraries
  354. * @return true if a library \a aNickname exists in the table.
  355. */
  356. bool HasLibraryWithPath( const wxString& aPath ) const;
  357. /**
  358. * Return the logical library names, all of them that are pertinent to
  359. * a look up done on this LIB_TABLE.
  360. */
  361. std::vector<wxString> GetLogicalLibs();
  362. /**
  363. * Return the full URI of the library mapped to \a aLibNickname.
  364. */
  365. wxString GetFullURI( const wxString& aLibNickname, bool aExpandEnvVars = true ) const;
  366. /**
  367. * Adds \a aRow if it does not already exist or if doReplace is true. If doReplace
  368. * is not true and the key for aRow already exists, the function fails and returns false.
  369. *
  370. * The key for the table is the nickName, and all in this table must be unique.
  371. *
  372. * @param aRow is the new row to insert, or to forcibly add if doReplace is true.
  373. * @param doReplace if true, means insert regardless of whether aRow's key already
  374. * exists. If false, then fail if the key already exists.
  375. *
  376. * @return bool - true if the operation succeeded.
  377. */
  378. bool InsertRow( LIB_TABLE_ROW* aRow, bool doReplace = false );
  379. /**
  380. * Removes a row from the table.
  381. * @param aRow is the row to remove
  382. * @return true if the row was found (and removed)
  383. */
  384. bool RemoveRow( const LIB_TABLE_ROW* aRow )
  385. {
  386. for( auto iter = m_rows.begin(); iter != m_rows.end(); ++iter )
  387. {
  388. if( *iter == *aRow )
  389. {
  390. m_rows.erase( iter, iter + 1 );
  391. reindex();
  392. return true;
  393. }
  394. }
  395. return false;
  396. }
  397. /**
  398. * @return a #LIB_TABLE_ROW pointer if \a aURI is found in this table or in any chained
  399. * fallBack table fragments, else NULL.
  400. */
  401. const LIB_TABLE_ROW* FindRowByURI( const wxString& aURI );
  402. /**
  403. * Load the library table using the path defined by \a aFileName aFallBackTable.
  404. *
  405. * @param aFileName contains the full path to the s-expression file.
  406. *
  407. * @throw IO_ERROR if an error occurs attempting to load the footprint library
  408. * table.
  409. */
  410. void Load( const wxString& aFileName );
  411. /**
  412. * Write this library table to \a aFileName in s-expression form.
  413. *
  414. * @param aFileName is the name of the file to write to.
  415. */
  416. void Save( const wxString& aFileName ) const;
  417. /**
  418. * Parses \a aOptionsList and places the result into a #PROPERTIES object which is
  419. * returned. If the options field is empty, then the returned PROPERTIES will be
  420. * a NULL pointer.
  421. *
  422. * <p>
  423. * Typically aOptionsList comes from the "options" field within a LIB_TABLE_ROW and
  424. * the format is simply a comma separated list of name value pairs. e.g.:
  425. * [name1[=value1][|name2[=value2]]] etc. When using the UI to create or edit
  426. * a library table, this formatting is handled for you.
  427. * </p>
  428. */
  429. static STRING_UTF8_MAP* ParseOptions( const std::string& aOptionsList );
  430. /**
  431. * Returns a list of options from the aProperties parameter.
  432. *
  433. * The name=value pairs will be separated with the '|' character. The =value portion may
  434. * not be present. You might expect something like "name1=value1|name2=value2|flag_me".
  435. * Notice that flag_me does not have a value. This is ok.
  436. *
  437. * @param aProperties is the PROPERTIES to format or NULL. If NULL the returned
  438. * string will be empty.
  439. */
  440. static UTF8 FormatOptions( const STRING_UTF8_MAP* aProperties );
  441. /**
  442. * Returns the version number (0 if unset)
  443. *
  444. * @return integer version number read from table
  445. */
  446. int GetVersion() const
  447. {
  448. return m_version;
  449. }
  450. protected:
  451. /**
  452. * Return a #LIB_TABLE_ROW if \a aNickname is found in this table or in any chained
  453. * fallBack table fragment, else NULL.
  454. *
  455. * @param aNickname is the name of the library table entry to find.
  456. * @param aCheckIfEnabled is a flag to check if the library table entry is enabled.
  457. * @return a pointer to the #LIB_TABLE_ROW found.
  458. */
  459. LIB_TABLE_ROW* findRow( const wxString& aNickname, bool aCheckIfEnabled = false ) const;
  460. /**
  461. * Updates the env vars from older version of KiCad, provided they do not currently
  462. * resolve to anything
  463. *
  464. * @return True if the tables were modified
  465. */
  466. bool migrate();
  467. void reindex()
  468. {
  469. std::lock_guard<std::mutex> lock( m_nickIndexMutex );
  470. m_nickIndex.clear();
  471. for( LIB_TABLE_ROWS_ITER it = m_rows.begin(); it != m_rows.end(); ++it )
  472. m_nickIndex.insert( INDEX_VALUE( it->GetNickName(), it - m_rows.begin() ) );
  473. }
  474. void ensureIndex()
  475. {
  476. // The dialog lib table editor may not maintain the nickIndex.
  477. // Lazy indexing may be required. To handle lazy indexing, we must enforce
  478. // that "nickIndex" is either empty or accurate, but never inaccurate.
  479. if( !m_nickIndex.size() )
  480. reindex();
  481. }
  482. private:
  483. friend class PANEL_FP_LIB_TABLE;
  484. friend class LIB_TABLE_GRID;
  485. protected:
  486. LIB_TABLE_ROWS m_rows;
  487. /// this is a non-owning index into the LIB_TABLE_ROWS table
  488. typedef std::map<wxString,int> INDEX; // "int" is std::vector array index
  489. typedef INDEX::iterator INDEX_ITER;
  490. typedef INDEX::const_iterator INDEX_CITER;
  491. typedef INDEX::value_type INDEX_VALUE;
  492. /// this particular key is the nickName within each row.
  493. INDEX m_nickIndex;
  494. LIB_TABLE* m_fallBack;
  495. /// Versioning to handle importing old tables
  496. mutable int m_version;
  497. /// Mutex to protect access to the nickIndex variable
  498. mutable std::mutex m_nickIndexMutex;
  499. };
  500. #endif // _LIB_TABLE_BASE_H_