Allow back-annotation of differing values and footprints.

Also fixes a couple of bugs where resolving a textVar reference
to the refDes or unit wouldn't get the correct value in a
hierarchical schematic. (Unlogged.)

Fixes https://gitlab.com/kicad/code/kicad/issues/5397
This commit is contained in:
Jeff Young 2020-08-29 14:41:47 +01:00
parent 306a8f57f7
commit be15053745
17 changed files with 231 additions and 311 deletions

View File

@ -646,11 +646,11 @@ int SCH_REFERENCE_LIST::CheckAnnotation( REPORTER& aReporter )
flatList[ii].GetRef(), flatList[ii].GetRef(),
flatList[ii].m_NumRef, flatList[ii].m_NumRef,
LIB_PART::SubReference( flatList[ii].m_Unit ), LIB_PART::SubReference( flatList[ii].m_Unit ),
flatList[ii].m_Value->GetText(), flatList[ii].m_Value,
flatList[next].GetRef(), flatList[next].GetRef(),
flatList[next].m_NumRef, flatList[next].m_NumRef,
LIB_PART::SubReference( flatList[next].m_Unit ), LIB_PART::SubReference( flatList[next].m_Unit ),
flatList[next].m_Value->GetText() ); flatList[next].m_Value );
aReporter.Report( msg, RPT_SEVERITY_ERROR ); aReporter.Report( msg, RPT_SEVERITY_ERROR );
error++; error++;
@ -670,6 +670,7 @@ SCH_REFERENCE::SCH_REFERENCE( SCH_COMPONENT* aComponent, LIB_PART* aLibPart,
m_Entry = aLibPart; // Warning: can be nullptr for orphan components m_Entry = aLibPart; // Warning: can be nullptr for orphan components
// (i.e. with a symbol library not found) // (i.e. with a symbol library not found)
m_Unit = aComponent->GetUnitSelection( &aSheetPath ); m_Unit = aComponent->GetUnitSelection( &aSheetPath );
m_Footprint = aComponent->GetFootprint( &aSheetPath );
m_SheetPath = aSheetPath; m_SheetPath = aSheetPath;
m_IsNew = false; m_IsNew = false;
m_Flag = 0; m_Flag = 0;
@ -688,7 +689,7 @@ SCH_REFERENCE::SCH_REFERENCE( SCH_COMPONENT* aComponent, LIB_PART* aLibPart,
if( aComponent->GetField( VALUE )->GetText().IsEmpty() ) if( aComponent->GetField( VALUE )->GetText().IsEmpty() )
aComponent->GetField( VALUE )->SetText( wxT( "~" ) ); aComponent->GetField( VALUE )->SetText( wxT( "~" ) );
m_Value = aComponent->GetField( VALUE ); m_Value = aComponent->GetValue( &aSheetPath );
} }

View File

@ -301,9 +301,9 @@ int ERC_TESTER::TestMultiunitFootprints()
SCH_MULTI_UNIT_REFERENCE_MAP refMap; SCH_MULTI_UNIT_REFERENCE_MAP refMap;
sheets.GetMultiUnitComponents( refMap, true ); sheets.GetMultiUnitComponents( refMap, true );
for( auto& component : refMap ) for( std::pair<const wxString, SCH_REFERENCE_LIST>& component : refMap )
{ {
auto& refList = component.second; SCH_REFERENCE_LIST& refList = component.second;
if( refList.GetCount() == 0 ) if( refList.GetCount() == 0 )
{ {
@ -316,10 +316,10 @@ int ERC_TESTER::TestMultiunitFootprints()
wxString unitName; wxString unitName;
wxString unitFP; wxString unitFP;
for( unsigned i = 0; i < component.second.GetCount(); ++i ) for( unsigned i = 0; i < refList.GetCount(); ++i )
{ {
SCH_SHEET_PATH sheetPath = refList.GetItem( i ).GetSheetPath(); SCH_SHEET_PATH sheetPath = refList.GetItem( i ).GetSheetPath();
unitFP = refList.GetItem( i ).GetComp()->GetField( FOOTPRINT )->GetText(); unitFP = refList.GetItem( i ).GetFootprint();
if( !unitFP.IsEmpty() ) if( !unitFP.IsEmpty() )
{ {
@ -329,12 +329,12 @@ int ERC_TESTER::TestMultiunitFootprints()
} }
} }
for( unsigned i = 0; i < component.second.GetCount(); ++i ) for( unsigned i = 0; i < refList.GetCount(); ++i )
{ {
SCH_REFERENCE& secondRef = refList.GetItem( i ); SCH_REFERENCE& secondRef = refList.GetItem( i );
SCH_COMPONENT* secondUnit = secondRef.GetComp(); SCH_COMPONENT* secondUnit = secondRef.GetComp();
wxString secondName = secondUnit->GetRef( &secondRef.GetSheetPath(), true ); wxString secondName = secondUnit->GetRef( &secondRef.GetSheetPath(), true );
const wxString secondFp = secondUnit->GetField( FOOTPRINT )->GetText(); const wxString secondFp = secondRef.GetFootprint();
wxString msg; wxString msg;
if( !secondFp.IsEmpty() && unitFP != secondFp ) if( !secondFp.IsEmpty() && unitFP != secondFp )

View File

@ -926,7 +926,7 @@ bool SCH_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType )
SCH_COMPONENT* cmp = static_cast<SCH_COMPONENT*>( item ); SCH_COMPONENT* cmp = static_cast<SCH_COMPONENT*>( item );
// Update footprint LIB_ID to point to the imported Eagle library // Update footprint LIB_ID to point to the imported Eagle library
auto fpField = cmp->GetField( FOOTPRINT ); SCH_FIELD* fpField = cmp->GetField( FOOTPRINT );
if( !fpField->GetText().IsEmpty() ) if( !fpField->GetText().IsEmpty() )
{ {

View File

@ -369,17 +369,21 @@ void SCH_COMPONENT::Print( RENDER_SETTINGS* aSettings, const wxPoint& aOffset )
void SCH_COMPONENT::AddHierarchicalReference( const KIID_PATH& aPath, const wxString& aRef, void SCH_COMPONENT::AddHierarchicalReference( const KIID_PATH& aPath, const wxString& aRef,
int aUnit ) int aUnit, const wxString& aValue,
const wxString& aFootprint )
{ {
// Search for an existing path and remove it if found (should not occur) // Search for an existing path and remove it if found (should not occur)
for( unsigned ii = 0; ii < m_instanceReferences.size(); ii++ ) for( unsigned ii = 0; ii < m_instanceReferences.size(); ii++ )
{ {
if( m_instanceReferences[ii].m_Path == aPath ) if( m_instanceReferences[ii].m_Path == aPath )
{ {
wxLogTrace( traceSchSheetPaths, wxLogTrace( traceSchSheetPaths, "Removing symbol instance:\n"
"Removing symbol instance:\n sheet path %s\n reference %s, unit %d\n from symbol %s.", " sheet path %s\n"
aPath.AsString(), m_instanceReferences[ii].m_Reference, " reference %s, unit %d from symbol %s.",
m_instanceReferences[ii].m_Unit, m_Uuid.AsString() ); aPath.AsString(),
m_instanceReferences[ii].m_Reference,
m_instanceReferences[ii].m_Unit,
m_Uuid.AsString() );
m_instanceReferences.erase( m_instanceReferences.begin() + ii ); m_instanceReferences.erase( m_instanceReferences.begin() + ii );
ii--; ii--;
@ -390,16 +394,22 @@ void SCH_COMPONENT::AddHierarchicalReference( const KIID_PATH& aPath, const wxSt
instance.m_Path = aPath; instance.m_Path = aPath;
instance.m_Reference = aRef; instance.m_Reference = aRef;
instance.m_Unit = aUnit; instance.m_Unit = aUnit;
instance.m_Value = aValue;
instance.m_Footprint = aFootprint;
wxLogTrace( traceSchSheetPaths, wxLogTrace( traceSchSheetPaths, "Adding symbol instance:\n"
"Adding symbol instance:\n sheet path %s\n reference %s, unit %d\n to symbol %s.", " sheet path %s\n"
aPath.AsString(), aRef, aUnit, m_Uuid.AsString() ); " reference %s, unit %d to symbol %s.",
aPath.AsString(),
aRef,
aUnit,
m_Uuid.AsString() );
m_instanceReferences.push_back( instance ); m_instanceReferences.push_back( instance );
} }
const wxString SCH_COMPONENT::GetRef( const SCH_SHEET_PATH* sheet, bool aIncludeUnit ) const wxString SCH_COMPONENT::GetRef( const SCH_SHEET_PATH* sheet, bool aIncludeUnit ) const
{ {
KIID_PATH path = sheet->Path(); KIID_PATH path = sheet->Path();
wxString ref; wxString ref;
@ -408,10 +418,6 @@ const wxString SCH_COMPONENT::GetRef( const SCH_SHEET_PATH* sheet, bool aInclude
{ {
if( instance.m_Path == path ) if( instance.m_Path == path )
{ {
wxLogTrace( traceSchSheetPaths,
"Setting symbol instance:\n sheet path %s\n reference %s, unit %d\n found in symbol %s.",
path.AsString(), instance.m_Reference, instance.m_Unit, m_Uuid.AsString() );
ref = instance.m_Reference; ref = instance.m_Reference;
break; break;
} }
@ -423,7 +429,7 @@ const wxString SCH_COMPONENT::GetRef( const SCH_SHEET_PATH* sheet, bool aInclude
// the same component references, but perhaps this is best. // the same component references, but perhaps this is best.
if( ref.IsEmpty() && !GetField( REFERENCE )->GetText().IsEmpty() ) if( ref.IsEmpty() && !GetField( REFERENCE )->GetText().IsEmpty() )
{ {
SetRef( sheet, GetField( REFERENCE )->GetText() ); const_cast<SCH_COMPONENT*>( this )->SetRef( sheet, GetField( REFERENCE )->GetText() );
ref = GetField( REFERENCE )->GetText(); ref = GetField( REFERENCE )->GetText();
} }
@ -541,7 +547,6 @@ int SCH_COMPONENT::GetUnitSelection( const SCH_SHEET_PATH* aSheet ) const
void SCH_COMPONENT::SetUnitSelection( const SCH_SHEET_PATH* aSheet, int aUnitSelection ) void SCH_COMPONENT::SetUnitSelection( const SCH_SHEET_PATH* aSheet, int aUnitSelection )
{ {
KIID_PATH path = aSheet->Path(); KIID_PATH path = aSheet->Path();
bool notInArray = true;
// check to see if it is already there before inserting it // check to see if it is already there before inserting it
for( COMPONENT_INSTANCE_REFERENCE& instance : m_instanceReferences ) for( COMPONENT_INSTANCE_REFERENCE& instance : m_instanceReferences )
@ -549,12 +554,86 @@ void SCH_COMPONENT::SetUnitSelection( const SCH_SHEET_PATH* aSheet, int aUnitSel
if( instance.m_Path == path ) if( instance.m_Path == path )
{ {
instance.m_Unit = aUnitSelection; instance.m_Unit = aUnitSelection;
notInArray = false; return;
} }
} }
if( notInArray ) // didn't find it; better add it
AddHierarchicalReference( path, m_prefix, aUnitSelection ); AddHierarchicalReference( path, m_prefix, aUnitSelection );
}
const wxString SCH_COMPONENT::GetValue( const SCH_SHEET_PATH* sheet ) const
{
KIID_PATH path = sheet->Path();
for( const COMPONENT_INSTANCE_REFERENCE& instance : m_instanceReferences )
{
if( instance.m_Path == path && !instance.m_Footprint.IsEmpty() )
{
SCH_FIELD dummy( wxDefaultPosition, VALUE, const_cast<SCH_COMPONENT*>( this ) );
dummy.SetText( instance.m_Value );
return dummy.GetShownText();
}
}
return GetField( VALUE )->GetShownText();
}
void SCH_COMPONENT::SetValue( const SCH_SHEET_PATH* sheet, const wxString& aValue )
{
KIID_PATH path = sheet->Path();
// check to see if it is already there before inserting it
for( COMPONENT_INSTANCE_REFERENCE& instance : m_instanceReferences )
{
if( instance.m_Path == path )
{
instance.m_Value = aValue;
return;
}
}
// didn't find it; better add it
AddHierarchicalReference( path, m_prefix, m_unit, aValue, wxEmptyString );
}
const wxString SCH_COMPONENT::GetFootprint( const SCH_SHEET_PATH* sheet ) const
{
KIID_PATH path = sheet->Path();
for( const COMPONENT_INSTANCE_REFERENCE& instance : m_instanceReferences )
{
if( instance.m_Path == path && !instance.m_Footprint.IsEmpty() )
{
SCH_FIELD dummy( wxDefaultPosition, FOOTPRINT, const_cast<SCH_COMPONENT*>( this ) );
dummy.SetText( instance.m_Footprint );
return dummy.GetShownText();
}
}
return GetField( FOOTPRINT )->GetShownText();
}
void SCH_COMPONENT::SetFootprint( const SCH_SHEET_PATH* sheet, const wxString& aFootprint )
{
KIID_PATH path = sheet->Path();
// check to see if it is already there before inserting it
for( COMPONENT_INSTANCE_REFERENCE& instance : m_instanceReferences )
{
if( instance.m_Path == path )
{
instance.m_Footprint = aFootprint;
return;
}
}
// didn't find it; better add it
AddHierarchicalReference( path, m_prefix, m_unit, wxEmptyString, aFootprint );
} }
@ -793,11 +872,21 @@ void SCH_COMPONENT::GetContextualTextVars( wxArrayString* aVars ) const
bool SCH_COMPONENT::ResolveTextVar( wxString* token, int aDepth ) const bool SCH_COMPONENT::ResolveTextVar( wxString* token, int aDepth ) const
{ {
SCHEMATIC* schematic = Schematic();
for( int i = 0; i < MANDATORY_FIELDS; ++i ) for( int i = 0; i < MANDATORY_FIELDS; ++i )
{ {
if( token->IsSameAs( m_Fields[ i ].GetCanonicalName().Upper() ) ) if( token->IsSameAs( m_Fields[ i ].GetCanonicalName().Upper() ) )
{ {
*token = m_Fields[ i ].GetShownText( aDepth + 1 ); if( i == REFERENCE && schematic )
*token = GetRef( &schematic->CurrentSheet(), true );
else if( i == VALUE && schematic )
*token = GetValue( &schematic->CurrentSheet() );
else if( i == FOOTPRINT && schematic )
*token = GetFootprint( &schematic->CurrentSheet() );
else
*token = m_Fields[ i ].GetShownText( aDepth + 1 );
return true; return true;
} }
} }
@ -814,23 +903,42 @@ bool SCH_COMPONENT::ResolveTextVar( wxString* token, int aDepth ) const
if( token->IsSameAs( wxT( "FOOTPRINT_LIBRARY" ) ) ) if( token->IsSameAs( wxT( "FOOTPRINT_LIBRARY" ) ) )
{ {
const SCH_FIELD& field = m_Fields[ FOOTPRINT ]; wxString footprint;
wxArrayString parts = wxSplit( field.GetText(), ':' );
if( schematic )
footprint = GetFootprint( &schematic->CurrentSheet() );
else
footprint = m_Fields[ FOOTPRINT ].GetShownText();
wxArrayString parts = wxSplit( footprint, ':' );
*token = parts[ 0 ]; *token = parts[ 0 ];
return true; return true;
} }
else if( token->IsSameAs( wxT( "FOOTPRINT_NAME" ) ) ) else if( token->IsSameAs( wxT( "FOOTPRINT_NAME" ) ) )
{ {
const SCH_FIELD& field = m_Fields[ FOOTPRINT ]; wxString footprint;
wxArrayString parts = wxSplit( field.GetText(), ':' );
if( schematic )
footprint = GetFootprint( &schematic->CurrentSheet() );
else
footprint = m_Fields[ FOOTPRINT ].GetShownText();
wxArrayString parts = wxSplit( footprint, ':' );
*token = parts[ std::min( 1, (int) parts.size() - 1 ) ]; *token = parts[ std::min( 1, (int) parts.size() - 1 ) ];
return true; return true;
} }
else if( token->IsSameAs( wxT( "UNIT" ) ) ) else if( token->IsSameAs( wxT( "UNIT" ) ) )
{ {
*token = LIB_PART::SubReference( GetUnit() ); int unit;
if( schematic )
unit = GetUnitSelection( &schematic->CurrentSheet() );
else
unit = GetUnit();
*token = LIB_PART::SubReference( unit );
return true; return true;
} }
@ -1238,9 +1346,9 @@ void SCH_COMPONENT::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, MSG_PANEL_ITEMS& aL
} }
// Display the current associated footprint, if exists. // Display the current associated footprint, if exists.
if( !GetField( FOOTPRINT )->IsVoid() ) msg = GetFootprint( &schframe->GetCurrentSheet() );
msg = GetField( FOOTPRINT )->GetShownText();
else if( msg.IsEmpty() )
msg = _( "<Unknown>" ); msg = _( "<Unknown>" );
aList.push_back( MSG_PANEL_ITEM( _( "Footprint" ), msg, DARKRED ) ); aList.push_back( MSG_PANEL_ITEM( _( "Footprint" ), msg, DARKRED ) );

View File

@ -514,7 +514,7 @@ public:
* *
* @return the reference for the sheet. * @return the reference for the sheet.
*/ */
const wxString GetRef( const SCH_SHEET_PATH* aSheet, bool aIncludeUnit = false ); const wxString GetRef( const SCH_SHEET_PATH* aSheet, bool aIncludeUnit = false ) const;
/** /**
* Set the reference for the given sheet path for this symbol. * Set the reference for the given sheet path for this symbol.
@ -538,17 +538,28 @@ public:
* timestamp&gt like /05678E50/A23EF560) * timestamp&gt like /05678E50/A23EF560)
* @param aRef is the local reference like C45, R56 * @param aRef is the local reference like C45, R56
* @param aUnit is the unit selection used for symbols with multiple units per package. * @param aUnit is the unit selection used for symbols with multiple units per package.
* @param aValue is the value used for this instance
* @param aFootprint is the footprint used for this instance (which might have different
* hole spacing or other board-specific changes from other intances)
*/ */
void AddHierarchicalReference( const KIID_PATH& aPath, void AddHierarchicalReference( const KIID_PATH& aPath,
const wxString& aRef, const wxString& aRef,
int aUnit ); int aUnit,
const wxString& aValue = wxEmptyString,
const wxString& aFootprint = wxEmptyString );
// returns the unit selection, for the given sheet path. // Returns the instance-specific unit selection for the given sheet path.
int GetUnitSelection( const SCH_SHEET_PATH* aSheet ) const; int GetUnitSelection( const SCH_SHEET_PATH* aSheet ) const;
// Set the unit selection, for the given sheet path.
void SetUnitSelection( const SCH_SHEET_PATH* aSheet, int aUnitSelection ); void SetUnitSelection( const SCH_SHEET_PATH* aSheet, int aUnitSelection );
// Returns the instance-specific value for the given sheet path.
const wxString GetValue( const SCH_SHEET_PATH* sheet ) const;
void SetValue( const SCH_SHEET_PATH* sheet, const wxString& aValue );
// Returns the instance-specific footprint assignment for the given sheet path.
const wxString GetFootprint( const SCH_SHEET_PATH* sheet ) const;
void SetFootprint( const SCH_SHEET_PATH* sheet, const wxString& aFootprint );
// Geometric transforms (used in block operations): // Geometric transforms (used in block operations):
void Move( const wxPoint& aMoveVector ) override void Move( const wxPoint& aMoveVector ) override

View File

@ -44,20 +44,14 @@
*/ */
//#define SEXPR_SCHEMATIC_FILE_VERSION 20200310 // Initial version. Sheet fields were named //#define SEXPR_SCHEMATIC_FILE_VERSION 20200310 // Initial version. Sheet fields were named
// incorectly (using symbol field vocabulary). // incorectly (using symbol field vocabulary).
//#define SEXPR_SCHEMATIC_FILE_VERSION 20200506 // Used "page" instead of "paper" for paper //#define SEXPR_SCHEMATIC_FILE_VERSION 20200506 // Used "page" instead of "paper" for paper
// sizes. // sizes.
//#define SEXPR_SCHEMATIC_FILE_VERSION 20200512 // Add support for exclude from BOM. //#define SEXPR_SCHEMATIC_FILE_VERSION 20200512 // Add support for exclude from BOM.
//#define SEXPR_SCHEMATIC_FILE_VERSION 20200602 // Add support for exclude from board. //#define SEXPR_SCHEMATIC_FILE_VERSION 20200602 // Add support for exclude from board.
//#define SEXPR_SCHEMATIC_FILE_VERSION 20200608 // Add support for bus and junction properties. //#define SEXPR_SCHEMATIC_FILE_VERSION 20200608 // Add support for bus and junction properties.
//#define SEXPR_SCHEMATIC_FILE_VERSION 20200618 // Disallow duplicate field ids. //#define SEXPR_SCHEMATIC_FILE_VERSION 20200618 // Disallow duplicate field ids.
//#define SEXPR_SCHEMATIC_FILE_VERSION 20200714 // Add alternate pin definitions. //#define SEXPR_SCHEMATIC_FILE_VERSION 20200714 // Add alternate pin definitions.
//#define SEXPR_SCHEMATIC_FILE_VERSION 20200820 //#define SEXPR_SCHEMATIC_FILE_VERSION 20200820
//#define SEXPR_SCHEMATIC_FILE_VERSION 20200827 // Remove host tag
#define SEXPR_SCHEMATIC_FILE_VERSION 20200827 // Remove host tag #define SEXPR_SCHEMATIC_FILE_VERSION 20200828 // Add footprint to symbol_instances.

View File

@ -54,12 +54,12 @@ class SCH_REFERENCE
///< used to annotate by X or Y position ///< used to annotate by X or Y position
int m_Unit; ///< The unit number for components with multiple parts int m_Unit; ///< The unit number for components with multiple parts
///< per package. ///< per package.
wxString m_Value; ///< The component value.
wxString m_Footprint; ///< The footprint assigned.
SCH_SHEET_PATH m_SheetPath; ///< The sheet path for this reference. SCH_SHEET_PATH m_SheetPath; ///< The sheet path for this reference.
bool m_IsNew; ///< True if not yet annotated. bool m_IsNew; ///< True if not yet annotated.
int m_SheetNum; ///< The sheet number for the reference. int m_SheetNum; ///< The sheet number for the reference.
KIID m_Uuid; ///< UUID of the component. KIID m_Uuid; ///< UUID of the component.
EDA_TEXT* m_Value; ///< The component value of the reference. It is the
///< same for all instances.
int m_NumRef; ///< The numeric part of the reference designator. int m_NumRef; ///< The numeric part of the reference designator.
int m_Flag; int m_Flag;
@ -74,7 +74,6 @@ public:
m_Entry = NULL; m_Entry = NULL;
m_Unit = 0; m_Unit = 0;
m_IsNew = false; m_IsNew = false;
m_Value = NULL;
m_NumRef = 0; m_NumRef = 0;
m_Flag = 0; m_Flag = 0;
m_SheetNum = 0; m_SheetNum = 0;
@ -92,9 +91,14 @@ public:
SCH_SHEET_PATH& GetSheetPath() { return m_SheetPath; } SCH_SHEET_PATH& GetSheetPath() { return m_SheetPath; }
int GetUnit() const { return m_Unit; } int GetUnit() const { return m_Unit; }
void SetUnit( int aUnit ) { m_Unit = aUnit; } void SetUnit( int aUnit ) { m_Unit = aUnit; }
const wxString GetValue() const { return m_Value; }
void SetValue( const wxString& aValue ) { m_Value = aValue; }
const wxString GetFootprint() const { return m_Footprint; }
void SetFootprint( const wxString& aFP ) { m_Footprint = aFP; }
void SetSheetNumber( int aSheetNumber ) { m_SheetNum = aSheetNumber; } void SetSheetNumber( int aSheetNumber ) { m_SheetNum = aSheetNumber; }
const wxString GetPath() const const wxString GetPath() const
@ -168,7 +172,7 @@ public:
int CompareValue( const SCH_REFERENCE& item ) const int CompareValue( const SCH_REFERENCE& item ) const
{ {
return m_Value->GetText().Cmp( item.m_Value->GetText() ); return m_Value.Cmp( item.m_Value );
} }
int CompareRef( const SCH_REFERENCE& item ) const int CompareRef( const SCH_REFERENCE& item ) const

View File

@ -1084,49 +1084,6 @@ SCH_TEXT* SCH_SCREEN::GetLabel( const wxPoint& aPosition, int aAccuracy )
} }
bool SCH_SCREEN::SetComponentFootprint( SCH_SHEET_PATH* aSheetPath, const wxString& aReference,
const wxString& aFootPrint, bool aSetVisible )
{
SCH_COMPONENT* component;
bool found = false;
for( SCH_ITEM* item : Items().OfType( SCH_COMPONENT_T ) )
{
component = static_cast<SCH_COMPONENT*>( item );
if( aReference.CmpNoCase( component->GetRef( aSheetPath ) ) == 0 )
{
// Found: Init Footprint Field
/* Give a reasonable value to the field position and
* orientation, if the text is empty at position 0, because
* it is probably not yet initialized
*/
SCH_FIELD * fpfield = component->GetField( FOOTPRINT );
if( fpfield->GetText().IsEmpty()
&& ( fpfield->GetTextPos() == component->GetPosition() ) )
{
fpfield->SetTextAngle( component->GetField( VALUE )->GetTextAngle() );
fpfield->SetTextPos( component->GetField( VALUE )->GetTextPos() );
fpfield->SetTextSize( component->GetField( VALUE )->GetTextSize() );
if( fpfield->GetTextAngle() == 0.0 )
fpfield->Offset( wxPoint( 0, Mils2iu( 100 ) ) );
else
fpfield->Offset( wxPoint( Mils2iu( 100 ), 0 ) );
}
fpfield->SetText( aFootPrint );
fpfield->SetVisible( aSetVisible );
found = true;
}
}
return found;
}
void SCH_SCREEN::AddLibSymbol( LIB_PART* aLibSymbol ) void SCH_SCREEN::AddLibSymbol( LIB_PART* aLibSymbol )
{ {
wxCHECK( aLibSymbol, /* void */ ); wxCHECK( aLibSymbol, /* void */ );

View File

@ -452,19 +452,6 @@ public:
*/ */
SCH_TEXT* GetLabel( const wxPoint& aPosition, int aAccuracy = 0 ); SCH_TEXT* GetLabel( const wxPoint& aPosition, int aAccuracy = 0 );
/**
* Search this screen for a symbol with \a aReference and set the footprint field to
* \a aFootPrint if found.
*
* @param aSheetPath The sheet path used to look up the reference designator.
* @param aReference The reference designator of the component.
* @param aFootPrint The value to set the footprint field.
* @param aSetVisible The value to set the field visibility flag.
* @return True if \a aReference was found otherwise false.
*/
bool SetComponentFootprint( SCH_SHEET_PATH* aSheetPath, const wxString& aReference,
const wxString& aFootPrint, bool aSetVisible );
/** /**
* Fetch a list of unique #LIB_PART object pointers required to properly render each * Fetch a list of unique #LIB_PART object pointers required to properly render each
* #SCH_COMPONENT in this schematic. * #SCH_COMPONENT in this schematic.

View File

@ -1835,8 +1835,18 @@ void SCH_SEXPR_PARSER::parseSchSymbolInstances( SCH_SCREEN* aScreen )
NeedRIGHT(); NeedRIGHT();
break; break;
case T_value:
instance.m_Value = FromUTF8();
NeedRIGHT();
break;
case T_footprint:
instance.m_Footprint = FromUTF8();
NeedRIGHT();
break;
default: default:
Expecting( "path or unit" ); Expecting( "path, unit, value or footprint" );
} }
} }

View File

@ -20,8 +20,6 @@
*/ */
#include <algorithm> #include <algorithm>
#include <boost/algorithm/string/join.hpp>
#include <cctype>
// For some reason wxWidgets is built with wxUSE_BASE64 unset so expose the wxWidgets // For some reason wxWidgets is built with wxUSE_BASE64 unset so expose the wxWidgets
// base64 code. // base64 code.
@ -29,7 +27,6 @@
#include <wx/base64.h> #include <wx/base64.h>
#include <wx/mstream.h> #include <wx/mstream.h>
#include <advanced_config.h> #include <advanced_config.h>
#include <build_version.h>
#include <pgm_base.h> #include <pgm_base.h>
#include <trace_helpers.h> #include <trace_helpers.h>
#include <sch_bitmap.h> #include <sch_bitmap.h>
@ -183,22 +180,11 @@ static float getPinAngle( int aOrientation )
{ {
switch( aOrientation ) switch( aOrientation )
{ {
case PIN_RIGHT: case PIN_RIGHT: return 0.0;
return 0.0; case PIN_LEFT: return 180.0;
case PIN_UP: return 90.0;
case PIN_LEFT: case PIN_DOWN: return 270.0;
return 180.0; default: wxFAIL_MSG( "Missing symbol library pin orientation type" ); return 0.0;
case PIN_UP:
return 90.0;
case PIN_DOWN:
return 270.0;
default:
wxFAIL_MSG( "Missing symbol library pin orientation type" );
return 0.0;
} }
} }
@ -726,9 +712,11 @@ void SCH_SEXPR_PLUGIN::Format( SCH_SHEET* aSheet )
{ {
m_out->Print( 2, "(path %s\n", m_out->Print( 2, "(path %s\n",
m_out->Quotew( instances[i].GetPath() ).c_str() ); m_out->Quotew( instances[i].GetPath() ).c_str() );
m_out->Print( 3, "(reference %s) (unit %d)\n", m_out->Print( 3, "(reference %s) (unit %d) (value %s) (footprint %s)\n",
m_out->Quotew( instances[i].GetRef() ).c_str(), m_out->Quotew( instances[i].GetRef() ).c_str(),
instances[i].GetUnit() ); instances[i].GetUnit(),
m_out->Quotew( instances[i].GetValue() ).c_str(),
m_out->Quotew( instances[i].GetFootprint() ).c_str() );
m_out->Print( 2, ")\n" ); m_out->Print( 2, ")\n" );
} }
} }

View File

@ -309,18 +309,6 @@ void SCH_SHEET_PATH::GetMultiUnitComponents( SCH_MULTI_UNIT_REFERENCE_MAP& aRefL
} }
bool SCH_SHEET_PATH::SetComponentFootprint( const wxString& aReference, const wxString& aFootPrint,
bool aSetVisible )
{
SCH_SCREEN* screen = LastScreen();
if( screen == NULL )
return false;
return screen->SetComponentFootprint( this, aReference, aFootPrint, aSetVisible );
}
bool SCH_SHEET_PATH::operator==( const SCH_SHEET_PATH& d1 ) const bool SCH_SHEET_PATH::operator==( const SCH_SHEET_PATH& d1 ) const
{ {
return m_current_hash == d1.GetCurrentHash(); return m_current_hash == d1.GetCurrentHash();
@ -704,18 +692,6 @@ void SCH_SHEET_LIST::GetMultiUnitComponents( SCH_MULTI_UNIT_REFERENCE_MAP &aRefL
} }
bool SCH_SHEET_LIST::SetComponentFootprint( const wxString& aReference,
const wxString& aFootPrint, bool aSetVisible )
{
bool found = false;
for( SCH_SHEET_PATH& sheet : *this )
found = sheet.SetComponentFootprint( aReference, aFootPrint, aSetVisible );
return found;
}
bool SCH_SHEET_LIST::TestForRecursion( const SCH_SHEET_LIST& aSrcSheetHierarchy, bool SCH_SHEET_LIST::TestForRecursion( const SCH_SHEET_LIST& aSrcSheetHierarchy,
const wxString& aDestFileName ) const wxString& aDestFileName )
{ {
@ -767,7 +743,7 @@ SCH_SHEET_PATH* SCH_SHEET_LIST::FindSheetForScreen( SCH_SCREEN* aScreen )
void SCH_SHEET_LIST::UpdateSymbolInstances( void SCH_SHEET_LIST::UpdateSymbolInstances(
const std::vector<COMPONENT_INSTANCE_REFERENCE>& aSymbolInstances ) const std::vector<COMPONENT_INSTANCE_REFERENCE>& aSymbolInstances )
{ {
SCH_REFERENCE_LIST symbolInstances; SCH_REFERENCE_LIST symbolInstances;
@ -777,15 +753,14 @@ void SCH_SHEET_LIST::UpdateSymbolInstances(
// Calculating the name of a path is somewhat expensive; on large designs with many components // Calculating the name of a path is somewhat expensive; on large designs with many components
// this can blow up to a serious amount of time when loading the schematic // this can blow up to a serious amount of time when loading the schematic
auto getName = auto getName = [&pathNameCache]( const KIID_PATH& aPath ) -> const wxString&
[&pathNameCache]( const KIID_PATH& aPath ) -> const wxString& {
{ if( pathNameCache.count( aPath ) )
if( pathNameCache.count( aPath ) ) return pathNameCache.at( aPath );
return pathNameCache.at( aPath );
pathNameCache[aPath] = aPath.AsString(); pathNameCache[aPath] = aPath.AsString();
return pathNameCache[aPath]; return pathNameCache[aPath];
}; };
for( size_t i = 0; i < symbolInstances.GetCount(); i++ ) for( size_t i = 0; i < symbolInstances.GetCount(); i++ )
{ {
@ -794,11 +769,10 @@ void SCH_SHEET_LIST::UpdateSymbolInstances(
wxString path = symbolInstances[i].GetPath(); wxString path = symbolInstances[i].GetPath();
auto it = std::find_if( aSymbolInstances.begin(), aSymbolInstances.end(), auto it = std::find_if( aSymbolInstances.begin(), aSymbolInstances.end(),
[ path, &getName ]( const COMPONENT_INSTANCE_REFERENCE& r ) -> bool [ path, &getName ]( const COMPONENT_INSTANCE_REFERENCE& r ) -> bool
{ {
return path == getName( r.m_Path ); return path == getName( r.m_Path );
} } );
);
if( it == aSymbolInstances.end() ) if( it == aSymbolInstances.end() )
{ {
@ -813,7 +787,8 @@ void SCH_SHEET_LIST::UpdateSymbolInstances(
// Symbol instance paths are stored and looked up in memory with the root path so use // Symbol instance paths are stored and looked up in memory with the root path so use
// the full path here. // the full path here.
symbol->AddHierarchicalReference( symbolInstances[i].GetSheetPath().Path(), symbol->AddHierarchicalReference( symbolInstances[i].GetSheetPath().Path(),
it->m_Reference, it->m_Unit ); it->m_Reference, it->m_Unit, it->m_Value,
it->m_Footprint );
symbol->GetField( REFERENCE )->SetText( it->m_Reference ); symbol->GetField( REFERENCE )->SetText( it->m_Reference );
} }
} }

View File

@ -43,8 +43,14 @@
struct COMPONENT_INSTANCE_REFERENCE struct COMPONENT_INSTANCE_REFERENCE
{ {
KIID_PATH m_Path; KIID_PATH m_Path;
// Things that can be annotated:
wxString m_Reference; wxString m_Reference;
int m_Unit; int m_Unit;
// Things that can be back-annotated:
wxString m_Value;
wxString m_Footprint;
}; };
@ -276,19 +282,6 @@ public:
void GetMultiUnitComponents( SCH_MULTI_UNIT_REFERENCE_MAP &aRefList, void GetMultiUnitComponents( SCH_MULTI_UNIT_REFERENCE_MAP &aRefList,
bool aIncludePowerSymbols = true ) const; bool aIncludePowerSymbols = true ) const;
/**
* Function SetFootprintField
* searches last sheet in the path for a component with \a aReference and set the footprint
* field to \a aFootPrint if found.
*
* @param aReference The reference designator of the component.
* @param aFootPrint The value to set the footprint field.
* @param aSetVisible The value to set the field visibility flag.
* @return true if \a aReference was found otherwise false.
*/
bool SetComponentFootprint( const wxString& aReference, const wxString& aFootPrint,
bool aSetVisible );
/** /**
* Function TestForRecursion * Function TestForRecursion
* *
@ -409,19 +402,6 @@ public:
void GetMultiUnitComponents( SCH_MULTI_UNIT_REFERENCE_MAP &aRefList, void GetMultiUnitComponents( SCH_MULTI_UNIT_REFERENCE_MAP &aRefList,
bool aIncludePowerSymbols = true ) const; bool aIncludePowerSymbols = true ) const;
/**
* Function SetFootprintField
* searches all the sheets for a component with \a aReference and set the footprint
* field to \a aFootPrint if found.
*
* @param aReference The reference designator of the component.
* @param aFootPrint The value to set the footprint field.
* @param aSetVisible The value to set the field visibility flag.
* @return True if \a aReference was found otherwise false.
*/
bool SetComponentFootprint( const wxString& aReference, const wxString& aFootPrint,
bool aSetVisible );
/** /**
* Function TestForRecursion * Function TestForRecursion
* *

View File

@ -33,6 +33,7 @@ end
extends extends
fill fill
font font
footprint
global_label global_label
hide hide
hierarchical_label hierarchical_label
@ -117,6 +118,7 @@ type
unit unit
unspecified unspecified
uuid uuid
value
version version
width width
wire wire

View File

@ -68,8 +68,7 @@ void SCH_EDITOR_CONTROL::BackAnnotateFootprints( const std::string& aChangedSetO
wxString reference = (UTF8&) ref->second.front().first; wxString reference = (UTF8&) ref->second.front().first;
// Ensure the "fpid" node contains a footprint name, // Ensure the "fpid" node contains a footprint name, and get it if exists
// and get it if exists
if( ref->second.get_child( "fpid" ).size() ) if( ref->second.get_child( "fpid" ).size() )
{ {
wxString tmp = (UTF8&) ref->second.get_child( "fpid" ).front().first; wxString tmp = (UTF8&) ref->second.get_child( "fpid" ).front().first;
@ -87,16 +86,17 @@ void SCH_EDITOR_CONTROL::BackAnnotateFootprints( const std::string& aChangedSetO
// Note: it can be not unique (multiple parts per package) // Note: it can be not unique (multiple parts per package)
// So we *do not* stop the search here // So we *do not* stop the search here
SCH_COMPONENT* component = refs[ii].GetComp(); SCH_COMPONENT* component = refs[ii].GetComp();
SCH_FIELD* fpfield = component->GetField( FOOTPRINT ); SCH_SHEET_PATH* sheetPath = &refs[ii].GetSheetPath();
const wxString& oldfp = fpfield->GetText(); wxString oldfp = refs[ii].GetFootprint();
if( !oldfp && fpfield->IsVisible() ) if( oldfp.IsEmpty() && component->GetField( FOOTPRINT )->IsVisible() )
fpfield->SetVisible( false ); component->GetField( FOOTPRINT )->SetVisible( false );
if( oldfp != footprint ) if( oldfp != footprint )
{
isChanged = true; isChanged = true;
component->SetFootprint( sheetPath, footprint );
fpfield->SetText( footprint ); }
} }
} }
} }
@ -185,9 +185,9 @@ bool SCH_EDITOR_CONTROL::processCmpToFootprintLinkFile( const wxString& aFullFil
// Note: it can be not unique (multiple units per part) // Note: it can be not unique (multiple units per part)
// So we *do not* stop the search here // So we *do not* stop the search here
SCH_COMPONENT* component = referencesList[ii].GetComp(); SCH_COMPONENT* component = referencesList[ii].GetComp();
SCH_FIELD* fpfield = component->GetField( FOOTPRINT ); SCH_SHEET_PATH* sheetPath = &referencesList[ii].GetSheetPath();
fpfield->SetText( footprint ); component->SetFootprint( sheetPath, footprint );
if( aForceVisibilityState ) if( aForceVisibilityState )
component->GetField( FOOTPRINT )->SetVisible( aVisibilityState ); component->GetField( FOOTPRINT )->SetVisible( aVisibilityState );

View File

@ -80,7 +80,6 @@ bool BACK_ANNOTATE::BackAnnotateSymbols( const std::string& aNetlist )
getChangeList(); getChangeList();
checkForUnusedSymbols(); checkForUnusedSymbols();
checkSharedSchematicErrors();
applyChangelist(); applyChangelist();
@ -295,88 +294,6 @@ void BACK_ANNOTATE::checkForUnusedSymbols()
} }
bool BACK_ANNOTATE::checkReuseViolation( PCB_MODULE_DATA& aFirst, PCB_MODULE_DATA& aSecond )
{
if( m_processFootprints && aFirst.m_footprint != aSecond.m_footprint )
return false;
if( m_processValues && aFirst.m_value != aSecond.m_value )
return false;
return true;
}
void BACK_ANNOTATE::checkSharedSchematicErrors()
{
std::sort( m_changelist.begin(), m_changelist.end(),
[]( CHANGELIST_ITEM& a, CHANGELIST_ITEM& b )
{
return a.first.GetComp() > b.first.GetComp();
} );
// We don't check that if no footprints or values updating
if( !m_processFootprints && !m_processValues )
return;
// We will count how many times every component used in our changelist
// Component in this case is SCH_COMPONENT which can be used by more than one symbol
int usageCount = 1;
for( auto it = m_changelist.begin(); it != m_changelist.end(); ++it )
{
int compUsage = it->first.GetComp()->GetInstanceReferences().size();
if( compUsage == 1 )
continue;
// If that's not the last reference in list and references share same component
if( ( it + 1 ) != m_changelist.end() && it->first.GetComp() == ( it + 1 )->first.GetComp() )
{
++usageCount;
if( !checkReuseViolation( *it->second, *( it + 1 )->second ) )
{
// Refs share same component but have different values or footprints
it->first.GetComp()->SetFlags( SKIP_STRUCT );
wxString msg;
msg.Printf( _( "\"%s\" and \"%s\" use the same schematic symbol.\n"
"They cannot have different footprints or values." ),
( it + 1 )->second->m_ref,
it->second->m_ref );
m_reporter.ReportTail( msg, RPT_SEVERITY_ERROR );
}
}
else
{
/* Next ref uses different component, so we count all components number for current
one. We compare that number to stored in the component itself. If that differs, it
means that this particular component is reused in some other project. */
if( !m_ignoreOtherProjects && compUsage > usageCount )
{
SCH_COMPONENT* comp = it->first.GetComp();
PCB_MODULE_DATA tmp{ "",
comp->GetField( FOOTPRINT )->GetText(),
comp->GetField( VALUE )->GetText(),
{} };
if( !checkReuseViolation( tmp, *it->second ) )
{
it->first.GetComp()->SetFlags( SKIP_STRUCT );
wxString msg;
msg.Printf( _( "Unable to change \"%s\" footprint or value because associated"
" symbol is reused in the another project" ),
it->second->m_ref );
m_reporter.ReportTail( msg, RPT_SEVERITY_ERROR );
}
}
usageCount = 1;
}
}
}
void BACK_ANNOTATE::applyChangelist() void BACK_ANNOTATE::applyChangelist()
{ {
std::set<wxString> handledNetChanges; std::set<wxString> handledNetChanges;
@ -389,8 +306,8 @@ void BACK_ANNOTATE::applyChangelist()
PCB_MODULE_DATA& module = *item.second; PCB_MODULE_DATA& module = *item.second;
SCH_COMPONENT* comp = ref.GetComp(); SCH_COMPONENT* comp = ref.GetComp();
SCH_SCREEN* screen = ref.GetSheetPath().LastScreen(); SCH_SCREEN* screen = ref.GetSheetPath().LastScreen();
wxString oldFootprint = comp->GetField( FOOTPRINT )->GetText(); wxString oldFootprint = ref.GetFootprint();
wxString oldValue = comp->GetField( VALUE )->GetText(); wxString oldValue = ref.GetValue();
bool skip = ( ref.GetComp()->GetFlags() & SKIP_STRUCT ) > 0; bool skip = ( ref.GetComp()->GetFlags() & SKIP_STRUCT ) > 0;
if( m_processReferences && ref.GetRef() != module.m_ref && !skip ) if( m_processReferences && ref.GetRef() != module.m_ref && !skip )
@ -415,14 +332,14 @@ void BACK_ANNOTATE::applyChangelist()
++m_changesCount; ++m_changesCount;
msg.Printf( _( "Change %s footprint from \"%s\" to \"%s\"." ), msg.Printf( _( "Change %s footprint from \"%s\" to \"%s\"." ),
ref.GetFullRef(), ref.GetFullRef(),
comp->GetField( FOOTPRINT )->GetText(), oldFootprint,
module.m_footprint ); module.m_footprint );
if( !m_dryRun ) if( !m_dryRun )
{ {
m_frame->SaveCopyInUndoList( screen, comp, UNDO_REDO::CHANGED, m_appendUndo ); m_frame->SaveCopyInUndoList( screen, comp, UNDO_REDO::CHANGED, m_appendUndo );
m_appendUndo = true; m_appendUndo = true;
ref.GetComp()->GetField( FOOTPRINT )->SetText( module.m_footprint ); comp->SetFootprint( &ref.GetSheetPath(), module.m_footprint );
} }
m_reporter.ReportHead( msg, RPT_SEVERITY_ACTION ); m_reporter.ReportHead( msg, RPT_SEVERITY_ACTION );
@ -433,14 +350,14 @@ void BACK_ANNOTATE::applyChangelist()
++m_changesCount; ++m_changesCount;
msg.Printf( _( "Change %s value from \"%s\" to \"%s\"." ), msg.Printf( _( "Change %s value from \"%s\" to \"%s\"." ),
ref.GetFullRef(), ref.GetFullRef(),
comp->GetField( VALUE )->GetText(), oldValue,
module.m_value ); module.m_value );
if( !m_dryRun ) if( !m_dryRun )
{ {
m_frame->SaveCopyInUndoList( screen, comp, UNDO_REDO::CHANGED, m_appendUndo ); m_frame->SaveCopyInUndoList( screen, comp, UNDO_REDO::CHANGED, m_appendUndo );
m_appendUndo = true; m_appendUndo = true;
comp->GetField( VALUE )->SetText( module.m_value ); comp->SetValue( &ref.GetSheetPath(), module.m_value );
} }
m_reporter.ReportHead( msg, RPT_SEVERITY_ACTION ); m_reporter.ReportHead( msg, RPT_SEVERITY_ACTION );

View File

@ -121,15 +121,6 @@ private:
int m_changesCount; // Number of user-level changes int m_changesCount; // Number of user-level changes
bool m_appendUndo; bool m_appendUndo;
/**
* @brief Check if modules has different data. Check only if corresponding \ref m_boardAdapter
* flag is rised
* @param aFirst first module to compare
* @param aSecond second module to compare
* @return true if no violation
*/
bool checkReuseViolation( PCB_MODULE_DATA& aFirst, PCB_MODULE_DATA& aSecond );
/** /**
* @brief Parse netlist sent over KiWay epress mail interface and fill \ref m_pcbModules * @brief Parse netlist sent over KiWay epress mail interface and fill \ref m_pcbModules
* @param aPayload - netlist from PCBnew * @param aPayload - netlist from PCBnew
@ -146,11 +137,6 @@ private:
*/ */
void checkForUnusedSymbols(); void checkForUnusedSymbols();
/**
* @brief Check for errors connected to reusing schematic in project or between projects
*/
void checkSharedSchematicErrors();
/** /**
* @brief Apply changelist to the schematic * @brief Apply changelist to the schematic
*/ */