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.

183 lines
6.5 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2022 KiCad Developers, see AUTHORS.TXT for contributors.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 3
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, you may find one at
  18. * http://www.gnu.org/licenses/
  19. */
  20. #include <schematic_file_util.h>
  21. #include <qa_utils/wx_utils/unit_test_utils.h> // GetEeschemaTestDataDir()
  22. #include <settings/settings_manager.h>
  23. #include <connection_graph.h>
  24. #include <lib_textbox.h>
  25. #include <schematic.h>
  26. #include <sch_screen.h>
  27. // For SCH parsing
  28. #include <sch_plugins/kicad/sch_sexpr_plugin.h>
  29. #include <sch_plugins/kicad/sch_sexpr_parser.h>
  30. #include <richio.h>
  31. #include <qa_utils/stdstream_line_reader.h>
  32. namespace KI_TEST
  33. {
  34. void DumpSchematicToFile( SCHEMATIC& aSchematic, SCH_SHEET& aSheet, const std::string& aFilename )
  35. {
  36. SCH_SEXPR_PLUGIN io;
  37. io.Save( aFilename, &aSheet, &aSchematic );
  38. }
  39. void LoadSheetSchematicContents( const std::string& fileName, SCH_SHEET* sheet )
  40. {
  41. std::ifstream fileStream;
  42. fileStream.open( fileName );
  43. wxASSERT( fileStream.is_open() );
  44. STDISTREAM_LINE_READER reader;
  45. reader.SetStream( fileStream );
  46. SCH_SEXPR_PARSER parser( &reader );
  47. parser.ParseSchematic( sheet );
  48. }
  49. void LoadHierarchy( SCHEMATIC* schematic, SCH_SHEET* sheet, const std::string& sheetFilename,
  50. std::unordered_map<std::string, SCH_SCREEN*>& parsedScreens )
  51. {
  52. SCH_SCREEN* screen = nullptr;
  53. if( !sheet->GetScreen() )
  54. {
  55. // Construct paths
  56. const wxFileName fileName( sheetFilename );
  57. const std::string filePath( fileName.GetPath( wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR ) );
  58. const std::string fileBareName( fileName.GetFullName() );
  59. // Check for existing screen
  60. auto screenFound = parsedScreens.find( fileBareName );
  61. if( screenFound != parsedScreens.end() )
  62. screen = screenFound->second;
  63. // Configure sheet with existing screen, or load screen
  64. if( screen )
  65. {
  66. // Screen already loaded - assign to sheet
  67. sheet->SetScreen( screen );
  68. sheet->GetScreen()->SetParent( schematic );
  69. }
  70. else
  71. {
  72. // Load screen and assign to sheet
  73. screen = new SCH_SCREEN( schematic );
  74. parsedScreens.insert( { fileBareName, screen } );
  75. sheet->SetScreen( screen );
  76. sheet->GetScreen()->SetFileName( sheetFilename );
  77. LoadSheetSchematicContents( sheetFilename, sheet );
  78. }
  79. // Recurse through child sheets
  80. for( SCH_ITEM* item : sheet->GetScreen()->Items().OfType( SCH_SHEET_T ) )
  81. {
  82. SCH_SHEET* childSheet = static_cast<SCH_SHEET*>( item );
  83. wxFileName childSheetFilename = childSheet->GetFileName();
  84. if( !childSheetFilename.IsAbsolute() )
  85. childSheetFilename.MakeAbsolute( filePath );
  86. std::string childSheetFullFilename( childSheetFilename.GetFullPath() );
  87. LoadHierarchy( schematic, childSheet, childSheetFullFilename, parsedScreens );
  88. }
  89. }
  90. }
  91. std::unique_ptr<SCHEMATIC> LoadHierarchyFromRoot( const std::string& rootFilename,
  92. PROJECT* project )
  93. {
  94. std::unique_ptr<SCHEMATIC> schematic( new SCHEMATIC( nullptr ) );
  95. std::unordered_map<std::string, SCH_SCREEN*> parsedScreens;
  96. schematic->SetProject( project );
  97. SCH_SHEET* rootSheet = new SCH_SHEET( schematic.get() );
  98. schematic->SetRoot( rootSheet );
  99. LoadHierarchy( schematic.get(), rootSheet, rootFilename, parsedScreens );
  100. return schematic;
  101. }
  102. void LoadSchematic( SETTINGS_MANAGER& aSettingsManager, const wxString& aRelPath,
  103. std::unique_ptr<SCHEMATIC>& aSchematic )
  104. {
  105. if( aSchematic )
  106. {
  107. PROJECT* prj = &aSchematic->Prj();
  108. aSchematic->SetProject( nullptr );
  109. aSettingsManager.UnloadProject( prj, false );
  110. aSchematic->Reset();
  111. }
  112. std::string absPath = GetEeschemaTestDataDir() + aRelPath.ToStdString();
  113. wxFileName projectFile( absPath + ".kicad_pro" );
  114. wxFileName legacyProject( absPath + ".pro" );
  115. std::string schematicPath = absPath + ".kicad_sch";
  116. if( projectFile.Exists() )
  117. aSettingsManager.LoadProject( projectFile.GetFullPath() );
  118. else if( legacyProject.Exists() )
  119. aSettingsManager.LoadProject( legacyProject.GetFullPath() );
  120. else
  121. aSettingsManager.LoadProject( "" );
  122. aSettingsManager.Prj().SetElem( PROJECT::ELEM_SCH_SYMBOL_LIBS, nullptr );
  123. aSchematic = LoadHierarchyFromRoot( schematicPath, &aSettingsManager.Prj() );
  124. aSchematic->CurrentSheet().push_back( &aSchematic->Root() );
  125. SCH_SCREENS screens( aSchematic->Root() );
  126. for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
  127. screen->UpdateLocalLibSymbolLinks();
  128. SCH_SHEET_LIST sheets = aSchematic->GetSheets();
  129. // Restore all of the loaded symbol instances from the root sheet screen.
  130. sheets.UpdateSymbolInstanceData( aSchematic->RootScreen()->GetSymbolInstances() );
  131. sheets.UpdateSheetInstanceData( aSchematic->RootScreen()->GetSheetInstances() );
  132. if( aSchematic->RootScreen()->GetFileFormatVersionAtLoad() < 20230221 )
  133. screens.FixLegacyPowerSymbolMismatches();
  134. if( aSchematic->RootScreen()->GetFileFormatVersionAtLoad() < 20221206 )
  135. {
  136. for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
  137. screen->MigrateSimModels();
  138. }
  139. sheets.AnnotatePowerSymbols();
  140. // NOTE: This is required for multi-unit symbols to be correct
  141. // Normally called from SCH_EDIT_FRAME::FixupJunctions() but could be refactored
  142. for( SCH_SHEET_PATH& sheet : sheets )
  143. sheet.UpdateAllScreenReferences();
  144. // NOTE: SchematicCleanUp is not called; QA schematics must already be clean or else
  145. // SchematicCleanUp must be freed from its UI dependencies.
  146. aSchematic->ConnectionGraph()->Recalculate( sheets, true );
  147. }
  148. } // namespace KI_TEST