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 );
if( m_sheet->IsNew() )
m_sheet->AddInstance( instance.Path() );
m_sheet->AddInstance( instance );
m_sheet->SetPageNumber( instance, m_pageNumberTextCtrl->GetValue() );
@ -412,6 +412,8 @@ bool DIALOG_SHEET_PROPERTIES::onSheetFilenameChanged( const wxString& aNewFilena
return false;
}
SCH_SHEET_LIST fullHierarchy = m_frame->Schematic().GetFullHierarchy();
std::vector<SCH_SHEET_INSTANCE> sheetInstances = fullHierarchy.GetSheetInstances();
wxFileName screenFileName( sheetFileName );
wxFileName tmp( sheetFileName );
@ -632,6 +634,11 @@ bool DIALOG_SHEET_PROPERTIES::onSheetFilenameChanged( const wxString& aNewFilena
if( restoreSheet )
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 )

View File

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

View File

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

View File

@ -265,7 +265,7 @@ void CADSTAR_SCH_ARCHIVE_LOADER::loadSheets()
const std::vector<LAYER_ID>& orphanSheets = findOrphanSheets();
SCH_SHEET_PATH rootPath;
rootPath.push_back( m_rootSheet );
m_rootSheet->AddInstance( rootPath.Path() );
m_rootSheet->AddInstance( rootPath );
m_rootSheet->SetPageNumber( rootPath, wxT( "1" ) );
if( orphanSheets.size() > 1 )
@ -2149,7 +2149,7 @@ void CADSTAR_SCH_ARCHIVE_LOADER::loadSheetAndChildSheets(
sheet->GetScreen()->SetFileName( fn.GetFullPath() );
aParentSheet.Last()->GetScreen()->Append( sheet );
instance.push_back( sheet );
sheet->AddInstance( instance.Path() );
sheet->AddInstance( instance );
wxString pageNumStr = wxString::Format( "%d", getSheetNumber( aCadstarSheetID ) );
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.size() > 0, false );
wxString path;
wxCHECK( aSheetPath.IsFullPath(), false );
for( const SCH_SHEET_INSTANCE& instance : m_instances )
{
// if aSheetPath is found, nothing to do:
if( instance.m_Path == aSheetPath )
if( instance.m_Path == aSheetPath.PathWithoutRootUuid() )
return false;
}
wxLogTrace( traceSchSheetPaths, wxT( "Adding instance `%s` to sheet `%s`." ),
aSheetPath.PathWithoutRootUuid().AsString(),
( GetName().IsEmpty() ) ? wxT( "root" ) : GetName() );
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.
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;
KIID_PATH path = aInstance.Path();
KIID_PATH path = aSheetPath.PathWithoutRootUuid();
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 )
{

View File

@ -392,7 +392,12 @@ public:
/**
* @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.
@ -401,14 +406,24 @@ public:
* 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.
*
* @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.
*/
bool AddInstance( const KIID_PATH& aInstance );
bool AddInstance( const SCH_SHEET_PATH& 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.
*/
wxString GetPageNumber( const SCH_SHEET_PATH& aInstance ) const;
@ -416,6 +431,11 @@ public:
/**
* 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] 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()
{
m_current_hash = 0;
@ -523,6 +529,8 @@ SCH_SHEET_LIST::SCH_SHEET_LIST( SCH_SHEET* aSheet, bool aCheckIntegrity )
if( aSheet != nullptr )
{
BuildSheetList( aSheet, aCheckIntegrity );
if( aSheet->IsRootSheet() )
SortByPageNumbers();
}
}
@ -944,27 +952,30 @@ void SCH_SHEET_LIST::UpdateSymbolInstances(
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(),
[ 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() )
{
wxLogTrace( traceSchSheetPaths, "No sheet instance found for path '%s'",
instance.PathWithoutRootUuid().AsString() );
path.PathWithoutRootUuid().AsString() );
continue;
}
SCH_SHEET* sheet = instance.Last();
wxCHECK2( sheet, continue );
sheet->AddInstance( instance.Path() );
sheet->SetPageNumber( instance, it->m_PageNumber );
wxLogTrace( traceSchSheetPaths, "Setting sheet '%s' instance '%s' page number '%s'",
( sheet->GetName().IsEmpty() ) ? wxT( "root" ) : sheet->GetName(),
path.PathWithoutRootUuid().AsString(), it->m_PageNumber );
sheet->AddInstance( path );
sheet->SetPageNumber( path, it->m_PageNumber );
}
}
@ -986,11 +997,11 @@ std::vector<SCH_SHEET_INSTANCE> SCH_SHEET_LIST::GetSheetInstances() const
for( const SCH_SHEET_PATH& path : *this )
{
SCH_SHEET_INSTANCE instance;
const SCH_SHEET* sheet = path.Last();
wxCHECK2( sheet, continue );
SCH_SHEET_INSTANCE instance;
instance.m_Path = path.PathWithoutRootUuid();
instance.m_PageNumber = sheet->GetPageNumber( path );
@ -1031,7 +1042,7 @@ void SCH_SHEET_LIST::SetInitialPageNumbers()
wxCHECK2( sheet, continue );
sheet->AddInstance( instance.Path() );
sheet->AddInstance( instance );
tmp.Printf( "%d", pageNumber );
sheet->SetPageNumber( instance, tmp );
pageNumber += 1;

View File

@ -202,6 +202,8 @@ public:
return retv;
}
bool IsFullPath() const;
/**
* Compare if this is the same sheet path as \a aSheetPathToTest.
*
@ -563,6 +565,11 @@ public:
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;
/**

View File

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

View File

@ -1369,7 +1369,7 @@ int SCH_DRAWING_TOOLS::DrawSheet( const TOOL_EVENT& aEvent )
{
SCH_SHEET_PATH sheetPath = instance;
sheetPath.push_back( sheet );
sheet->AddInstance( sheetPath.Path() );
sheet->AddInstance( sheetPath );
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;
sheetPath.push_back( aSheet );
aSheet->AddInstance( sheetPath.Path() );
aSheet->AddInstance( sheetPath );
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 );
// 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)
BOOST_CHECK_EQUAL( m_empty_path.Last(), nullptr );
@ -135,14 +135,14 @@ BOOST_AUTO_TEST_CASE( Compare )
*/
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.
BOOST_CHECK( m_linear.Last()->AddInstance( m_linear.Path() ) );
m_linear.SetPageNumber( "1" );
BOOST_CHECK_EQUAL( m_linear.GetPageNumber(), "1" );
m_linear.SetPageNumber( "i" );
BOOST_CHECK_EQUAL( m_linear.GetPageNumber(), "i" );
// BOOST_CHECK( m_linear.Last()->AddInstance( m_linear.Path() ) );
// m_linear.SetPageNumber( "1" );
// BOOST_CHECK_EQUAL( m_linear.GetPageNumber(), "1" );
// m_linear.SetPageNumber( "i" );
// BOOST_CHECK_EQUAL( m_linear.GetPageNumber(), "i" );
}