From 2d6ab62da4d5ab455e5c02885122ddad4f4608ff Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Thu, 9 Mar 2023 11:25:32 +0000 Subject: [PATCH] ADDED: schematic/library diff for symbols. --- common/CMakeLists.txt | 2 + .../dialogs/dialog_constraints_reporter.cpp | 15 +- .../dialog_constraints_reporter_base.cpp | 0 .../dialog_constraints_reporter_base.fbp | 0 .../dialog_constraints_reporter_base.h | 0 eeschema/cross-probing.cpp | 29 +- eeschema/lib_field.cpp | 11 +- eeschema/lib_symbol.cpp | 278 ++++++++++++------ eeschema/lib_symbol.h | 4 +- eeschema/menubar.cpp | 3 + eeschema/sch_edit_frame.h | 8 +- eeschema/tools/ee_actions.cpp | 6 + eeschema/tools/ee_actions.h | 1 + eeschema/tools/ee_inspection_tool.cpp | 120 +++++++- eeschema/tools/ee_inspection_tool.h | 10 +- .../dialogs/dialog_constraints_reporter.h | 10 +- pcbnew/CMakeLists.txt | 2 - pcbnew/cross-probing.cpp | 73 +++-- pcbnew/dialogs/dialog_drc.cpp | 9 +- .../drc/drc_test_provider_library_parity.cpp | 148 +++++----- pcbnew/tools/board_inspection_tool.cpp | 66 +++-- pcbnew/tools/board_inspection_tool.h | 4 +- pcbnew/tools/pcb_actions.cpp | 4 +- qa/unittests/eeschema/test_lib_part.cpp | 2 +- 24 files changed, 552 insertions(+), 253 deletions(-) rename {pcbnew => common}/dialogs/dialog_constraints_reporter.cpp (82%) rename {pcbnew => common}/dialogs/dialog_constraints_reporter_base.cpp (100%) rename {pcbnew => common}/dialogs/dialog_constraints_reporter_base.fbp (100%) rename {pcbnew => common}/dialogs/dialog_constraints_reporter_base.h (100%) rename {pcbnew => include}/dialogs/dialog_constraints_reporter.h (86%) diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index c47da6aaa8..74347c2753 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -110,6 +110,8 @@ set( COMMON_DLG_SRCS dialogs/dialog_color_picker_base.cpp dialogs/dialog_configure_paths.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_edit_library_tables.cpp dialogs/dialog_global_lib_table_config.cpp diff --git a/pcbnew/dialogs/dialog_constraints_reporter.cpp b/common/dialogs/dialog_constraints_reporter.cpp similarity index 82% rename from pcbnew/dialogs/dialog_constraints_reporter.cpp rename to common/dialogs/dialog_constraints_reporter.cpp index 0957d2d132..dc1504fbe1 100644 --- a/pcbnew/dialogs/dialog_constraints_reporter.cpp +++ b/common/dialogs/dialog_constraints_reporter.cpp @@ -1,7 +1,7 @@ /* * 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 * 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 */ -#include -#include -#include +#include #include -#include #include -DIALOG_CONSTRAINTS_REPORTER::DIALOG_CONSTRAINTS_REPORTER( PCB_EDIT_FRAME* aParent ) : + +DIALOG_CONSTRAINTS_REPORTER::DIALOG_CONSTRAINTS_REPORTER( KIWAY_PLAYER* aParent ) : DIALOG_CONSTRAINTS_REPORTER_BASE( aParent ), m_frame( aParent ) { @@ -50,10 +48,7 @@ void DIALOG_CONSTRAINTS_REPORTER::DeleteAllPages() void DIALOG_CONSTRAINTS_REPORTER::OnErrorLinkClicked( wxHtmlLinkEvent& event ) { - if( event.GetLinkInfo().GetHref() == wxT( "boardsetup" ) ) - m_frame->ShowBoardSetupDialog( _( "Custom Rules" ) ); - else if( event.GetLinkInfo().GetHref() == wxT( "drc" ) ) - m_frame->GetToolManager()->RunAction( PCB_ACTIONS::runDRC, true ); + m_frame->ExecuteRemoteCommand( event.GetLinkInfo().GetHref().ToStdString().c_str() ); } diff --git a/pcbnew/dialogs/dialog_constraints_reporter_base.cpp b/common/dialogs/dialog_constraints_reporter_base.cpp similarity index 100% rename from pcbnew/dialogs/dialog_constraints_reporter_base.cpp rename to common/dialogs/dialog_constraints_reporter_base.cpp diff --git a/pcbnew/dialogs/dialog_constraints_reporter_base.fbp b/common/dialogs/dialog_constraints_reporter_base.fbp similarity index 100% rename from pcbnew/dialogs/dialog_constraints_reporter_base.fbp rename to common/dialogs/dialog_constraints_reporter_base.fbp diff --git a/pcbnew/dialogs/dialog_constraints_reporter_base.h b/common/dialogs/dialog_constraints_reporter_base.h similarity index 100% rename from pcbnew/dialogs/dialog_constraints_reporter_base.h rename to common/dialogs/dialog_constraints_reporter_base.h diff --git a/eeschema/cross-probing.cpp b/eeschema/cross-probing.cpp index b37bd61c0b..eba22b0ce8 100644 --- a/eeschema/cross-probing.cpp +++ b/eeschema/cross-probing.cpp @@ -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 ) { SCH_EDITOR_CONTROL* editor = m_toolManager->GetTool(); @@ -199,7 +213,17 @@ void SCH_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline ) 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 ) return; @@ -216,8 +240,7 @@ void SCH_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline ) SetStatusText( _( "Selected net:" ) + wxS( " " ) + UnescapeString( netName ) ); return; } - - if( strcmp( idcmd, "$CLEAR:" ) == 0 ) + else if( strcmp( idcmd, "$CLEAR:" ) == 0 ) { // Cross-probing is now done through selection so we no longer need a clear command return; diff --git a/eeschema/lib_field.cpp b/eeschema/lib_field.cpp index 995a401d88..b6403d9ae4 100644 --- a/eeschema/lib_field.cpp +++ b/eeschema/lib_field.cpp @@ -260,11 +260,14 @@ int LIB_FIELD::compare( const LIB_ITEM& aOther, int aCompareFlags ) const if( retv != 0 ) return retv; - if( GetTextPos().x != tmp->GetTextPos().x ) - return GetTextPos().x - tmp->GetTextPos().x; + if( aCompareFlags & LIB_ITEM::COMPARE_FLAGS::EQUALITY ) + { + if( GetTextPos().x != tmp->GetTextPos().x ) + return GetTextPos().x - tmp->GetTextPos().x; - if( GetTextPos().y != tmp->GetTextPos().y ) - return GetTextPos().y - tmp->GetTextPos().y; + if( GetTextPos().y != tmp->GetTextPos().y ) + return GetTextPos().y - tmp->GetTextPos().y; + } if( GetTextWidth() != tmp->GetTextWidth() ) return GetTextWidth() - tmp->GetTextWidth(); diff --git a/eeschema/lib_symbol.cpp b/eeschema/lib_symbol.cpp index 85e71058a5..1be2989ca2 100644 --- a/eeschema/lib_symbol.cpp +++ b/eeschema/lib_symbol.cpp @@ -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 ) return 0; - int retv = 0; - - if( ( aCompareFlags & LIB_ITEM::COMPARE_FLAGS::ERC ) == 0 ) + if( !aReporter && ( 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 ) - return retv; + if( int tmp = m_libId.compare( aRhs.m_libId ) ) + return tmp; - retv = m_libId.compare( aRhs.m_libId ); + if( m_parent.lock() < aRhs.m_parent.lock() ) + return -1; - if( retv ) - return retv; + if( m_parent.lock() > aRhs.m_parent.lock() ) + return 1; } - if( m_parent.lock() < aRhs.m_parent.lock() ) - return -1; - - if( m_parent.lock() > aRhs.m_parent.lock() ) - return 1; + int retv = 0; if( m_options != aRhs.m_options ) - return ( m_options == ENTRY_NORMAL ) ? -1 : 1; + { + retv = ( m_options == ENTRY_NORMAL ) ? -1 : 1; + REPORT( _( "Power flag differs." ) ); + } - if( m_unitCount != aRhs.m_unitCount ) - return m_unitCount - aRhs.m_unitCount; + CHECKPOINT; - if( m_drawings.size() != aRhs.m_drawings.size() ) - return m_drawings.size() - aRhs.m_drawings.size(); + if( int tmp = m_unitCount - aRhs.m_unitCount ) + { + retv = tmp; + REPORT( _( "Unit count differs." ) ); + } + + CHECKPOINT; - LIB_ITEMS_CONTAINER::CONST_ITERATOR lhsItemIt = m_drawings.begin(); - LIB_ITEMS_CONTAINER::CONST_ITERATOR rhsItemIt = aRhs.m_drawings.begin(); + std::set aShapes; + std::set aFields; + std::set aPins; - while( lhsItemIt != m_drawings.end() ) + for( auto it = m_drawings.begin(); it != m_drawings.end(); ++it ) { - const LIB_ITEM* lhsItem = static_cast( &(*lhsItemIt) ); - const LIB_ITEM* rhsItem = static_cast( &(*rhsItemIt) ); + 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) ); + } - wxCHECK( lhsItem && rhsItem, lhsItem - rhsItem ); + std::set bShapes; + std::set bFields; + std::set bPins; - if( lhsItem->Type() != rhsItem->Type() ) - return lhsItem->Type() - rhsItem->Type(); + 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) ); + } - // Non-mandatory fields are a special case. They can have different ordinal numbers - // and are compared separately below. - if( lhsItem->Type() == LIB_FIELD_T ) + if( int tmp = static_cast( 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( lhsItem ); - - if( lhsField->GetId() == VALUE_FIELD ) + if( int tmp2 = (*aIt)->compare( *(*bIt), aCompareFlags ) ) { - if( ( aCompareFlags & LIB_ITEM::COMPARE_FLAGS::ERC ) == 0 || IsPower() ) - retv = lhsItem->compare( *rhsItem, aCompareFlags ); - } - else if( lhsField->IsMandatory() ) - { - retv = lhsItem->compare( *rhsItem, aCompareFlags ); + retv = tmp2; + REPORT( wxString::Format( _( "%s differs." ), ITEM_DESC( *aIt ) ) ); } } + } + + CHECKPOINT; + + for( const LIB_ITEM* aPinItem : aPins ) + { + const LIB_PIN* aPin = static_cast( aPinItem ); + const LIB_PIN* bPin = aRhs.GetPin( aPin->GetNumber() ); + int tmp = 0; + + if( !bPin ) + tmp = 1; else + tmp = aPinItem->compare( *bPin, aCompareFlags ); + + if( tmp ) { - retv = lhsItem->compare( *rhsItem, aCompareFlags ); + retv = tmp; + REPORT( wxString::Format( _( "Pin %s differs." ), aPin->GetNumber() ) ); } - - if( retv ) - return retv; - - ++lhsItemIt; - ++rhsItemIt; } - // Compare the optional fields. - for( const LIB_ITEM& item : m_drawings[ LIB_FIELD_T ] ) + if( int tmp = static_cast( aPins.size() - bPins.size() ) ) { - const LIB_FIELD* field = dynamic_cast( &item ); + retv = tmp; + REPORT( _( "Pin count differs." ) ); + } - wxCHECK2( field, continue ); + for( const LIB_ITEM* aFieldItem : aFields ) + { + const LIB_FIELD* aField = static_cast( aFieldItem ); + const LIB_FIELD* bField = nullptr; + int tmp = 0; - // Mandatory fields were already compared above. - if( field->IsMandatory() ) - continue; + if( aField->GetId() < MANDATORY_FIELDS ) + bField = aRhs.GetFieldById( aField->GetId() ); + else + bField = aRhs.FindField( aField->GetName() ); - const LIB_FIELD* foundField = aRhs.FindField( field->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 + { + tmp = aFieldItem->compare( *bField, aCompareFlags ); + } - if( foundField == nullptr ) - return 1; + if( tmp ) + { + retv = tmp; + REPORT( wxString::Format( _( "%s field differs." ), aField->GetName( false ) ) ); + } + } - retv = item.compare( static_cast( *foundField ), aCompareFlags ); + CHECKPOINT; - if( retv ) - return retv; + if( int tmp = static_cast( aFields.size() - bFields.size() ) ) + { + retv = tmp; + REPORT( _( "Field count differs." ) ); } - if( m_fpFilters.GetCount() != aRhs.m_fpFilters.GetCount() ) - return m_fpFilters.GetCount() - aRhs.m_fpFilters.GetCount(); + CHECKPOINT; - for( size_t i = 0; i < m_fpFilters.GetCount(); i++ ) + if( int tmp = static_cast( m_fpFilters.GetCount() - aRhs.m_fpFilters.GetCount() ) ) { - retv = m_fpFilters[i].Cmp( aRhs.m_fpFilters[i] ); - - if( retv ) - return retv; + retv = tmp; + REPORT( _( "Footprint filters differs." ) ); } + 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; + } + } + } + + CHECKPOINT; - retv = m_description.Cmp( aRhs.m_description ); + if( int tmp = m_description.Cmp( aRhs.m_description ) ) + { + retv = tmp; + REPORT( _( "Symbol descriptions differ." ) ); + } - if( retv ) - return retv; + CHECKPOINT; - retv = m_keyWords.Cmp( aRhs.m_keyWords ); + if( int tmp = m_keyWords.Cmp( aRhs.m_keyWords ) ) + { + retv = tmp; + REPORT( _( "Symbol keywords differ." ) ); + } - if( retv ) - return retv; + CHECKPOINT; - if( m_pinNameOffset != aRhs.m_pinNameOffset ) - return m_pinNameOffset - aRhs.m_pinNameOffset; + if( int tmp = m_pinNameOffset - aRhs.m_pinNameOffset ) + { + retv = tmp; + REPORT( _( "Symbol pin name offsets differ." ) ); + } - if( m_unitsLocked != aRhs.m_unitsLocked ) - return ( m_unitsLocked ) ? 1 : -1; + CHECKPOINT; if( ( aCompareFlags & LIB_ITEM::COMPARE_FLAGS::ERC ) == 0 ) { 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 ) - return ( m_showPinNumbers ) ? 1 : -1; + { + retv = ( m_showPinNumbers ) ? 1 : -1; + REPORT( _( "Show pin numbers settings differ." ) ); + } 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 ) - return ( m_includeOnBoard ) ? 1 : -1; + { + retv = ( m_includeOnBoard ) ? 1 : -1; + REPORT( _( "Exclude from board settings differ." ) ); + } } - // Compare unit display names - if( m_unitDisplayNames < aRhs.m_unitDisplayNames ) - { - return -1; - } - else if( m_unitDisplayNames > aRhs.m_unitDisplayNames ) + CHECKPOINT; + if( !aReporter ) { - return 1; + if( m_unitsLocked != aRhs.m_unitsLocked ) + return ( m_unitsLocked ) ? 1 : -1; + + // Compare unit display names + if( m_unitDisplayNames < aRhs.m_unitDisplayNames ) + { + return -1; + } + else if( m_unitDisplayNames > aRhs.m_unitDisplayNames ) + { + return 1; + } } - return 0; + return retv; } diff --git a/eeschema/lib_symbol.h b/eeschema/lib_symbol.h index 7e135f996e..6eeb3d4e76 100644 --- a/eeschema/lib_symbol.h +++ b/eeschema/lib_symbol.h @@ -36,6 +36,7 @@ class LINE_READER; class OUTPUTFORMATTER; +class REPORTER; class SYMBOL_LIB; class LIB_SYMBOL; class LIB_FIELD; @@ -657,7 +658,8 @@ public: * 1 if this symbol is greater than \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 diff --git a/eeschema/menubar.cpp b/eeschema/menubar.cpp index 7f724f855c..91011de1b1 100644 --- a/eeschema/menubar.cpp +++ b/eeschema/menubar.cpp @@ -253,6 +253,9 @@ void SCH_EDIT_FRAME::doReCreateMenuBar() inspectMenu->Add( ACTIONS::nextMarker ); inspectMenu->Add( ACTIONS::excludeMarker ); + inspectMenu->AppendSeparator(); + inspectMenu->Add( EE_ACTIONS::inspectLibraryDiff ); + #ifdef KICAD_SPICE inspectMenu->AppendSeparator(); inspectMenu->Add( EE_ACTIONS::showSimulator ); diff --git a/eeschema/sch_edit_frame.h b/eeschema/sch_edit_frame.h index 04fb41f8e2..e78fbec391 100644 --- a/eeschema/sch_edit_frame.h +++ b/eeschema/sch_edit_frame.h @@ -166,11 +166,11 @@ public: 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 - * symbol or pin and moves cursor on the item. The socket port used - * is #KICAD_SCH_PORT_SERVICE_NUMBER which defaults to 4243. + * When user selects a footprint or pin in Pcbnew, Eeschema shows that same symbol or pin + * and moves cursor on the item. * * Valid commands are: * \li \c \$PART: \c "reference" Put cursor on symbol. diff --git a/eeschema/tools/ee_actions.cpp b/eeschema/tools/ee_actions.cpp index 72f4b01389..0fa1197861 100644 --- a/eeschema/tools/ee_actions.cpp +++ b/eeschema/tools/ee_actions.cpp @@ -50,6 +50,12 @@ TOOL_ACTION EE_ACTIONS::checkSymbol( "eeschema.InspectionTool.checkSymbol", _( "Symbol Checker" ), _( "Show the symbol checker window" ), 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", AS_GLOBAL, 0, "", _( "Simulator..." ), _( "Simulate circuit in SPICE" ), diff --git a/eeschema/tools/ee_actions.h b/eeschema/tools/ee_actions.h index e4007d6214..6df5c73e20 100644 --- a/eeschema/tools/ee_actions.h +++ b/eeschema/tools/ee_actions.h @@ -162,6 +162,7 @@ public: static TOOL_ACTION schematicSetup; static TOOL_ACTION editPageNumber; static TOOL_ACTION checkSymbol; + static TOOL_ACTION inspectLibraryDiff; static TOOL_ACTION rescueSymbols; static TOOL_ACTION remapSymbols; diff --git a/eeschema/tools/ee_inspection_tool.cpp b/eeschema/tools/ee_inspection_tool.cpp index e76d45db54..2b072ca1a3 100644 --- a/eeschema/tools/ee_inspection_tool.cpp +++ b/eeschema/tools/ee_inspection_tool.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +42,8 @@ #include #include #include +#include +#include #include // 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( 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( "" ) + _( "Schematic vs library diff for:" ) + wxS( "" ) ); + r->Report( wxS( "
  • " ) + EscapeHTML( symbolDesc ) + wxS( "
  • " ) + + wxS( "
  • " ) + _( "Library: " ) + EscapeHTML( libName ) + wxS( "
  • " ) + + wxS( "
  • " ) + _( "Library item: " ) + EscapeHTML( symbolName ) + wxS( "
" ) ); + + 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( "   " ) + + wxS( "" ) + _( "Manage Symbol Libraries" ) + wxS( "" ) ); + } + else if( !libTable->HasLibrary( libName, true ) ) + { + r->Report( _( "The library is not enabled in the current configuration." ) + + wxS( "   " ) + + wxS( "" ) + _( "Manage Symbol Libraries" ) + wxS( "" ) ); + } + else + { + std::unique_ptr flattenedLibSymbol; + std::unique_ptr 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 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 ) { #ifdef KICAD_SPICE @@ -298,7 +415,7 @@ int EE_INSPECTION_TOOL::ShowDatasheet( const TOOL_EVENT& aEvent ) tmp->SetNameShown( name_shown ); } - if( datasheet.IsEmpty() || datasheet == wxT( "~" ) ) + if( datasheet.IsEmpty() || datasheet == wxS( "~" ) ) { 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::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::ShowDatasheet, EE_ACTIONS::showDatasheet.MakeEvent() ); diff --git a/eeschema/tools/ee_inspection_tool.h b/eeschema/tools/ee_inspection_tool.h index eb4b126f7c..e1cbcda24b 100644 --- a/eeschema/tools/ee_inspection_tool.h +++ b/eeschema/tools/ee_inspection_tool.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * 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 * modify it under the terms of the GNU General Public License @@ -26,6 +26,7 @@ #define EE_INSPECTION_TOOL_H #include +#include #include @@ -34,7 +35,7 @@ class SCH_BASE_FRAME; class DIALOG_ERC; -class EE_INSPECTION_TOOL : public EE_TOOL_BASE +class EE_INSPECTION_TOOL : public wxEvtHandler, public EE_TOOL_BASE { public: EE_INSPECTION_TOOL(); @@ -58,6 +59,7 @@ public: int ExcludeMarker( const TOOL_EVENT& aEvent ); int CheckSymbol( const TOOL_EVENT& aEvent ); + int InspectLibraryDiff( const TOOL_EVENT& aEvent ); int RunSimulation( const TOOL_EVENT& aEvent ); @@ -67,11 +69,15 @@ public: int UpdateMessagePanel( const TOOL_EVENT& aEvent ); private: + void onInspectLibraryDiffDialogClosed( wxCommandEvent& aEvent ); + ///< @copydoc TOOL_INTERACTIVE::setTransitions(); void setTransitions() override; private: DIALOG_ERC* m_ercDialog; + + std::unique_ptr m_inspectLibraryDiffDialog; }; #endif /* EE_INSPECTION_TOOL_H */ diff --git a/pcbnew/dialogs/dialog_constraints_reporter.h b/include/dialogs/dialog_constraints_reporter.h similarity index 86% rename from pcbnew/dialogs/dialog_constraints_reporter.h rename to include/dialogs/dialog_constraints_reporter.h index 1f2d5a961c..2bac38a278 100644 --- a/pcbnew/dialogs/dialog_constraints_reporter.h +++ b/include/dialogs/dialog_constraints_reporter.h @@ -1,7 +1,7 @@ /* * 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 * modify it under the terms of the GNU General Public License @@ -24,16 +24,16 @@ #ifndef DIALOG_CONSTRAINTS_REPORTER_H #define DIALOG_CONSTRAINTS_REPORTER_H -#include +#include -class PCB_EDIT_FRAME; +class KIWAY_PLAYER; class WX_HTML_REPORT_BOX; class wxHtmlLinkEvent; class DIALOG_CONSTRAINTS_REPORTER : public DIALOG_CONSTRAINTS_REPORTER_BASE { public: - DIALOG_CONSTRAINTS_REPORTER( PCB_EDIT_FRAME* aParent ); + DIALOG_CONSTRAINTS_REPORTER( KIWAY_PLAYER* aParent ); void FinishInitialization(); @@ -51,7 +51,7 @@ public: int GetPageCount() const; protected: - PCB_EDIT_FRAME* m_frame; + KIWAY_PLAYER* m_frame; }; #endif // DIALOG_CONSTRAINTS_REPORTER_H diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index 27344e192b..65626b28c4 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -44,8 +44,6 @@ set( PCBNEW_DIALOGS dialogs/dialog_cleanup_graphics_base.cpp dialogs/dialog_cleanup_tracks_and_vias.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_base.cpp dialogs/dialog_create_array.cpp diff --git a/pcbnew/cross-probing.cpp b/pcbnew/cross-probing.cpp index 1989ab677e..c0fef90fd1 100644 --- a/pcbnew/cross-probing.cpp +++ b/pcbnew/cross-probing.cpp @@ -1,7 +1,7 @@ /* * 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 * modify it under the terms of the GNU General Public License @@ -55,14 +55,17 @@ #include #include -/* Execute a remote command send by Eeschema via a socket, - * port KICAD_PCB_PORT_SERVICE_NUMBER - * cmdline = received command from Eeschema +/* Execute a remote command sent via a socket on port KICAD_PCB_PORT_SERVICE_NUMBER + * * 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 - * $CLEAR Clear existing highlight - * They are a keyword followed by a quoted string. + * $CLEAR Clear existing highlight + * + * $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 ) { @@ -91,7 +94,39 @@ void PCB_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline ) if( idcmd == nullptr ) 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 ) return; @@ -108,9 +143,10 @@ void PCB_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline ) netinfo->GetMsgPanelInfo( this, items ); SetMsgPanel( items ); } - } - if( strcmp( idcmd, "$NETS:" ) == 0 ) + // fall through to hihglighting section + } + else if( strcmp( idcmd, "$NETS:" ) == 0 ) { if( !crossProbingSettings.auto_highlight ) return; @@ -145,23 +181,8 @@ void PCB_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline ) } netcode = -1; - } - else if( strcmp( idcmd, "$CLEAR" ) == 0 ) - { - if( renderSettings->IsHighlightEnabled() ) - { - renderSettings->SetHighlight( false ); - view->UpdateAllLayersColor(); - } - if( pcb->IsHighLightNetON() ) - { - pcb->ResetNetHighLight(); - SetMsgPanel( pcb ); - } - - GetCanvas()->Refresh(); - return; + // fall through to highlighting section } BOX2I bbox; diff --git a/pcbnew/dialogs/dialog_drc.cpp b/pcbnew/dialogs/dialog_drc.cpp index b208bd7c8c..050ea5adfb 100644 --- a/pcbnew/dialogs/dialog_drc.cpp +++ b/pcbnew/dialogs/dialog_drc.cpp @@ -3,7 +3,7 @@ * * Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr * 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 * 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_messages->Clear(); - m_messages->Report( _( "DRC incomplete: could not compile custom design rules. " ) - + wxT( "" ) - + _( "Show design rules." ) - + wxT( "" ) ); + m_messages->Report( _( "DRC incomplete: could not compile custom design rules." ) + + wxS( "  " ) + + wxS( "" ) + _( "Show design rules." ) + wxT( "" ) ); m_messages->Flush(); Raise(); diff --git a/pcbnew/drc/drc_test_provider_library_parity.cpp b/pcbnew/drc/drc_test_provider_library_parity.cpp index 9b52d2b17c..46b56a8c18 100644 --- a/pcbnew/drc/drc_test_provider_library_parity.cpp +++ b/pcbnew/drc/drc_test_provider_library_parity.cpp @@ -77,16 +77,14 @@ public: #define TEST( a, b, msg ) \ if( a != b ) \ { \ + diff = true; \ + \ if( aReporter ) \ - { \ aReporter->Report( msg ); \ - diff = true; \ - } \ - else \ - { \ - return true; \ - } \ } \ + \ + if( diff && !aReporter ) \ + return diff; \ /* Prevent binding to else following macro */ \ else {} @@ -94,16 +92,14 @@ public: #define TEST_D( a, b, msg ) \ if( abs( a - b ) > EPSILON ) \ { \ + diff = true; \ + \ if( aReporter ) \ - { \ aReporter->Report( msg ); \ - diff = true; \ - } \ - else \ - { \ - return true; \ - } \ } \ + \ + if( diff && !aReporter ) \ + return diff; \ /* Prevent binding to else following macro */ \ else {} @@ -112,16 +108,14 @@ public: || abs( a.y - b.y ) > EPSILON \ || abs( a.z - b.z ) > EPSILON ) \ { \ + diff = true; \ + \ if( aReporter ) \ - { \ aReporter->Report( msg ); \ - diff = true; \ - } \ - else \ - { \ - return true; \ - } \ } \ + \ + if( diff && !aReporter ) \ + return diff; \ /* Prevent binding to else following macro */ \ else {} @@ -491,6 +485,10 @@ bool FOOTPRINT::FootprintNeedsUpdate( const FOOTPRINT* aLibFootprint, REPORTER* _( "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 // it gets messy. // @@ -521,86 +519,88 @@ bool FOOTPRINT::FootprintNeedsUpdate( const FOOTPRINT* aLibFootprint, REPORTER* return item->Type() == PCB_FP_SHAPE_T; } ); - std::set aPads( Pads().begin(), Pads().end() ); - std::set bPads( aLibFootprint->Pads().begin(), aLibFootprint->Pads().end() ); + 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( *aIt ), static_cast( *bIt ) ) ) + { + diff = true; + REPORT( wxString::Format( _( "%s differs." ), ITEM_DESC( *aIt ) ) ); + } + } + } + } - std::set aZones( Zones().begin(), Zones().end() ); - std::set bZones( aLibFootprint->Zones().begin(), aLibFootprint->Zones().end() ); + CHECKPOINT; - TEST( aPads.size(), bPads.size(), _( "Pad count differs." ) ); - TEST( aZones.size(), bZones.size(), _( "Rule area count differs." ) ); - TEST( aShapes.size(), bShapes.size(), _( "Graphic item count differs." ) ); + std::set aPads( Pads().begin(), Pads().end() ); + std::set bPads( aLibFootprint->Pads().begin(), aLibFootprint->Pads().end() ); - for( auto aIt = aPads.begin(), bIt = bPads.begin(); aIt != aPads.end(); aIt++, bIt++ ) + if( aPads.size() != bPads.size() ) { - if( padNeedsUpdate( *aIt, *bIt ) ) + diff = true; + REPORT( _( "Pad count differs." ) ); + } + else + { + for( auto aIt = aPads.begin(), bIt = bPads.begin(); aIt != aPads.end(); aIt++, bIt++ ) { - if( aReporter ) + if( padNeedsUpdate( *aIt, *bIt ) ) { - wxString msg = (*aIt)->GetItemDescription( &unitsProvider ); - aReporter->Report( wxString::Format( _( "%s differs." ), msg ) ); diff = true; + REPORT( wxString::Format( _( "%s differs." ), ITEM_DESC( *aIt ) ) ); } - else + else if( aReporter && padHasOverrides( *aIt, *bIt ) ) { - return true; + diff = true; + REPORT( wxString::Format( _( "%s has overrides." ), ITEM_DESC( *aIt ) ) ); } } - else if( aReporter && padHasOverrides( *aIt, *bIt ) ) - { - wxString msg = (*aIt)->GetItemDescription( &unitsProvider ); - aReporter->Report( wxString::Format( _( "%s has overrides." ), msg ) ); - diff = true; - } } - for( auto aIt = aShapes.begin(), bIt = bShapes.begin(); aIt != aShapes.end(); aIt++, bIt++ ) + CHECKPOINT; + + std::set aZones( Zones().begin(), Zones().end() ); + std::set bZones( aLibFootprint->Zones().begin(), aLibFootprint->Zones().end() ); + + if( aZones.size() != bZones.size() ) { - if( ( *aIt )->Type() == PCB_FP_SHAPE_T ) - { - if( shapeNeedsUpdate( static_cast( *aIt ), static_cast( *bIt ) ) ) - { - if( aReporter ) - { - wxString msg = (*aIt)->GetItemDescription( &unitsProvider ); - aReporter->Report( wxString::Format( _( "%s differs." ), msg ) ); - diff = true; - } - else - { - return true; - } - } - } + diff = true; + REPORT( _( "Rule area count differs." ) ); } - - for( auto aIt = aZones.begin(), bIt = bZones.begin(); aIt != aZones.end(); aIt++, bIt++ ) + else { - if( zonesNeedUpdate( *aIt, *bIt ) ) + for( auto aIt = aZones.begin(), bIt = bZones.begin(); aIt != aZones.end(); aIt++, bIt++ ) { - if( aReporter ) + if( zonesNeedUpdate( *aIt, *bIt ) ) { - wxString msg = (*aIt)->GetItemDescription( &unitsProvider ); - aReporter->Report( wxString::Format( _( "%s differs." ), msg ) ); diff = true; - } - else - { - return true; + REPORT( wxString::Format( _( "%s differs." ), ITEM_DESC( *aIt ) ) ); } } } - TEST( Models().size(), aLibFootprint->Models().size(), _( "3D model count differs." ) ); + CHECKPOINT; - for( size_t ii = 0; ii < Models().size(); ++ii ) + if( Models().size() != aLibFootprint->Models().size() ) + { + diff = true; + REPORT( _( "3D model count differs." ) ); + } + else { - 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; - else - return true; } } diff --git a/pcbnew/tools/board_inspection_tool.cpp b/pcbnew/tools/board_inspection_tool.cpp index 1d6a28ebc8..466db23e19 100644 --- a/pcbnew/tools/board_inspection_tool.cpp +++ b/pcbnew/tools/board_inspection_tool.cpp @@ -1,7 +1,7 @@ /* * 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 * 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 ) { r->Report( "" ); - r->Report( _( "Report incomplete: could not compile custom design rules. " ) - + wxT( "" ) + _( "Show design rules." ) + wxT( "" ) ); + r->Report( _( "Report incomplete: could not compile custom design rules." ) + + wxS( "  " ) + + wxS( "" ) + _( "Show design rules." ) + wxS( "" ) ); } @@ -1282,7 +1283,8 @@ int BOARD_INSPECTION_TOOL::InspectConstraints( const TOOL_EVENT& aEvent ) { r->Report( "" ); r->Report( _( "Report may be incomplete: some footprint courtyards are malformed." ) - + wxT( " " ) + _( "Run DRC for a full analysis." ) + wxT( "" ) ); + + wxS( "  " ) + + wxS( "" ) + _( "Run DRC for a full analysis." ) + wxS( "" ) ); } r->Report( "" ); @@ -1304,7 +1306,8 @@ int BOARD_INSPECTION_TOOL::InspectConstraints( const TOOL_EVENT& aEvent ) { r->Report( "" ); r->Report( _( "Report may be incomplete: some footprint courtyards are malformed." ) - + wxT( " " ) + _( "Run DRC for a full analysis." ) + wxT( "" ) ); + + wxS( "  " ) + + wxS( "" ) + _( "Run DRC for a full analysis." ) + wxS( "" ) ); } 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 ) { - 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; } - if( m_inspectConstraintsDialog == nullptr ) + if( m_inspectLibraryDiffDialog == nullptr ) { - m_inspectConstraintsDialog = std::make_unique( m_frame ); - m_inspectConstraintsDialog->SetTitle( _( "Check Footprint against Library" ) ); + m_inspectLibraryDiffDialog = std::make_unique( m_frame ); + m_inspectLibraryDiffDialog->SetTitle( _( "Diff Footprint with Library" ) ); - m_inspectConstraintsDialog->Connect( wxEVT_CLOSE_WINDOW, - wxCommandEventHandler( BOARD_INSPECTION_TOOL::onInspectConstraintsDialogClosed ), + m_inspectLibraryDiffDialog->Connect( wxEVT_CLOSE_WINDOW, + wxCommandEventHandler( BOARD_INSPECTION_TOOL::onInspectLibraryDiffDialogClosed ), nullptr, this ); } - m_inspectConstraintsDialog->DeleteAllPages(); + m_inspectLibraryDiffDialog->DeleteAllPages(); FOOTPRINT* footprint = static_cast( selection.GetItem( 0 ) ); LIB_ID fpID = footprint->GetFPID(); @@ -1358,12 +1361,12 @@ int BOARD_INSPECTION_TOOL::InspectLibraryDiff( const TOOL_EVENT& aEvent ) wxString fpName = fpID.GetLibItemName(); WX_HTML_REPORT_BOX* r = nullptr; - r = m_inspectConstraintsDialog->AddPage( _( "Diff" ) ); + r = m_inspectLibraryDiffDialog->AddPage( _( "Summary" ) ); - r->Report( wxT( "" ) + _( "Board/library check for:" ) + wxT( "" ) ); - r->Report( wxT( "
  • " ) + EscapeHTML( getItemDescription( footprint ) ) + wxT( "
  • " ) - + wxT( "
  • " ) + _( "Library: " ) + EscapeHTML( libName ) + wxT( "
  • " ) - + wxT( "
  • " ) + _( "Library item: " ) + EscapeHTML( fpName ) + wxT( "
" ) ); + r->Report( wxS( "" ) + _( "Board vs library diff for:" ) + wxS( "" ) ); + r->Report( wxS( "
  • " ) + EscapeHTML( getItemDescription( footprint ) ) + wxS( "
  • " ) + + wxS( "
  • " ) + _( "Library: " ) + EscapeHTML( libName ) + wxS( "
  • " ) + + wxS( "
  • " ) + _( "Library item: " ) + EscapeHTML( fpName ) + wxS( "
" ) ); r->Report( "" ); @@ -1381,11 +1384,17 @@ int BOARD_INSPECTION_TOOL::InspectLibraryDiff( const TOOL_EVENT& aEvent ) if( !libTableRow ) { - r->Report( _( "The current configuration does not include the library." ) ); + r->Report( _( "The library is not included in the current configuration." ) + + wxS( "   " ) + + wxS( "" ) + _( "Manage Footprint Libraries" ) + wxS( "" ) ); + } 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( "   " ) + + wxS( "" ) + _( "Manage Footprint Libraries" ) + wxS( "" ) ); + } else { @@ -1406,15 +1415,15 @@ int BOARD_INSPECTION_TOOL::InspectLibraryDiff( const TOOL_EVENT& aEvent ) } else if( !footprint->FootprintNeedsUpdate( libFootprint.get(), r ) ) { - r->Report( _( "Footprint matches library equivalent." ) ); + r->Report( _( "No relevant differences detected." ) ); } } r->Flush(); - m_inspectConstraintsDialog->FinishInitialization(); - m_inspectConstraintsDialog->Raise(); - m_inspectConstraintsDialog->Show( true ); + m_inspectLibraryDiffDialog->FinishInitialization(); + m_inspectLibraryDiffDialog->Raise(); + m_inspectLibraryDiffDialog->Show( true ); 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 ) { doHideRatsnestNet( aEvent.Parameter(), true ); diff --git a/pcbnew/tools/board_inspection_tool.h b/pcbnew/tools/board_inspection_tool.h index 48dd5046ea..c4c8d8b656 100644 --- a/pcbnew/tools/board_inspection_tool.h +++ b/pcbnew/tools/board_inspection_tool.h @@ -1,7 +1,7 @@ /* * 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 * modify it under the terms of the GNU General Public License @@ -119,6 +119,7 @@ private: void onListNetsDialogClosed( wxCommandEvent& aEvent ); void onInspectClearanceDialogClosed( wxCommandEvent& aEvent ); void onInspectConstraintsDialogClosed( wxCommandEvent& aEvent ); + void onInspectLibraryDiffDialogClosed( wxCommandEvent& aEvent ); DRC_ENGINE makeDRCEngine( bool* aCompileError, bool* aCourtyardError = nullptr ); @@ -143,6 +144,7 @@ private: std::unique_ptr m_inspectClearanceDialog; std::unique_ptr m_inspectConstraintsDialog; + std::unique_ptr m_inspectLibraryDiffDialog; }; #endif //BOARD_INSPECTION_TOOL_H diff --git a/pcbnew/tools/pcb_actions.cpp b/pcbnew/tools/pcb_actions.cpp index 5205b8ee42..a3e64c9d4d 100644 --- a/pcbnew/tools/pcb_actions.cpp +++ b/pcbnew/tools/pcb_actions.cpp @@ -1175,9 +1175,9 @@ TOOL_ACTION PCB_ACTIONS::inspectConstraints( "pcbnew.InspectionTool.InspectConst TOOL_ACTION PCB_ACTIONS::inspectLibraryDiff( "pcbnew.InspectionTool.InspectLibraryDiff", AS_GLOBAL, 0, "", - _( "Check Footprint against Library..." ), + _( "Diff Footprint with Library..." ), _( "Check for differences between board footprint and its library equivalent" ), - BITMAPS::show_footprint ); + BITMAPS::library ); //Geographic re-annotation tool TOOL_ACTION PCB_ACTIONS::boardReannotate( "pcbnew.ReannotateTool.ShowReannotateDialog", diff --git a/qa/unittests/eeschema/test_lib_part.cpp b/qa/unittests/eeschema/test_lib_part.cpp index 26d9f3a9bf..a033c97fea 100644 --- a/qa/unittests/eeschema/test_lib_part.cpp +++ b/qa/unittests/eeschema/test_lib_part.cpp @@ -425,10 +425,10 @@ BOOST_AUTO_TEST_CASE( Compare ) m_part_no_data.AddDrawItem( new LIB_SHAPE( &m_part_no_data, SHAPE_T::ARC ) ); BOOST_CHECK( m_part_no_data.Compare( testPart ) > 0 ); 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 ) ); BOOST_CHECK( m_part_no_data.Compare( testPart ) > 0 ); 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. wxArrayString footPrintFilters;