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.

514 lines
18 KiB

6 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
  5. * Copyright (C) 2011 Wayne Stambaugh <stambaughw@gmail.com>
  6. * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.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. /**
  26. * @file sch_sheet_path.h
  27. * Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
  28. */
  29. #ifndef CLASS_DRAWSHEET_PATH_H
  30. #define CLASS_DRAWSHEET_PATH_H
  31. #include <eda_item.h>
  32. #include <erc_item.h>
  33. #include <map>
  34. /**
  35. * A simple container for schematic symbol instance information.
  36. */
  37. struct SYMBOL_INSTANCE_REFERENCE
  38. {
  39. KIID_PATH m_Path;
  40. // Things that can be annotated:
  41. wxString m_Reference;
  42. int m_Unit;
  43. // Things that can be back-annotated:
  44. wxString m_Value;
  45. wxString m_Footprint;
  46. };
  47. /**
  48. * A simple container for sheet instance information.
  49. */
  50. struct SCH_SHEET_INSTANCE
  51. {
  52. KIID_PATH m_Path;
  53. wxString m_PageNumber;
  54. };
  55. /**
  56. * Complex hierarchies
  57. *
  58. * A hierarchical schematic uses sheets (hierarchical sheets) included in a given sheet.
  59. * Each sheet corresponds to a schematic drawing handled by a SCH_SCREEN structure. A
  60. * SCH_SCREEN structure contains drawings, and have a filename to write it's data. Also a
  61. * SCH_SCREEN displays a sheet number and the name of the sheet.
  62. *
  63. * In simple (and flat) hierarchies a sheet is linked to a SCH_SCREEN, and a SCH_SCREEN is
  64. * used by the single hierarchical sheet.
  65. *
  66. * In complex hierarchies the same SCH_SCREEN (and its data) is shared by more than one sheet.
  67. * Therefore subsheets (like subsheets in a SCH_SCREEN shared by many sheets) can also be
  68. * shared. So the same SCH_SCREEN must handle different symbol references and unit selections
  69. * depending on which sheet is currently selected, and how a given subsheet is selected. Two
  70. * sheets share the same SCH_SCREEN (the same drawings) if they have the same filename.
  71. *
  72. * In KiCad each symbol and sheet receives (when created) a uuid. So each sheet has 2 id: its
  73. * uuid (which cannot change) and its name (that can be edited and therefore is not reliable
  74. * for strong identification).
  75. * A given sheet in a hierarchy is fully labeled by its path (or sheet path) that is the list
  76. * of uuids found to access it through the hierarchy. The root sheet is /. All other sheets
  77. * have a path like /1234ABCD or /4567FEDC/AA2233DD/. This path can be displayed as human
  78. * readable sheet name like: / or /sheet1/include_sheet/ or /sheet2/include_sheet/
  79. *
  80. * So to know for a given SCH_SCREEN (a given schematic drawings) we must:
  81. * 1) Handle all references possibilities.
  82. * 2) When acceded by a given selected sheet, display (update) the
  83. * corresponding references and sheet path
  84. *
  85. * The class SCH_SHEET_PATH handles paths used to access a sheet. The class SCH_SHEET_LIST
  86. * allows one to handle the full (or partial) list of sheets and their paths in a complex
  87. * hierarchy. The class EDA_ScreenList allows one to handle the list of SCH_SCREEN. It is
  88. * useful to clear or save data, but is not suitable to handle the full complex hierarchy
  89. * possibilities (usable in flat and simple hierarchies).
  90. */
  91. class wxFindReplaceData;
  92. class SCH_SHEET;
  93. class SCH_SCREEN;
  94. class SCH_MARKER;
  95. class SCH_ITEM;
  96. class SCH_REFERENCE_LIST;
  97. /**
  98. * Container to map reference designators for multi-unit parts.
  99. */
  100. typedef std::map<wxString, SCH_REFERENCE_LIST> SCH_MULTI_UNIT_REFERENCE_MAP;
  101. /**
  102. * Handle access to a stack of flattened #SCH_SHEET objects by way of a path for
  103. * creating a flattened schematic hierarchy.
  104. *
  105. * <p>
  106. * The #SCH_SHEET objects are stored in a list from first (usually the root sheet) to a
  107. * given sheet in last position. The _last_ sheet is usually the sheet we want to select
  108. * or reach (which is what the function Last() returns). Others sheets constitute the
  109. * "path" from the first to the last sheet.
  110. * </p>
  111. */
  112. class SCH_SHEET_PATH
  113. {
  114. protected:
  115. std::vector< SCH_SHEET* > m_sheets;
  116. size_t m_current_hash;
  117. int m_virtualPageNumber; /// Page numbers are maintained by the sheet load order.
  118. std::map<std::pair<wxString, wxString>, bool> m_recursion_test_cache;
  119. public:
  120. SCH_SHEET_PATH();
  121. SCH_SHEET_PATH( const SCH_SHEET_PATH& aOther );
  122. SCH_SHEET_PATH& operator=( const SCH_SHEET_PATH& aOther );
  123. ~SCH_SHEET_PATH() = default;
  124. /// Forwarded method from std::vector
  125. SCH_SHEET* at( size_t aIndex ) const { return m_sheets.at( aIndex ); }
  126. /// Forwarded method from std::vector
  127. void clear()
  128. {
  129. m_sheets.clear();
  130. Rehash();
  131. }
  132. /// Forwarded method from std::vector
  133. bool empty() const { return m_sheets.empty(); }
  134. /// Forwarded method from std::vector
  135. void pop_back()
  136. {
  137. m_sheets.pop_back();
  138. Rehash();
  139. }
  140. /// Forwarded method from std::vector
  141. void push_back( SCH_SHEET* aSheet )
  142. {
  143. m_sheets.push_back( aSheet );
  144. Rehash();
  145. }
  146. /// Forwarded method from std::vector
  147. size_t size() const { return m_sheets.size(); }
  148. void Rehash();
  149. size_t GetCurrentHash() const { return m_current_hash; }
  150. /**
  151. * Set the sheet instance virtual page number.
  152. *
  153. * Virtual page numbers are incremental integers set automatically when the sheet path
  154. * hierarchy is created (@see #SCH_SHEET_LIST::BuildSheetList). The virtual page
  155. * numbering is ordered by the X and Y position of the sheet in a schematic which
  156. * mimics the page numbering code prior to the addition of actual user definable page
  157. * numbers. Virtual page numbers should only be use when annotating schematics.
  158. */
  159. void SetVirtualPageNumber( int aPageNumber ) { m_virtualPageNumber = aPageNumber; }
  160. int GetVirtualPageNumber() const { return m_virtualPageNumber; }
  161. /**
  162. * Set the sheet instance user definable page number.
  163. *
  164. * @note User definable page numbers can be any string devoid of white space characters.
  165. */
  166. void SetPageNumber( const wxString& aPageNumber );
  167. wxString GetPageNumber() const;
  168. const SCH_SHEET* GetSheet( unsigned aIndex ) const
  169. {
  170. SCH_SHEET* retv = NULL;
  171. if( aIndex < size() )
  172. retv = at( aIndex );
  173. return retv;
  174. }
  175. /**
  176. * Compare if this is the same sheet path as aSheetPathToTest
  177. *
  178. * @param aSheetPathToTest = sheet path to compare
  179. * @return 1 if this sheet path has more sheets than aSheetPathToTest,
  180. * -1 if this sheet path has fewer sheets than aSheetPathToTest,
  181. * or 0 if same
  182. */
  183. int Cmp( const SCH_SHEET_PATH& aSheetPathToTest ) const;
  184. /**
  185. * Return a pointer to the last #SCH_SHEET of the list.
  186. *
  187. * One can see the others sheet as the "path" to reach this last sheet.
  188. */
  189. SCH_SHEET* Last() const;
  190. /**
  191. * @return the #SCH_SCREEN relative to the last sheet in list.
  192. */
  193. SCH_SCREEN* LastScreen();
  194. ///< @copydoc SCH_SHEET_PATH::LastScreen()
  195. SCH_SCREEN* LastScreen() const;
  196. /**
  197. * Return the path of time stamps which do not changes even when editing sheet parameters.
  198. *
  199. * A path is something like / (root) or /34005677 or /34005677/00AE4523.
  200. */
  201. wxString PathAsString() const;
  202. /**
  203. * Get the sheet path as an #KIID_PATH.
  204. *
  205. * @note This #KIID_PATH includes the root sheet UUID prefixed to the path.
  206. * @return
  207. */
  208. KIID_PATH Path() const;
  209. /**
  210. * Get the sheet path as an #KIID_PATH without the root sheet UUID prefix.
  211. *
  212. * @note This #KIID_PATH does not include the root sheet UUID prefixed to the path.
  213. * @return
  214. */
  215. KIID_PATH PathWithoutRootUuid() const;
  216. /**
  217. * Return the sheet path in a human readable form made from the sheet names.
  218. *
  219. * The the "normal" path instead uses the #KIID objects in the path that do not change
  220. * even when editing sheet parameters.
  221. */
  222. wxString PathHumanReadable( bool aUseShortRootName = true ) const;
  223. /**
  224. * Update all the symbol references for this sheet path.
  225. *
  226. * Mandatory in complex hierarchies because sheets may use the same screen (basic schematic)
  227. * more than once but with different references and units according to the displayed sheet.
  228. */
  229. void UpdateAllScreenReferences();
  230. /**
  231. * Adds #SCH_REFERENCE object to \a aReferences for each component in the sheet.
  232. *
  233. * @param aReferences List of references to populate.
  234. * @param aIncludePowerSymbols : false to only get normal components.
  235. * @param aForceIncludeOrphanComponents : true to include components having no symbol found
  236. * in lib.
  237. * ( orphan components)
  238. * The normal option is false, and set to true only to build the full list of components.
  239. */
  240. void GetSymbols( SCH_REFERENCE_LIST& aReferences, bool aIncludePowerSymbols = true,
  241. bool aForceIncludeOrphanComponents = false ) const;
  242. /**
  243. * Add a #SCH_REFERENCE_LIST object to \a aRefList for each same-reference set of
  244. * multi-unit parts in the sheet.
  245. *
  246. * The map key for each element will be the reference designator.
  247. *
  248. * @param aRefList Map of reference designators to reference lists
  249. * @param aIncludePowerSymbols : false to only get normal components.
  250. */
  251. void GetMultiUnitComponents( SCH_MULTI_UNIT_REFERENCE_MAP &aRefList,
  252. bool aIncludePowerSymbols = true ) const;
  253. /**
  254. * Test the SCH_SHEET_PATH file names to check adding the sheet stored in the file
  255. * \a aSrcFileName to the sheet stored in file \a aDestFileName will cause a sheet
  256. * path recursion.
  257. *
  258. * @param aSrcFileName is the source file name of the sheet add to \a aDestFileName.
  259. * @param aDestFileName is the file name of the destination sheet for \a aSrcFileName.
  260. * @return true if \a aFileName will cause recursion in the sheet path. Otherwise false.
  261. */
  262. bool TestForRecursion( const wxString& aSrcFileName, const wxString& aDestFileName );
  263. bool operator==( const SCH_SHEET_PATH& d1 ) const;
  264. bool operator!=( const SCH_SHEET_PATH& d1 ) const { return !( *this == d1 ) ; }
  265. bool operator<( const SCH_SHEET_PATH& d1 ) const { return m_sheets < d1.m_sheets; }
  266. private:
  267. void initFromOther( const SCH_SHEET_PATH& aOther );
  268. };
  269. namespace std
  270. {
  271. template<> struct hash<SCH_SHEET_PATH>
  272. {
  273. size_t operator()( const SCH_SHEET_PATH& path ) const;
  274. };
  275. }
  276. typedef std::vector< SCH_SHEET_PATH > SCH_SHEET_PATHS;
  277. typedef SCH_SHEET_PATHS::iterator SCH_SHEET_PATHS_ITER;
  278. /**
  279. * A container for handling #SCH_SHEET_PATH objects in a flattened hierarchy.
  280. *
  281. * #SCH_SHEET objects are not unique, there can be many sheets with the same filename and
  282. * that share the same #SCH_SCREEN reference. Each The schematic file (#SCH_SCREEN) may
  283. * be shared between these sheets and component references are specific to a sheet path.
  284. * When a sheet is entered, component references and sheet page number are updated.
  285. */
  286. class SCH_SHEET_LIST : public SCH_SHEET_PATHS
  287. {
  288. private:
  289. SCH_SHEET_PATH m_currentSheetPath;
  290. public:
  291. /**
  292. * Construct a flattened list of SCH_SHEET_PATH objects from \a aSheet.
  293. *
  294. * If aSheet == NULL, then this is an empty hierarchy which the user can populate.
  295. */
  296. SCH_SHEET_LIST( SCH_SHEET* aSheet = nullptr, bool aCheckIntegrity = false );
  297. ~SCH_SHEET_LIST() {}
  298. /**
  299. * Check the entire hierarchy for any modifications.
  300. *
  301. * @return True if the hierarchy is modified otherwise false.
  302. */
  303. bool IsModified();
  304. void ClearModifyStatus();
  305. /**
  306. * Fetch a SCH_ITEM by ID. Also returns the sheet the item was found on in \a aPathOut.
  307. */
  308. SCH_ITEM* GetItem( const KIID& aID, SCH_SHEET_PATH* aPathOut = nullptr );
  309. /**
  310. * Fill an item cache for temporary use when many items need to be fetched.
  311. */
  312. void FillItemMap( std::map<KIID, EDA_ITEM*>& aMap );
  313. /**
  314. * Silently annotate the not yet annotated power symbols of the entire hierarchy of the
  315. * sheet path list.
  316. *
  317. * It is called before creating a netlist, to annotate power symbols, without prompting
  318. * the user about not annotated or duplicate for these symbols, if only these symbols
  319. * need annotation ( a very frequent case ).
  320. */
  321. void AnnotatePowerSymbols();
  322. /**
  323. * Add a #SCH_REFERENCE object to \a aReferences for each component in the list
  324. * of sheets.
  325. *
  326. * @param aReferences List of references to populate.
  327. * @param aIncludePowerSymbols Set to false to only get normal components.
  328. * @param aForceIncludeOrphanComponents : true to include components having no symbol found
  329. * in lib.
  330. * ( orphan components)
  331. * The normal option is false, and set to true only to build the full list of components.
  332. */
  333. void GetSymbols( SCH_REFERENCE_LIST& aReferences, bool aIncludePowerSymbols = true,
  334. bool aForceIncludeOrphanComponents = false ) const;
  335. /**
  336. * Add a #SCH_REFERENCE_LIST object to \a aRefList for each same-reference set of
  337. * multi-unit parts in the list of sheets. The map key for each element will be the
  338. * reference designator.
  339. *
  340. * @param aRefList Map of reference designators to reference lists
  341. * @param aIncludePowerSymbols Set to false to only get normal components.
  342. */
  343. void GetMultiUnitSymbols( SCH_MULTI_UNIT_REFERENCE_MAP &aRefList,
  344. bool aIncludePowerSymbols = true ) const;
  345. /**
  346. * Test every #SCH_SHEET_PATH in this #SCH_SHEET_LIST to verify if adding the sheets stored
  347. * in \a aSrcSheetHierarchy to the sheet stored in \a aDestFileName will cause recursion.
  348. *
  349. * @param aSrcSheetHierarchy is the SCH_SHEET_LIST of the source sheet add to \a aDestFileName.
  350. * @param aDestFileName is the file name of the destination sheet for \a aSrcFileName.
  351. * @return true if \a aFileName will cause recursion in the sheet path. Otherwise false.
  352. */
  353. bool TestForRecursion( const SCH_SHEET_LIST& aSrcSheetHierarchy,
  354. const wxString& aDestFileName );
  355. /**
  356. * Return a pointer to the first #SCH_SHEET_PATH object (not necessarily the only one) using
  357. * a particular screen.
  358. */
  359. SCH_SHEET_PATH* FindSheetForScreen( SCH_SCREEN* aScreen );
  360. /**
  361. * Build the list of sheets and their sheet path from \a aSheet.
  362. *
  363. * If \a aSheet is the root sheet, the full sheet path and sheet list are built.
  364. *
  365. * The list will be ordered as per #SCH_SCREEN::GetSheets which results in sheets being ordered
  366. * in the legacy way of using the X and Y positions of the sheets.
  367. *
  368. * @see #SortByPageNumbers to sort by page numbers
  369. *
  370. * @param aSheet is the starting sheet from which the list is built, or NULL
  371. * indicating that g_RootSheet should be used.
  372. * @throw std::bad_alloc if the memory for the sheet path list could not be allocated.
  373. */
  374. void BuildSheetList( SCH_SHEET* aSheet, bool aCheckIntegrity );
  375. /**
  376. * Sorts the list of sheets by page number. This should be called after #BuildSheetList
  377. *
  378. * @param aUpdateVirtualPageNums If true, updates the virtual page numbers to match the new
  379. * ordering
  380. */
  381. void SortByPageNumbers( bool aUpdateVirtualPageNums = true );
  382. bool NameExists( const wxString& aSheetName );
  383. /**
  384. * Update all of the symbol instance information using \a aSymbolInstances.
  385. * WARNING: Do not call this on anything other than the full hierarchy.
  386. * @param aSymbolInstances is the symbol path information loaded from the root schematic.
  387. */
  388. void UpdateSymbolInstances( const std::vector<SYMBOL_INSTANCE_REFERENCE>& aSymbolInstances );
  389. /**
  390. * Update all of the sheet instance information using \a aSheetInstances.
  391. *
  392. * @warning Do not call this on anything other than the full hierarchy.
  393. *
  394. * @param aSymbolInstances is the symbol path information loaded from the root schematic.
  395. */
  396. void UpdateSheetInstances( const std::vector<SCH_SHEET_INSTANCE>& aSheetInstances );
  397. std::vector<KIID_PATH> GetPaths() const;
  398. /**
  399. * Update all of the symbol sheet paths to the sheet paths defined in \a aOldSheetPaths.
  400. *
  401. * @note The list of old sheet paths must be the exact same size and order as the existing
  402. * sheet paths. This should not be an issue if no new sheets where added between the
  403. * creation of this sheet list and \a aOldSheetPaths. This should only be called
  404. * when updating legacy schematics to the new schematic file format. Once this
  405. * happens, the schematic cannot be save to the legacy file format because the
  406. * time stamp part of UUIDs are no longer guaranteed to be unique.
  407. *
  408. * @param aOldSheetPaths is the #SHEET_PATH_LIST to update from.
  409. */
  410. void ReplaceLegacySheetPaths( const std::vector<KIID_PATH>& aOldSheetPaths );
  411. /**
  412. * Check all of the sheet instance for empty page numbers.
  413. *
  414. * @note This should only return true when loading a legacy schematic or an s-expression
  415. * schematic before version 20201005.
  416. *
  417. * @return true if all sheet instance page numbers are not defined. Otherwise false.
  418. */
  419. bool AllSheetPageNumbersEmpty() const;
  420. /**
  421. * Set initial sheet page numbers.
  422. *
  423. * The number scheme is base on the old psuedo sheet numbering algorithm prior to
  424. * the implementation of user definable sheet page numbers.
  425. */
  426. void SetInitialPageNumbers();
  427. };
  428. #endif // CLASS_DRAWSHEET_PATH_H