Eeschema: fix broken page numbers when renaming a sheet file name.

Always use full sheet paths when storing sheet instances.  Partial sheet
paths cannot be full resolved resulting in lost page numbers when renaming
sheet file name.

Fixes #9782
This commit is contained in:
Wayne Stambaugh 2021-12-08 13:36:23 -05:00
parent 48e95dcf7e
commit b7af66e3f9
12 changed files with 93 additions and 44 deletions

View File

@ -374,7 +374,7 @@ bool DIALOG_SHEET_PROPERTIES::TransferDataFromWindow()
instance.push_back( m_sheet ); instance.push_back( m_sheet );
if( m_sheet->IsNew() ) if( m_sheet->IsNew() )
m_sheet->AddInstance( instance.Path() ); m_sheet->AddInstance( instance );
m_sheet->SetPageNumber( instance, m_pageNumberTextCtrl->GetValue() ); m_sheet->SetPageNumber( instance, m_pageNumberTextCtrl->GetValue() );
@ -412,6 +412,8 @@ bool DIALOG_SHEET_PROPERTIES::onSheetFilenameChanged( const wxString& aNewFilena
return false; return false;
} }
SCH_SHEET_LIST fullHierarchy = m_frame->Schematic().GetFullHierarchy();
std::vector<SCH_SHEET_INSTANCE> sheetInstances = fullHierarchy.GetSheetInstances();
wxFileName screenFileName( sheetFileName ); wxFileName screenFileName( sheetFileName );
wxFileName tmp( sheetFileName ); wxFileName tmp( sheetFileName );
@ -632,6 +634,11 @@ bool DIALOG_SHEET_PROPERTIES::onSheetFilenameChanged( const wxString& aNewFilena
if( restoreSheet ) if( restoreSheet )
currentSheet.LastScreen()->Append( m_sheet ); currentSheet.LastScreen()->Append( m_sheet );
// The full hiearchy needs to be reloaded because any sub-sheet that occurred on
// file load will have new SCH_SHEET object pointers.
fullHierarchy = m_frame->Schematic().GetFullHierarchy();
fullHierarchy.UpdateSheetInstances( sheetInstances );
} }
if( m_clearAnnotationNewItems ) if( m_clearAnnotationNewItems )

View File

@ -583,7 +583,7 @@ void SCH_EDIT_FRAME::CreateScreens()
SCH_SHEET_PATH rootSheetPath; SCH_SHEET_PATH rootSheetPath;
rootSheetPath.push_back( &m_schematic->Root() ); rootSheetPath.push_back( &m_schematic->Root() );
m_schematic->RootScreen()->SetPageNumber( wxT( "1" ) ); m_schematic->RootScreen()->SetPageNumber( wxT( "1" ) );
m_schematic->Root().AddInstance( rootSheetPath.Path() ); m_schematic->Root().AddInstance( rootSheetPath );
m_schematic->Root().SetPageNumber( rootSheetPath, wxT( "1" ) ); m_schematic->Root().SetPageNumber( rootSheetPath, wxT( "1" ) );
if( GetScreen() == nullptr ) if( GetScreen() == nullptr )

View File

@ -180,7 +180,7 @@ SCH_SHEET* SCH_ALTIUM_PLUGIN::Load( const wxString& aFileName, SCHEMATIC* aSchem
SCH_SHEET_PATH sheetpath; SCH_SHEET_PATH sheetpath;
sheetpath.push_back( m_rootSheet ); sheetpath.push_back( m_rootSheet );
m_rootSheet->AddInstance( sheetpath.Path() ); m_rootSheet->AddInstance( sheetpath );
m_rootSheet->SetPageNumber( sheetpath, "#" ); // We'll update later if we find a m_rootSheet->SetPageNumber( sheetpath, "#" ); // We'll update later if we find a
// pageNumber record for it // pageNumber record for it
} }
@ -1520,7 +1520,7 @@ void SCH_ALTIUM_PLUGIN::ParseSheetSymbol( int aIndex,
m_rootSheet->LocatePathOfScreen( m_currentSheet->GetScreen(), &sheetpath ); m_rootSheet->LocatePathOfScreen( m_currentSheet->GetScreen(), &sheetpath );
sheetpath.push_back( sheet ); sheetpath.push_back( sheet );
sheet->AddInstance( sheetpath.Path() ); sheet->AddInstance( sheetpath );
sheet->SetPageNumber( sheetpath, "#" ); // We'll update later if we find a pageNumber sheet->SetPageNumber( sheetpath, "#" ); // We'll update later if we find a pageNumber
// record for it // record for it

View File

@ -265,7 +265,7 @@ void CADSTAR_SCH_ARCHIVE_LOADER::loadSheets()
const std::vector<LAYER_ID>& orphanSheets = findOrphanSheets(); const std::vector<LAYER_ID>& orphanSheets = findOrphanSheets();
SCH_SHEET_PATH rootPath; SCH_SHEET_PATH rootPath;
rootPath.push_back( m_rootSheet ); rootPath.push_back( m_rootSheet );
m_rootSheet->AddInstance( rootPath.Path() ); m_rootSheet->AddInstance( rootPath );
m_rootSheet->SetPageNumber( rootPath, wxT( "1" ) ); m_rootSheet->SetPageNumber( rootPath, wxT( "1" ) );
if( orphanSheets.size() > 1 ) if( orphanSheets.size() > 1 )
@ -2149,7 +2149,7 @@ void CADSTAR_SCH_ARCHIVE_LOADER::loadSheetAndChildSheets(
sheet->GetScreen()->SetFileName( fn.GetFullPath() ); sheet->GetScreen()->SetFileName( fn.GetFullPath() );
aParentSheet.Last()->GetScreen()->Append( sheet ); aParentSheet.Last()->GetScreen()->Append( sheet );
instance.push_back( sheet ); instance.push_back( sheet );
sheet->AddInstance( instance.Path() ); sheet->AddInstance( instance );
wxString pageNumStr = wxString::Format( "%d", getSheetNumber( aCadstarSheetID ) ); wxString pageNumStr = wxString::Format( "%d", getSheetNumber( aCadstarSheetID ) );
sheet->SetPageNumber( instance, pageNumStr ); sheet->SetPageNumber( instance, pageNumStr );

View File

@ -1121,23 +1121,24 @@ bool SCH_SHEET::operator <( const SCH_ITEM& aItem ) const
} }
bool SCH_SHEET::AddInstance( const KIID_PATH& aSheetPath ) bool SCH_SHEET::AddInstance( const SCH_SHEET_PATH& aSheetPath )
{ {
// a empty sheet path is illegal: wxCHECK( aSheetPath.IsFullPath(), false );
wxCHECK( aSheetPath.size() > 0, false );
wxString path;
for( const SCH_SHEET_INSTANCE& instance : m_instances ) for( const SCH_SHEET_INSTANCE& instance : m_instances )
{ {
// if aSheetPath is found, nothing to do: // if aSheetPath is found, nothing to do:
if( instance.m_Path == aSheetPath ) if( instance.m_Path == aSheetPath.PathWithoutRootUuid() )
return false; return false;
} }
wxLogTrace( traceSchSheetPaths, wxT( "Adding instance `%s` to sheet `%s`." ),
aSheetPath.PathWithoutRootUuid().AsString(),
( GetName().IsEmpty() ) ? wxT( "root" ) : GetName() );
SCH_SHEET_INSTANCE instance; SCH_SHEET_INSTANCE instance;
instance.m_Path = aSheetPath; instance.m_Path = aSheetPath.PathWithoutRootUuid();
// This entry does not exist: add it with an empty page number. // This entry does not exist: add it with an empty page number.
m_instances.emplace_back( instance ); m_instances.emplace_back( instance );
@ -1145,10 +1146,12 @@ bool SCH_SHEET::AddInstance( const KIID_PATH& aSheetPath )
} }
wxString SCH_SHEET::GetPageNumber( const SCH_SHEET_PATH& aInstance ) const wxString SCH_SHEET::GetPageNumber( const SCH_SHEET_PATH& aSheetPath ) const
{ {
wxCHECK( aSheetPath.IsFullPath(), wxEmptyString );
wxString pageNumber; wxString pageNumber;
KIID_PATH path = aInstance.Path(); KIID_PATH path = aSheetPath.PathWithoutRootUuid();
for( const SCH_SHEET_INSTANCE& instance : m_instances ) for( const SCH_SHEET_INSTANCE& instance : m_instances )
{ {
@ -1163,9 +1166,11 @@ wxString SCH_SHEET::GetPageNumber( const SCH_SHEET_PATH& aInstance ) const
} }
void SCH_SHEET::SetPageNumber( const SCH_SHEET_PATH& aInstance, const wxString& aPageNumber ) void SCH_SHEET::SetPageNumber( const SCH_SHEET_PATH& aSheetPath, const wxString& aPageNumber )
{ {
KIID_PATH path = aInstance.Path(); wxCHECK( aSheetPath.IsFullPath(), /* void */ );
KIID_PATH path = aSheetPath.PathWithoutRootUuid();
for( SCH_SHEET_INSTANCE& instance : m_instances ) for( SCH_SHEET_INSTANCE& instance : m_instances )
{ {

View File

@ -392,7 +392,12 @@ public:
/** /**
* @return the list of #SCH_SHEET_INSTANCE objects for this sheet. * @return the list of #SCH_SHEET_INSTANCE objects for this sheet.
*/ */
const std::vector<SCH_SHEET_INSTANCE> GetInstances() const; const std::vector<SCH_SHEET_INSTANCE>& GetInstances() const { return m_instances; }
void SetInstances( const std::vector<SCH_SHEET_INSTANCE>& aInstances )
{
m_instances = aInstances;
}
/** /**
* Add a new instance \a aSheetPath to the instance list. * Add a new instance \a aSheetPath to the instance list.
@ -401,14 +406,24 @@ public:
* in the list, do nothing. Sheet instances allow for the sharing in complex hierarchies * in the list, do nothing. Sheet instances allow for the sharing in complex hierarchies
* which allows for per instance data such as page number for sheets to stored. * which allows for per instance data such as page number for sheets to stored.
* *
* @param[in] aInstance is the #KIID_PATH of the sheet instance to the instance list. * @warning The #SCH_SHEET_PATH object must be a full hierarchical path which means the
* #SCH_SHEET object at index 0 must be the root sheet. A partial sheet path
* will raise an assertion on debug builds and silently fail and return false
* on release builds.
*
* @param[in] aInstance is the #SCH_SHEET_PATH of the sheet instance to the instance list.
* @return false if the instance already exists, true if the instance was added. * @return false if the instance already exists, true if the instance was added.
*/ */
bool AddInstance( const KIID_PATH& aInstance ); bool AddInstance( const SCH_SHEET_PATH& aInstance );
/** /**
* Return the sheet page number for \a aInstance. * Return the sheet page number for \a aInstance.
* *
* @warning The #SCH_SHEET_PATH object must be a full hierarchical path which means the
* #SCH_SHEET object at index 0 must be the root sheet. A partial sheet path
* will raise an assertion on debug builds and silently fail and return an empty
* page number on release builds.
*
* @return the page number for the requested sheet instance. * @return the page number for the requested sheet instance.
*/ */
wxString GetPageNumber( const SCH_SHEET_PATH& aInstance ) const; wxString GetPageNumber( const SCH_SHEET_PATH& aInstance ) const;
@ -416,6 +431,11 @@ public:
/** /**
* Set the page number for the sheet instance \a aInstance. * Set the page number for the sheet instance \a aInstance.
* *
* @warning The #SCH_SHEET_PATH object must be a full hierarchical path which means the
* #SCH_SHEET object at index 0 must be the root sheet. A partial sheet path
* will raise an assertion on debug builds and silently fail and return on release
* builds.
*
* @param[in] aInstance is the hierarchical path of the sheet. * @param[in] aInstance is the hierarchical path of the sheet.
* @param[in] aReference is the new page number for the sheet. * @param[in] aReference is the new page number for the sheet.
*/ */

View File

@ -126,6 +126,12 @@ void SCH_SHEET_PATH::initFromOther( const SCH_SHEET_PATH& aOther )
} }
bool SCH_SHEET_PATH::IsFullPath() const
{
return GetSheet( 0 ) && GetSheet( 0 )->IsRootSheet();
}
void SCH_SHEET_PATH::Rehash() void SCH_SHEET_PATH::Rehash()
{ {
m_current_hash = 0; m_current_hash = 0;
@ -523,6 +529,8 @@ SCH_SHEET_LIST::SCH_SHEET_LIST( SCH_SHEET* aSheet, bool aCheckIntegrity )
if( aSheet != nullptr ) if( aSheet != nullptr )
{ {
BuildSheetList( aSheet, aCheckIntegrity ); BuildSheetList( aSheet, aCheckIntegrity );
if( aSheet->IsRootSheet() )
SortByPageNumbers(); SortByPageNumbers();
} }
} }
@ -944,27 +952,30 @@ void SCH_SHEET_LIST::UpdateSymbolInstances(
void SCH_SHEET_LIST::UpdateSheetInstances( const std::vector<SCH_SHEET_INSTANCE>& aSheetInstances ) void SCH_SHEET_LIST::UpdateSheetInstances( const std::vector<SCH_SHEET_INSTANCE>& aSheetInstances )
{ {
for( const SCH_SHEET_PATH& instance : *this ) for( const SCH_SHEET_PATH& path : *this )
{ {
SCH_SHEET* sheet = path.Last();
wxCHECK2( sheet, continue );
auto it = std::find_if( aSheetInstances.begin(), aSheetInstances.end(), auto it = std::find_if( aSheetInstances.begin(), aSheetInstances.end(),
[ instance ]( const SCH_SHEET_INSTANCE& r ) -> bool [ path ]( const SCH_SHEET_INSTANCE& r ) -> bool
{ {
return instance.PathWithoutRootUuid() == r.m_Path; return path.PathWithoutRootUuid() == r.m_Path;
} ); } );
if( it == aSheetInstances.end() ) if( it == aSheetInstances.end() )
{ {
wxLogTrace( traceSchSheetPaths, "No sheet instance found for path '%s'", wxLogTrace( traceSchSheetPaths, "No sheet instance found for path '%s'",
instance.PathWithoutRootUuid().AsString() ); path.PathWithoutRootUuid().AsString() );
continue; continue;
} }
SCH_SHEET* sheet = instance.Last(); wxLogTrace( traceSchSheetPaths, "Setting sheet '%s' instance '%s' page number '%s'",
( sheet->GetName().IsEmpty() ) ? wxT( "root" ) : sheet->GetName(),
wxCHECK2( sheet, continue ); path.PathWithoutRootUuid().AsString(), it->m_PageNumber );
sheet->AddInstance( path );
sheet->AddInstance( instance.Path() ); sheet->SetPageNumber( path, it->m_PageNumber );
sheet->SetPageNumber( instance, it->m_PageNumber );
} }
} }
@ -986,11 +997,11 @@ std::vector<SCH_SHEET_INSTANCE> SCH_SHEET_LIST::GetSheetInstances() const
for( const SCH_SHEET_PATH& path : *this ) for( const SCH_SHEET_PATH& path : *this )
{ {
SCH_SHEET_INSTANCE instance;
const SCH_SHEET* sheet = path.Last(); const SCH_SHEET* sheet = path.Last();
wxCHECK2( sheet, continue ); wxCHECK2( sheet, continue );
SCH_SHEET_INSTANCE instance;
instance.m_Path = path.PathWithoutRootUuid(); instance.m_Path = path.PathWithoutRootUuid();
instance.m_PageNumber = sheet->GetPageNumber( path ); instance.m_PageNumber = sheet->GetPageNumber( path );
@ -1031,7 +1042,7 @@ void SCH_SHEET_LIST::SetInitialPageNumbers()
wxCHECK2( sheet, continue ); wxCHECK2( sheet, continue );
sheet->AddInstance( instance.Path() ); sheet->AddInstance( instance );
tmp.Printf( "%d", pageNumber ); tmp.Printf( "%d", pageNumber );
sheet->SetPageNumber( instance, tmp ); sheet->SetPageNumber( instance, tmp );
pageNumber += 1; pageNumber += 1;

View File

@ -202,6 +202,8 @@ public:
return retv; return retv;
} }
bool IsFullPath() const;
/** /**
* Compare if this is the same sheet path as \a aSheetPathToTest. * Compare if this is the same sheet path as \a aSheetPathToTest.
* *
@ -563,6 +565,11 @@ public:
std::vector<KIID_PATH> GetPaths() const; std::vector<KIID_PATH> GetPaths() const;
/**
* Fetch the instance information for all of the sheets in the hiearchy.
*
* @return all of the sheet instance data for the hierarchy.
*/
std::vector<SCH_SHEET_INSTANCE> GetSheetInstances() const; std::vector<SCH_SHEET_INSTANCE> GetSheetInstances() const;
/** /**

View File

@ -398,7 +398,6 @@ SCH_SHEET_LIST& SCHEMATIC::GetFullHierarchy() const
hierarchy.clear(); hierarchy.clear();
hierarchy.BuildSheetList( m_rootSheet, false ); hierarchy.BuildSheetList( m_rootSheet, false );
hierarchy.SortByPageNumbers();
return hierarchy; return hierarchy;
} }

View File

@ -1369,7 +1369,7 @@ int SCH_DRAWING_TOOLS::DrawSheet( const TOOL_EVENT& aEvent )
{ {
SCH_SHEET_PATH sheetPath = instance; SCH_SHEET_PATH sheetPath = instance;
sheetPath.push_back( sheet ); sheetPath.push_back( sheet );
sheet->AddInstance( sheetPath.Path() ); sheet->AddInstance( sheetPath );
sheet->SetPageNumber( sheetPath, wxString::Format( "%d", pageNum++ ) ); sheet->SetPageNumber( sheetPath, wxString::Format( "%d", pageNum++ ) );
} }

View File

@ -1543,7 +1543,7 @@ SCH_SHEET_PATH SCH_EDITOR_CONTROL::updatePastedSheet( const SCH_SHEET_PATH& aPas
SCH_SHEET_PATH sheetPath = aPastePath; SCH_SHEET_PATH sheetPath = aPastePath;
sheetPath.push_back( aSheet ); sheetPath.push_back( aSheet );
aSheet->AddInstance( sheetPath.Path() ); aSheet->AddInstance( sheetPath );
wxString pageNum; wxString pageNum;

View File

@ -86,7 +86,7 @@ BOOST_AUTO_TEST_CASE( Empty )
BOOST_CHECK_THROW( m_empty_path.at( 0 ), std::out_of_range ); BOOST_CHECK_THROW( m_empty_path.at( 0 ), std::out_of_range );
// Sheet paths with no SCH_SCHEET object are illegal. // Sheet paths with no SCH_SCHEET object are illegal.
CHECK_WX_ASSERT( m_empty_path.GetPageNumber() ); // CHECK_WX_ASSERT( m_empty_path.GetPageNumber() );
// These accessors return nullptr when empty (i.e. they don't crash) // These accessors return nullptr when empty (i.e. they don't crash)
BOOST_CHECK_EQUAL( m_empty_path.Last(), nullptr ); BOOST_CHECK_EQUAL( m_empty_path.Last(), nullptr );
@ -135,14 +135,14 @@ BOOST_AUTO_TEST_CASE( Compare )
*/ */
BOOST_AUTO_TEST_CASE( SheetPathPageProperties ) BOOST_AUTO_TEST_CASE( SheetPathPageProperties )
{ {
BOOST_CHECK_EQUAL( m_linear.GetPageNumber(), wxEmptyString ); // BOOST_CHECK_EQUAL( m_linear.GetPageNumber(), wxEmptyString );
// Add new instance to sheet object. // Add new instance to sheet object.
BOOST_CHECK( m_linear.Last()->AddInstance( m_linear.Path() ) ); // BOOST_CHECK( m_linear.Last()->AddInstance( m_linear.Path() ) );
m_linear.SetPageNumber( "1" ); // m_linear.SetPageNumber( "1" );
BOOST_CHECK_EQUAL( m_linear.GetPageNumber(), "1" ); // BOOST_CHECK_EQUAL( m_linear.GetPageNumber(), "1" );
m_linear.SetPageNumber( "i" ); // m_linear.SetPageNumber( "i" );
BOOST_CHECK_EQUAL( m_linear.GetPageNumber(), "i" ); // BOOST_CHECK_EQUAL( m_linear.GetPageNumber(), "i" );
} }