From e325d2e18fc9aa3d2a87760dbee663951cdf01f1 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Mon, 8 Jun 2020 19:36:25 +0100 Subject: [PATCH] Allow Net Inspector to create, rename and delete nets. ADDED: create/edit/delete nets in PCBnew Net Inspector ADDED: update from PCB now allows updating of changed nets Fixes https://gitlab.com/kicad/code/kicad/issues/1996 --- common/validators.cpp | 59 ++- eeschema/dialogs/dialog_update_from_pcb.cpp | 51 +- eeschema/dialogs/dialog_update_from_pcb.h | 15 +- .../dialogs/dialog_update_from_pcb_base.cpp | 8 + .../dialogs/dialog_update_from_pcb_base.fbp | 75 +++ .../dialogs/dialog_update_from_pcb_base.h | 1 + eeschema/sch_component.cpp | 8 +- eeschema/sch_validators.cpp | 76 +-- eeschema/sch_validators.h | 41 +- eeschema/tools/backannotate.cpp | 477 +++++++++++++----- eeschema/tools/backannotate.h | 76 ++- include/validators.h | 27 + pcbnew/cross-probing.cpp | 26 +- .../dialogs/dialog_select_net_from_list.cpp | 276 +++++++--- pcbnew/dialogs/dialog_select_net_from_list.h | 3 + .../dialog_select_net_from_list_base.cpp | 38 +- .../dialog_select_net_from_list_base.fbp | 326 +++++++++++- .../dialog_select_net_from_list_base.h | 11 +- pcbnew/netinfo.h | 15 + .../netlist_reader/board_netlist_updater.cpp | 1 - pcbnew/netlist_reader/pcb_netlist.cpp | 20 +- pcbnew/netlist_reader/pcb_netlist.h | 65 +-- 22 files changed, 1182 insertions(+), 513 deletions(-) diff --git a/common/validators.cpp b/common/validators.cpp index e3877b1b3f..b3b3cc3397 100644 --- a/common/validators.cpp +++ b/common/validators.cpp @@ -36,7 +36,7 @@ #include #include #include - +#include GRID_CELL_TEXT_EDITOR::GRID_CELL_TEXT_EDITOR() : wxGridCellTextEditor() { @@ -316,6 +316,63 @@ bool LIB_ID_VALIDATOR::Validate( wxWindow *aParent ) } +NETNAME_VALIDATOR::NETNAME_VALIDATOR( wxString *aVal ) : + wxTextValidator(), + m_allowSpaces( false ) +{ +} + + +NETNAME_VALIDATOR::NETNAME_VALIDATOR( const NETNAME_VALIDATOR& aValidator ) : + wxTextValidator( aValidator ), + m_allowSpaces( aValidator.m_allowSpaces ) +{ +} + + +NETNAME_VALIDATOR::NETNAME_VALIDATOR( bool aAllowSpaces ) : + wxTextValidator(), + m_allowSpaces( aAllowSpaces ) +{ +} + + +bool NETNAME_VALIDATOR::Validate( wxWindow *aParent ) +{ + // If window is disabled, simply return + if ( !m_validatorWindow->IsEnabled() ) + return true; + + wxTextEntry * const text = GetTextEntry(); + + if ( !text ) + return false; + + const wxString& errormsg = IsValid( text->GetValue() ); + + if( !errormsg.empty() ) + { + m_validatorWindow->SetFocus(); + wxMessageBox( errormsg, _( "Invalid signal name" ), wxOK | wxICON_EXCLAMATION, aParent ); + return false; + } + + return true; +} + + +wxString NETNAME_VALIDATOR::IsValid( const wxString& str ) const +{ + if( str.Contains( '\r' ) || str.Contains( '\n' ) ) + return _( "Signal names cannot contain CR or LF characters" ); + + if( !m_allowSpaces && ( str.Contains( ' ' ) || str.Contains( '\t' ) ) ) + return _( "Signal names cannot contain spaces" ); + + return wxString(); +} + + void KIUI::ValidatorTransferToWindowWithoutEvents( wxValidator& aValidator ) { wxWindow* ctrl = aValidator.GetWindow(); diff --git a/eeschema/dialogs/dialog_update_from_pcb.cpp b/eeschema/dialogs/dialog_update_from_pcb.cpp index 054794b3c3..f0854641ee 100644 --- a/eeschema/dialogs/dialog_update_from_pcb.cpp +++ b/eeschema/dialogs/dialog_update_from_pcb.cpp @@ -1,12 +1,8 @@ -/** - * @file eeschema/dialogs/dialog_update_from_pcb.cpp - */ - /* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2019 Alexander Shuklin - * Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2020 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 @@ -27,20 +23,14 @@ */ #include -#include -#include -#include #include -#include #include #include -#include -#include #include // Saved dialog settings DIALOG_UPDATE_FROM_PCB::DIALOG_UPDATE_FROM_PCB_SAVED_STATE - DIALOG_UPDATE_FROM_PCB::s_savedDialogState{ true, false, false, false }; + DIALOG_UPDATE_FROM_PCB::s_savedDialogState{ true, true, true, true, false }; DIALOG_UPDATE_FROM_PCB::DIALOG_UPDATE_FROM_PCB( SCH_EDIT_FRAME* aParent ) : DIALOG_UPDATE_FROM_PCB_BASE( aParent ), @@ -55,6 +45,7 @@ DIALOG_UPDATE_FROM_PCB::DIALOG_UPDATE_FROM_PCB( SCH_EDIT_FRAME* aParent ) m_cbUpdateReferences->SetValue( s_savedDialogState.UpdateReferences ); m_cbUpdateFootprints->SetValue( s_savedDialogState.UpdateFootprints ); m_cbUpdateValues->SetValue( s_savedDialogState.UpdateValues ); + m_cbUpdateNetNames->SetValue( s_savedDialogState.UpdateNetNames ); m_cbIgnoreOtherProjects->SetValue( s_savedDialogState.IgnoreOtherProjectsErrors ); // We use a sdbSizer to get platform-dependent ordering of the action buttons, but @@ -67,22 +58,23 @@ DIALOG_UPDATE_FROM_PCB::DIALOG_UPDATE_FROM_PCB( SCH_EDIT_FRAME* aParent ) FinishDialogSettings(); } -BACK_ANNOTATE::SETTINGS DIALOG_UPDATE_FROM_PCB::getSettings( bool aDryRun ) -{ - return BACK_ANNOTATE::SETTINGS{ m_messagePanel->Reporter(), m_cbUpdateFootprints->GetValue(), - m_cbUpdateValues->GetValue(), m_cbUpdateReferences->GetValue(), - m_cbIgnoreOtherProjects->GetValue(), aDryRun }; -} - void DIALOG_UPDATE_FROM_PCB::updateData() { bool successfulRun = false; m_messagePanel->Clear(); - BACK_ANNOTATE backAnno( this->m_frame, getSettings( true ) ); + BACK_ANNOTATE backAnno( this->m_frame, + m_messagePanel->Reporter(), + m_cbUpdateFootprints->GetValue(), + m_cbUpdateValues->GetValue(), + m_cbUpdateReferences->GetValue(), + m_cbUpdateNetNames->GetValue(), + m_cbIgnoreOtherProjects->GetValue(), + true ); std::string netlist; if( backAnno.FetchNetlistFromPCB( netlist ) ) successfulRun = backAnno.BackAnnotateSymbols( netlist ); + m_sdbSizerOK->Enable( successfulRun ); m_messagePanel->Flush( false ); } @@ -103,23 +95,22 @@ void DIALOG_UPDATE_FROM_PCB::OnOptionChanged( wxCommandEvent& event ) s_savedDialogState.UpdateReferences = m_cbUpdateReferences->GetValue(); s_savedDialogState.UpdateFootprints = m_cbUpdateFootprints->GetValue(); s_savedDialogState.UpdateValues = m_cbUpdateValues->GetValue(); + s_savedDialogState.UpdateNetNames = m_cbUpdateNetNames->GetValue(); s_savedDialogState.IgnoreOtherProjectsErrors = m_cbIgnoreOtherProjects->GetValue(); } void DIALOG_UPDATE_FROM_PCB::OnUpdateClick( wxCommandEvent& event ) { - KIDIALOG dlg( this, - _( "\n\nThis operation will change the existing annotation and cannot be undone." ), - _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING ); - dlg.SetOKLabel( _( "Back annotate" ) ); - dlg.DoNotShowCheckbox( __FILE__, __LINE__ ); - - if( dlg.ShowModal() == wxID_CANCEL ) - return; - std::string netlist; m_messagePanel->Clear(); - BACK_ANNOTATE backAnno( this->m_frame, getSettings( false ) ); + BACK_ANNOTATE backAnno( m_frame, + m_messagePanel->Reporter(), + m_cbUpdateFootprints->GetValue(), + m_cbUpdateValues->GetValue(), + m_cbUpdateReferences->GetValue(), + m_cbUpdateNetNames->GetValue(), + m_cbIgnoreOtherProjects->GetValue(), + false ); if( backAnno.FetchNetlistFromPCB( netlist ) && backAnno.BackAnnotateSymbols( netlist ) ) { diff --git a/eeschema/dialogs/dialog_update_from_pcb.h b/eeschema/dialogs/dialog_update_from_pcb.h index 20c065ab51..69a792d0f7 100644 --- a/eeschema/dialogs/dialog_update_from_pcb.h +++ b/eeschema/dialogs/dialog_update_from_pcb.h @@ -1,12 +1,8 @@ -/** - * @file eeschema/dialogs/dialog_update_from_pcb.h - */ - /* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2019 Alexander Shuklin - * Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2020 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 @@ -38,7 +34,6 @@ class SCH_EDITOR_CONTROL; class DIALOG_UPDATE_FROM_PCB : public DIALOG_UPDATE_FROM_PCB_BASE { - /** * Struct containing the dialog last saved state */ @@ -48,6 +43,7 @@ class DIALOG_UPDATE_FROM_PCB : public DIALOG_UPDATE_FROM_PCB_BASE bool UpdateReferences; bool UpdateFootprints; bool UpdateValues; + bool UpdateNetNames; bool IgnoreOtherProjectsErrors; }; @@ -64,13 +60,6 @@ public: private: void updateData(); - /** - * @brief Creates back annotate settings from dialog ui - * @param aDryRun - is it dry run - * @return back annotation settings structure - */ - BACK_ANNOTATE::SETTINGS getSettings( bool aDryRun ); - bool TransferDataToWindow() override; void OnOptionChanged( wxCommandEvent& event ) override; void OnUpdateClick( wxCommandEvent& event ) override; diff --git a/eeschema/dialogs/dialog_update_from_pcb_base.cpp b/eeschema/dialogs/dialog_update_from_pcb_base.cpp index b8f0b064b7..1a0cc27552 100644 --- a/eeschema/dialogs/dialog_update_from_pcb_base.cpp +++ b/eeschema/dialogs/dialog_update_from_pcb_base.cpp @@ -54,6 +54,12 @@ DIALOG_UPDATE_FROM_PCB_BASE::DIALOG_UPDATE_FROM_PCB_BASE( wxWindow* parent, wxWi fgSizer1->Add( m_cbUpdateFootprints, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + fgSizer1->Add( 0, 0, 1, wxEXPAND, 5 ); + + m_cbUpdateNetNames = new wxCheckBox( sbSizerOptions->GetStaticBox(), wxID_ANY, _("Update net names"), wxDefaultPosition, wxDefaultSize, 0 ); + fgSizer1->Add( m_cbUpdateNetNames, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + sbSizerOptions->Add( fgSizer1, 1, wxEXPAND, 5 ); @@ -91,6 +97,7 @@ DIALOG_UPDATE_FROM_PCB_BASE::DIALOG_UPDATE_FROM_PCB_BASE( wxWindow* parent, wxWi m_cbIgnoreOtherProjects->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_UPDATE_FROM_PCB_BASE::OnOptionChanged ), NULL, this ); m_cbUpdateValues->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_UPDATE_FROM_PCB_BASE::OnOptionChanged ), NULL, this ); m_cbUpdateFootprints->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_UPDATE_FROM_PCB_BASE::OnOptionChanged ), NULL, this ); + m_cbUpdateNetNames->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_UPDATE_FROM_PCB_BASE::OnOptionChanged ), NULL, this ); m_sdbSizerOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_UPDATE_FROM_PCB_BASE::OnUpdateClick ), NULL, this ); } @@ -101,6 +108,7 @@ DIALOG_UPDATE_FROM_PCB_BASE::~DIALOG_UPDATE_FROM_PCB_BASE() m_cbIgnoreOtherProjects->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_UPDATE_FROM_PCB_BASE::OnOptionChanged ), NULL, this ); m_cbUpdateValues->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_UPDATE_FROM_PCB_BASE::OnOptionChanged ), NULL, this ); m_cbUpdateFootprints->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_UPDATE_FROM_PCB_BASE::OnOptionChanged ), NULL, this ); + m_cbUpdateNetNames->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_UPDATE_FROM_PCB_BASE::OnOptionChanged ), NULL, this ); m_sdbSizerOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_UPDATE_FROM_PCB_BASE::OnUpdateClick ), NULL, this ); } diff --git a/eeschema/dialogs/dialog_update_from_pcb_base.fbp b/eeschema/dialogs/dialog_update_from_pcb_base.fbp index 5ae266d9fc..73732d57a3 100644 --- a/eeschema/dialogs/dialog_update_from_pcb_base.fbp +++ b/eeschema/dialogs/dialog_update_from_pcb_base.fbp @@ -365,6 +365,81 @@ OnOptionChanged + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 5 + wxBOTTOM|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Update net names + + 0 + + + 0 + + 1 + m_cbUpdateNetNames + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnOptionChanged + + diff --git a/eeschema/dialogs/dialog_update_from_pcb_base.h b/eeschema/dialogs/dialog_update_from_pcb_base.h index 4c5c87d080..bec9f5d2db 100644 --- a/eeschema/dialogs/dialog_update_from_pcb_base.h +++ b/eeschema/dialogs/dialog_update_from_pcb_base.h @@ -39,6 +39,7 @@ class DIALOG_UPDATE_FROM_PCB_BASE : public DIALOG_SHIM wxCheckBox* m_cbIgnoreOtherProjects; wxCheckBox* m_cbUpdateValues; wxCheckBox* m_cbUpdateFootprints; + wxCheckBox* m_cbUpdateNetNames; WX_HTML_REPORT_PANEL* m_messagePanel; wxStdDialogButtonSizer* m_sdbSizer; wxButton* m_sdbSizerOK; diff --git a/eeschema/sch_component.cpp b/eeschema/sch_component.cpp index b0dcfa37f9..88aff98da0 100644 --- a/eeschema/sch_component.cpp +++ b/eeschema/sch_component.cpp @@ -142,9 +142,9 @@ SCH_COMPONENT::SCH_COMPONENT( LIB_PART& aPart, LIB_ID aLibId, SCH_SHEET_PATH* sh } -SCH_COMPONENT::SCH_COMPONENT( - LIB_PART& aPart, SCH_SHEET_PATH* aSheet, COMPONENT_SELECTION& aSel, const wxPoint& pos ) - : SCH_COMPONENT( aPart, aSel.LibId, aSheet, aSel.Unit, aSel.Convert, pos ) +SCH_COMPONENT::SCH_COMPONENT( LIB_PART& aPart, SCH_SHEET_PATH* aSheet, COMPONENT_SELECTION& aSel, + const wxPoint& pos ) : + SCH_COMPONENT( aPart, aSel.LibId, aSheet, aSel.Unit, aSel.Convert, pos ) { // Set any fields that were modified as part of the component selection for( auto const& i : aSel.Fields ) @@ -262,9 +262,7 @@ void SCH_COMPONENT::SetLibSymbol( LIB_PART* aLibSymbol ) wxString SCH_COMPONENT::GetDescription() const { if( m_part ) - { return m_part->GetDescription(); - } return wxEmptyString; } diff --git a/eeschema/sch_validators.cpp b/eeschema/sch_validators.cpp index da144fe515..078d299605 100644 --- a/eeschema/sch_validators.cpp +++ b/eeschema/sch_validators.cpp @@ -27,6 +27,7 @@ * @brief Implementation of control validators for schematic dialogs. */ +#include #include #include #include @@ -183,73 +184,6 @@ bool SCH_FIELD_VALIDATOR::Validate( wxWindow *aParent ) } -SCH_NETNAME_VALIDATOR::SCH_NETNAME_VALIDATOR( wxString *aVal ) - : wxValidator(), - m_allowSpaces( false ) -{ -} - - -SCH_NETNAME_VALIDATOR::SCH_NETNAME_VALIDATOR( const SCH_NETNAME_VALIDATOR& aValidator ) - : wxValidator(), - m_allowSpaces( aValidator.m_allowSpaces ) -{ -} - - -SCH_NETNAME_VALIDATOR::SCH_NETNAME_VALIDATOR( bool aAllowSpaces ) - : wxValidator(), - m_allowSpaces( aAllowSpaces ) -{ -} - - -wxTextEntry *SCH_NETNAME_VALIDATOR::GetTextEntry() -{ -#if wxUSE_TEXTCTRL - if( wxDynamicCast( m_validatorWindow, wxTextCtrl ) ) - return static_cast( m_validatorWindow ); -#endif - -#if wxUSE_COMBOBOX - if( wxDynamicCast( m_validatorWindow, wxComboBox ) ) - return static_cast( m_validatorWindow ); -#endif - -#if wxUSE_COMBOCTRL - if( wxDynamicCast( m_validatorWindow, wxComboCtrl ) ) - return static_cast( m_validatorWindow ); -#endif - - wxFAIL_MSG( "SCH_NETNAME_VALIDATOR can only be used with wxTextCtrl, wxComboBox, or wxComboCtrl" ); - return nullptr; -} - - -bool SCH_NETNAME_VALIDATOR::Validate( wxWindow *aParent ) -{ - // If window is disabled, simply return - if ( !m_validatorWindow->IsEnabled() ) - return true; - - wxTextEntry * const text = GetTextEntry(); - - if ( !text ) - return false; - - const wxString& errormsg = IsValid( text->GetValue() ); - - if( !errormsg.empty() ) - { - m_validatorWindow->SetFocus(); - wxMessageBox( errormsg, _( "Invalid signal name" ), wxOK | wxICON_EXCLAMATION, aParent ); - return false; - } - - return true; -} - - wxString SCH_NETNAME_VALIDATOR::IsValid( const wxString& str ) const { if( NET_SETTINGS::ParseBusGroup( str, nullptr, nullptr ) ) @@ -259,11 +193,5 @@ wxString SCH_NETNAME_VALIDATOR::IsValid( const wxString& str ) const !NET_SETTINGS::ParseBusVector( str, nullptr, nullptr ) ) return _( "Signal name contains '[' or ']' but is not a valid vector bus name" ); - if( str.Contains( '\r' ) || str.Contains( '\n' ) ) - return _( "Signal names cannot contain CR or LF characters" ); - - if( !m_allowSpaces && ( str.Contains( ' ' ) || str.Contains( '\t' ) ) ) - return _( "Signal names cannot contain spaces" ); - - return wxString(); + return NETNAME_VALIDATOR::IsValid( str ); } diff --git a/eeschema/sch_validators.h b/eeschema/sch_validators.h index 38f91c18bf..6bbc379176 100644 --- a/eeschema/sch_validators.h +++ b/eeschema/sch_validators.h @@ -31,7 +31,7 @@ #define _SCH_VALIDATORS_H_ #include - +#include #define FIELD_NAME -1 #define FIELD_VALUE -2 @@ -71,38 +71,27 @@ public: }; -class SCH_NETNAME_VALIDATOR : public wxValidator +/* + * A refinement of the NETNAME_VALIDATOR which also allows (and checks) bus definitions. + */ +class SCH_NETNAME_VALIDATOR : public NETNAME_VALIDATOR { public: - SCH_NETNAME_VALIDATOR( wxString *aVal = nullptr ); + SCH_NETNAME_VALIDATOR( wxString *aVal = nullptr ) : + NETNAME_VALIDATOR( aVal ) + { } - SCH_NETNAME_VALIDATOR( bool aAllowSpaces ); + SCH_NETNAME_VALIDATOR( bool aAllowSpaces ) : + NETNAME_VALIDATOR( aAllowSpaces ) + { } - SCH_NETNAME_VALIDATOR( const SCH_NETNAME_VALIDATOR& aValidator ); - - void SetAllowSpaces( bool aAllowSpaces = true ) { m_allowSpaces = aAllowSpaces; } - - bool GetAllowSpaces() const { return m_allowSpaces; } - - bool Copy( const SCH_NETNAME_VALIDATOR& val ); - - virtual wxObject* Clone() const override { return new SCH_NETNAME_VALIDATOR( *this ); } - - virtual bool TransferToWindow() override { return true; } - - virtual bool TransferFromWindow() override { return true; } - - wxTextEntry* GetTextEntry(); - - virtual bool Validate( wxWindow *aParent ) override; + SCH_NETNAME_VALIDATOR( const SCH_NETNAME_VALIDATOR& aValidator ) : + NETNAME_VALIDATOR( aValidator ) + { } protected: - // returns the error message if the contents of 'val' are invalid - virtual wxString IsValid( const wxString& aVal ) const; - -private: - bool m_allowSpaces; + wxString IsValid( const wxString& aVal ) const override; }; #endif // _SCH_VALIDATORS_H_ diff --git a/eeschema/tools/backannotate.cpp b/eeschema/tools/backannotate.cpp index 78804fbcc9..67186d101b 100644 --- a/eeschema/tools/backannotate.cpp +++ b/eeschema/tools/backannotate.cpp @@ -1,12 +1,8 @@ -/** - * @file eeschema/tools/backannotate.cpp - */ - /* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2019 Alexander Shuklin - * Copyright (C) 2004-2019 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2004-2020 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 @@ -31,18 +27,25 @@ #include #include #include -#include -#include #include #include #include #include #include -#include +#include -BACK_ANNOTATE::BACK_ANNOTATE( SCH_EDIT_FRAME* aFrame, SETTINGS aSettings ) : - m_settings( aSettings ), +BACK_ANNOTATE::BACK_ANNOTATE( SCH_EDIT_FRAME* aFrame, REPORTER& aReporter, + bool aProcessFootprints, bool aProcessValues, + bool aProcessReferences, bool aProcessNetNames, + bool aIgnoreOtherProjects, bool aDryRun ) : + m_reporter( aReporter ), + m_processFootprints( aProcessFootprints ), + m_processValues( aProcessValues ), + m_processReferences( aProcessReferences ), + m_processNetNames( aProcessNetNames ), + m_ignoreOtherProjects( aIgnoreOtherProjects ), + m_dryRun( aDryRun ), m_frame( aFrame ), m_changesCount( 0 ) { @@ -59,103 +62,100 @@ bool BACK_ANNOTATE::BackAnnotateSymbols( const std::string& aNetlist ) m_changesCount = 0; wxString msg; - if( !m_settings.processValues && !m_settings.processFootprints - && !m_settings.processReferences ) + if( !m_processValues && !m_processFootprints && !m_processReferences && !m_processNetNames ) { - m_settings.reporter.ReportTail( - _( "Select at least one property to back annotate" ), RPT_SEVERITY_ERROR ); + m_reporter.ReportTail( _( "Select at least one property to back annotate." ), + RPT_SEVERITY_ERROR ); return false; } - int errors = getPcbModulesFromString( aNetlist ); + getPcbModulesFromString( aNetlist ); SCH_SHEET_LIST sheets = m_frame->Schematic().GetSheets(); sheets.GetComponents( m_refs, false ); sheets.GetMultiUnitComponents( m_multiUnitsRefs ); - errors += getChangeList(); - errors += checkForUnusedSymbols(); - errors += checkSharedSchematicErrors(); + getChangeList(); + checkForUnusedSymbols(); + checkSharedSchematicErrors(); - if( errors > 0 ) - m_settings.dryRun = true; + SCH_SHEET_PATH current = m_frame->GetCurrentSheet(); applyChangelist(); + m_frame->SetCurrentSheet( current ); - if( !errors ) - { - - if( !m_settings.dryRun ) - { - msg.Printf( _( "Schematic is back-annotated. %d changes applied." ), m_changesCount ); - m_settings.reporter.ReportTail( msg, RPT_SEVERITY_ACTION ); - } - else - m_settings.reporter.ReportTail( - _( "No errors during dry run. Ready to go." ), RPT_SEVERITY_ACTION ); - } - else - { - msg.Printf( _( "Found %d errors. Fix them and run back annotation." ), errors ); - m_settings.reporter.ReportTail( msg, RPT_SEVERITY_ERROR ); - } - - return !errors; + return true; } bool BACK_ANNOTATE::FetchNetlistFromPCB( std::string& aNetlist ) { - if( Kiface().IsSingle() ) { - DisplayErrorMessage( - m_frame, _( "Cannot fetch PCB netlist because eeschema is opened in " - "stand-alone mode.\n" - "You must launch the KiCad project manager " - "and create a project." ) ); - return false; - } - - KIWAY_PLAYER* player = m_frame->Kiway().Player( FRAME_PCB_EDITOR, false ); - - if( !player ) - { - DisplayErrorMessage( - this->m_frame, _( "Please open Pcbnew and run back annotation again" ) ); + DisplayErrorMessage( m_frame, _( "Cannot fetch PCB netlist because eeschema is opened " + "in stand-alone mode.\n" + "You must launch the KiCad project manager and create " + "a project." ) ); return false; } + m_frame->Kiway().Player( FRAME_PCB_EDITOR, true ); m_frame->Kiway().ExpressMail( FRAME_PCB_EDITOR, MAIL_PCB_GET_NETLIST, aNetlist ); return true; } -int BACK_ANNOTATE::getPcbModulesFromString( const std::string& aPayload ) +void BACK_ANNOTATE::getPcbModulesFromString( const std::string& aPayload ) { + auto getStr = []( const PTREE& pt ) -> wxString + { + return UTF8( pt.front().first ); + }; + DSNLEXER lexer( aPayload, FROM_UTF8( __func__ ) ); PTREE doc; - Scan( &doc, &lexer ); - CPTREE& tree = doc.get_child( "pcb_netlist" ); - wxString msg; - int errors = 0; + // NOTE: KiCad's PTREE scanner constructs a property *name* tree, not a property tree. + // Every token in the s-expr is stored as a property name; the property's value is then + // either the nested s-exprs or an empty PTREE; there are *no* literal property values. + + Scan( &doc, &lexer ); + + PTREE& tree = doc.get_child( "pcb_netlist" ); + wxString msg; m_pcbModules.clear(); - for( auto& item : tree ) + + for( const std::pair& item : tree ) { wxString path, value, footprint; + std::map pinNetMap; wxASSERT( item.first == "ref" ); - wxString ref = UTF8( item.second.front().first ); + wxString ref = getStr( item.second ); + try { - path = UTF8( item.second.get_child( "timestamp" ).front().first ); + path = getStr( item.second.get_child( "timestamp" ) ); if( path == "" ) { msg.Printf( _( "Footprint \"%s\" has no symbol associated." ), ref ); - m_settings.reporter.ReportHead( msg, RPT_SEVERITY_WARNING ); + m_reporter.ReportHead( msg, RPT_SEVERITY_WARNING ); continue; } - footprint = UTF8( item.second.get_child( "fpid" ).front().first ); - value = UTF8( item.second.get_child( "value" ).front().first ); + + footprint = getStr( item.second.get_child( "fpid" ) ); + value = getStr( item.second.get_child( "value" ) ); + + boost::optional nets = item.second.get_child_optional( "nets" ); + + if( nets ) + { + for( const std::pair& pin_net : nets.get() ) + { + wxASSERT( pin_net.first == "pin_net" ); + wxString pinNumber = UTF8( pin_net.second.front().first ); + wxString netName = UTF8( pin_net.second.back().first ); + pinNetMap[ pinNumber ] = netName; + } + } } catch( ... ) { @@ -169,34 +169,30 @@ int BACK_ANNOTATE::getPcbModulesFromString( const std::string& aPayload ) { // Module with this path already exists - generate error msg.Printf( _( "Pcb footprints \"%s\" and \"%s\" linked to same symbol" ), - nearestItem->second->ref, ref ); - m_settings.reporter.ReportHead( msg, RPT_SEVERITY_ERROR ); - ++errors; + nearestItem->second->m_ref, ref ); + m_reporter.ReportHead( msg, RPT_SEVERITY_ERROR ); } else { // Add module to the map - PCB_MODULE_DATA data( ref, footprint, value ); - m_pcbModules.insert( nearestItem, - std::make_pair( path, std::make_shared( data ) ) ); + auto data = std::make_shared( ref, footprint, value, pinNetMap ); + m_pcbModules.insert( nearestItem, std::make_pair( path, data ) ); } } - return errors; } -int BACK_ANNOTATE::getChangeList() -{ - int errors = 0; - for( auto& module : m_pcbModules ) +void BACK_ANNOTATE::getChangeList() +{ + for( std::pair>& module : m_pcbModules ) { - auto& pcbPath = module.first; - auto& pcbData = module.second; - bool foundInMultiunit = false; + const wxString& pcbPath = module.first; + auto& pcbData = module.second; + bool foundInMultiunit = false; for( auto& item : m_multiUnitsRefs ) { - auto& refList = item.second; + SCH_REFERENCE_LIST& refList = item.second; if( refList.FindRefByPath( pcbPath ) >= 0 ) { @@ -206,8 +202,10 @@ int BACK_ANNOTATE::getChangeList() foundInMultiunit = true; for( size_t i = 0; i < refList.GetCount(); ++i ) { - m_changelist.push_back( CHANGELIST_ITEM( refList[i], pcbData ) ); + refList[i].GetComp()->ClearFlags( SKIP_STRUCT ); + m_changelist.emplace_back( CHANGELIST_ITEM( refList[i], pcbData ) ); } + break; } } @@ -218,23 +216,22 @@ int BACK_ANNOTATE::getChangeList() int refIndex = m_refs.FindRefByPath( pcbPath ); if( refIndex >= 0 ) - m_changelist.push_back( CHANGELIST_ITEM( m_refs[refIndex], pcbData ) ); + { + m_refs[refIndex].GetComp()->ClearFlags( SKIP_STRUCT ); + m_changelist.emplace_back( CHANGELIST_ITEM( m_refs[refIndex], pcbData ) ); + } else { // Haven't found linked symbol in multiunits or common refs. Generate error wxString msg; - msg.Printf( _( "Cannot find symbol for \"%s\" footprint" ), pcbData->ref ); - ++errors; - m_settings.reporter.ReportTail( msg, RPT_SEVERITY_ERROR ); + msg.Printf( _( "Cannot find symbol for \"%s\" footprint" ), pcbData->m_ref ); + m_reporter.ReportTail( msg, RPT_SEVERITY_ERROR ); } } - return errors; } -int BACK_ANNOTATE::checkForUnusedSymbols() +void BACK_ANNOTATE::checkForUnusedSymbols() { - int errors = 0; - m_refs.SortByTimeStamp(); std::sort( m_changelist.begin(), m_changelist.end(), @@ -244,32 +241,31 @@ int BACK_ANNOTATE::checkForUnusedSymbols() } ); size_t i = 0; + for( auto& item : m_changelist ) { // Refs and changelist are both sorted by paths, so we just go over m_refs and // generate errors before we will find m_refs member to which item linked while( i < m_refs.GetCount() && m_refs[i].GetPath() != item.first.GetPath() ) { - ++errors; wxString msg; msg.Printf( _( "Cannot find footprint for \"%s\" symbol" ), m_refs[i++].GetFullRef() ); - m_settings.reporter.ReportTail( msg, RPT_SEVERITY_ERROR ); + m_reporter.ReportTail( msg, RPT_SEVERITY_ERROR ); } ++i; } - return errors; } bool BACK_ANNOTATE::checkReuseViolation( PCB_MODULE_DATA& aFirst, PCB_MODULE_DATA& aSecond ) { - - if( m_settings.processFootprints && aFirst.footprint != aSecond.footprint ) + if( m_processFootprints && aFirst.m_footprint != aSecond.m_footprint ) return false; - if( m_settings.processValues && aFirst.value != aSecond.value ) + if( m_processValues && aFirst.m_value != aSecond.m_value ) return false; + return true; } @@ -279,18 +275,17 @@ wxString BACK_ANNOTATE::getTextFromField( const SCH_REFERENCE& aRef, const NumFi } -int BACK_ANNOTATE::checkSharedSchematicErrors() +void BACK_ANNOTATE::checkSharedSchematicErrors() { - std::sort( m_changelist.begin(), m_changelist.end(), - []( CHANGELIST_ITEM& a, CHANGELIST_ITEM& b ) { - return a.first.GetComp() > b.first.GetComp(); - } ); + []( CHANGELIST_ITEM& a, CHANGELIST_ITEM& b ) + { + return a.first.GetComp() > b.first.GetComp(); + } ); // We don't check that if no footprints or values updating - if( !m_settings.processFootprints && !m_settings.processValues ) - return 0; - int errors = 0; + if( !m_processFootprints && !m_processValues ) + return; // We will count how many times every component used in our changelist // Component in this case is SCH_COMPONENT which can be used by more than one symbol @@ -307,90 +302,302 @@ int BACK_ANNOTATE::checkSharedSchematicErrors() if( ( it + 1 ) != m_changelist.end() && it->first.GetComp() == ( it + 1 )->first.GetComp() ) { ++usageCount; + if( !checkReuseViolation( *it->second, *( it + 1 )->second ) ) { // Refs share same component but have different values or footprints - ++errors; + it->first.GetComp()->SetFlags( SKIP_STRUCT ); + wxString msg; msg.Printf( _( "\"%s\" and \"%s\" use the same schematic symbol.\n" "They cannot have different footprints or values." ), - ( it + 1 )->second->ref, it->second->ref ); - m_settings.reporter.ReportTail( msg, RPT_SEVERITY_ERROR ); + ( it + 1 )->second->m_ref, + it->second->m_ref ); + m_reporter.ReportTail( msg, RPT_SEVERITY_ERROR ); } } else { /* Next ref uses different component, so we count all components number for current one. We compare that number to stored in the component itself. If that differs, it - means that this particular component is reused in some another project. */ - if( !m_settings.ignoreOtherProjects && compUsage > usageCount ) + means that this particular component is reused in some other project. */ + if( !m_ignoreOtherProjects && compUsage > usageCount ) { - PCB_MODULE_DATA tmp{ "", getTextFromField( it->first, FOOTPRINT ), - getTextFromField( it->first, VALUE ) }; + PCB_MODULE_DATA tmp{ "", + getTextFromField( it->first, FOOTPRINT ), + getTextFromField( it->first, VALUE ), + {} }; + if( !checkReuseViolation( tmp, *it->second ) ) { + it->first.GetComp()->SetFlags( SKIP_STRUCT ); + wxString msg; msg.Printf( _( "Unable to change \"%s\" footprint or value because associated" " symbol is reused in the another project" ), - it->second->ref ); - m_settings.reporter.ReportTail( msg, RPT_SEVERITY_ERROR ); - ++errors; + it->second->m_ref ); + m_reporter.ReportTail( msg, RPT_SEVERITY_ERROR ); } } usageCount = 1; } } - return errors; } void BACK_ANNOTATE::applyChangelist() { - wxString msg; - int leftUnchanged = 0; + std::set handledNetChanges; + wxString msg; + int leftUnchanged = 0; // Apply changes from change list - for( auto& item : m_changelist ) + for( CHANGELIST_ITEM& item : m_changelist ) { SCH_REFERENCE& ref = item.first; PCB_MODULE_DATA& module = *item.second; wxString oldFootprint = getTextFromField( ref, FOOTPRINT ); wxString oldValue = getTextFromField( ref, VALUE ); int changesCountBefore = m_changesCount; + bool skip = ( ref.GetComp()->GetFlags() & SKIP_STRUCT ) > 0; - if( m_settings.processReferences && ref.GetRef() != module.ref ) + if( m_processReferences && ref.GetRef() != module.m_ref && !skip ) { ++m_changesCount; - msg.Printf( _( "Change \"%s\" reference designator to \"%s\"." ), ref.GetFullRef(), module.ref ); - if( !m_settings.dryRun ) - ref.GetComp()->SetRef( &ref.GetSheetPath(), module.ref ); - m_settings.reporter.ReportHead( msg, RPT_SEVERITY_ACTION ); + msg.Printf( _( "Change \"%s\" reference designator to \"%s\"." ), + ref.GetFullRef(), + module.m_ref ); + + if( !m_dryRun ) + ref.GetComp()->SetRef( &ref.GetSheetPath(), module.m_ref ); + + m_reporter.ReportHead( msg, RPT_SEVERITY_ACTION ); } - if( m_settings.processFootprints && oldFootprint != module.footprint ) + if( m_processFootprints && oldFootprint != module.m_footprint && !skip ) { ++m_changesCount; - msg.Printf( _( "Change %s footprint from \"%s\" to \"%s\"." ), ref.GetFullRef(), - getTextFromField( ref, FOOTPRINT ), module.footprint ); + msg.Printf( _( "Change %s footprint from \"%s\" to \"%s\"." ), + ref.GetFullRef(), + getTextFromField( ref, FOOTPRINT ), + module.m_footprint ); - if( !m_settings.dryRun ) - ref.GetComp()->GetField( FOOTPRINT )->SetText( module.footprint ); - m_settings.reporter.ReportHead( msg, RPT_SEVERITY_ACTION ); + if( !m_dryRun ) + ref.GetComp()->GetField( FOOTPRINT )->SetText( module.m_footprint ); + + m_reporter.ReportHead( msg, RPT_SEVERITY_ACTION ); } - if( m_settings.processValues && oldValue != module.value ) + if( m_processValues && oldValue != module.m_value && !skip ) { ++m_changesCount; - msg.Printf( _( "Change \"%s\" value from \"%s\" to \"\"%s\"." ), ref.GetFullRef(), - getTextFromField( ref, VALUE ), module.value ); - if( !m_settings.dryRun ) - item.first.GetComp()->GetField( VALUE )->SetText( module.value ); - m_settings.reporter.ReportHead( msg, RPT_SEVERITY_ACTION ); + msg.Printf( _( "Change %s value from \"%s\" to \"%s\"." ), + ref.GetFullRef(), + getTextFromField( ref, VALUE ), + module.m_value ); + + if( !m_dryRun ) + item.first.GetComp()->GetField( VALUE )->SetText( module.m_value ); + + m_reporter.ReportHead( msg, RPT_SEVERITY_ACTION ); + } + + if( m_processNetNames ) + { + for( const std::pair& entry : module.m_pinMap ) + { + const wxString& pinNumber = entry.first; + const wxString& shortNetName = entry.second; + SCH_COMPONENT* comp = ref.GetComp(); + LIB_PIN* pin = comp->GetPin( pinNumber ); + SCH_CONNECTION* conn = comp->GetConnectionForPin( pin, ref.GetSheetPath() ); + + wxString key = shortNetName + ref.GetSheetPath().PathAsString(); + + if( handledNetChanges.count( key ) ) + continue; + else + handledNetChanges.insert( key ); + + if( conn && conn->Name( true ) != shortNetName ) + processNetNameChange( conn, conn->Name( true ), shortNetName ); + } } if( changesCountBefore == m_changesCount ) ++leftUnchanged; } msg.Printf( _( "%d symbols left unchanged" ), leftUnchanged ); - m_settings.reporter.ReportHead( msg, RPT_SEVERITY_INFO ); + m_reporter.ReportHead( msg, RPT_SEVERITY_INFO ); } + + +void BACK_ANNOTATE::processNetNameChange( SCH_CONNECTION* aConn, const wxString& aOldName, + const wxString& aNewName ) +{ + wxString msg; + SCH_ITEM* driver = aConn->Driver(); + + auto editMatchingLabels = + [this]( SCH_SCREEN* aScreen, KICAD_T aType, const wxString& oldName, + const wxString& newName ) + { + for( SCH_ITEM* schItem : aScreen->Items().OfType( aType ) ) + { + SCH_TEXT* label = static_cast( schItem ); + + if( EscapeString( label->GetShownText(), CTX_NETNAME ) == oldName ) + { + m_frame->SaveCopyInUndoList( label, UR_CHANGED ); + static_cast( label )->SetText( newName ); + } + } + }; + + switch( driver->Type() ) + { + case SCH_LABEL_T: + ++m_changesCount; + msg.Printf( _( "Change \"%s\" labels to \"%s\"." ), + aOldName, + aNewName ); + + if( !m_dryRun ) + { + m_frame->Schematic().SetCurrentSheet( aConn->Sheet() ); + + for( SCH_ITEM* label : m_frame->GetScreen()->Items().OfType( SCH_LABEL_T ) ) + { + SCH_CONNECTION* conn = label->Connection( aConn->Sheet() ); + + if( conn && conn->Driver() == driver ) + { + m_frame->SaveCopyInUndoList( label, UR_CHANGED ); + static_cast( label )->SetText( aNewName ); + } + } + } + + m_reporter.ReportHead( msg, RPT_SEVERITY_ACTION ); + break; + + case SCH_GLOBAL_LABEL_T: + ++m_changesCount; + msg.Printf( _( "Change \"%s\" global labels to \"%s\"." ), + aConn->Name( true ), + aNewName ); + + if( !m_dryRun ) + { + SCH_SHEET_LIST all_sheets = m_frame->Schematic().GetSheets(); + + for( const SCH_SHEET_PATH& sheet : all_sheets ) + { + m_frame->Schematic().SetCurrentSheet( sheet ); + editMatchingLabels( m_frame->GetScreen(), SCH_GLOBAL_LABEL_T, aOldName, aNewName ); + } + } + + m_reporter.ReportHead( msg, RPT_SEVERITY_ACTION ); + break; + + case SCH_HIER_LABEL_T: + ++m_changesCount; + msg.Printf( _( "Change \"%s\" hierarchical label to \"%s\"." ), + aConn->Name( true ), + aNewName ); + + if( !m_dryRun ) + { + m_frame->Schematic().SetCurrentSheet( aConn->Sheet() ); + editMatchingLabels( m_frame->GetScreen(), SCH_HIER_LABEL_T, aOldName, aNewName ); + + SCH_SHEET* sheet = dynamic_cast( driver->GetParent() ); + m_frame->SetScreen( sheet->GetScreen() ); + + for( SCH_SHEET_PIN* pin : sheet->GetPins() ) + { + if( EscapeString( pin->GetShownText(), CTX_NETNAME ) == aOldName ) + { + m_frame->SaveCopyInUndoList( pin, UR_CHANGED ); + static_cast( pin )->SetText( aNewName ); + } + } + } + + m_reporter.ReportHead( msg, RPT_SEVERITY_ACTION ); + break; + + case SCH_SHEET_PIN_T: + ++m_changesCount; + msg.Printf( _( "Change \"%s\" hierarchical label to \"%s\"." ), + aConn->Name( true ), + aNewName ); + + if( !m_dryRun ) + { + m_frame->Schematic().SetCurrentSheet( aConn->Sheet() ); + m_frame->SaveCopyInUndoList( driver, UR_CHANGED ); + static_cast( driver )->SetText( aNewName ); + + SCH_SHEET* sheet = static_cast( driver )->GetParent(); + m_frame->SetScreen( sheet->GetScreen() ); + editMatchingLabels( sheet->GetScreen(), SCH_HIER_LABEL_T, aOldName, aNewName ); + } + + m_reporter.ReportHead( msg, RPT_SEVERITY_ACTION ); + break; + + case LIB_PIN_T: + { + LIB_PIN* pin = dynamic_cast( driver ); + LABEL_SPIN_STYLE spin = LABEL_SPIN_STYLE::RIGHT; + + if( pin->IsPowerConnection() ) + { + msg.Printf( _( "Net \"%s\" cannot be changed to \"%s\" because it " + "is driven by a power pin." ), + aOldName, + aNewName ); + + m_reporter.ReportHead( msg, RPT_SEVERITY_ERROR ); + break; + } + + switch( pin->GetOrientation() ) + { + case PIN_UP: spin = LABEL_SPIN_STYLE::UP; break; + case PIN_DOWN: spin = LABEL_SPIN_STYLE::BOTTOM; break; + case PIN_LEFT: spin = LABEL_SPIN_STYLE::LEFT; break; + case PIN_RIGHT: spin = LABEL_SPIN_STYLE::RIGHT; break; + } + + ++m_changesCount; + msg.Printf( _( "Add label \"%s\" to net \"%s\"." ), + aNewName, + aConn->Name( true ) ); + + if( !m_dryRun ) + { + SCHEMATIC_SETTINGS& settings = m_frame->Schematic().Settings(); + SCH_LABEL* label = new SCH_LABEL( driver->GetPosition(), aNewName ); + label->SetParent( &m_frame->Schematic() ); + label->SetTextSize( wxSize( settings.m_DefaultTextSize, + settings.m_DefaultTextSize ) ); + label->SetLabelSpinStyle( spin ); + label->SetFlags( IS_NEW ); + + m_frame->Schematic().SetCurrentSheet( aConn->Sheet() ); + m_frame->AddItemToScreenAndUndoList( label ); + } + + m_reporter.ReportHead( msg, RPT_SEVERITY_ACTION ); + } + break; + + default: + break; + } + + m_frame->Schematic().SetCurrentSheet( SCH_SHEET_PATH() ); +} \ No newline at end of file diff --git a/eeschema/tools/backannotate.h b/eeschema/tools/backannotate.h index 355fecf273..28c6d19478 100644 --- a/eeschema/tools/backannotate.h +++ b/eeschema/tools/backannotate.h @@ -1,12 +1,8 @@ -/** - * @file eeschema/tools/backannotate.h - */ - /* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2019 Alexander Shuklin - * Copyright (C) 2004-2019 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2004-2020 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 @@ -44,8 +40,9 @@ class SCH_EDIT_FRAME; /** - * @brief Back annotation algorithm class. It used to recieve, check and apply \ref NETLIST - * from PCBNEW. Class check for following collisions: + * @brief Back annotation algorithm class used to recieve, check, and apply a \ref NETLIST from + * PCBNEW. + * The following checks are made: * - Schematic symbol exists, but linked PCBnew module missing * - PCBnew module exists but no schematic symbol connected to * - PCBnew module is standalone @@ -58,31 +55,23 @@ class SCH_EDIT_FRAME; class BACK_ANNOTATE { public: - /** - * @brief settings struct to set up back annotation - */ - struct SETTINGS - { - REPORTER& reporter; - bool processFootprints; - bool processValues; - bool processReferences; - bool ignoreOtherProjects; - bool dryRun; - }; - /** * @brief Struct to hold PCBnew module data */ struct PCB_MODULE_DATA { - PCB_MODULE_DATA(wxString aRef, wxString aFootprint, wxString aValue) : - ref(aRef), - footprint(aFootprint), - value(aValue){}; - wxString ref; - wxString footprint; - wxString value; + PCB_MODULE_DATA( const wxString& aRef, const wxString& aFootprint, + const wxString& aValue, const std::map aPinMap ) : + m_ref( aRef ), + m_footprint( aFootprint ), + m_value( aValue ), + m_pinMap( aPinMap ) + {}; + + wxString m_ref; + wxString m_footprint; + wxString m_value; + std::map m_pinMap; }; ///> Map to hold NETLIST modules data @@ -90,11 +79,9 @@ public: using CHANGELIST_ITEM = std::pair>; - ///> To hold match between reference and PCBnew module - using CHANGELIST = std::deque; - - - BACK_ANNOTATE( SCH_EDIT_FRAME* aFrame, SETTINGS aSettings ); + BACK_ANNOTATE( SCH_EDIT_FRAME* aFrame, REPORTER& aReporter, bool aProcessFootprints, + bool aProcessValues, bool aProcessReferences, bool aProcessNetNames, + bool aIgnoreOtherProjects, bool aDryRun ); ~BACK_ANNOTATE(); /** @@ -113,11 +100,19 @@ public: bool BackAnnotateSymbols( const std::string& aNetlist ); private: - SETTINGS m_settings; + REPORTER& m_reporter; + + bool m_processFootprints; + bool m_processValues; + bool m_processReferences; + bool m_processNetNames; + bool m_ignoreOtherProjects; + bool m_dryRun; + PCB_MODULES_MAP m_pcbModules; SCH_REFERENCE_LIST m_refs; SCH_MULTI_UNIT_REFERENCE_MAP m_multiUnitsRefs; - CHANGELIST m_changelist; + std::deque m_changelist; SCH_EDIT_FRAME* m_frame; ///> To count number of changes applied to the schematic @@ -140,28 +135,29 @@ private: * @param aPayload - netlist from PCBnew * @return number of errors during parsing */ - int getPcbModulesFromString( const std::string& aPayload ); + void getPcbModulesFromString( const std::string& aPayload ); ///> Create changelist - int getChangeList(); + void getChangeList(); /** * @brief Check if some symbols are not represented in PCB modules and vice versa. * \ref m_refs must be sorted by path - * @return number of errors */ - int checkForUnusedSymbols(); + void checkForUnusedSymbols(); /** * @brief Check for errors connected to reusing schematic in project or between projects - * @return number of errors */ - int checkSharedSchematicErrors(); + void checkSharedSchematicErrors(); /** * @brief Apply changelist to the schematic */ void applyChangelist(); + + void processNetNameChange( SCH_CONNECTION* aConn, const wxString& aOldName, + const wxString& aNewName ); }; #endif diff --git a/include/validators.h b/include/validators.h index f9790b53d2..c3fc1635ca 100644 --- a/include/validators.h +++ b/include/validators.h @@ -194,6 +194,33 @@ protected: LIB_ID::LIB_ID_TYPE m_idType; }; + +class NETNAME_VALIDATOR : public wxTextValidator +{ +public: + NETNAME_VALIDATOR( wxString *aVal = nullptr ); + + NETNAME_VALIDATOR( bool aAllowSpaces ); + + NETNAME_VALIDATOR( const NETNAME_VALIDATOR& aValidator ); + + virtual wxObject* Clone() const override { return new NETNAME_VALIDATOR( *this ); } + + virtual bool TransferToWindow() override { return true; } + + virtual bool TransferFromWindow() override { return true; } + + virtual bool Validate( wxWindow *aParent ) override; + +protected: + // returns the error message if the contents of 'val' are invalid + wxString IsValid( const wxString& aVal ) const override; + +private: + bool m_allowSpaces; +}; + + namespace KIUI { /** diff --git a/pcbnew/cross-probing.cpp b/pcbnew/cross-probing.cpp index e9061c80f1..5a6582b1a5 100644 --- a/pcbnew/cross-probing.cpp +++ b/pcbnew/cross-probing.cpp @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -43,14 +42,10 @@ #include #include #include -#include -#include #include -#include #include #include #include -#include /* Execute a remote command send by Eeschema via a socket, * port KICAD_PCB_PORT_SERVICE_NUMBER @@ -402,13 +397,24 @@ void PCB_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail ) { NETLIST netlist; STRING_FORMATTER sf; - for( auto& module : this->GetBoard()->Modules() ) + + for( MODULE* module : this->GetBoard()->Modules() ) { - netlist.AddComponent( new COMPONENT( module->GetFPID(), module->GetReference(), - module->GetValue(), module->GetPath() ) ); + COMPONENT* component = new COMPONENT( module->GetFPID(), module->GetReference(), + module->GetValue(), module->GetPath() ); + + for( D_PAD* pad : module->Pads() ) + { + const wxString& netname = pad->GetShortNetname(); + + if( !netname.IsEmpty() ) + component->AddNet( pad->GetName(), netname, wxEmptyString ); + } + + netlist.AddComponent( component ); } - netlist.Format( - "pcb_netlist", &sf, 0, CTL_OMIT_FILTERS | CTL_OMIT_NETS | CTL_OMIT_FILTERS ); + + netlist.Format( "pcb_netlist", &sf, 0, CTL_OMIT_FILTERS ); payload = sf.GetString(); break; } diff --git a/pcbnew/dialogs/dialog_select_net_from_list.cpp b/pcbnew/dialogs/dialog_select_net_from_list.cpp index f6deca903e..d070923222 100644 --- a/pcbnew/dialogs/dialog_select_net_from_list.cpp +++ b/pcbnew/dialogs/dialog_select_net_from_list.cpp @@ -3,7 +3,7 @@ * * Copyright (C) 2020 Oleg Endo * Copyright (C) 2019 Jean-Pierre Charras, jp.charras at wanadoo.fr - * Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2020 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,19 +24,18 @@ */ #include -#include -#include #include #include #include #include #include #include -#include #include #include -#include #include +#include +#include +#include struct DIALOG_SELECT_NET_FROM_LIST::COLUMN_ID { @@ -122,27 +121,23 @@ struct DIALOG_SELECT_NET_FROM_LIST::ROW_DESC }; -DIALOG_SELECT_NET_FROM_LIST::DIALOG_SELECT_NET_FROM_LIST( - PCB_EDIT_FRAME* aParent, const SETTINGS& aSettings ) - : DIALOG_SELECT_NET_FROM_LIST_BASE( aParent ), m_frame( aParent ) +DIALOG_SELECT_NET_FROM_LIST::DIALOG_SELECT_NET_FROM_LIST( PCB_EDIT_FRAME* aParent, + const SETTINGS& aSettings ) : + DIALOG_SELECT_NET_FROM_LIST_BASE( aParent ), + m_frame( aParent ) { m_brd = aParent->GetBoard(); m_wasSelected = false; - m_netsList->AppendTextColumn( - COLUMN_NET.display_name, wxDATAVIEW_CELL_INERT, 0, wxALIGN_LEFT, 0 ); - m_netsList->AppendTextColumn( - COLUMN_NAME.display_name, wxDATAVIEW_CELL_INERT, 0, wxALIGN_LEFT, 0 ); - m_netsList->AppendTextColumn( - COLUMN_PAD_COUNT.display_name, wxDATAVIEW_CELL_INERT, 0, wxALIGN_CENTER, 0 ); - m_netsList->AppendTextColumn( - COLUMN_VIA_COUNT.display_name, wxDATAVIEW_CELL_INERT, 0, wxALIGN_CENTER, 0 ); - m_netsList->AppendTextColumn( - COLUMN_BOARD_LENGTH.display_name, wxDATAVIEW_CELL_INERT, 0, wxALIGN_CENTER, 0 ); - m_netsList->AppendTextColumn( - COLUMN_CHIP_LENGTH.display_name, wxDATAVIEW_CELL_INERT, 0, wxALIGN_CENTER, 0 ); - m_netsList->AppendTextColumn( - COLUMN_TOTAL_LENGTH.display_name, wxDATAVIEW_CELL_INERT, 0, wxALIGN_CENTER, 0 ); +#define ADD_COL( name, flag, align ) m_netsList->AppendTextColumn( name, flag, 0, align, 0 ); + + ADD_COL( COLUMN_NET.display_name, wxDATAVIEW_CELL_INERT, wxALIGN_LEFT ); + ADD_COL( COLUMN_NAME.display_name, wxDATAVIEW_CELL_INERT, wxALIGN_LEFT ); + ADD_COL( COLUMN_PAD_COUNT.display_name, wxDATAVIEW_CELL_INERT, wxALIGN_CENTER ); + ADD_COL( COLUMN_VIA_COUNT.display_name, wxDATAVIEW_CELL_INERT, wxALIGN_CENTER ); + ADD_COL( COLUMN_BOARD_LENGTH.display_name, wxDATAVIEW_CELL_INERT, wxALIGN_CENTER ); + ADD_COL( COLUMN_CHIP_LENGTH.display_name, wxDATAVIEW_CELL_INERT, wxALIGN_CENTER ); + ADD_COL( COLUMN_TOTAL_LENGTH.display_name, wxDATAVIEW_CELL_INERT, wxALIGN_CENTER ); // The fact that we're a list should keep the control from reserving space for the // expander buttons... but it doesn't. Fix by forcing the indent to 0. @@ -155,6 +150,10 @@ DIALOG_SELECT_NET_FROM_LIST::DIALOG_SELECT_NET_FROM_LIST( adjustListColumns(); + m_addNet->SetBitmap( KiBitmap( small_plus_xpm ) ); + m_renameNet->SetBitmap( KiBitmap( small_edit_xpm ) ); + m_deleteNet->SetBitmap( KiBitmap( trash_xpm ) ); + m_sdbSizerOK->SetDefault(); FinishDialogSettings(); @@ -277,7 +276,7 @@ std::vector DIALOG_SELECT_NET_FROM_LIST::relevantConnectivityItems() c std::vector cn_items; cn_items.reserve( 1024 ); - for( auto& cn_item : m_brd->GetConnectivity()->GetConnectivityAlgo()->ItemList() ) + for( CN_ITEM* cn_item : m_brd->GetConnectivity()->GetConnectivityAlgo()->ItemList() ) { if( cn_item->Valid() && type_bits[cn_item->Parent()->Type()] ) cn_items.push_back( cn_item ); @@ -323,8 +322,8 @@ void DIALOG_SELECT_NET_FROM_LIST::deleteRow( const ROW_DESC& aRow ) } -void DIALOG_SELECT_NET_FROM_LIST::setValue( - const ROW_DESC& aRow, const COLUMN_ID& aCol, wxString aVal ) +void DIALOG_SELECT_NET_FROM_LIST::setValue( const ROW_DESC& aRow, const COLUMN_ID& aCol, + wxString aVal ) { if( aRow ) m_netsList->SetValue( aVal, aRow.row_num, aCol.col_num ); @@ -369,7 +368,7 @@ void DIALOG_SELECT_NET_FROM_LIST::OnBoardItemAdded( BOARD& aBoard, BOARD_ITEM* a std::sort( m_list_items_by_net.begin(), m_list_items_by_net.end(), LIST_ITEM_NET_CMP_LESS( m_list_items ) ); - auto& new_i = m_list_items.back(); + LIST_ITEM& new_i = m_list_items.back(); new_i.m_pad_count = m_brd->GetNodesCount( net->GetNet() ); wxVector new_row( 7 ); @@ -386,14 +385,14 @@ void DIALOG_SELECT_NET_FROM_LIST::OnBoardItemAdded( BOARD& aBoard, BOARD_ITEM* a return; } - else if( auto* i = dynamic_cast( aBoardItem ) ) + else if( BOARD_CONNECTED_ITEM* i = dynamic_cast( aBoardItem ) ) { - auto r = findRow( i->GetNet() ); + const ROW_DESC& r = findRow( i->GetNet() ); if( r ) { // try to handle frequent operations quickly. - if( auto* track = dynamic_cast( i ) ) + if( TRACK* track = dynamic_cast( i ) ) { int len = track->GetLength(); r.by_row->m_board_wire_length += len; @@ -420,16 +419,16 @@ void DIALOG_SELECT_NET_FROM_LIST::OnBoardItemAdded( BOARD& aBoard, BOARD_ITEM* a void DIALOG_SELECT_NET_FROM_LIST::OnBoardItemRemoved( BOARD& aBoard, BOARD_ITEM* aBoardItem ) { - if( auto* net = dynamic_cast( aBoardItem ) ) + if( NETINFO_ITEM* net = dynamic_cast( aBoardItem ) ) { deleteRow( findRow( net ) ); return; } - else if( auto* mod = dynamic_cast( aBoardItem ) ) + else if( MODULE* mod = dynamic_cast( aBoardItem ) ) { for( const D_PAD* pad : mod->Pads() ) { - auto r = findRow( pad->GetNet() ); + const ROW_DESC& r = findRow( pad->GetNet() ); if( r ) { @@ -442,14 +441,14 @@ void DIALOG_SELECT_NET_FROM_LIST::OnBoardItemRemoved( BOARD& aBoard, BOARD_ITEM* } } } - else if( auto* i = dynamic_cast( aBoardItem ) ) + else if( BOARD_CONNECTED_ITEM* i = dynamic_cast( aBoardItem ) ) { - auto r = findRow( i->GetNet() ); + const ROW_DESC& r = findRow( i->GetNet() ); if( r ) { // try to handle frequent operations quickly. - if( auto* track = dynamic_cast( i ) ) + if( TRACK* track = dynamic_cast( i ) ) { int len = track->GetLength(); r.by_row->m_board_wire_length -= len; @@ -520,22 +519,22 @@ void DIALOG_SELECT_NET_FROM_LIST::updateNet( NETINFO_ITEM* aNet ) return; } - auto all_cn_items = relevantConnectivityItems(); + std::vector all_cn_items = relevantConnectivityItems(); LIST_ITEM list_item( aNet ); list_item.m_pad_count = node_count; - const auto cn_items = std::equal_range( - all_cn_items.begin(), all_cn_items.end(), aNet->GetNet(), NETCODE_CMP_LESS() ); + const auto cn_items = std::equal_range( all_cn_items.begin(), all_cn_items.end(), + aNet->GetNet(), NETCODE_CMP_LESS() ); for( auto i = cn_items.first; i != cn_items.second; ++i ) { - auto item = ( *i )->Parent(); + BOARD_CONNECTED_ITEM* item = ( *i )->Parent(); if( item->Type() == PCB_PAD_T ) list_item.m_chip_wire_length += static_cast( item )->GetPadToDieLength(); - else if( auto* track = dynamic_cast( item ) ) + else if( TRACK* track = dynamic_cast( item ) ) { list_item.m_board_wire_length += track->GetLength(); @@ -589,7 +588,6 @@ void DIALOG_SELECT_NET_FROM_LIST::buildNetsList() std::vector prefiltered_cn_items = relevantConnectivityItems(); - // collect all nets which pass the filter string. struct NET_INFO @@ -618,7 +616,7 @@ void DIALOG_SELECT_NET_FROM_LIST::buildNetsList() std::vector nets; nets.reserve( m_brd->GetNetInfo().NetsByNetcode().size() ); - for( auto&& ni : m_brd->GetNetInfo().NetsByNetcode() ) + for( const std::pair& ni : m_brd->GetNetInfo().NetsByNetcode() ) { if( netFilterMatches( ni.second ) ) nets.emplace_back( NET_INFO{ ni.first, ni.second, 0 } ); @@ -627,37 +625,37 @@ void DIALOG_SELECT_NET_FROM_LIST::buildNetsList() // count the pads for each net. since the nets are sorted by netcode // this way around is faster than using counting pads for each net. - for( auto&& mod : m_brd->Modules() ) + for( MODULE* mod : m_brd->Modules() ) { - for( auto&& pad : mod->Pads() ) + for( D_PAD* pad : mod->Pads() ) { - auto i = std::lower_bound( - nets.begin(), nets.end(), pad->GetNetCode(), NET_INFO_CMP_LESS() ); + auto i = std::lower_bound( nets.begin(), nets.end(), pad->GetNetCode(), + NET_INFO_CMP_LESS() ); if( i != nets.end() && i->netcode == pad->GetNetCode() ) i->pad_count += 1; } } - for( auto&& ni : nets ) + for( NET_INFO& ni : nets ) { if( !m_cbShowZeroPad->IsChecked() && ni.pad_count == 0 ) continue; m_list_items.emplace_back( ni.net ); - auto& list_item = m_list_items.back(); + LIST_ITEM& list_item = m_list_items.back(); const auto cn_items = std::equal_range( prefiltered_cn_items.begin(), prefiltered_cn_items.end(), ni.netcode, NETCODE_CMP_LESS() ); for( auto i = cn_items.first; i != cn_items.second; ++i ) { - auto item = ( *i )->Parent(); + BOARD_CONNECTED_ITEM* item = ( *i )->Parent(); if( item->Type() == PCB_PAD_T ) list_item.m_chip_wire_length += static_cast( item )->GetPadToDieLength(); - else if( auto* track = dynamic_cast( item ) ) + else if( TRACK* track = dynamic_cast( item ) ) { list_item.m_board_wire_length += track->GetLength(); @@ -673,7 +671,7 @@ void DIALOG_SELECT_NET_FROM_LIST::buildNetsList() wxVector dataLine; dataLine.resize( 7 ); - for( auto& i : m_list_items ) + for( LIST_ITEM& i : m_list_items ) { dataLine[COLUMN_NET] = formatNetCode( i.m_net ); dataLine[COLUMN_NAME] = formatNetName( i.m_net ); @@ -699,14 +697,14 @@ void DIALOG_SELECT_NET_FROM_LIST::buildNetsList() m_wasSelected = false; else { - auto r = findRow( prev_selected_netcode ); + const ROW_DESC& r = findRow( prev_selected_netcode ); if( r ) { m_selection = r.by_row->m_net->GetNetname(); m_wasSelected = true; - auto i = m_netsList->RowToItem( r.row_num ); + wxDataViewItem i = m_netsList->RowToItem( r.row_num ); m_netsList->Select( i ); m_netsList->EnsureVisible( i ); } @@ -716,11 +714,11 @@ void DIALOG_SELECT_NET_FROM_LIST::buildNetsList() void DIALOG_SELECT_NET_FROM_LIST::HighlightNet( NETINFO_ITEM* aNet ) { - const auto r = findRow( aNet ); + const ROW_DESC& r = findRow( aNet ); if( r ) { - auto i = m_netsList->RowToItem( r.row_num ); + wxDataViewItem i = m_netsList->RowToItem( r.row_num ); m_netsList->Select( i ); m_netsList->EnsureVisible( i ); } @@ -754,7 +752,7 @@ void DIALOG_SELECT_NET_FROM_LIST::onSelChanged( wxDataViewEvent& ) if( selected_row >= 0 && selected_row < static_cast( m_list_items.size() ) ) { - auto* net = m_list_items[selected_row].m_net; + NETINFO_ITEM* net = m_list_items[selected_row].m_net; m_selection = net->GetNetname(); m_wasSelected = true; @@ -772,10 +770,9 @@ void DIALOG_SELECT_NET_FROM_LIST::adjustListColumns() int w0, w1, w2, w3, w4, w5, w6; /** - * Calculating optimal width of the first (Net) and - * the last (Pad Count) columns. That width must be - * enough to fit column header label and be not less - * than width of four chars (0000). + * Calculating optimal width of the first (Net) and the last (Pad Count) columns. + * That width must be enough to fit column header label and be not less than width of + * four chars (0000). */ wxClientDC dc( GetParent() ); @@ -792,26 +789,19 @@ void DIALOG_SELECT_NET_FROM_LIST::adjustListColumns() // Considering left and right margins. // For wxRenderGeneric it is 5px. - w0 = std::max( w0+10, minw_col0); - w2 = std::max( w2+10, minw); - w3 = std::max( w3+10, minw); - w4 = std::max( w4+10, minw); - w5 = std::max( w5+10, minw); - w6 = std::max( w6+10, minw); - - m_netsList->GetColumn( 0 )->SetWidth( w0 ); - m_netsList->GetColumn( 2 )->SetWidth( w2 ); - m_netsList->GetColumn( 3 )->SetWidth( w3 ); - m_netsList->GetColumn( 4 )->SetWidth( w4 ); - m_netsList->GetColumn( 5 )->SetWidth( w5 ); - m_netsList->GetColumn( 6 )->SetWidth( w6 ); + m_netsList->GetColumn( 0 )->SetWidth( std::max( w0 + 10, minw_col0 ) ); + m_netsList->GetColumn( 2 )->SetWidth( w2 + 10 ); + m_netsList->GetColumn( 3 )->SetWidth( w3 + 10 ); + m_netsList->GetColumn( 4 )->SetWidth( std::max( w4 + 10, minw ) ); + m_netsList->GetColumn( 5 )->SetWidth( std::max( w5 + 10, minw ) ); + m_netsList->GetColumn( 6 )->SetWidth( std::max( w6 + 10, minw ) ); // At resizing of the list the width of middle column (Net Names) changes only. int width = m_netsList->GetClientSize().x; w1 = width - w0 - w2 - w3 - w4 - w5 - w6; // Column 1 (net names) need a minimal width to display net names - dc.GetTextExtent( "MMMMMMMMMMMMMMMMMMMM", &minw, &h ); + dc.GetTextExtent( "MMMMMMMMMMMMMMMMMM", &minw, &h ); w1 = std::max( w1, minw ); m_netsList->GetColumn( 1 )->SetWidth( w1 ); @@ -834,6 +824,129 @@ bool DIALOG_SELECT_NET_FROM_LIST::GetNetName( wxString& aName ) const } +void DIALOG_SELECT_NET_FROM_LIST::onAddNet( wxCommandEvent& aEvent ) +{ + wxString newNetName; + NETNAME_VALIDATOR validator( &newNetName ); + + WX_TEXT_ENTRY_DIALOG dlg( this, _( "Net name:" ), _( "New Net" ), newNetName ); + dlg.SetTextValidator( validator ); + + while( true ) + { + if( dlg.ShowModal() != wxID_OK || dlg.GetValue().IsEmpty() ) + return; //Aborted by user + + newNetName = dlg.GetValue(); + + if( m_brd->FindNet( newNetName ) ) + { + DisplayError( this, wxString::Format( _( "Net name '%s' is already in use." ), + newNetName ) ); + newNetName = wxEmptyString; + } + else + { + break; + } + } + + NETINFO_ITEM *newnet = new NETINFO_ITEM( m_brd, dlg.GetValue(), 0 ); + + m_brd->Add( newnet ); + m_frame->OnModify(); + + // We'll get an OnBoardItemChanged callback from this to update our listbox +} + + +void DIALOG_SELECT_NET_FROM_LIST::onRenameNet( wxCommandEvent& aEvent ) +{ + int selected_row = m_netsList->GetSelectedRow(); + + if( selected_row >= 0 && selected_row < static_cast( m_list_items.size() ) ) + { + NETINFO_ITEM* net = m_list_items[selected_row].m_net; + wxString fullNetName = net->GetNetname(); + wxString netPath; + wxString shortNetName; + + if( fullNetName.Contains( "/" ) ) + { + netPath = fullNetName.BeforeLast( '/' ) + '/'; + shortNetName = fullNetName.AfterLast( '/' ); + } + else + { + shortNetName = fullNetName; + } + + wxString unescapedShortName = UnescapeString( shortNetName ); + + WX_TEXT_ENTRY_DIALOG dlg( this, _( "Net name:" ), _( "Rename Net" ), unescapedShortName ); + NETNAME_VALIDATOR validator( &unescapedShortName ); + dlg.SetTextValidator( validator ); + + while( true ) + { + if( dlg.ShowModal() != wxID_OK ) + return; //Aborted by user + + unescapedShortName = dlg.GetValue(); + + if( unescapedShortName.IsEmpty() ) + { + DisplayError( this, wxString::Format( _( "Net name cannot be empty." ), + unescapedShortName ) ); + continue; + } + + shortNetName = EscapeString( unescapedShortName, CTX_NETNAME ); + fullNetName = netPath + shortNetName; + + if( m_brd->FindNet( shortNetName ) || m_brd->FindNet( fullNetName ) ) + { + DisplayError( this, wxString::Format( _( "Net name '%s' is already in use." ), + unescapedShortName ) ); + unescapedShortName = wxEmptyString; + } + else + { + break; + } + } + + net->SetNetname( fullNetName ); + m_frame->OnModify(); + + buildNetsList(); + m_netsList->Refresh(); + } +} + + +void DIALOG_SELECT_NET_FROM_LIST::onDeleteNet( wxCommandEvent& aEvent ) +{ + int selected_row = m_netsList->GetSelectedRow(); + + if( selected_row >= 0 && selected_row < static_cast( m_list_items.size() ) ) + { + NETINFO_ITEM* net = m_list_items[selected_row].m_net; + + if( m_list_items[selected_row].m_pad_count > 0 ) + { + if( !IsOK( this, _( "Net is in use. Delete anyway?" ) ) ) + return; + } + + m_brd->Remove( net ); + m_frame->OnModify(); + + // We'll get an OnBoardItemChanged callback from this to update our listbox + } +} + + void DIALOG_SELECT_NET_FROM_LIST::onReport( wxCommandEvent& aEvent ) { wxFileDialog dlg( this, _( "Report file" ), "", "", @@ -860,13 +973,14 @@ void DIALOG_SELECT_NET_FROM_LIST::onReport( wxCommandEvent& aEvent ) // Print list of nets: for( int row = 1; row < rows; row++ ) { - txt.Printf( "%s;\"%s\";%s;%s;%s;%s;%s;", m_netsList->GetTextValue( row, COLUMN_NET ), - m_netsList->GetTextValue( row, COLUMN_NAME ), - m_netsList->GetTextValue( row, COLUMN_PAD_COUNT ), - m_netsList->GetTextValue( row, COLUMN_VIA_COUNT ), - m_netsList->GetTextValue( row, COLUMN_BOARD_LENGTH ), - m_netsList->GetTextValue( row, COLUMN_CHIP_LENGTH ), - m_netsList->GetTextValue( row, COLUMN_TOTAL_LENGTH ) ); + txt.Printf( "%s;\"%s\";%s;%s;%s;%s;%s;", + m_netsList->GetTextValue( row, COLUMN_NET ), + m_netsList->GetTextValue( row, COLUMN_NAME ), + m_netsList->GetTextValue( row, COLUMN_PAD_COUNT ), + m_netsList->GetTextValue( row, COLUMN_VIA_COUNT ), + m_netsList->GetTextValue( row, COLUMN_BOARD_LENGTH ), + m_netsList->GetTextValue( row, COLUMN_CHIP_LENGTH ), + m_netsList->GetTextValue( row, COLUMN_TOTAL_LENGTH ) ); f.AddLine( txt ); } diff --git a/pcbnew/dialogs/dialog_select_net_from_list.h b/pcbnew/dialogs/dialog_select_net_from_list.h index 1127327e4f..e936dca070 100644 --- a/pcbnew/dialogs/dialog_select_net_from_list.h +++ b/pcbnew/dialogs/dialog_select_net_from_list.h @@ -94,6 +94,9 @@ private: void onSelChanged( wxDataViewEvent& event ) override; void onFilterChange( wxCommandEvent& event ) override; void onListSize( wxSizeEvent& event ) override; + void onAddNet( wxCommandEvent& event ) override; + void onRenameNet( wxCommandEvent& event ) override; + void onDeleteNet( wxCommandEvent& event ) override; void onReport( wxCommandEvent& event ) override; void buildNetsList(); diff --git a/pcbnew/dialogs/dialog_select_net_from_list_base.cpp b/pcbnew/dialogs/dialog_select_net_from_list_base.cpp index c9a8c70141..2d95a19350 100644 --- a/pcbnew/dialogs/dialog_select_net_from_list_base.cpp +++ b/pcbnew/dialogs/dialog_select_net_from_list_base.cpp @@ -41,14 +41,35 @@ DIALOG_SELECT_NET_FROM_LIST_BASE::DIALOG_SELECT_NET_FROM_LIST_BASE( wxWindow* pa bSizerMain->Add( m_netsList, 1, wxEXPAND|wxRIGHT|wxLEFT, 10 ); - wxBoxSizer* bSizerBottom; - bSizerBottom = new wxBoxSizer( wxHORIZONTAL ); + wxBoxSizer* bSizerListButtons; + bSizerListButtons = new wxBoxSizer( wxHORIZONTAL ); + + m_addNet = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 ); + bSizerListButtons->Add( m_addNet, 0, wxTOP|wxBOTTOM|wxLEFT, 5 ); + + m_renameNet = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 ); + bSizerListButtons->Add( m_renameNet, 0, wxALL, 5 ); + + + bSizerListButtons->Add( 15, 0, 0, wxEXPAND, 5 ); + + m_deleteNet = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 ); + bSizerListButtons->Add( m_deleteNet, 0, wxALL, 5 ); + + + bSizerListButtons->Add( 0, 0, 1, wxEXPAND, 5 ); m_ReportButt = new wxButton( this, wxID_ANY, _("Create Report..."), wxDefaultPosition, wxDefaultSize, 0 ); - bSizerBottom->Add( m_ReportButt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + bSizerListButtons->Add( m_ReportButt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); - bSizerBottom->Add( 0, 0, 1, wxEXPAND, 5 ); + bSizerMain->Add( bSizerListButtons, 0, wxEXPAND|wxALL, 5 ); + + m_staticline1 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + bSizerMain->Add( m_staticline1, 0, wxEXPAND | wxALL, 5 ); + + wxBoxSizer* bSizerBottom; + bSizerBottom = new wxBoxSizer( wxHORIZONTAL ); m_sdbSizer = new wxStdDialogButtonSizer(); m_sdbSizerOK = new wxButton( this, wxID_OK ); @@ -57,7 +78,7 @@ DIALOG_SELECT_NET_FROM_LIST_BASE::DIALOG_SELECT_NET_FROM_LIST_BASE( wxWindow* pa m_sdbSizer->AddButton( m_sdbSizerCancel ); m_sdbSizer->Realize(); - bSizerBottom->Add( m_sdbSizer, 0, wxALL|wxEXPAND, 5 ); + bSizerBottom->Add( m_sdbSizer, 1, wxALL|wxEXPAND, 5 ); bSizerMain->Add( bSizerBottom, 0, wxEXPAND|wxLEFT, 5 ); @@ -65,6 +86,7 @@ DIALOG_SELECT_NET_FROM_LIST_BASE::DIALOG_SELECT_NET_FROM_LIST_BASE( wxWindow* pa this->SetSizer( bSizerMain ); this->Layout(); + bSizerMain->Fit( this ); this->Centre( wxBOTH ); @@ -73,6 +95,9 @@ DIALOG_SELECT_NET_FROM_LIST_BASE::DIALOG_SELECT_NET_FROM_LIST_BASE( wxWindow* pa m_cbShowZeroPad->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_SELECT_NET_FROM_LIST_BASE::onFilterChange ), NULL, this ); m_netsList->Connect( wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED, wxDataViewEventHandler( DIALOG_SELECT_NET_FROM_LIST_BASE::onSelChanged ), NULL, this ); m_netsList->Connect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_SELECT_NET_FROM_LIST_BASE::onListSize ), NULL, this ); + m_addNet->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SELECT_NET_FROM_LIST_BASE::onAddNet ), NULL, this ); + m_renameNet->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SELECT_NET_FROM_LIST_BASE::onRenameNet ), NULL, this ); + m_deleteNet->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SELECT_NET_FROM_LIST_BASE::onDeleteNet ), NULL, this ); m_ReportButt->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SELECT_NET_FROM_LIST_BASE::onReport ), NULL, this ); } @@ -83,6 +108,9 @@ DIALOG_SELECT_NET_FROM_LIST_BASE::~DIALOG_SELECT_NET_FROM_LIST_BASE() m_cbShowZeroPad->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_SELECT_NET_FROM_LIST_BASE::onFilterChange ), NULL, this ); m_netsList->Disconnect( wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED, wxDataViewEventHandler( DIALOG_SELECT_NET_FROM_LIST_BASE::onSelChanged ), NULL, this ); m_netsList->Disconnect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_SELECT_NET_FROM_LIST_BASE::onListSize ), NULL, this ); + m_addNet->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SELECT_NET_FROM_LIST_BASE::onAddNet ), NULL, this ); + m_renameNet->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SELECT_NET_FROM_LIST_BASE::onRenameNet ), NULL, this ); + m_deleteNet->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SELECT_NET_FROM_LIST_BASE::onDeleteNet ), NULL, this ); m_ReportButt->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SELECT_NET_FROM_LIST_BASE::onReport ), NULL, this ); } diff --git a/pcbnew/dialogs/dialog_select_net_from_list_base.fbp b/pcbnew/dialogs/dialog_select_net_from_list_base.fbp index 7a0942d429..9ae9135e4e 100644 --- a/pcbnew/dialogs/dialog_select_net_from_list_base.fbp +++ b/pcbnew/dialogs/dialog_select_net_from_list_base.fbp @@ -45,7 +45,7 @@ -1,-1 DIALOG_SELECT_NET_FROM_LIST_BASE - 720,397 + -1,-1 wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER DIALOG_SHIM; dialog_shim.h Net Inspector @@ -301,13 +301,252 @@ 5 - wxEXPAND|wxLEFT + wxEXPAND|wxALL 0 - bSizerBottom + bSizerListButtons wxHORIZONTAL none + + 5 + wxTOP|wxBOTTOM|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_ANY + Add Net + + 0 + + 0 + + + 0 + + 1 + m_addNet + 1 + + + protected + 1 + + + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + onAddNet + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_ANY + Rename Net + + 0 + + 0 + + + 0 + + 1 + m_renameNet + 1 + + + protected + 1 + + + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + onRenameNet + + + + 5 + wxEXPAND + 0 + + 0 + protected + 15 + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_ANY + Delete Net + + 0 + + 0 + + + 0 + + 1 + m_deleteNet + 1 + + + protected + 1 + + + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + onDeleteNet + + + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + 5 wxALL|wxALIGN_CENTER_VERTICAL @@ -381,20 +620,79 @@ onReport - - 5 - wxEXPAND - 1 - - 0 - protected - 0 - - + + + + 5 + wxEXPAND | wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline1 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + ; ; forward_declare + 0 + + + + + + + + 5 + wxEXPAND|wxLEFT + 0 + + + bSizerBottom + wxHORIZONTAL + none 5 wxALL|wxEXPAND - 0 + 1 0 1 diff --git a/pcbnew/dialogs/dialog_select_net_from_list_base.h b/pcbnew/dialogs/dialog_select_net_from_list_base.h index 274dbd820e..44809cd479 100644 --- a/pcbnew/dialogs/dialog_select_net_from_list_base.h +++ b/pcbnew/dialogs/dialog_select_net_from_list_base.h @@ -21,10 +21,12 @@ #include #include #include +#include #include #include #include #include +#include #include /////////////////////////////////////////////////////////////////////////// @@ -42,7 +44,11 @@ class DIALOG_SELECT_NET_FROM_LIST_BASE : public DIALOG_SHIM wxTextCtrl* m_textCtrlFilter; wxCheckBox* m_cbShowZeroPad; wxDataViewListCtrl* m_netsList; + wxBitmapButton* m_addNet; + wxBitmapButton* m_renameNet; + wxBitmapButton* m_deleteNet; wxButton* m_ReportButt; + wxStaticLine* m_staticline1; wxStdDialogButtonSizer* m_sdbSizer; wxButton* m_sdbSizerOK; wxButton* m_sdbSizerCancel; @@ -51,12 +57,15 @@ class DIALOG_SELECT_NET_FROM_LIST_BASE : public DIALOG_SHIM virtual void onFilterChange( wxCommandEvent& event ) { event.Skip(); } virtual void onSelChanged( wxDataViewEvent& event ) { event.Skip(); } virtual void onListSize( wxSizeEvent& event ) { event.Skip(); } + virtual void onAddNet( wxCommandEvent& event ) { event.Skip(); } + virtual void onRenameNet( wxCommandEvent& event ) { event.Skip(); } + virtual void onDeleteNet( wxCommandEvent& event ) { event.Skip(); } virtual void onReport( wxCommandEvent& event ) { event.Skip(); } public: - DIALOG_SELECT_NET_FROM_LIST_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Net Inspector"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 720,397 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + DIALOG_SELECT_NET_FROM_LIST_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Net Inspector"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); ~DIALOG_SELECT_NET_FROM_LIST_BASE(); }; diff --git a/pcbnew/netinfo.h b/pcbnew/netinfo.h index fdeb8a8d66..43849e44f3 100644 --- a/pcbnew/netinfo.h +++ b/pcbnew/netinfo.h @@ -236,6 +236,21 @@ public: */ const wxString& GetShortNetname() const { return m_ShortNetname; } + /** + * Function SetNetname + * Sets the long netname to \a aNetName, and the short netname to the last token in + * the long netname's path. + */ + void SetNetname( const wxString& aNewName ) + { + m_Netname = aNewName; + + if( aNewName.Contains( "/" ) ) + m_ShortNetname = aNewName.AfterLast( '/' ); + else + m_ShortNetname = aNewName; + } + bool IsCurrent() const { return m_isCurrent; } void SetIsCurrent( bool isCurrent ) { m_isCurrent = isCurrent; } diff --git a/pcbnew/netlist_reader/board_netlist_updater.cpp b/pcbnew/netlist_reader/board_netlist_updater.cpp index 05c25196fa..4d4a8c3aba 100644 --- a/pcbnew/netlist_reader/board_netlist_updater.cpp +++ b/pcbnew/netlist_reader/board_netlist_updater.cpp @@ -864,6 +864,5 @@ bool BOARD_NETLIST_UPDATER::UpdateNetlist( NETLIST& aNetlist ) return false; } - m_reporter->ReportTail( _( "Netlist update successful!" ), RPT_SEVERITY_ACTION ); return true; } diff --git a/pcbnew/netlist_reader/pcb_netlist.cpp b/pcbnew/netlist_reader/pcb_netlist.cpp index 0ce5898ee6..28e0f352a6 100644 --- a/pcbnew/netlist_reader/pcb_netlist.cpp +++ b/pcbnew/netlist_reader/pcb_netlist.cpp @@ -1,12 +1,9 @@ -/** - * @file pcb_netlist.cpp - */ /* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 1992-2011 Jean-Pierre Charras. * Copyright (C) 2013 Wayne Stambaugh . - * Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2020 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 @@ -27,13 +24,9 @@ */ -#include #include -#include - #include "pcb_netlist.h" #include -#include int COMPONENT_NET::Format( OUTPUTFORMATTER* aOut, int aNestLevel, int aCtl ) @@ -220,14 +213,3 @@ bool NETLIST::AnyFootprintsLinked() const } -bool NETLIST::AllFootprintsLinked() const -{ - for( unsigned i = 0; i < m_components.size(); i++ ) - { - if( m_components[i].GetFPID().empty() ) - return false; - } - - return true; -} - diff --git a/pcbnew/netlist_reader/pcb_netlist.h b/pcbnew/netlist_reader/pcb_netlist.h index 92d50eaf99..e3eb7cc53f 100644 --- a/pcbnew/netlist_reader/pcb_netlist.h +++ b/pcbnew/netlist_reader/pcb_netlist.h @@ -97,7 +97,6 @@ class COMPONENT /// The #LIB_ID of the footprint assigned to the component. LIB_ID m_fpid; - /// The alt LIB_ID of the footprint, when there are 2 different assigned footprints, /// One from the netlist, the other from the .cmp file. /// this one is a copy of the netlist footprint assignment @@ -106,15 +105,12 @@ class COMPONENT /// The #MODULE loaded for #m_fpid. std::unique_ptr< MODULE > m_footprint; - /// Set to true if #m_fpid was changed when the footprint link file was read. - bool m_footprintChanged; - static COMPONENT_NET m_emptyNet; public: - COMPONENT( const LIB_ID& aFPID, - const wxString& aReference, - const wxString& aValue, + COMPONENT( const LIB_ID& aFPID, + const wxString& aReference, + const wxString& aValue, const KIID_PATH& aPath ) { m_fpid = aFPID; @@ -122,7 +118,6 @@ public: m_value = aValue; m_pinCount = 0; m_path = aPath; - m_footprintChanged = false; } virtual ~COMPONENT() { }; @@ -150,35 +145,18 @@ public: const wxString& GetValue() const { return m_value; } - void SetFPID( const LIB_ID& aFPID ) - { - m_footprintChanged = !m_fpid.empty() && (m_fpid != aFPID); - m_fpid = aFPID; - } - - void SetAltFPID( const LIB_ID& aFPID ) - { - m_altFpid = aFPID; - } - + void SetFPID( const LIB_ID& aFPID ) { m_fpid = aFPID; } const LIB_ID& GetFPID() const { return m_fpid; } + void SetAltFPID( const LIB_ID& aFPID ) { m_altFpid = aFPID; } const LIB_ID& GetAltFPID() const { return m_altFpid; } const KIID_PATH& GetPath() const { return m_path; } - void SetFootprintFilters( const wxArrayString& aFilterList ) - { - m_footprintFilters = aFilterList; - } - + void SetFootprintFilters( const wxArrayString& aFilters ) { m_footprintFilters = aFilters; } const wxArrayString& GetFootprintFilters() const { return m_footprintFilters; } - void SetPinCount( int aPinCount ) - { - m_pinCount = aPinCount; - } - + void SetPinCount( int aPinCount ) { m_pinCount = aPinCount; } int GetPinCount() const { return m_pinCount; } MODULE* GetModule( bool aRelease = false ) @@ -193,15 +171,11 @@ public: return aLibrary == m_library && aName == m_name; } - bool FootprintChanged() const { return m_footprintChanged; } - void Format( OUTPUTFORMATTER* aOut, int aNestLevel, int aCtl ); }; typedef boost::ptr_vector< COMPONENT > COMPONENTS; -typedef COMPONENTS::iterator COMPONENTS_ITER; -typedef COMPONENTS::const_iterator COMPONENTS_CITER; /** @@ -300,12 +274,6 @@ public: m_deleteExtraFootprints = aDeleteExtraFootprints; } - bool GetDeleteExtraFootprints() const { return m_deleteExtraFootprints; } - - void SetIsDryRun( bool aIsDryRun ) { m_isDryRun = aIsDryRun; } - - bool IsDryRun() const { return m_isDryRun; } - void SetFindByTimeStamp( bool aFindByTimeStamp ) { m_findByTimeStamp = aFindByTimeStamp; } bool IsFindByTimeStamp() const { return m_findByTimeStamp; } @@ -323,25 +291,6 @@ public: */ bool AnyFootprintsLinked() const; - /** - * Function AllFootprintsLinked - * @return true if all components have a footprint link. - */ - bool AllFootprintsLinked() const; - - /** - * Function NoFootprintsLinked - * @return true if none of the components have a footprint link. - */ - bool NoFootprintsLinked() const { return !AnyFootprintsLinked(); } - - /** - * Function AnyFootprintsChanged - * @return true if any components footprints were changed when the footprint link file - * (*.cmp) was loaded. - */ - bool AnyFootprintsChanged() const; - void Format( const char* aDocName, OUTPUTFORMATTER* aOut, int aNestLevel, int aCtl = 0 ); #define CTL_OMIT_EXTRA (1<<0)