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 /** 27 * @file sch_sheet_path.h 28 * Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema. 29 */ 30 31 #ifndef CLASS_DRAWSHEET_PATH_H 32 #define CLASS_DRAWSHEET_PATH_H 33 34 #include <map> 35 36 #include <kiid.h> 37 38 /** 39 * A simple container for schematic symbol instance information. 40 */ 41 struct SYMBOL_INSTANCE_REFERENCE 42 { 43 KIID_PATH m_Path; 44 45 // Things that can be annotated: 46 wxString m_Reference; 47 int m_Unit; 48 49 // Things that can be back-annotated: 50 wxString m_Value; 51 wxString m_Footprint; 52 }; 53 54 55 /** 56 * A simple container for sheet instance information. 57 */ 58 struct SCH_SHEET_INSTANCE 59 { 60 KIID_PATH m_Path; 61 62 wxString m_PageNumber; 63 }; 64 65 66 /** 67 * Complex hierarchies 68 * 69 * A hierarchical schematic uses sheets (hierarchical sheets) included in a given sheet. 70 * Each sheet corresponds to a schematic drawing handled by a SCH_SCREEN structure. A 71 * SCH_SCREEN structure contains drawings, and have a filename to write its data. Also a 72 * SCH_SCREEN displays a sheet number and the name of the sheet. 73 * 74 * In simple (and flat) hierarchies a sheet is linked to a SCH_SCREEN, and a SCH_SCREEN is 75 * used by the single hierarchical sheet. 76 * 77 * In complex hierarchies the same SCH_SCREEN (and its data) is shared by more than one sheet. 78 * Therefore subsheets (like subsheets in a SCH_SCREEN shared by many sheets) can also be 79 * shared. So the same SCH_SCREEN must handle different symbol references and unit selections 80 * depending on which sheet is currently selected, and how a given subsheet is selected. Two 81 * sheets share the same SCH_SCREEN (the same drawings) if they have the same filename. 82 * 83 * In KiCad each symbol and sheet receives (when created) a uuid. So each sheet has 2 id: its 84 * uuid (which cannot change) and its name (that can be edited and therefore is not reliable 85 * for strong identification). 86 * A given sheet in a hierarchy is fully labeled by its path (or sheet path) that is the list 87 * of uuids found to access it through the hierarchy. The root sheet is /. All other sheets 88 * have a path like /1234ABCD or /4567FEDC/AA2233DD/. This path can be displayed as human 89 * readable sheet name like: / or /sheet1/include_sheet/ or /sheet2/include_sheet/ 90 * 91 * So to know for a given SCH_SCREEN (a given schematic drawings) we must: 92 * 1) Handle all references possibilities. 93 * 2) When acceded by a given selected sheet, display (update) the 94 * corresponding references and sheet path 95 * 96 * The class SCH_SHEET_PATH handles paths used to access a sheet. The class SCH_SHEET_LIST 97 * allows one to handle the full (or partial) list of sheets and their paths in a complex 98 * hierarchy. The class EDA_ScreenList allows one to handle the list of SCH_SCREEN. It is 99 * useful to clear or save data, but is not suitable to handle the full complex hierarchy 100 * possibilities (usable in flat and simple hierarchies). 101 */ 102 103 104 class wxFindReplaceData; 105 class EDA_ITEM; 106 class SCH_SHEET; 107 class SCH_SCREEN; 108 class SCH_MARKER; 109 class SCH_ITEM; 110 class SCH_SYMBOL; 111 class SCH_REFERENCE_LIST; 112 113 114 /** 115 * Container to map reference designators for multi-unit parts. 116 */ 117 typedef std::map<wxString, SCH_REFERENCE_LIST> SCH_MULTI_UNIT_REFERENCE_MAP; 118 119 /** 120 * Handle access to a stack of flattened #SCH_SHEET objects by way of a path for 121 * creating a flattened schematic hierarchy. 122 * 123 * The #SCH_SHEET objects are stored in a list from first (usually the root sheet) to a 124 * given sheet in last position. The _last_ sheet is usually the sheet we want to select 125 * or reach (which is what the function Last() returns). Others sheets constitute the 126 * "path" from the first to the last sheet. 127 */ 128 class SCH_SHEET_PATH 129 { 130 public: 131 SCH_SHEET_PATH(); 132 133 SCH_SHEET_PATH( const SCH_SHEET_PATH& aOther ); 134 135 SCH_SHEET_PATH& operator=( const SCH_SHEET_PATH& aOther ); 136 137 ~SCH_SHEET_PATH() = default; 138 139 /// Forwarded method from std::vector at(size_t aIndex)140 SCH_SHEET* at( size_t aIndex ) const { return m_sheets.at( aIndex ); } 141 142 /// Forwarded method from std::vector clear()143 void clear() 144 { 145 m_sheets.clear(); 146 Rehash(); 147 } 148 149 /// Forwarded method from std::vector empty()150 bool empty() const { return m_sheets.empty(); } 151 152 /// Forwarded method from std::vector pop_back()153 void pop_back() 154 { 155 m_sheets.pop_back(); 156 Rehash(); 157 } 158 159 /// Forwarded method from std::vector push_back(SCH_SHEET * aSheet)160 void push_back( SCH_SHEET* aSheet ) 161 { 162 m_sheets.push_back( aSheet ); 163 Rehash(); 164 } 165 166 /// Forwarded method from std::vector size()167 size_t size() const { return m_sheets.size(); } 168 169 void Rehash(); 170 GetCurrentHash()171 size_t GetCurrentHash() const { return m_current_hash; } 172 173 /** 174 * Set the sheet instance virtual page number. 175 * 176 * Virtual page numbers are incremental integers set automatically when the sheet path 177 * hierarchy is created (@see #SCH_SHEET_LIST::BuildSheetList). The virtual page 178 * numbering is ordered by the X and Y position of the sheet in a schematic which 179 * mimics the page numbering code prior to the addition of actual user definable page 180 * numbers. Virtual page numbers should only be use when annotating schematics. 181 */ SetVirtualPageNumber(int aPageNumber)182 void SetVirtualPageNumber( int aPageNumber ) { m_virtualPageNumber = aPageNumber; } 183 GetVirtualPageNumber()184 int GetVirtualPageNumber() const { return m_virtualPageNumber; } 185 186 /** 187 * Set the sheet instance user definable page number. 188 * 189 * @note User definable page numbers can be any string devoid of white space characters. 190 */ 191 void SetPageNumber( const wxString& aPageNumber ); 192 193 wxString GetPageNumber() const; 194 GetSheet(unsigned aIndex)195 const SCH_SHEET* GetSheet( unsigned aIndex ) const 196 { 197 SCH_SHEET* retv = nullptr; 198 199 if( aIndex < size() ) 200 retv = at( aIndex ); 201 202 return retv; 203 } 204 205 bool IsFullPath() const; 206 207 /** 208 * Compare if this is the same sheet path as \a aSheetPathToTest. 209 * 210 * @param aSheetPathToTest is the sheet path to compare. 211 * @return 1 if this sheet path has more sheets than aSheetPathToTest, 212 * -1 if this sheet path has fewer sheets than aSheetPathToTest, 213 * or 0 if same 214 */ 215 int Cmp( const SCH_SHEET_PATH& aSheetPathToTest ) const; 216 217 /** 218 * Compare sheets by their page number and then by their name. Finally 219 * compare using #Cmp() 220 * 221 * @return -1 if aSheetPathToTest is greater than this (should appear later in the sort order) 222 * 0 if aSheetPathToTest is equal to this 223 * 1 if aSheetPathToTest is less than this (should appear earlier in the sort order) 224 */ 225 int ComparePageNumAndName( const SCH_SHEET_PATH& aSheetPathToTest ) const; 226 227 /** 228 * Check if this path is contained inside aSheetPathToTest. 229 * 230 * @param aSheetPathToTest is the sheet path to compare against. 231 * @return true if this path is contained inside or equal to aSheetPathToTest. 232 */ 233 bool IsContainedWithin( const SCH_SHEET_PATH& aSheetPathToTest ) const; 234 235 /** 236 * Return a pointer to the last #SCH_SHEET of the list. 237 * 238 * One can see the others sheet as the "path" to reach this last sheet. 239 */ 240 SCH_SHEET* Last() const; 241 242 /** 243 * @return the #SCH_SCREEN relative to the last sheet in list. 244 */ 245 SCH_SCREEN* LastScreen(); 246 247 248 ///< @copydoc SCH_SHEET_PATH::LastScreen() 249 SCH_SCREEN* LastScreen() const; 250 251 /** 252 * Return the path of time stamps which do not changes even when editing sheet parameters. 253 * 254 * A path is something like / (root) or /34005677 or /34005677/00AE4523. 255 */ 256 wxString PathAsString() const; 257 258 /** 259 * Get the sheet path as an #KIID_PATH. 260 * 261 * @note This #KIID_PATH includes the root sheet UUID prefixed to the path. 262 */ 263 KIID_PATH Path() const; 264 265 /** 266 * Get the sheet path as an #KIID_PATH without the root sheet UUID prefix. 267 * 268 * @note This #KIID_PATH does not include the root sheet UUID prefixed to the path. 269 */ 270 KIID_PATH PathWithoutRootUuid() const; 271 272 /** 273 * Return the sheet path in a human readable form made from the sheet names. 274 * 275 * The "normal" path instead uses the #KIID objects in the path that do not change 276 * even when editing sheet parameters. 277 */ 278 wxString PathHumanReadable( bool aUseShortRootName = true ) const; 279 280 /** 281 * Update all the symbol references for this sheet path. 282 * 283 * Mandatory in complex hierarchies because sheets may use the same screen (basic schematic) 284 * more than once but with different references and units according to the displayed sheet. 285 */ 286 void UpdateAllScreenReferences(); 287 288 /** 289 * Append a #SCH_REFERENCE object to \a aReferences based on \a aSymbol 290 * 291 * @param aReferences List of references to populate. 292 * @param aSymbol A symbol to add to aReferences 293 * @param aIncludePowerSymbols set to false to only get normal symbols. 294 * @param aForceIncludeOrphanSymbols set to true to include symbols having no symbol found 295 * in lib. The normal option is false, and set to true 296 * only to build the full list of symbols. 297 */ 298 void AppendSymbol( SCH_REFERENCE_LIST& aReferences, SCH_SYMBOL* aSymbol, 299 bool aIncludePowerSymbols = true, 300 bool aForceIncludeOrphanSymbols = false ) const; 301 302 /** 303 * Adds #SCH_REFERENCE object to \a aReferences for each symbol in the sheet. 304 * 305 * @param aReferences List of references to populate. 306 * @param aIncludePowerSymbols set to false to only get normal symbols. 307 * @param aForceIncludeOrphanSymbols set to true to include symbols having no symbol found 308 * in lib. The normal option is false, and set to true 309 * only to build the full list of symbols. 310 */ 311 void GetSymbols( SCH_REFERENCE_LIST& aReferences, bool aIncludePowerSymbols = true, 312 bool aForceIncludeOrphanSymbols = false ) const; 313 314 /** 315 * Append a #SCH_REFERENCE_LIST object to \a aRefList based on \a aSymbol, 316 * storing same-reference set of multi-unit parts together. 317 * 318 * The map key for each element will be the reference designator. 319 * 320 * @param aRefList Map of reference designators to reference lists 321 * @param aSymbol A symbol to add to aRefList 322 * @param aIncludePowerSymbols Set to false to only get normal symbols. 323 */ 324 void AppendMultiUnitSymbol( SCH_MULTI_UNIT_REFERENCE_MAP& aRefList, SCH_SYMBOL* aSymbol, 325 bool aIncludePowerSymbols = true ) const; 326 327 /** 328 * Add a #SCH_REFERENCE_LIST object to \a aRefList for each same-reference set of 329 * multi-unit parts in the sheet. 330 * 331 * The map key for each element will be the reference designator. 332 * 333 * @param aRefList Map of reference designators to reference lists 334 * @param aIncludePowerSymbols Set to false to only get normal symbols. 335 */ 336 void GetMultiUnitSymbols( SCH_MULTI_UNIT_REFERENCE_MAP &aRefList, 337 bool aIncludePowerSymbols = true ) const; 338 339 /** 340 * Test the SCH_SHEET_PATH file names to check adding the sheet stored in the file 341 * \a aSrcFileName to the sheet stored in file \a aDestFileName will cause a sheet 342 * path recursion. 343 * 344 * @param aSrcFileName is the source file name of the sheet add to \a aDestFileName. 345 * @param aDestFileName is the file name of the destination sheet for \a aSrcFileName. 346 * @return true if \a aFileName will cause recursion in the sheet path. Otherwise false. 347 */ 348 bool TestForRecursion( const wxString& aSrcFileName, const wxString& aDestFileName ); 349 350 /** 351 * Make the sheet file name relative to its parent sheet. 352 * 353 * This should only be called when changing the parent sheet path such performing a save 354 * as or a new schematic without a project in stand alone mode. The sheet file name is 355 * only made relative if the current file name is relative. Absolute sheet file name paths 356 * are a user choice so do not change them. 357 * 358 * Sheet file name paths are set according to the following criteria: 359 * - If the sheet file name path is in the same as the parent sheet file name path, set 360 * the sheet file name to just the file name and extension with no path. 361 * - If the sheet file name path can be made relative to the parent sheet file name path, 362 * set the sheet file name using the relative path. 363 * - If the sheet file name path cannot be converted to a relative path, then fall back to 364 * the absolute file name path. 365 */ 366 void MakeFilePathRelativeToParentSheet(); 367 368 bool operator==( const SCH_SHEET_PATH& d1 ) const; 369 370 bool operator!=( const SCH_SHEET_PATH& d1 ) const { return !( *this == d1 ) ; } 371 372 bool operator<( const SCH_SHEET_PATH& d1 ) const { return m_sheets < d1.m_sheets; } 373 374 private: 375 void initFromOther( const SCH_SHEET_PATH& aOther ); 376 377 protected: 378 std::vector< SCH_SHEET* > m_sheets; 379 380 size_t m_current_hash; 381 382 int m_virtualPageNumber; /// Page numbers are maintained by the sheet load order. 383 384 std::map<std::pair<wxString, wxString>, bool> m_recursion_test_cache; 385 }; 386 387 388 namespace std 389 { 390 template<> struct hash<SCH_SHEET_PATH> 391 { 392 size_t operator()( const SCH_SHEET_PATH& path ) const; 393 }; 394 } 395 396 397 typedef std::vector< SCH_SHEET_PATH > SCH_SHEET_PATHS; 398 typedef SCH_SHEET_PATHS::iterator SCH_SHEET_PATHS_ITER; 399 400 401 /** 402 * A container for handling #SCH_SHEET_PATH objects in a flattened hierarchy. 403 * 404 * #SCH_SHEET objects are not unique, there can be many sheets with the same filename and 405 * that share the same #SCH_SCREEN reference. Each The schematic file (#SCH_SCREEN) may 406 * be shared between these sheets and symbol references are specific to a sheet path. 407 * When a sheet is entered, symbol references and sheet page number are updated. 408 */ 409 class SCH_SHEET_LIST : public SCH_SHEET_PATHS 410 { 411 public: 412 /** 413 * Construct a flattened list of SCH_SHEET_PATH objects from \a aSheet. 414 * 415 * If aSheet == NULL, then this is an empty hierarchy which the user can populate. 416 */ 417 SCH_SHEET_LIST( SCH_SHEET* aSheet = nullptr, bool aCheckIntegrity = false ); 418 419 ~SCH_SHEET_LIST() {} 420 421 /** 422 * Check the entire hierarchy for any modifications. 423 * 424 * @return True if the hierarchy is modified otherwise false. 425 */ 426 bool IsModified() const; 427 428 void ClearModifyStatus(); 429 430 /** 431 * Fetch a SCH_ITEM by ID. Also returns the sheet the item was found on in \a aPathOut. 432 */ 433 SCH_ITEM* GetItem( const KIID& aID, SCH_SHEET_PATH* aPathOut = nullptr ) const; 434 435 /** 436 * Fill an item cache for temporary use when many items need to be fetched. 437 */ 438 void FillItemMap( std::map<KIID, EDA_ITEM*>& aMap ); 439 440 /** 441 * Silently annotate the not yet annotated power symbols of the entire hierarchy of the 442 * sheet path list. 443 * 444 * It is called before creating a netlist, to annotate power symbols, without prompting 445 * the user about not annotated or duplicate for these symbols, if only these symbols 446 * need annotation ( a very frequent case ). 447 */ 448 void AnnotatePowerSymbols(); 449 450 /** 451 * Add a #SCH_REFERENCE object to \a aReferences for each symbol in the list of sheets. 452 * 453 * @param aReferences List of references to populate. 454 * @param aIncludePowerSymbols Set to false to only get normal symbols. 455 * @param aForceIncludeOrphanSymbols Set to true to include symbols having no symbol found 456 * in lib. The normal option is false, and set to true 457 * only to build the full list of symbols. 458 */ 459 void GetSymbols( SCH_REFERENCE_LIST& aReferences, bool aIncludePowerSymbols = true, 460 bool aForceIncludeOrphanSymbols = false ) const; 461 462 /** 463 * Add a #SCH_REFERENCE object to \a aReferences for each symbol in the list of sheets that are 464 * contained within \a aSheetPath as well as recursively downwards inside aSheetPath. 465 * 466 * @param aReferences List of references to populate. 467 * @param aSheetPath Path to return symbols from 468 * @param aIncludePowerSymbols Set to false to only get normal symbols. 469 * @param aForceIncludeOrphanSymbols Set to true to include symbols having no symbol found 470 * in lib. The normal option is false, and set to true 471 * only to build the full list of symbols. 472 */ 473 void GetSymbolsWithinPath( SCH_REFERENCE_LIST& aReferences, const SCH_SHEET_PATH& aSheetPath, 474 bool aIncludePowerSymbols = true, 475 bool aForceIncludeOrphanSymbols = false ) const; 476 477 /** 478 * Add a #SCH_SHEET_PATH object to \a aSheets for each sheet in the list that are 479 * contained within \a aSheetPath as well as recursively downwards inside aSheetPath. 480 * 481 * @param aReferences List of sheets to populate. 482 * @param aSheetPath Path to return sheets from 483 */ 484 void GetSheetsWithinPath( SCH_SHEET_PATHS& aSheets, const SCH_SHEET_PATH& aSheetPath ) const; 485 486 /** 487 * Add a #SCH_REFERENCE_LIST object to \a aRefList for each same-reference set of 488 * multi-unit parts in the list of sheets. The map key for each element will be the 489 * reference designator. 490 * 491 * @param aRefList Map of reference designators to reference lists 492 * @param aIncludePowerSymbols Set to false to only get normal symbols. 493 */ 494 void GetMultiUnitSymbols( SCH_MULTI_UNIT_REFERENCE_MAP &aRefList, 495 bool aIncludePowerSymbols = true ) const; 496 497 /** 498 * Test every #SCH_SHEET_PATH in this #SCH_SHEET_LIST to verify if adding the sheets stored 499 * in \a aSrcSheetHierarchy to the sheet stored in \a aDestFileName will cause recursion. 500 * 501 * @param aSrcSheetHierarchy is the SCH_SHEET_LIST of the source sheet add to \a aDestFileName. 502 * @param aDestFileName is the file name of the destination sheet for \a aSrcFileName. 503 * @return true if \a aFileName will cause recursion in the sheet path. Otherwise false. 504 */ 505 bool TestForRecursion( const SCH_SHEET_LIST& aSrcSheetHierarchy, 506 const wxString& aDestFileName ); 507 508 /** 509 * Return a pointer to the first #SCH_SHEET_PATH object (not necessarily the only one) using 510 * a particular screen. 511 */ 512 SCH_SHEET_PATH* FindSheetForScreen( const SCH_SCREEN* aScreen ); 513 514 /** 515 * Return a #SCH_SHEET_LIST with a copy of all the #SCH_SHEET_PATH using a particular screen. 516 */ 517 SCH_SHEET_LIST FindAllSheetsForScreen( const SCH_SCREEN* aScreen ) const; 518 519 /** 520 * Build the list of sheets and their sheet path from \a aSheet. 521 * 522 * If \a aSheet is the root sheet, the full sheet path and sheet list are built. 523 * 524 * The list will be ordered as per #SCH_SCREEN::GetSheets which results in sheets being ordered 525 * in the legacy way of using the X and Y positions of the sheets. 526 * 527 * @see #SortByPageNumbers to sort by page numbers 528 * 529 * @param aSheet is the starting sheet from which the list is built, or NULL 530 * indicating that g_RootSheet should be used. 531 * @throw std::bad_alloc if the memory for the sheet path list could not be allocated. 532 */ 533 void BuildSheetList( SCH_SHEET* aSheet, bool aCheckIntegrity ); 534 535 /** 536 * Sort the list of sheets by page number. This should be called after #BuildSheetList 537 * 538 * If page numbers happen to be equal, then it compares the sheet names to ensure deterministic 539 * ordering. 540 * 541 * @param aUpdateVirtualPageNums If true, updates the virtual page numbers to match the new 542 * ordering 543 */ 544 void SortByPageNumbers( bool aUpdateVirtualPageNums = true ); 545 546 bool NameExists( const wxString& aSheetName ) const; 547 548 bool PageNumberExists( const wxString& aPageNumber ) const; 549 550 /** 551 * Update all of the symbol instance information using \a aSymbolInstances. 552 * WARNING: Do not call this on anything other than the full hierarchy. 553 * @param aSymbolInstances is the symbol path information loaded from the root schematic. 554 */ 555 void UpdateSymbolInstances( const std::vector<SYMBOL_INSTANCE_REFERENCE>& aSymbolInstances ); 556 557 /** 558 * Update all of the sheet instance information using \a aSheetInstances. 559 * 560 * @warning Do not call this on anything other than the full hierarchy. 561 * 562 * @param aSymbolInstances is the symbol path information loaded from the root schematic. 563 */ 564 void UpdateSheetInstances( const std::vector<SCH_SHEET_INSTANCE>& aSheetInstances ); 565 566 std::vector<KIID_PATH> GetPaths() const; 567 568 /** 569 * Fetch the instance information for all of the sheets in the hiearchy. 570 * 571 * @return all of the sheet instance data for the hierarchy. 572 */ 573 std::vector<SCH_SHEET_INSTANCE> GetSheetInstances() const; 574 575 /** 576 * Check all of the sheet instance for empty page numbers. 577 * 578 * @note This should only return true when loading a legacy schematic or an s-expression 579 * schematic before version 20201005. 580 * 581 * @return true if all sheet instance page numbers are not defined. Otherwise false. 582 */ 583 bool AllSheetPageNumbersEmpty() const; 584 585 /** 586 * Set initial sheet page numbers. 587 * 588 * The number scheme is base on the old pseudo sheet numbering algorithm prior to 589 * the implementation of user definable sheet page numbers. 590 */ 591 void SetInitialPageNumbers(); 592 593 private: 594 SCH_SHEET_PATH m_currentSheetPath; 595 }; 596 597 #endif // CLASS_DRAWSHEET_PATH_H 598