ADDED: schematic/library diff for symbols.

This commit is contained in:
Jeff Young 2023-03-09 11:25:32 +00:00
parent b96f3d085c
commit 2d6ab62da4
24 changed files with 569 additions and 270 deletions

View File

@ -110,6 +110,8 @@ set( COMMON_DLG_SRCS
dialogs/dialog_color_picker_base.cpp dialogs/dialog_color_picker_base.cpp
dialogs/dialog_configure_paths.cpp dialogs/dialog_configure_paths.cpp
dialogs/dialog_configure_paths_base.cpp dialogs/dialog_configure_paths_base.cpp
dialogs/dialog_constraints_reporter.cpp
dialogs/dialog_constraints_reporter_base.cpp
dialogs/dialog_display_html_text_base.cpp dialogs/dialog_display_html_text_base.cpp
dialogs/dialog_edit_library_tables.cpp dialogs/dialog_edit_library_tables.cpp
dialogs/dialog_global_lib_table_config.cpp dialogs/dialog_global_lib_table_config.cpp

View File

@ -1,7 +1,7 @@
/* /*
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2020-2022 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2020-2023 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -21,14 +21,12 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#include <dialog_constraints_reporter.h> #include <dialogs/dialog_constraints_reporter.h>
#include <pcb_edit_frame.h>
#include <tool/tool_manager.h>
#include <widgets/wx_html_report_box.h> #include <widgets/wx_html_report_box.h>
#include <tools/pcb_actions.h>
#include <wx/wxhtml.h> #include <wx/wxhtml.h>
DIALOG_CONSTRAINTS_REPORTER::DIALOG_CONSTRAINTS_REPORTER( PCB_EDIT_FRAME* aParent ) :
DIALOG_CONSTRAINTS_REPORTER::DIALOG_CONSTRAINTS_REPORTER( KIWAY_PLAYER* aParent ) :
DIALOG_CONSTRAINTS_REPORTER_BASE( aParent ), DIALOG_CONSTRAINTS_REPORTER_BASE( aParent ),
m_frame( aParent ) m_frame( aParent )
{ {
@ -50,10 +48,7 @@ void DIALOG_CONSTRAINTS_REPORTER::DeleteAllPages()
void DIALOG_CONSTRAINTS_REPORTER::OnErrorLinkClicked( wxHtmlLinkEvent& event ) void DIALOG_CONSTRAINTS_REPORTER::OnErrorLinkClicked( wxHtmlLinkEvent& event )
{ {
if( event.GetLinkInfo().GetHref() == wxT( "boardsetup" ) ) m_frame->ExecuteRemoteCommand( event.GetLinkInfo().GetHref().ToStdString().c_str() );
m_frame->ShowBoardSetupDialog( _( "Custom Rules" ) );
else if( event.GetLinkInfo().GetHref() == wxT( "drc" ) )
m_frame->GetToolManager()->RunAction( PCB_ACTIONS::runDRC, true );
} }

View File

@ -183,6 +183,20 @@ SCH_ITEM* SCH_EDITOR_CONTROL::FindSymbolAndItem( const wxString* aPath, const wx
} }
/* Execute a remote command sent via a socket on port KICAD_PCB_PORT_SERVICE_NUMBER
*
* Commands are:
*
* $PART: "reference" Put cursor on symbol.
* $PART: "reference" $REF: "ref" Put cursor on symbol reference.
* $PART: "reference" $VAL: "value" Put cursor on symbol value.
* $PART: "reference" $PAD: "pin name" Put cursor on the symbol pin.
* $NET: "netname" Highlight a specified net
* $CLEAR: "HIGHLIGHTED" Clear symbols highlight
*
* $CONFIG Show the Manage Symbol Libraries dialog
* $ERC Show the ERC dialog
*/
void SCH_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline ) void SCH_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline )
{ {
SCH_EDITOR_CONTROL* editor = m_toolManager->GetTool<SCH_EDITOR_CONTROL>(); SCH_EDITOR_CONTROL* editor = m_toolManager->GetTool<SCH_EDITOR_CONTROL>();
@ -199,7 +213,17 @@ void SCH_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline )
CROSS_PROBING_SETTINGS& crossProbingSettings = eeconfig()->m_CrossProbing; CROSS_PROBING_SETTINGS& crossProbingSettings = eeconfig()->m_CrossProbing;
if( strcmp( idcmd, "$NET:" ) == 0 ) if( strcmp( idcmd, "$CONFIG" ) == 0 )
{
GetToolManager()->RunAction( ACTIONS::showSymbolLibTable, true );
return;
}
else if( strcmp( idcmd, "$ERC" ) == 0 )
{
GetToolManager()->RunAction( EE_ACTIONS::runERC, true );
return;
}
else if( strcmp( idcmd, "$NET:" ) == 0 )
{ {
if( !crossProbingSettings.auto_highlight ) if( !crossProbingSettings.auto_highlight )
return; return;
@ -216,8 +240,7 @@ void SCH_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline )
SetStatusText( _( "Selected net:" ) + wxS( " " ) + UnescapeString( netName ) ); SetStatusText( _( "Selected net:" ) + wxS( " " ) + UnescapeString( netName ) );
return; return;
} }
else if( strcmp( idcmd, "$CLEAR:" ) == 0 )
if( strcmp( idcmd, "$CLEAR:" ) == 0 )
{ {
// Cross-probing is now done through selection so we no longer need a clear command // Cross-probing is now done through selection so we no longer need a clear command
return; return;

View File

@ -260,11 +260,14 @@ int LIB_FIELD::compare( const LIB_ITEM& aOther, int aCompareFlags ) const
if( retv != 0 ) if( retv != 0 )
return retv; return retv;
if( GetTextPos().x != tmp->GetTextPos().x ) if( aCompareFlags & LIB_ITEM::COMPARE_FLAGS::EQUALITY )
return GetTextPos().x - tmp->GetTextPos().x; {
if( GetTextPos().x != tmp->GetTextPos().x )
return GetTextPos().x - tmp->GetTextPos().x;
if( GetTextPos().y != tmp->GetTextPos().y ) if( GetTextPos().y != tmp->GetTextPos().y )
return GetTextPos().y - tmp->GetTextPos().y; return GetTextPos().y - tmp->GetTextPos().y;
}
if( GetTextWidth() != tmp->GetTextWidth() ) if( GetTextWidth() != tmp->GetTextWidth() )
return GetTextWidth() - tmp->GetTextWidth(); return GetTextWidth() - tmp->GetTextWidth();

View File

@ -230,157 +230,257 @@ const LIB_SYMBOL& LIB_SYMBOL::operator=( const LIB_SYMBOL& aSymbol )
} }
int LIB_SYMBOL::Compare( const LIB_SYMBOL& aRhs, int aCompareFlags ) const #define REPORT( msg ) { if( aReporter ) aReporter->Report( msg ); }
#define ITEM_DESC( item ) ( item )->GetItemDescription( &unitsProvider )
#define CHECKPOINT { if( retv && !aReporter ) return retv; }
int LIB_SYMBOL::Compare( const LIB_SYMBOL& aRhs, int aCompareFlags, REPORTER* aReporter ) const
{ {
UNITS_PROVIDER unitsProvider( schIUScale, EDA_UNITS::MILLIMETRES );
if( m_me == aRhs.m_me ) if( m_me == aRhs.m_me )
return 0; return 0;
int retv = 0; if( !aReporter && ( aCompareFlags & LIB_ITEM::COMPARE_FLAGS::ERC ) == 0 )
if( ( aCompareFlags & LIB_ITEM::COMPARE_FLAGS::ERC ) == 0 )
{ {
retv = m_name.Cmp( aRhs.m_name ); if( int tmp = m_name.Cmp( aRhs.m_name ) )
return tmp;
if( retv ) if( int tmp = m_libId.compare( aRhs.m_libId ) )
return retv; return tmp;
retv = m_libId.compare( aRhs.m_libId ); if( m_parent.lock() < aRhs.m_parent.lock() )
return -1;
if( retv ) if( m_parent.lock() > aRhs.m_parent.lock() )
return retv; return 1;
} }
if( m_parent.lock() < aRhs.m_parent.lock() ) int retv = 0;
return -1;
if( m_parent.lock() > aRhs.m_parent.lock() )
return 1;
if( m_options != aRhs.m_options ) if( m_options != aRhs.m_options )
return ( m_options == ENTRY_NORMAL ) ? -1 : 1;
if( m_unitCount != aRhs.m_unitCount )
return m_unitCount - aRhs.m_unitCount;
if( m_drawings.size() != aRhs.m_drawings.size() )
return m_drawings.size() - aRhs.m_drawings.size();
LIB_ITEMS_CONTAINER::CONST_ITERATOR lhsItemIt = m_drawings.begin();
LIB_ITEMS_CONTAINER::CONST_ITERATOR rhsItemIt = aRhs.m_drawings.begin();
while( lhsItemIt != m_drawings.end() )
{ {
const LIB_ITEM* lhsItem = static_cast<const LIB_ITEM*>( &(*lhsItemIt) ); retv = ( m_options == ENTRY_NORMAL ) ? -1 : 1;
const LIB_ITEM* rhsItem = static_cast<const LIB_ITEM*>( &(*rhsItemIt) ); REPORT( _( "Power flag differs." ) );
}
wxCHECK( lhsItem && rhsItem, lhsItem - rhsItem ); CHECKPOINT;
if( lhsItem->Type() != rhsItem->Type() ) if( int tmp = m_unitCount - aRhs.m_unitCount )
return lhsItem->Type() - rhsItem->Type(); {
retv = tmp;
REPORT( _( "Unit count differs." ) );
}
// Non-mandatory fields are a special case. They can have different ordinal numbers CHECKPOINT;
// and are compared separately below.
if( lhsItem->Type() == LIB_FIELD_T ) std::set<const LIB_ITEM*> aShapes;
std::set<const LIB_ITEM*> aFields;
std::set<const LIB_ITEM*> aPins;
for( auto it = m_drawings.begin(); it != m_drawings.end(); ++it )
{
if( it->Type() == LIB_SHAPE_T )
aShapes.insert( &(*it) );
else if( it->Type() == LIB_FIELD_T )
aFields.insert( &(*it) );
else if( it->Type() == LIB_PIN_T )
aPins.insert( &(*it) );
}
std::set<const LIB_ITEM*> bShapes;
std::set<const LIB_ITEM*> bFields;
std::set<const LIB_ITEM*> bPins;
for( auto it = aRhs.m_drawings.begin(); it != aRhs.m_drawings.end(); ++it )
{
if( it->Type() == LIB_SHAPE_T )
bShapes.insert( &(*it) );
else if( it->Type() == LIB_FIELD_T )
bFields.insert( &(*it) );
else if( it->Type() == LIB_PIN_T )
bPins.insert( &(*it) );
}
if( int tmp = static_cast<int>( aShapes.size() - bShapes.size() ) )
{
retv = tmp;
REPORT( _( "Graphic item count differs." ) );
}
else
{
for( auto aIt = aShapes.begin(), bIt = bShapes.begin(); aIt != aShapes.end(); aIt++, bIt++ )
{ {
const LIB_FIELD* lhsField = static_cast<const LIB_FIELD*>( lhsItem ); if( int tmp2 = (*aIt)->compare( *(*bIt), aCompareFlags ) )
{
retv = tmp2;
REPORT( wxString::Format( _( "%s differs." ), ITEM_DESC( *aIt ) ) );
}
}
}
if( lhsField->GetId() == VALUE_FIELD ) CHECKPOINT;
{
if( ( aCompareFlags & LIB_ITEM::COMPARE_FLAGS::ERC ) == 0 || IsPower() ) for( const LIB_ITEM* aPinItem : aPins )
retv = lhsItem->compare( *rhsItem, aCompareFlags ); {
} const LIB_PIN* aPin = static_cast<const LIB_PIN*>( aPinItem );
else if( lhsField->IsMandatory() ) const LIB_PIN* bPin = aRhs.GetPin( aPin->GetNumber() );
{ int tmp = 0;
retv = lhsItem->compare( *rhsItem, aCompareFlags );
} if( !bPin )
tmp = 1;
else
tmp = aPinItem->compare( *bPin, aCompareFlags );
if( tmp )
{
retv = tmp;
REPORT( wxString::Format( _( "Pin %s differs." ), aPin->GetNumber() ) );
}
}
if( int tmp = static_cast<int>( aPins.size() - bPins.size() ) )
{
retv = tmp;
REPORT( _( "Pin count differs." ) );
}
for( const LIB_ITEM* aFieldItem : aFields )
{
const LIB_FIELD* aField = static_cast<const LIB_FIELD*>( aFieldItem );
const LIB_FIELD* bField = nullptr;
int tmp = 0;
if( aField->GetId() < MANDATORY_FIELDS )
bField = aRhs.GetFieldById( aField->GetId() );
else
bField = aRhs.FindField( aField->GetName() );
if( !bField )
{
tmp = 1;
}
else if( aField->GetId() == REFERENCE_FIELD )
{
if( aCompareFlags & LIB_ITEM::COMPARE_FLAGS::EQUALITY )
tmp = aFieldItem->compare( *bField, aCompareFlags );
}
else if( aField->GetId() == VALUE_FIELD )
{
if( ( aCompareFlags & LIB_ITEM::COMPARE_FLAGS::ERC ) == 0 || IsPower() )
tmp = aFieldItem->compare( *bField, aCompareFlags );
} }
else else
{ {
retv = lhsItem->compare( *rhsItem, aCompareFlags ); tmp = aFieldItem->compare( *bField, aCompareFlags );
} }
if( retv ) if( tmp )
return retv; {
retv = tmp;
++lhsItemIt; REPORT( wxString::Format( _( "%s field differs." ), aField->GetName( false ) ) );
++rhsItemIt; }
} }
// Compare the optional fields. CHECKPOINT;
for( const LIB_ITEM& item : m_drawings[ LIB_FIELD_T ] )
if( int tmp = static_cast<int>( aFields.size() - bFields.size() ) )
{ {
const LIB_FIELD* field = dynamic_cast<const LIB_FIELD*>( &item ); retv = tmp;
REPORT( _( "Field count differs." ) );
wxCHECK2( field, continue );
// Mandatory fields were already compared above.
if( field->IsMandatory() )
continue;
const LIB_FIELD* foundField = aRhs.FindField( field->GetName() );
if( foundField == nullptr )
return 1;
retv = item.compare( static_cast<const LIB_ITEM&>( *foundField ), aCompareFlags );
if( retv )
return retv;
} }
if( m_fpFilters.GetCount() != aRhs.m_fpFilters.GetCount() ) CHECKPOINT;
return m_fpFilters.GetCount() - aRhs.m_fpFilters.GetCount();
for( size_t i = 0; i < m_fpFilters.GetCount(); i++ ) if( int tmp = static_cast<int>( m_fpFilters.GetCount() - aRhs.m_fpFilters.GetCount() ) )
{ {
retv = m_fpFilters[i].Cmp( aRhs.m_fpFilters[i] ); retv = tmp;
REPORT( _( "Footprint filters differs." ) );
if( retv ) }
return retv; else
{
for( size_t i = 0; i < m_fpFilters.GetCount(); i++ )
{
if( int tmp2 = m_fpFilters[i].Cmp( aRhs.m_fpFilters[i] ) )
{
retv = tmp2;
REPORT( _( "Footprint filters differ." ) );
break;
}
}
} }
retv = m_description.Cmp( aRhs.m_description ); CHECKPOINT;
if( retv ) if( int tmp = m_description.Cmp( aRhs.m_description ) )
return retv; {
retv = tmp;
REPORT( _( "Symbol descriptions differ." ) );
}
retv = m_keyWords.Cmp( aRhs.m_keyWords ); CHECKPOINT;
if( retv ) if( int tmp = m_keyWords.Cmp( aRhs.m_keyWords ) )
return retv; {
retv = tmp;
REPORT( _( "Symbol keywords differ." ) );
}
if( m_pinNameOffset != aRhs.m_pinNameOffset ) CHECKPOINT;
return m_pinNameOffset - aRhs.m_pinNameOffset;
if( m_unitsLocked != aRhs.m_unitsLocked ) if( int tmp = m_pinNameOffset - aRhs.m_pinNameOffset )
return ( m_unitsLocked ) ? 1 : -1; {
retv = tmp;
REPORT( _( "Symbol pin name offsets differ." ) );
}
CHECKPOINT;
if( ( aCompareFlags & LIB_ITEM::COMPARE_FLAGS::ERC ) == 0 ) if( ( aCompareFlags & LIB_ITEM::COMPARE_FLAGS::ERC ) == 0 )
{ {
if( m_showPinNames != aRhs.m_showPinNames ) if( m_showPinNames != aRhs.m_showPinNames )
return ( m_showPinNames ) ? 1 : -1; {
retv = ( m_showPinNames ) ? 1 : -1;
REPORT( _( "Show pin names settings differ." ) );
}
if( m_showPinNumbers != aRhs.m_showPinNumbers ) if( m_showPinNumbers != aRhs.m_showPinNumbers )
return ( m_showPinNumbers ) ? 1 : -1; {
retv = ( m_showPinNumbers ) ? 1 : -1;
REPORT( _( "Show pin numbers settings differ." ) );
}
if( m_includeInBom != aRhs.m_includeInBom ) if( m_includeInBom != aRhs.m_includeInBom )
return ( m_includeInBom ) ? 1 : -1; {
retv = ( m_includeInBom ) ? 1 : -1;
REPORT( _( "Exclude from bill of materials settings differ." ) );
}
if( m_includeOnBoard != aRhs.m_includeOnBoard ) if( m_includeOnBoard != aRhs.m_includeOnBoard )
return ( m_includeOnBoard ) ? 1 : -1; {
retv = ( m_includeOnBoard ) ? 1 : -1;
REPORT( _( "Exclude from board settings differ." ) );
}
} }
// Compare unit display names CHECKPOINT;
if( m_unitDisplayNames < aRhs.m_unitDisplayNames ) if( !aReporter )
{ {
return -1; if( m_unitsLocked != aRhs.m_unitsLocked )
} return ( m_unitsLocked ) ? 1 : -1;
else if( m_unitDisplayNames > aRhs.m_unitDisplayNames )
{ // Compare unit display names
return 1; if( m_unitDisplayNames < aRhs.m_unitDisplayNames )
{
return -1;
}
else if( m_unitDisplayNames > aRhs.m_unitDisplayNames )
{
return 1;
}
} }
return 0; return retv;
} }

View File

@ -36,6 +36,7 @@
class LINE_READER; class LINE_READER;
class OUTPUTFORMATTER; class OUTPUTFORMATTER;
class REPORTER;
class SYMBOL_LIB; class SYMBOL_LIB;
class LIB_SYMBOL; class LIB_SYMBOL;
class LIB_FIELD; class LIB_FIELD;
@ -657,7 +658,8 @@ public:
* 1 if this symbol is greater than \a aRhs * 1 if this symbol is greater than \a aRhs
* 0 if this symbol is the same as \a aRhs * 0 if this symbol is the same as \a aRhs
*/ */
int Compare( const LIB_SYMBOL& aRhs, int aCompareFlags = 0 ) const; int Compare( const LIB_SYMBOL& aRhs, int aCompareFlags = 0,
REPORTER* aReporter = nullptr ) const;
bool operator==( const LIB_SYMBOL* aSymbol ) const { return this == aSymbol; } bool operator==( const LIB_SYMBOL* aSymbol ) const { return this == aSymbol; }
bool operator==( const LIB_SYMBOL& aSymbol ) const bool operator==( const LIB_SYMBOL& aSymbol ) const

View File

@ -253,6 +253,9 @@ void SCH_EDIT_FRAME::doReCreateMenuBar()
inspectMenu->Add( ACTIONS::nextMarker ); inspectMenu->Add( ACTIONS::nextMarker );
inspectMenu->Add( ACTIONS::excludeMarker ); inspectMenu->Add( ACTIONS::excludeMarker );
inspectMenu->AppendSeparator();
inspectMenu->Add( EE_ACTIONS::inspectLibraryDiff );
#ifdef KICAD_SPICE #ifdef KICAD_SPICE
inspectMenu->AppendSeparator(); inspectMenu->AppendSeparator();
inspectMenu->Add( EE_ACTIONS::showSimulator ); inspectMenu->Add( EE_ACTIONS::showSimulator );

View File

@ -166,11 +166,11 @@ public:
wxString GetScreenDesc() const override; wxString GetScreenDesc() const override;
/** /**
* Execute a remote command sent by Pcbnew via a socket connection. * Execute a remote command sent via a socket on port KICAD_SCH_PORT_SERVICE_NUMBER (which
* defaults to 4243).
* *
* When user selects a footprint or pin in Pcbnew, Eeschema shows that same * When user selects a footprint or pin in Pcbnew, Eeschema shows that same symbol or pin
* symbol or pin and moves cursor on the item. The socket port used * and moves cursor on the item.
* is #KICAD_SCH_PORT_SERVICE_NUMBER which defaults to 4243.
* *
* Valid commands are: * Valid commands are:
* \li \c \$PART: \c "reference" Put cursor on symbol. * \li \c \$PART: \c "reference" Put cursor on symbol.

View File

@ -50,6 +50,12 @@ TOOL_ACTION EE_ACTIONS::checkSymbol( "eeschema.InspectionTool.checkSymbol",
_( "Symbol Checker" ), _( "Show the symbol checker window" ), _( "Symbol Checker" ), _( "Show the symbol checker window" ),
BITMAPS::erc ); BITMAPS::erc );
TOOL_ACTION EE_ACTIONS::inspectLibraryDiff( "eeschema.InspectionTool.inspectLibraryDiff",
AS_GLOBAL, 0, "",
_( "Check Symbol against Library..." ),
_( "Check for differences between schematic symbol and its library equivalent" ),
BITMAPS::library );
TOOL_ACTION EE_ACTIONS::showSimulator( "eeschema.EditorControl.showSimulator", TOOL_ACTION EE_ACTIONS::showSimulator( "eeschema.EditorControl.showSimulator",
AS_GLOBAL, 0, "", AS_GLOBAL, 0, "",
_( "Simulator..." ), _( "Simulate circuit in SPICE" ), _( "Simulator..." ), _( "Simulate circuit in SPICE" ),

View File

@ -162,6 +162,7 @@ public:
static TOOL_ACTION schematicSetup; static TOOL_ACTION schematicSetup;
static TOOL_ACTION editPageNumber; static TOOL_ACTION editPageNumber;
static TOOL_ACTION checkSymbol; static TOOL_ACTION checkSymbol;
static TOOL_ACTION inspectLibraryDiff;
static TOOL_ACTION rescueSymbols; static TOOL_ACTION rescueSymbols;
static TOOL_ACTION remapSymbols; static TOOL_ACTION remapSymbols;

View File

@ -26,6 +26,7 @@
#include <id.h> #include <id.h>
#include <kiway.h> #include <kiway.h>
#include <confirm.h> #include <confirm.h>
#include <string_utils.h>
#include <tool/conditional_menu.h> #include <tool/conditional_menu.h>
#include <tool/selection_conditions.h> #include <tool/selection_conditions.h>
#include <tools/ee_actions.h> #include <tools/ee_actions.h>
@ -41,6 +42,8 @@
#include <project.h> #include <project.h>
#include <dialogs/html_message_box.h> #include <dialogs/html_message_box.h>
#include <dialogs/dialog_erc.h> #include <dialogs/dialog_erc.h>
#include <dialogs/dialog_constraints_reporter.h>
#include <widgets/wx_html_report_box.h>
#include <math/util.h> // for KiROUND #include <math/util.h> // for KiROUND
@ -235,6 +238,120 @@ int EE_INSPECTION_TOOL::CheckSymbol( const TOOL_EVENT& aEvent )
} }
int EE_INSPECTION_TOOL::InspectLibraryDiff( const TOOL_EVENT& aEvent )
{
if( !m_frame->IsType( FRAME_SCH ) )
return 0;
EE_SELECTION& selection = m_selectionTool->RequestSelection( { SCH_SYMBOL_T } );
if( selection.Empty() )
{
m_frame->ShowInfoBarError( _( "Select a symbol to diff against its library equivalent." ) );
return 0;
}
if( m_inspectLibraryDiffDialog == nullptr )
{
m_inspectLibraryDiffDialog = std::make_unique<DIALOG_CONSTRAINTS_REPORTER>( m_frame );
m_inspectLibraryDiffDialog->SetTitle( _( "Diff Symbol with Library" ) );
m_inspectLibraryDiffDialog->Connect( wxEVT_CLOSE_WINDOW,
wxCommandEventHandler( EE_INSPECTION_TOOL::onInspectLibraryDiffDialogClosed ),
nullptr, this );
}
m_inspectLibraryDiffDialog->DeleteAllPages();
SCH_SYMBOL* symbol = (SCH_SYMBOL*) selection.Front();
wxString symbolDesc = wxString::Format( _( "Symbol %s" ),
symbol->GetField( REFERENCE_FIELD )->GetText() );
LIB_ID libId = symbol->GetLibId();
wxString libName = libId.GetLibNickname();
wxString symbolName = libId.GetLibItemName();
WX_HTML_REPORT_BOX* r = m_inspectLibraryDiffDialog->AddPage( _( "Summary" ) );
r->Report( wxS( "<h7>" ) + _( "Schematic vs library diff for:" ) + wxS( "</h7>" ) );
r->Report( wxS( "<ul><li>" ) + EscapeHTML( symbolDesc ) + wxS( "</li>" )
+ wxS( "<li>" ) + _( "Library: " ) + EscapeHTML( libName ) + wxS( "</li>" )
+ wxS( "<li>" ) + _( "Library item: " ) + EscapeHTML( symbolName ) + wxS( "</li></ul>" ) );
r->Report( "" );
SYMBOL_LIB_TABLE* libTable = m_frame->Prj().SchSymbolLibTable();
const LIB_TABLE_ROW* libTableRow = libTable->FindRow( libName );
if( !libTableRow )
{
r->Report( _( "The library is not included in the current configuration." )
+ wxS( "&nbsp;&nbsp;&nbsp" )
+ wxS( "<a href='$CONFIG'>" ) + _( "Manage Symbol Libraries" ) + wxS( "</a>" ) );
}
else if( !libTable->HasLibrary( libName, true ) )
{
r->Report( _( "The library is not enabled in the current configuration." )
+ wxS( "&nbsp;&nbsp;&nbsp" )
+ wxS( "<a href='$CONFIG'>" ) + _( "Manage Symbol Libraries" ) + wxS( "</a>" ) );
}
else
{
std::unique_ptr<LIB_SYMBOL> flattenedLibSymbol;
std::unique_ptr<LIB_SYMBOL> flattenedSchSymbol = symbol->GetLibSymbolRef()->Flatten();
try
{
if( LIB_SYMBOL* libAlias = libTable->LoadSymbol( libName, symbolName ) )
flattenedLibSymbol = libAlias->Flatten();
}
catch( const IO_ERROR& )
{
}
if( !flattenedLibSymbol )
{
r->Report( wxString::Format( _( "The library no longer contains the item %s." ),
symbolName ) );
}
else
{
std::vector<LIB_FIELD> fields;
for( SCH_FIELD& field : symbol->GetFields() )
{
fields.emplace_back( LIB_FIELD( flattenedLibSymbol.get(), field.GetId(),
field.GetName( false ) ) );
fields.back().CopyText( field );
fields.back().SetAttributes( field );
}
flattenedSchSymbol->SetFields( fields );
if( flattenedSchSymbol->Compare( *flattenedLibSymbol, 0, r ) == 0 )
r->Report( _( "No relevant differences detected." ) );
}
}
r->Flush();
m_inspectLibraryDiffDialog->FinishInitialization();
m_inspectLibraryDiffDialog->Raise();
m_inspectLibraryDiffDialog->Show( true );
return 0;
}
void EE_INSPECTION_TOOL::onInspectLibraryDiffDialogClosed( wxCommandEvent& event )
{
m_inspectLibraryDiffDialog->Disconnect( wxEVT_CLOSE_WINDOW,
wxCommandEventHandler( EE_INSPECTION_TOOL::onInspectLibraryDiffDialogClosed ),
nullptr, this );
m_inspectLibraryDiffDialog->Destroy();
m_inspectLibraryDiffDialog.release();
}
int EE_INSPECTION_TOOL::RunSimulation( const TOOL_EVENT& aEvent ) int EE_INSPECTION_TOOL::RunSimulation( const TOOL_EVENT& aEvent )
{ {
#ifdef KICAD_SPICE #ifdef KICAD_SPICE
@ -298,7 +415,7 @@ int EE_INSPECTION_TOOL::ShowDatasheet( const TOOL_EVENT& aEvent )
tmp->SetNameShown( name_shown ); tmp->SetNameShown( name_shown );
} }
if( datasheet.IsEmpty() || datasheet == wxT( "~" ) ) if( datasheet.IsEmpty() || datasheet == wxS( "~" ) )
{ {
m_frame->ShowInfoBarError( _( "No datasheet defined." ) ); m_frame->ShowInfoBarError( _( "No datasheet defined." ) );
} }
@ -350,6 +467,7 @@ void EE_INSPECTION_TOOL::setTransitions()
Go( &EE_INSPECTION_TOOL::ExcludeMarker, EE_ACTIONS::excludeMarker.MakeEvent() ); Go( &EE_INSPECTION_TOOL::ExcludeMarker, EE_ACTIONS::excludeMarker.MakeEvent() );
Go( &EE_INSPECTION_TOOL::CheckSymbol, EE_ACTIONS::checkSymbol.MakeEvent() ); Go( &EE_INSPECTION_TOOL::CheckSymbol, EE_ACTIONS::checkSymbol.MakeEvent() );
Go( &EE_INSPECTION_TOOL::InspectLibraryDiff, EE_ACTIONS::inspectLibraryDiff.MakeEvent() );
Go( &EE_INSPECTION_TOOL::RunSimulation, EE_ACTIONS::showSimulator.MakeEvent() ); Go( &EE_INSPECTION_TOOL::RunSimulation, EE_ACTIONS::showSimulator.MakeEvent() );
Go( &EE_INSPECTION_TOOL::ShowDatasheet, EE_ACTIONS::showDatasheet.MakeEvent() ); Go( &EE_INSPECTION_TOOL::ShowDatasheet, EE_ACTIONS::showDatasheet.MakeEvent() );

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2019 CERN * Copyright (C) 2019 CERN
* Copyright (C) 2019-2022 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2019-2023 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -26,6 +26,7 @@
#define EE_INSPECTION_TOOL_H #define EE_INSPECTION_TOOL_H
#include <tools/ee_tool_base.h> #include <tools/ee_tool_base.h>
#include <dialogs/dialog_constraints_reporter.h>
#include <sch_base_frame.h> #include <sch_base_frame.h>
@ -34,7 +35,7 @@ class SCH_BASE_FRAME;
class DIALOG_ERC; class DIALOG_ERC;
class EE_INSPECTION_TOOL : public EE_TOOL_BASE<SCH_BASE_FRAME> class EE_INSPECTION_TOOL : public wxEvtHandler, public EE_TOOL_BASE<SCH_BASE_FRAME>
{ {
public: public:
EE_INSPECTION_TOOL(); EE_INSPECTION_TOOL();
@ -58,6 +59,7 @@ public:
int ExcludeMarker( const TOOL_EVENT& aEvent ); int ExcludeMarker( const TOOL_EVENT& aEvent );
int CheckSymbol( const TOOL_EVENT& aEvent ); int CheckSymbol( const TOOL_EVENT& aEvent );
int InspectLibraryDiff( const TOOL_EVENT& aEvent );
int RunSimulation( const TOOL_EVENT& aEvent ); int RunSimulation( const TOOL_EVENT& aEvent );
@ -67,11 +69,15 @@ public:
int UpdateMessagePanel( const TOOL_EVENT& aEvent ); int UpdateMessagePanel( const TOOL_EVENT& aEvent );
private: private:
void onInspectLibraryDiffDialogClosed( wxCommandEvent& aEvent );
///< @copydoc TOOL_INTERACTIVE::setTransitions(); ///< @copydoc TOOL_INTERACTIVE::setTransitions();
void setTransitions() override; void setTransitions() override;
private: private:
DIALOG_ERC* m_ercDialog; DIALOG_ERC* m_ercDialog;
std::unique_ptr<DIALOG_CONSTRAINTS_REPORTER> m_inspectLibraryDiffDialog;
}; };
#endif /* EE_INSPECTION_TOOL_H */ #endif /* EE_INSPECTION_TOOL_H */

View File

@ -1,7 +1,7 @@
/* /*
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2020-2023 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -24,16 +24,16 @@
#ifndef DIALOG_CONSTRAINTS_REPORTER_H #ifndef DIALOG_CONSTRAINTS_REPORTER_H
#define DIALOG_CONSTRAINTS_REPORTER_H #define DIALOG_CONSTRAINTS_REPORTER_H
#include <dialog_constraints_reporter_base.h> #include <dialogs/dialog_constraints_reporter_base.h>
class PCB_EDIT_FRAME; class KIWAY_PLAYER;
class WX_HTML_REPORT_BOX; class WX_HTML_REPORT_BOX;
class wxHtmlLinkEvent; class wxHtmlLinkEvent;
class DIALOG_CONSTRAINTS_REPORTER : public DIALOG_CONSTRAINTS_REPORTER_BASE class DIALOG_CONSTRAINTS_REPORTER : public DIALOG_CONSTRAINTS_REPORTER_BASE
{ {
public: public:
DIALOG_CONSTRAINTS_REPORTER( PCB_EDIT_FRAME* aParent ); DIALOG_CONSTRAINTS_REPORTER( KIWAY_PLAYER* aParent );
void FinishInitialization(); void FinishInitialization();
@ -51,7 +51,7 @@ public:
int GetPageCount() const; int GetPageCount() const;
protected: protected:
PCB_EDIT_FRAME* m_frame; KIWAY_PLAYER* m_frame;
}; };
#endif // DIALOG_CONSTRAINTS_REPORTER_H #endif // DIALOG_CONSTRAINTS_REPORTER_H

View File

@ -44,8 +44,6 @@ set( PCBNEW_DIALOGS
dialogs/dialog_cleanup_graphics_base.cpp dialogs/dialog_cleanup_graphics_base.cpp
dialogs/dialog_cleanup_tracks_and_vias.cpp dialogs/dialog_cleanup_tracks_and_vias.cpp
dialogs/dialog_cleanup_tracks_and_vias_base.cpp dialogs/dialog_cleanup_tracks_and_vias_base.cpp
dialogs/dialog_constraints_reporter.cpp
dialogs/dialog_constraints_reporter_base.cpp
dialogs/dialog_copper_zones.cpp dialogs/dialog_copper_zones.cpp
dialogs/dialog_copper_zones_base.cpp dialogs/dialog_copper_zones_base.cpp
dialogs/dialog_create_array.cpp dialogs/dialog_create_array.cpp

View File

@ -1,7 +1,7 @@
/* /*
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2019-2022 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2019-2023 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -55,14 +55,17 @@
#include <netlist_reader/netlist_reader.h> #include <netlist_reader/netlist_reader.h>
#include <wx/log.h> #include <wx/log.h>
/* Execute a remote command send by Eeschema via a socket, /* Execute a remote command sent via a socket on port KICAD_PCB_PORT_SERVICE_NUMBER
* port KICAD_PCB_PORT_SERVICE_NUMBER *
* cmdline = received command from Eeschema
* Commands are: * Commands are:
* $NET: "net name" Highlight the given net *
* $NET: "net name" Highlight the given net
* $NETS: "net name 1,net name 2" Highlight all given nets * $NETS: "net name 1,net name 2" Highlight all given nets
* $CLEAR Clear existing highlight * $CLEAR Clear existing highlight
* They are a keyword followed by a quoted string. *
* $CONFIG Show the Manage Footprint Libraries dialog
* $CUSTOM_RULES Show the "Custom Rules" page of the Board Setup dialog
* $DRC Show the DRC dialog
*/ */
void PCB_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline ) void PCB_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline )
{ {
@ -91,7 +94,39 @@ void PCB_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline )
if( idcmd == nullptr ) if( idcmd == nullptr )
return; return;
if( strcmp( idcmd, "$NET:" ) == 0 ) if( strcmp( idcmd, "$CONFIG" ) == 0 )
{
GetToolManager()->RunAction( ACTIONS::showSymbolLibTable, true );
return;
}
else if( strcmp( idcmd, "$CUSTOM_RULES" ) == 0 )
{
ShowBoardSetupDialog( _( "Custom Rules" ) );
return;
}
else if( strcmp( idcmd, "$DRC" ) == 0 )
{
GetToolManager()->RunAction( PCB_ACTIONS::runDRC, true );
return;
}
else if( strcmp( idcmd, "$CLEAR" ) == 0 )
{
if( renderSettings->IsHighlightEnabled() )
{
renderSettings->SetHighlight( false );
view->UpdateAllLayersColor();
}
if( pcb->IsHighLightNetON() )
{
pcb->ResetNetHighLight();
SetMsgPanel( pcb );
}
GetCanvas()->Refresh();
return;
}
else if( strcmp( idcmd, "$NET:" ) == 0 )
{ {
if( !crossProbingSettings.auto_highlight ) if( !crossProbingSettings.auto_highlight )
return; return;
@ -108,9 +143,10 @@ void PCB_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline )
netinfo->GetMsgPanelInfo( this, items ); netinfo->GetMsgPanelInfo( this, items );
SetMsgPanel( items ); SetMsgPanel( items );
} }
}
if( strcmp( idcmd, "$NETS:" ) == 0 ) // fall through to hihglighting section
}
else if( strcmp( idcmd, "$NETS:" ) == 0 )
{ {
if( !crossProbingSettings.auto_highlight ) if( !crossProbingSettings.auto_highlight )
return; return;
@ -145,23 +181,8 @@ void PCB_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline )
} }
netcode = -1; netcode = -1;
}
else if( strcmp( idcmd, "$CLEAR" ) == 0 )
{
if( renderSettings->IsHighlightEnabled() )
{
renderSettings->SetHighlight( false );
view->UpdateAllLayersColor();
}
if( pcb->IsHighLightNetON() ) // fall through to highlighting section
{
pcb->ResetNetHighLight();
SetMsgPanel( pcb );
}
GetCanvas()->Refresh();
return;
} }
BOX2I bbox; BOX2I bbox;

View File

@ -3,7 +3,7 @@
* *
* Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2009-2016 Dick Hollenbeck, dick@softplc.com * Copyright (C) 2009-2016 Dick Hollenbeck, dick@softplc.com
* Copyright (C) 2004-2022 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2004-2023 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -260,10 +260,9 @@ void DIALOG_DRC::OnRunDRCClick( wxCommandEvent& aEvent )
m_saveReport->Enable( false ); m_saveReport->Enable( false );
m_messages->Clear(); m_messages->Clear();
m_messages->Report( _( "DRC incomplete: could not compile custom design rules. " ) m_messages->Report( _( "DRC incomplete: could not compile custom design rules." )
+ wxT( "<a href='boardsetup'>" ) + wxS( "&nbsp;&nbsp;" )
+ _( "Show design rules." ) + wxS( "<a href='$CUSTOM_RULES'>" ) + _( "Show design rules." ) + wxT( "</a>" ) );
+ wxT( "</a>" ) );
m_messages->Flush(); m_messages->Flush();
Raise(); Raise();

View File

@ -77,16 +77,14 @@ public:
#define TEST( a, b, msg ) \ #define TEST( a, b, msg ) \
if( a != b ) \ if( a != b ) \
{ \ { \
diff = true; \
\
if( aReporter ) \ if( aReporter ) \
{ \
aReporter->Report( msg ); \ aReporter->Report( msg ); \
diff = true; \
} \
else \
{ \
return true; \
} \
} \ } \
\
if( diff && !aReporter ) \
return diff; \
/* Prevent binding to else following macro */ \ /* Prevent binding to else following macro */ \
else {} else {}
@ -94,16 +92,14 @@ public:
#define TEST_D( a, b, msg ) \ #define TEST_D( a, b, msg ) \
if( abs( a - b ) > EPSILON ) \ if( abs( a - b ) > EPSILON ) \
{ \ { \
diff = true; \
\
if( aReporter ) \ if( aReporter ) \
{ \
aReporter->Report( msg ); \ aReporter->Report( msg ); \
diff = true; \
} \
else \
{ \
return true; \
} \
} \ } \
\
if( diff && !aReporter ) \
return diff; \
/* Prevent binding to else following macro */ \ /* Prevent binding to else following macro */ \
else {} else {}
@ -112,16 +108,14 @@ public:
|| abs( a.y - b.y ) > EPSILON \ || abs( a.y - b.y ) > EPSILON \
|| abs( a.z - b.z ) > EPSILON ) \ || abs( a.z - b.z ) > EPSILON ) \
{ \ { \
diff = true; \
\
if( aReporter ) \ if( aReporter ) \
{ \
aReporter->Report( msg ); \ aReporter->Report( msg ); \
diff = true; \
} \
else \
{ \
return true; \
} \
} \ } \
\
if( diff && !aReporter ) \
return diff; \
/* Prevent binding to else following macro */ \ /* Prevent binding to else following macro */ \
else {} else {}
@ -491,6 +485,10 @@ bool FOOTPRINT::FootprintNeedsUpdate( const FOOTPRINT* aLibFootprint, REPORTER*
_( "Net tie pad groups differ." ) ); _( "Net tie pad groups differ." ) );
} }
#define REPORT( msg ) { if( aReporter ) aReporter->Report( msg ); }
#define ITEM_DESC( item ) ( item )->GetItemDescription( &unitsProvider )
#define CHECKPOINT { if( diff && !aReporter ) return diff; }
// Text items are really problematic. We don't want to test the reference, but after that // Text items are really problematic. We don't want to test the reference, but after that
// it gets messy. // it gets messy.
// //
@ -521,86 +519,88 @@ bool FOOTPRINT::FootprintNeedsUpdate( const FOOTPRINT* aLibFootprint, REPORTER*
return item->Type() == PCB_FP_SHAPE_T; return item->Type() == PCB_FP_SHAPE_T;
} ); } );
if( aShapes.size() != aShapes.size() )
{
diff = true;
REPORT( _( "Graphic item count differs." ) );
}
else
{
for( auto aIt = aShapes.begin(), bIt = bShapes.begin(); aIt != aShapes.end(); aIt++, bIt++ )
{
if( ( *aIt )->Type() == PCB_FP_SHAPE_T )
{
if( shapeNeedsUpdate( static_cast<FP_SHAPE*>( *aIt ), static_cast<FP_SHAPE*>( *bIt ) ) )
{
diff = true;
REPORT( wxString::Format( _( "%s differs." ), ITEM_DESC( *aIt ) ) );
}
}
}
}
CHECKPOINT;
std::set<PAD*, FOOTPRINT::cmp_pads> aPads( Pads().begin(), Pads().end() ); std::set<PAD*, FOOTPRINT::cmp_pads> aPads( Pads().begin(), Pads().end() );
std::set<PAD*, FOOTPRINT::cmp_pads> bPads( aLibFootprint->Pads().begin(), aLibFootprint->Pads().end() ); std::set<PAD*, FOOTPRINT::cmp_pads> bPads( aLibFootprint->Pads().begin(), aLibFootprint->Pads().end() );
if( aPads.size() != bPads.size() )
{
diff = true;
REPORT( _( "Pad count differs." ) );
}
else
{
for( auto aIt = aPads.begin(), bIt = bPads.begin(); aIt != aPads.end(); aIt++, bIt++ )
{
if( padNeedsUpdate( *aIt, *bIt ) )
{
diff = true;
REPORT( wxString::Format( _( "%s differs." ), ITEM_DESC( *aIt ) ) );
}
else if( aReporter && padHasOverrides( *aIt, *bIt ) )
{
diff = true;
REPORT( wxString::Format( _( "%s has overrides." ), ITEM_DESC( *aIt ) ) );
}
}
}
CHECKPOINT;
std::set<FP_ZONE*, FOOTPRINT::cmp_zones> aZones( Zones().begin(), Zones().end() ); std::set<FP_ZONE*, FOOTPRINT::cmp_zones> aZones( Zones().begin(), Zones().end() );
std::set<FP_ZONE*, FOOTPRINT::cmp_zones> bZones( aLibFootprint->Zones().begin(), aLibFootprint->Zones().end() ); std::set<FP_ZONE*, FOOTPRINT::cmp_zones> bZones( aLibFootprint->Zones().begin(), aLibFootprint->Zones().end() );
TEST( aPads.size(), bPads.size(), _( "Pad count differs." ) ); if( aZones.size() != bZones.size() )
TEST( aZones.size(), bZones.size(), _( "Rule area count differs." ) );
TEST( aShapes.size(), bShapes.size(), _( "Graphic item count differs." ) );
for( auto aIt = aPads.begin(), bIt = bPads.begin(); aIt != aPads.end(); aIt++, bIt++ )
{ {
if( padNeedsUpdate( *aIt, *bIt ) ) diff = true;
{ REPORT( _( "Rule area count differs." ) );
if( aReporter )
{
wxString msg = (*aIt)->GetItemDescription( &unitsProvider );
aReporter->Report( wxString::Format( _( "%s differs." ), msg ) );
diff = true;
}
else
{
return true;
}
}
else if( aReporter && padHasOverrides( *aIt, *bIt ) )
{
wxString msg = (*aIt)->GetItemDescription( &unitsProvider );
aReporter->Report( wxString::Format( _( "%s has overrides." ), msg ) );
diff = true;
}
} }
else
for( auto aIt = aShapes.begin(), bIt = bShapes.begin(); aIt != aShapes.end(); aIt++, bIt++ )
{ {
if( ( *aIt )->Type() == PCB_FP_SHAPE_T ) for( auto aIt = aZones.begin(), bIt = bZones.begin(); aIt != aZones.end(); aIt++, bIt++ )
{ {
if( shapeNeedsUpdate( static_cast<FP_SHAPE*>( *aIt ), static_cast<FP_SHAPE*>( *bIt ) ) ) if( zonesNeedUpdate( *aIt, *bIt ) )
{ {
if( aReporter ) diff = true;
{ REPORT( wxString::Format( _( "%s differs." ), ITEM_DESC( *aIt ) ) );
wxString msg = (*aIt)->GetItemDescription( &unitsProvider );
aReporter->Report( wxString::Format( _( "%s differs." ), msg ) );
diff = true;
}
else
{
return true;
}
} }
} }
} }
for( auto aIt = aZones.begin(), bIt = bZones.begin(); aIt != aZones.end(); aIt++, bIt++ ) CHECKPOINT;
if( Models().size() != aLibFootprint->Models().size() )
{ {
if( zonesNeedUpdate( *aIt, *bIt ) ) diff = true;
{ REPORT( _( "3D model count differs." ) );
if( aReporter )
{
wxString msg = (*aIt)->GetItemDescription( &unitsProvider );
aReporter->Report( wxString::Format( _( "%s differs." ), msg ) );
diff = true;
}
else
{
return true;
}
}
} }
else
TEST( Models().size(), aLibFootprint->Models().size(), _( "3D model count differs." ) );
for( size_t ii = 0; ii < Models().size(); ++ii )
{ {
if( modelsNeedUpdate( Models()[ii], aLibFootprint->Models()[ii], aReporter ) ) for( size_t ii = 0; ii < Models().size(); ++ii )
{ {
if( aReporter ) if( modelsNeedUpdate( Models()[ii], aLibFootprint->Models()[ii], aReporter ) )
diff = true; diff = true;
else
return true;
} }
} }

View File

@ -1,7 +1,7 @@
/* /*
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2019-2022 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2019-2023 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -173,8 +173,9 @@ wxString BOARD_INSPECTION_TOOL::getItemDescription( BOARD_ITEM* aItem )
void BOARD_INSPECTION_TOOL::reportCompileError( REPORTER* r ) void BOARD_INSPECTION_TOOL::reportCompileError( REPORTER* r )
{ {
r->Report( "" ); r->Report( "" );
r->Report( _( "Report incomplete: could not compile custom design rules. " ) r->Report( _( "Report incomplete: could not compile custom design rules." )
+ wxT( "<a href='boardsetup'>" ) + _( "Show design rules." ) + wxT( "</a>" ) ); + wxS( "&nbsp;&nbsp;" )
+ wxS( "<a href='$CUSTOM_RULES'>" ) + _( "Show design rules." ) + wxS( "</a>" ) );
} }
@ -1282,7 +1283,8 @@ int BOARD_INSPECTION_TOOL::InspectConstraints( const TOOL_EVENT& aEvent )
{ {
r->Report( "" ); r->Report( "" );
r->Report( _( "Report may be incomplete: some footprint courtyards are malformed." ) r->Report( _( "Report may be incomplete: some footprint courtyards are malformed." )
+ wxT( " <a href='drc'>" ) + _( "Run DRC for a full analysis." ) + wxT( "</a>" ) ); + wxS( "&nbsp;&nbsp;" )
+ wxS( "<a href='$DRC'>" ) + _( "Run DRC for a full analysis." ) + wxS( "</a>" ) );
} }
r->Report( "" ); r->Report( "" );
@ -1304,7 +1306,8 @@ int BOARD_INSPECTION_TOOL::InspectConstraints( const TOOL_EVENT& aEvent )
{ {
r->Report( "" ); r->Report( "" );
r->Report( _( "Report may be incomplete: some footprint courtyards are malformed." ) r->Report( _( "Report may be incomplete: some footprint courtyards are malformed." )
+ wxT( " <a href='drc'>" ) + _( "Run DRC for a full analysis." ) + wxT( "</a>" ) ); + wxS( "&nbsp;&nbsp;" )
+ wxS( "<a href='$DRC'>" ) + _( "Run DRC for a full analysis." ) + wxS( "</a>" ) );
} }
drcEngine.ProcessAssertions( item, []( const DRC_CONSTRAINT* c ){}, r ); drcEngine.ProcessAssertions( item, []( const DRC_CONSTRAINT* c ){}, r );
@ -1336,21 +1339,21 @@ int BOARD_INSPECTION_TOOL::InspectLibraryDiff( const TOOL_EVENT& aEvent )
if( selection.Size() != 1 ) if( selection.Size() != 1 )
{ {
m_frame->ShowInfoBarError( _( "Select a footprint to check against its library equivalent." ) ); m_frame->ShowInfoBarError( _( "Select a footprint to diff against its library equivalent." ) );
return 0; return 0;
} }
if( m_inspectConstraintsDialog == nullptr ) if( m_inspectLibraryDiffDialog == nullptr )
{ {
m_inspectConstraintsDialog = std::make_unique<DIALOG_CONSTRAINTS_REPORTER>( m_frame ); m_inspectLibraryDiffDialog = std::make_unique<DIALOG_CONSTRAINTS_REPORTER>( m_frame );
m_inspectConstraintsDialog->SetTitle( _( "Check Footprint against Library" ) ); m_inspectLibraryDiffDialog->SetTitle( _( "Diff Footprint with Library" ) );
m_inspectConstraintsDialog->Connect( wxEVT_CLOSE_WINDOW, m_inspectLibraryDiffDialog->Connect( wxEVT_CLOSE_WINDOW,
wxCommandEventHandler( BOARD_INSPECTION_TOOL::onInspectConstraintsDialogClosed ), wxCommandEventHandler( BOARD_INSPECTION_TOOL::onInspectLibraryDiffDialogClosed ),
nullptr, this ); nullptr, this );
} }
m_inspectConstraintsDialog->DeleteAllPages(); m_inspectLibraryDiffDialog->DeleteAllPages();
FOOTPRINT* footprint = static_cast<FOOTPRINT*>( selection.GetItem( 0 ) ); FOOTPRINT* footprint = static_cast<FOOTPRINT*>( selection.GetItem( 0 ) );
LIB_ID fpID = footprint->GetFPID(); LIB_ID fpID = footprint->GetFPID();
@ -1358,12 +1361,12 @@ int BOARD_INSPECTION_TOOL::InspectLibraryDiff( const TOOL_EVENT& aEvent )
wxString fpName = fpID.GetLibItemName(); wxString fpName = fpID.GetLibItemName();
WX_HTML_REPORT_BOX* r = nullptr; WX_HTML_REPORT_BOX* r = nullptr;
r = m_inspectConstraintsDialog->AddPage( _( "Diff" ) ); r = m_inspectLibraryDiffDialog->AddPage( _( "Summary" ) );
r->Report( wxT( "<h7>" ) + _( "Board/library check for:" ) + wxT( "</h7>" ) ); r->Report( wxS( "<h7>" ) + _( "Board vs library diff for:" ) + wxS( "</h7>" ) );
r->Report( wxT( "<ul><li>" ) + EscapeHTML( getItemDescription( footprint ) ) + wxT( "</li>" ) r->Report( wxS( "<ul><li>" ) + EscapeHTML( getItemDescription( footprint ) ) + wxS( "</li>" )
+ wxT( "<li>" ) + _( "Library: " ) + EscapeHTML( libName ) + wxT( "</li>" ) + wxS( "<li>" ) + _( "Library: " ) + EscapeHTML( libName ) + wxS( "</li>" )
+ wxT( "<li>" ) + _( "Library item: " ) + EscapeHTML( fpName ) + wxT( "</li></ul>" ) ); + wxS( "<li>" ) + _( "Library item: " ) + EscapeHTML( fpName ) + wxS( "</li></ul>" ) );
r->Report( "" ); r->Report( "" );
@ -1381,11 +1384,17 @@ int BOARD_INSPECTION_TOOL::InspectLibraryDiff( const TOOL_EVENT& aEvent )
if( !libTableRow ) if( !libTableRow )
{ {
r->Report( _( "The current configuration does not include the library." ) ); r->Report( _( "The library is not included in the current configuration." )
+ wxS( "&nbsp;&nbsp;&nbsp" )
+ wxS( "<a href='$CONFIG'>" ) + _( "Manage Footprint Libraries" ) + wxS( "</a>" ) );
} }
else if( !libTable->HasLibrary( libName, true ) ) else if( !libTable->HasLibrary( libName, true ) )
{ {
r->Report( _( "The library is not enabled in the current configuration." ) ); r->Report( _( "The library is not enabled in the current configuration." )
+ wxS( "&nbsp;&nbsp;&nbsp" )
+ wxS( "<a href='$CONFIG'>" ) + _( "Manage Footprint Libraries" ) + wxS( "</a>" ) );
} }
else else
{ {
@ -1406,15 +1415,15 @@ int BOARD_INSPECTION_TOOL::InspectLibraryDiff( const TOOL_EVENT& aEvent )
} }
else if( !footprint->FootprintNeedsUpdate( libFootprint.get(), r ) ) else if( !footprint->FootprintNeedsUpdate( libFootprint.get(), r ) )
{ {
r->Report( _( "Footprint matches library equivalent." ) ); r->Report( _( "No relevant differences detected." ) );
} }
} }
r->Flush(); r->Flush();
m_inspectConstraintsDialog->FinishInitialization(); m_inspectLibraryDiffDialog->FinishInitialization();
m_inspectConstraintsDialog->Raise(); m_inspectLibraryDiffDialog->Raise();
m_inspectConstraintsDialog->Show( true ); m_inspectLibraryDiffDialog->Show( true );
return 0; return 0;
} }
@ -1898,6 +1907,17 @@ void BOARD_INSPECTION_TOOL::onInspectConstraintsDialogClosed( wxCommandEvent& ev
} }
void BOARD_INSPECTION_TOOL::onInspectLibraryDiffDialogClosed( wxCommandEvent& event )
{
m_inspectLibraryDiffDialog->Disconnect( wxEVT_CLOSE_WINDOW,
wxCommandEventHandler( BOARD_INSPECTION_TOOL::onInspectLibraryDiffDialogClosed ),
nullptr, this );
m_inspectLibraryDiffDialog->Destroy();
m_inspectLibraryDiffDialog.release();
}
int BOARD_INSPECTION_TOOL::HideNetInRatsnest( const TOOL_EVENT& aEvent ) int BOARD_INSPECTION_TOOL::HideNetInRatsnest( const TOOL_EVENT& aEvent )
{ {
doHideRatsnestNet( aEvent.Parameter<intptr_t>(), true ); doHideRatsnestNet( aEvent.Parameter<intptr_t>(), true );

View File

@ -1,7 +1,7 @@
/* /*
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2019-2021 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2019-2023 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -119,6 +119,7 @@ private:
void onListNetsDialogClosed( wxCommandEvent& aEvent ); void onListNetsDialogClosed( wxCommandEvent& aEvent );
void onInspectClearanceDialogClosed( wxCommandEvent& aEvent ); void onInspectClearanceDialogClosed( wxCommandEvent& aEvent );
void onInspectConstraintsDialogClosed( wxCommandEvent& aEvent ); void onInspectConstraintsDialogClosed( wxCommandEvent& aEvent );
void onInspectLibraryDiffDialogClosed( wxCommandEvent& aEvent );
DRC_ENGINE makeDRCEngine( bool* aCompileError, bool* aCourtyardError = nullptr ); DRC_ENGINE makeDRCEngine( bool* aCompileError, bool* aCourtyardError = nullptr );
@ -143,6 +144,7 @@ private:
std::unique_ptr<DIALOG_CONSTRAINTS_REPORTER> m_inspectClearanceDialog; std::unique_ptr<DIALOG_CONSTRAINTS_REPORTER> m_inspectClearanceDialog;
std::unique_ptr<DIALOG_CONSTRAINTS_REPORTER> m_inspectConstraintsDialog; std::unique_ptr<DIALOG_CONSTRAINTS_REPORTER> m_inspectConstraintsDialog;
std::unique_ptr<DIALOG_CONSTRAINTS_REPORTER> m_inspectLibraryDiffDialog;
}; };
#endif //BOARD_INSPECTION_TOOL_H #endif //BOARD_INSPECTION_TOOL_H

View File

@ -1175,9 +1175,9 @@ TOOL_ACTION PCB_ACTIONS::inspectConstraints( "pcbnew.InspectionTool.InspectConst
TOOL_ACTION PCB_ACTIONS::inspectLibraryDiff( "pcbnew.InspectionTool.InspectLibraryDiff", TOOL_ACTION PCB_ACTIONS::inspectLibraryDiff( "pcbnew.InspectionTool.InspectLibraryDiff",
AS_GLOBAL, 0, "", AS_GLOBAL, 0, "",
_( "Check Footprint against Library..." ), _( "Diff Footprint with Library..." ),
_( "Check for differences between board footprint and its library equivalent" ), _( "Check for differences between board footprint and its library equivalent" ),
BITMAPS::show_footprint ); BITMAPS::library );
//Geographic re-annotation tool //Geographic re-annotation tool
TOOL_ACTION PCB_ACTIONS::boardReannotate( "pcbnew.ReannotateTool.ShowReannotateDialog", TOOL_ACTION PCB_ACTIONS::boardReannotate( "pcbnew.ReannotateTool.ShowReannotateDialog",

View File

@ -425,10 +425,10 @@ BOOST_AUTO_TEST_CASE( Compare )
m_part_no_data.AddDrawItem( new LIB_SHAPE( &m_part_no_data, SHAPE_T::ARC ) ); m_part_no_data.AddDrawItem( new LIB_SHAPE( &m_part_no_data, SHAPE_T::ARC ) );
BOOST_CHECK( m_part_no_data.Compare( testPart ) > 0 ); BOOST_CHECK( m_part_no_data.Compare( testPart ) > 0 );
m_part_no_data.RemoveDrawItem( &m_part_no_data.GetDrawItems()[LIB_SHAPE_T].front() ); m_part_no_data.RemoveDrawItem( &m_part_no_data.GetDrawItems()[LIB_SHAPE_T].front() );
testPart.RemoveDrawItem( &testPart.GetDrawItems()[LIB_SHAPE_T].front() );
m_part_no_data.AddDrawItem( new LIB_PIN( &m_part_no_data ) ); m_part_no_data.AddDrawItem( new LIB_PIN( &m_part_no_data ) );
BOOST_CHECK( m_part_no_data.Compare( testPart ) > 0 ); BOOST_CHECK( m_part_no_data.Compare( testPart ) > 0 );
m_part_no_data.RemoveDrawItem( &m_part_no_data.GetDrawItems()[LIB_PIN_T].front() ); m_part_no_data.RemoveDrawItem( &m_part_no_data.GetDrawItems()[LIB_PIN_T].front() );
testPart.RemoveDrawItem( &testPart.GetDrawItems()[LIB_SHAPE_T].front() );
// Footprint filter array comparison tests. // Footprint filter array comparison tests.
wxArrayString footPrintFilters; wxArrayString footPrintFilters;