Eeschema: fix incorrect references clearing for shared sheet paths.

Previously, when creating a new instance of a sheet, the full set of references
was cleared.
Moreover, if this sheet has sub-sheets, the annotation was incorrectly handled

Now only (and all) new sheet path(s) created have a reference cleared, as expected.
(new sheet paths can be more than one, if the new instance of the sheet has sub-sheets)

Fixes: lp:1789048
https://bugs.launchpad.net/kicad/+bug/1789048
This commit is contained in:
jean-pierre charras 2018-09-03 12:11:39 +02:00
parent e29e7ff95d
commit 500abd0ac4
8 changed files with 218 additions and 8 deletions

View File

@ -1111,6 +1111,32 @@ void SCH_COMPONENT::ClearAnnotation( SCH_SHEET_PATH* aSheetPath )
}
void SCH_COMPONENT::AddSheetPathReferenceEntry( const wxString& aSheetPathName )
{
if( aSheetPathName.IsEmpty() )
return;
wxString reference_path;
// The full component reference path is aSheetPathName + the component time stamp itself
// full_AR_path is the alternate reference path to search
wxString full_AR_path = aSheetPathName + wxString::Format( "%8.8X", GetTimeStamp() );
for( unsigned int ii = 0; ii < m_PathsAndReferences.GetCount(); ii++ )
{
// Break hierarchical reference in path, ref and multi selection:
reference_path = m_PathsAndReferences[ii].BeforeFirst( ' ' );
// if aSheetPath is found, nothing to do:
if( reference_path.Cmp( full_AR_path ) == 0 )
return;
}
// This entry does not exist: add it, with a (temporary?) reference (last ref used for display)
AddHierarchicalReference( full_AR_path, m_Fields[REFERENCE].GetText(), m_unit );
}
void SCH_COMPONENT::SetOrientation( int aOrientation )
{
TRANSFORM temp = TRANSFORM();

View File

@ -299,6 +299,16 @@ public:
*/
void ClearAnnotation( SCH_SHEET_PATH* aSheetPath );
/**
* Add aSheetPath in m_PathsAndReferences alternate references list,
* if this entry does not exist
* Do nothing if already exists.
* In component lists shared by more than one sheet path, an entry for each
* sheet path must exist to manage references
* @param aSheetPathName is the candidate sheet path name
*/
void AddSheetPathReferenceEntry( const wxString& aSheetPathName );
/**
* Change the time stamp to \a aNewTimeStamp and updates the reference path.
*

View File

@ -1402,13 +1402,19 @@ void SCH_EDIT_FRAME::addCurrentItemToList( bool aRedraw )
if( item->IsNew() )
{
// When a new sheet is added to the hierarchy, a clear annotation can be needed
// for all new sheet paths added by the new sheet (if this sheet is loaded from
// and existing sheet or a existing file, it can also contain subsheets)
bool doClearAnnotation = false;
SCH_SHEET_LIST initial_sheetpathList( g_RootSheet );
if( item->Type() == SCH_SHEET_T )
{
// Fix the size and position of the new sheet using the last values set by
// the m_mouseCaptureCallback function.
m_canvas->SetMouseCapture( NULL, NULL );
if( !EditSheet( (SCH_SHEET*)item, m_CurrentSheet ) )
if( !EditSheet( (SCH_SHEET*)item, m_CurrentSheet, &doClearAnnotation ) )
{
screen->SetCurItem( NULL );
delete item;
@ -1446,6 +1452,14 @@ void SCH_EDIT_FRAME::addCurrentItemToList( bool aRedraw )
wxLogMessage( wxT( "addCurrentItemToList: expected type = SCH_SHEET_PIN_T, actual type = %d" ),
item->Type() );
}
if( doClearAnnotation )
{
// Clear annotation of new sheet paths: the new sheet and its sub-sheets
// If needed the missing alternate references of components will be created
SCH_SCREENS screensList( g_RootSheet );
screensList.ClearAnnotationOfNewSheetPaths( initial_sheetpathList );
}
}
else
{

View File

@ -1111,8 +1111,15 @@ public:
* the current associated screen file name is changed and saved to disk.
*
* Note: the screen is not refresh. The caller is responsible to do that
*
* @param aSheet is the sheet to edit
* @param aHierarchy is the current hierarchy containing aSheet
* @param aClearAnnotationNewItems is a reference to a bool to know if the items managed by
* this sheet need to have their annotation cleared i.e. when an existing item list is used.
* it can happens when the edited sheet used an existying file, or becomes a new instance
* of a already existing sheet.
*/
bool EditSheet( SCH_SHEET* aSheet, SCH_SHEET_PATH* aHierarchy );
bool EditSheet( SCH_SHEET* aSheet, SCH_SHEET_PATH* aHierarchy, bool* aClearAnnotationNewItems );
wxPoint GetLastSheetPinPosition() const { return m_lastSheetPinPosition; }

View File

@ -734,6 +734,24 @@ void SCH_SCREEN::ClearAnnotation( SCH_SHEET_PATH* aSheetPath )
}
void SCH_SCREEN::EnsureAlternateReferencesExist()
{
if( GetClientSheetPathsCount() <= 1 ) // No need for alternate reference
return;
for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() )
{
if( item->Type() != SCH_COMPONENT_T )
continue;
// Add (when not existing) all sheet path entries
for( unsigned int ii = 0; ii < m_clientSheetPathList.GetCount(); ii++ )
((SCH_COMPONENT*)item)->AddSheetPathReferenceEntry( m_clientSheetPathList[ii] );
}
}
void SCH_SCREEN::GetHierarchicalItems( EDA_ITEMS& aItems )
{
SCH_ITEM* item = m_drawList.begin();
@ -1348,6 +1366,51 @@ void SCH_SCREENS::ClearAnnotation()
m_screens[i]->ClearAnnotation( NULL );
}
void SCH_SCREENS::ClearAnnotationOfNewSheetPaths( SCH_SHEET_LIST& aInitialSheetPathList )
{
// Clear the annotation for the components inside new sheetpaths
// not already in aInitialSheetList
SCH_SCREENS screensList( g_RootSheet ); // The list of screens, shared by sheet paths
screensList.BuildClientSheetPathList(); // build the shared by sheet paths, by screen
// Search for new sheet paths, not existing in aInitialSheetPathList
// and existing in sheetpathList
SCH_SHEET_LIST sheetpathList( g_RootSheet );
for( SCH_SHEET_PATH& sheetpath: sheetpathList )
{
bool path_exists = false;
for( const SCH_SHEET_PATH& existing_sheetpath: aInitialSheetPathList )
{
if( existing_sheetpath.Path() == sheetpath.Path() )
{
path_exists = true;
break;
}
}
if( !path_exists )
{
// A new sheet path is found: clear the annotation corresponding to this new path:
SCH_SCREEN* curr_screen = sheetpath.LastScreen();
#if 0 // For test and debug only
wxLogMessage(">>>new path %s <%s> screen %p usage %d",
sheetpath.Path(), sheetpath.PathHumanReadable(),
curr_screen, curr_screen->GetClientSheetPathsCount() );
#endif
// Clear annotation and create the AR for this path, if not exists,
// when the screen is shared by sheet paths.
// Otherwise ClearAnnotation do nothing, because the F1 field is used as
// reference default value and takes the latest displayed value
curr_screen->EnsureAlternateReferencesExist();
curr_screen->ClearAnnotation( &sheetpath );
}
}
}
int SCH_SCREENS::ReplaceDuplicateTimeStamps()
{
EDA_ITEMS items;
@ -1556,3 +1619,28 @@ int SCH_SCREENS::ChangeSymbolLibNickname( const wxString& aFrom, const wxString&
return cnt;
}
void SCH_SCREENS::BuildClientSheetPathList()
{
SCH_SHEET_LIST sheetList( g_RootSheet );
for( SCH_SCREEN* curr_screen = GetFirst(); curr_screen; curr_screen = GetNext() )
curr_screen->GetClientSheetPaths().Clear();
for( SCH_SHEET_PATH& sheetpath: sheetList )
{
SCH_SCREEN* used_screen = sheetpath.LastScreen();
// SEarch for the used_screen in list and add this unique sheet path:
for( SCH_SCREEN* curr_screen = GetFirst(); curr_screen; curr_screen = GetNext() )
{
if( used_screen == curr_screen )
{
curr_screen->GetClientSheetPaths().Add( sheetpath.Path() );
break;
}
}
}
}

View File

@ -50,6 +50,7 @@ class SCH_SHEET_PIN;
class SCH_LINE;
class SCH_TEXT;
class PLOTTER;
class SCH_SHEET_LIST;
enum SCH_LINE_TEST_T
@ -73,6 +74,14 @@ private:
int m_refCount; ///< Number of sheets referencing this screen.
///< Delete when it goes to zero.
/** the list of scheet paths sharing this screen
* used in some annotation calculations to update alternate references
* Note: a screen having a m_refCount = 1 (only one sheet path using it)
* can have many scheet paths sharing this screen, if this sheet is inside
* an other sheet having many instances (one sheet path by parent sheet instance).
*/
wxArrayString m_clientSheetPathList;
/// The size of the paper to print or plot on
PAGE_INFO m_paper; // keep with the MVC 'model' if this class gets split
@ -132,6 +141,17 @@ public:
int GetRefCount() const { return m_refCount; }
/**
* @return the sheet paths count sharing this screen
* if 1 this screen is not in a complex hierarchy: the reference field can be
* used to store the component reference
* if > 1 this screen is in a complex hierarchy, and components must have
* a full alternate reference management
*/
int GetClientSheetPathsCount() { return (int) m_clientSheetPathList.GetCount(); }
wxArrayString& GetClientSheetPaths() { return m_clientSheetPathList; }
/**
* @return A pointer to the first item in the linked list of draw items.
*/
@ -401,6 +421,17 @@ public:
*/
void ClearAnnotation( SCH_SHEET_PATH* aSheetPath );
/**
* For screens shared by many sheetpaths (complex hierarchies):
* to be able to clear or modify any reference related sharing this screen
* (i.e. thie list of components), an entry for each screen path must exist.
* This function creates missing entries, using as default reference the current
* reference field and unit number
* Note: m_clientSheetPathList must be up to date
* ( built by SCH_SCREENS::BuildClientSheetPathList() )
*/
void EnsureAlternateReferencesExist();
/**
* Add all schematic sheet and component objects in the screen to \a aItems.
*
@ -519,6 +550,16 @@ public:
*/
void ClearAnnotation();
/**
* Clear the annotation for the components inside new sheetpaths
* when a complex hierarchy is modified and new sheetpaths added
* when a screen shares more than one sheet path, missing alternate references are added
* and alternate references of new sheet paths are cleared
*
* @param aInitialSheetPathList is the initial sheet paths list of hierarchy before changes.
*/
void ClearAnnotationOfNewSheetPaths( SCH_SHEET_LIST& aInitialSheetPathList );
/**
* Test all sheet and component objects in the schematic for duplicate time stamps
* and replaces them as necessary.
@ -590,6 +631,12 @@ public:
*/
int ChangeSymbolLibNickname( const wxString& aFrom, const wxString& aTo );
/**
* built the list of sheet paths sharing a screen for each screen in use
*/
void BuildClientSheetPathList();
private:
void addScreenToList( SCH_SCREEN* aScreen );
void buildScreenList( SCH_SHEET* aSheet);

View File

@ -1046,8 +1046,28 @@ void SCH_EDIT_FRAME::OnEditItem( wxCommandEvent& aEvent )
}
case SCH_SHEET_T:
if( EditSheet( (SCH_SHEET*) item, m_CurrentSheet ) )
{
bool doClearAnnotation;
bool doRefresh = false;
// Keep trace of existing sheet paths. EditSheet() can modify this list
SCH_SHEET_LIST initial_sheetpathList( g_RootSheet );
doRefresh = EditSheet( (SCH_SHEET*) item, m_CurrentSheet, &doClearAnnotation );
if( doClearAnnotation ) // happens when the current sheet load a existing file
{ // we must clear "new" components annotation
SCH_SCREENS screensList( g_RootSheet );
// We clear annotation of new sheet paths here:
screensList.ClearAnnotationOfNewSheetPaths( initial_sheetpathList );
// Clear annotation of m_CurrentSheet itself, because its sheetpath
// is not a new path, but components managed by its sheet path must have
// their annotation cleared, becuase they are new:
((SCH_SHEET*) item)->GetScreen()->ClearAnnotation( m_CurrentSheet );
}
if( doRefresh )
m_canvas->Refresh();
}
break;
case SCH_SHEET_PIN_T:

View File

@ -42,7 +42,7 @@
#include <dialogs/dialog_sch_sheet_props.h>
bool SCH_EDIT_FRAME::EditSheet( SCH_SHEET* aSheet, SCH_SHEET_PATH* aHierarchy )
bool SCH_EDIT_FRAME::EditSheet( SCH_SHEET* aSheet, SCH_SHEET_PATH* aHierarchy, bool* aClearAnnotationNewItems )
{
if( aSheet == NULL || aHierarchy == NULL )
return false;
@ -331,10 +331,8 @@ bool SCH_EDIT_FRAME::EditSheet( SCH_SHEET* aSheet, SCH_SHEET_PATH* aHierarchy )
return false;
}
if( clearAnnotation )
{
newScreens.ClearAnnotation();
}
if( aClearAnnotationNewItems )
*aClearAnnotationNewItems = clearAnnotation;
m_canvas->MoveCursorToCrossHair();
m_canvas->SetIgnoreMouseEvents( false );