Fix schematic editor crash when saving shared schematics.
Shared schematics can have a root sheet instance when opened with the schematic editor in stand alone mode. This would cause a crash when opening the shared schematic in a project where it was shared because the root instance was trying to be saved in the normal sheet instance data which is not valid. Fixes https://gitlab.com/kicad/code/kicad/-/issues/13102
This commit is contained in:
parent
9a2d8e6b6b
commit
945361ca65
|
@ -473,10 +473,12 @@ void SCH_SEXPR_PLUGIN::Format( SCH_SHEET* aSheet )
|
|||
}
|
||||
}
|
||||
|
||||
// If this is the root sheet, save the virtual root sheet instance information.
|
||||
if( aSheet->IsRootSheet() )
|
||||
if( aSheet->HasRootInstance() )
|
||||
{
|
||||
saveInstances( aSheet->GetInstances(), 1 );
|
||||
std::vector< SCH_SHEET_INSTANCE> instances;
|
||||
|
||||
instances.emplace_back( aSheet->GetRootInstance() );
|
||||
saveInstances( instances, 1 );
|
||||
}
|
||||
|
||||
m_out->Print( 0, ")\n" );
|
||||
|
@ -1004,7 +1006,20 @@ void SCH_SEXPR_PLUGIN::saveSheet( SCH_SHEET* aSheet, int aNestLevel )
|
|||
m_out->Print( aNestLevel + 1, ")\n" ); // Closes pin token.
|
||||
}
|
||||
|
||||
if( !aSheet->GetInstances().empty() )
|
||||
// We all sheet instances here except the root sheet instance.
|
||||
std::vector< SCH_SHEET_INSTANCE > sheetInstances = aSheet->GetInstances();
|
||||
|
||||
auto it = sheetInstances.begin();
|
||||
|
||||
while( it != sheetInstances.end() )
|
||||
{
|
||||
if( it->m_Path.size() == 0 )
|
||||
it = sheetInstances.erase( it );
|
||||
else
|
||||
it++;
|
||||
}
|
||||
|
||||
if( !sheetInstances.empty() )
|
||||
{
|
||||
m_out->Print( aNestLevel + 1, "(instances\n" );
|
||||
|
||||
|
@ -1013,18 +1028,18 @@ void SCH_SEXPR_PLUGIN::saveSheet( SCH_SHEET* aSheet, int aNestLevel )
|
|||
SCH_SHEET_LIST fullHierarchy = m_schematic->GetSheets();
|
||||
bool project_open = false;
|
||||
|
||||
for( size_t i = 0; i < aSheet->GetInstances().size(); i++ )
|
||||
for( size_t i = 0; i < sheetInstances.size(); i++ )
|
||||
{
|
||||
// If the instance data is part of this design but no longer has an associated sheet
|
||||
// path, don't save it. This prevents large amounts of orphaned instance data for the
|
||||
// current project from accumulating in the schematic files.
|
||||
//
|
||||
// Keep all instance data when copying to the clipboard. It may be needed on paste.
|
||||
if( ( aSheet->GetInstances()[i].m_Path[0] == rootSheetUuid )
|
||||
&& !fullHierarchy.GetSheetPathByKIIDPath( aSheet->GetInstances()[i].m_Path ) )
|
||||
if( ( sheetInstances[i].m_Path[0] == rootSheetUuid )
|
||||
&& !fullHierarchy.GetSheetPathByKIIDPath( sheetInstances[i].m_Path ) )
|
||||
{
|
||||
if( project_open && ( ( i + 1 == aSheet->GetInstances().size() )
|
||||
|| lastProjectUuid != aSheet->GetInstances()[i+1].m_Path[0] ) )
|
||||
if( project_open && ( ( i + 1 == sheetInstances.size() )
|
||||
|| lastProjectUuid != sheetInstances[i+1].m_Path[0] ) )
|
||||
{
|
||||
m_out->Print( aNestLevel + 2, ")\n" ); // Closes `project`.
|
||||
project_open = false;
|
||||
|
@ -1033,29 +1048,29 @@ void SCH_SEXPR_PLUGIN::saveSheet( SCH_SHEET* aSheet, int aNestLevel )
|
|||
continue;
|
||||
}
|
||||
|
||||
if( lastProjectUuid != aSheet->GetInstances()[i].m_Path[0] )
|
||||
if( lastProjectUuid != sheetInstances[i].m_Path[0] )
|
||||
{
|
||||
wxString projectName;
|
||||
|
||||
if( aSheet->GetInstances()[i].m_Path[0] == rootSheetUuid )
|
||||
if( sheetInstances[i].m_Path[0] == rootSheetUuid )
|
||||
projectName = m_schematic->Prj().GetProjectName();
|
||||
else
|
||||
projectName = aSheet->GetInstances()[i].m_ProjectName;
|
||||
projectName = sheetInstances[i].m_ProjectName;
|
||||
|
||||
lastProjectUuid = aSheet->GetInstances()[i].m_Path[0];
|
||||
lastProjectUuid = sheetInstances[i].m_Path[0];
|
||||
m_out->Print( aNestLevel + 2, "(project %s\n",
|
||||
m_out->Quotew( projectName ).c_str() );
|
||||
project_open = true;
|
||||
}
|
||||
|
||||
wxString path = aSheet->GetInstances()[i].m_Path.AsString();
|
||||
wxString path = sheetInstances[i].m_Path.AsString();
|
||||
|
||||
m_out->Print( aNestLevel + 3, "(path %s (page %s))\n",
|
||||
m_out->Quotew( path ).c_str(),
|
||||
m_out->Quotew( aSheet->GetInstances()[i].m_PageNumber ).c_str() );
|
||||
m_out->Quotew( sheetInstances[i].m_PageNumber ).c_str() );
|
||||
|
||||
if( project_open && ( ( i + 1 == aSheet->GetInstances().size() )
|
||||
|| lastProjectUuid != aSheet->GetInstances()[i+1].m_Path[0] ) )
|
||||
if( project_open && ( ( i + 1 == sheetInstances.size() )
|
||||
|| lastProjectUuid != sheetInstances[i+1].m_Path[0] ) )
|
||||
{
|
||||
m_out->Print( aNestLevel + 2, ")\n" ); // Closes `project`.
|
||||
project_open = false;
|
||||
|
@ -1345,15 +1360,15 @@ void SCH_SEXPR_PLUGIN::saveBusAlias( std::shared_ptr<BUS_ALIAS> aAlias, int aNes
|
|||
}
|
||||
|
||||
|
||||
void SCH_SEXPR_PLUGIN::saveInstances( const std::vector<SCH_SHEET_INSTANCE>& aSheets,
|
||||
void SCH_SEXPR_PLUGIN::saveInstances( const std::vector<SCH_SHEET_INSTANCE>& aInstances,
|
||||
int aNestLevel )
|
||||
{
|
||||
if( aSheets.size() )
|
||||
if( aInstances.size() )
|
||||
{
|
||||
m_out->Print( 0, "\n" );
|
||||
m_out->Print( aNestLevel, "(sheet_instances\n" );
|
||||
|
||||
for( const SCH_SHEET_INSTANCE& instance : aSheets )
|
||||
for( const SCH_SHEET_INSTANCE& instance : aInstances )
|
||||
{
|
||||
wxString path = instance.m_Path.AsString();
|
||||
|
||||
|
@ -1370,7 +1385,8 @@ void SCH_SEXPR_PLUGIN::saveInstances( const std::vector<SCH_SHEET_INSTANCE>& aSh
|
|||
}
|
||||
|
||||
|
||||
void SCH_SEXPR_PLUGIN::cacheLib( const wxString& aLibraryFileName, const STRING_UTF8_MAP* aProperties )
|
||||
void SCH_SEXPR_PLUGIN::cacheLib( const wxString& aLibraryFileName,
|
||||
const STRING_UTF8_MAP* aProperties )
|
||||
{
|
||||
if( !m_cache || !m_cache->IsFile( aLibraryFileName ) || m_cache->IsFileChanged() )
|
||||
{
|
||||
|
|
|
@ -1228,6 +1228,34 @@ bool SCH_SHEET::AddInstance( const SCH_SHEET_PATH& aSheetPath )
|
|||
}
|
||||
|
||||
|
||||
bool SCH_SHEET::HasRootInstance() const
|
||||
{
|
||||
for( const SCH_SHEET_INSTANCE& instance : m_instances )
|
||||
{
|
||||
if( instance.m_Path.size() == 0 )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const SCH_SHEET_INSTANCE& SCH_SHEET::GetRootInstance() const
|
||||
{
|
||||
for( const SCH_SHEET_INSTANCE& instance : m_instances )
|
||||
{
|
||||
if( instance.m_Path.size() == 0 )
|
||||
return instance;
|
||||
}
|
||||
|
||||
wxFAIL;
|
||||
|
||||
static SCH_SHEET_INSTANCE dummy;
|
||||
|
||||
return dummy;
|
||||
}
|
||||
|
||||
|
||||
wxString SCH_SHEET::getPageNumber( const SCH_SHEET_PATH& aSheetPath ) const
|
||||
{
|
||||
wxCHECK( aSheetPath.IsFullPath(), wxEmptyString );
|
||||
|
|
|
@ -400,6 +400,27 @@ public:
|
|||
*/
|
||||
bool AddInstance( const SCH_SHEET_PATH& aInstance );
|
||||
|
||||
/**
|
||||
* Check to see if this sheet has a root sheet instance.
|
||||
*
|
||||
* @note It is possible for sheets to contain both sheet instances from other projects as
|
||||
* well as a root sheet instance for this schematic. This will happen with a
|
||||
* shared schematic is opened by the schematic editor in stand alone model.
|
||||
*
|
||||
* @return true if the instance data contains a root sheet instance.
|
||||
*/
|
||||
bool HasRootInstance() const;
|
||||
|
||||
/**
|
||||
* Return the root sheet instance data.
|
||||
*
|
||||
* @note If no root sheet instance data exists, an assertion will be raise in debug builds
|
||||
* and an empty instance will be returned.
|
||||
*
|
||||
* @return the root sheet instance data.
|
||||
*/
|
||||
const SCH_SHEET_INSTANCE& GetRootInstance() const;
|
||||
|
||||
/**
|
||||
* Compares page numbers of schematic sheets.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue