ADDED: ERC/DRC exclusion comments.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/16020
This commit is contained in:
Jeff Young 2024-01-29 15:59:28 +00:00
parent c8d2a9340b
commit d7e4a8cebd
17 changed files with 379 additions and 133 deletions

View File

@ -27,15 +27,20 @@
WX_TEXT_ENTRY_DIALOG::WX_TEXT_ENTRY_DIALOG( wxWindow* aParent,
const wxString& aFieldLabel,
const wxString& aCaption,
const wxString& aDefaultValue ) :
const wxString& aDefaultValue,
bool aExtraWidth ) :
WX_TEXT_ENTRY_DIALOG_BASE( aParent, wxID_ANY, aCaption, wxDefaultPosition, wxDefaultSize )
{
m_label->SetLabel( aFieldLabel );
m_textCtrl->SetValue( aDefaultValue );
m_textCtrl->SetMinSize( FromDIP( aExtraWidth ? wxSize( 700, -1 ) : wxSize( 300, -1 ) ) );
SetupStandardButtons();
SetInitialFocus( m_textCtrl );
this->Layout();
m_mainSizer->Fit( this );
}

View File

@ -84,12 +84,12 @@ wxString RC_ITEM::getSeverityString( SEVERITY aSeverity )
switch( aSeverity )
{
case RPT_SEVERITY_ERROR: severity = wxS( "error" ); break;
case RPT_SEVERITY_WARNING: severity = wxS( "warning" ); break;
case RPT_SEVERITY_ACTION: severity = wxS( "action" ); break;
case RPT_SEVERITY_INFO: severity = wxS( "info" ); break;
case RPT_SEVERITY_ERROR: severity = wxS( "error" ); break;
case RPT_SEVERITY_WARNING: severity = wxS( "warning" ); break;
case RPT_SEVERITY_ACTION: severity = wxS( "action" ); break;
case RPT_SEVERITY_INFO: severity = wxS( "info" ); break;
case RPT_SEVERITY_EXCLUSION: severity = wxS( "exclusion" ); break;
case RPT_SEVERITY_DEBUG: severity = wxS( "debug" ); break;
case RPT_SEVERITY_DEBUG: severity = wxS( "debug" ); break;
default:;
};
@ -123,41 +123,48 @@ wxString RC_ITEM::ShowReport( UNITS_PROVIDER* aUnitsProvider, SEVERITY aSeverity
// 2) try not to re-order or change syntax
// 3) report settings key (which should be more stable) in addition to message
wxString msg;
if( mainItem && auxItem )
{
return wxString::Format( wxT( "[%s]: %s\n %s; %s\n %s: %s\n %s: %s\n" ),
GetSettingsKey(),
GetErrorMessage(),
GetViolatingRuleDesc(),
severity,
showCoord( aUnitsProvider, mainItem->GetPosition()),
mainItem->GetItemDescription( aUnitsProvider ),
showCoord( aUnitsProvider, auxItem->GetPosition()),
auxItem->GetItemDescription( aUnitsProvider ) );
msg.Printf( wxT( "[%s]: %s\n %s; %s\n %s: %s\n %s: %s\n" ),
GetSettingsKey(),
GetErrorMessage(),
GetViolatingRuleDesc(),
severity,
showCoord( aUnitsProvider, mainItem->GetPosition()),
mainItem->GetItemDescription( aUnitsProvider ),
showCoord( aUnitsProvider, auxItem->GetPosition()),
auxItem->GetItemDescription( aUnitsProvider ) );
}
else if( mainItem )
{
return wxString::Format( wxT( "[%s]: %s\n %s; %s\n %s: %s\n" ),
GetSettingsKey(),
GetErrorMessage(),
GetViolatingRuleDesc(),
severity,
showCoord( aUnitsProvider, mainItem->GetPosition()),
mainItem->GetItemDescription( aUnitsProvider ) );
msg.Printf( wxT( "[%s]: %s\n %s; %s\n %s: %s\n" ),
GetSettingsKey(),
GetErrorMessage(),
GetViolatingRuleDesc(),
severity,
showCoord( aUnitsProvider, mainItem->GetPosition()),
mainItem->GetItemDescription( aUnitsProvider ) );
}
else
{
return wxString::Format( wxT( "[%s]: %s\n %s; %s\n" ),
GetSettingsKey(),
GetErrorMessage(),
GetViolatingRuleDesc(),
severity );
msg.Printf( wxT( "[%s]: %s\n %s; %s\n" ),
GetSettingsKey(),
GetErrorMessage(),
GetViolatingRuleDesc(),
severity );
}
if( m_parent && m_parent->IsExcluded() && !m_parent->GetComment().IsEmpty() )
msg += wxString::Format( wxS( " %s\n" ), m_parent->GetComment() );
return msg;
}
void RC_ITEM::GetJsonViolation( RC_JSON::VIOLATION& aViolation, UNITS_PROVIDER* aUnitsProvider,
SEVERITY aSeverity,
SEVERITY aSeverity,
const std::map<KIID, EDA_ITEM*>& aItemMap ) const
{
wxString severity = getSeverityString( aSeverity );
@ -221,6 +228,7 @@ KIID RC_TREE_MODEL::ToUUID( wxDataViewItem aItem )
switch( node->m_Type )
{
case RC_TREE_NODE::MARKER:
case RC_TREE_NODE::COMMENT:
// rc_item->GetParent() can be null, if the parent is not existing
// when a RC item has no corresponding ERC/DRC marker
if( rc_item->GetParent() )
@ -310,6 +318,12 @@ void RC_TREE_MODEL::rebuildModel( std::shared_ptr<RC_ITEMS_PROVIDER> aProvider,
if( rcItem->GetAuxItem3ID() != niluuid )
n->m_Children.push_back( new RC_TREE_NODE( n, rcItem, RC_TREE_NODE::AUX_ITEM3 ) );
if( MARKER_BASE* marker = rcItem->GetParent() )
{
if( marker->IsExcluded() && !marker->GetComment().IsEmpty() )
n->m_Children.push_back( new RC_TREE_NODE( n, rcItem, RC_TREE_NODE::COMMENT ) );
}
}
// Must be called after a significant change of items to force the
@ -444,6 +458,12 @@ void RC_TREE_MODEL::GetValue( wxVariant& aVariant,
case RC_TREE_NODE::AUX_ITEM3:
item = m_editFrame->GetItem( rcItem->GetAuxItem3ID() );
break;
case RC_TREE_NODE::COMMENT:
if( marker )
msg = marker->GetComment();
break;
}
if( item )
@ -494,19 +514,51 @@ bool RC_TREE_MODEL::GetAttr( wxDataViewItem const& aItem,
}
void RC_TREE_MODEL::ValueChanged( const RC_TREE_NODE* aNode )
void RC_TREE_MODEL::ValueChanged( RC_TREE_NODE* aNode )
{
if( aNode->m_Type == RC_TREE_NODE::MAIN_ITEM || aNode->m_Type == RC_TREE_NODE::AUX_ITEM )
if( aNode->m_Type != RC_TREE_NODE::MARKER )
{
ValueChanged( aNode->m_Parent );
return;
}
if( aNode->m_Type == RC_TREE_NODE::MARKER )
{
wxDataViewModel::ValueChanged( ToItem( aNode ), 0 );
wxDataViewItem markerItem = ToItem( aNode );
for( const RC_TREE_NODE* child : aNode->m_Children )
wxDataViewModel::ValueChanged( ToItem( child ), 0 );
wxDataViewModel::ValueChanged( markerItem, 0 );
for( const RC_TREE_NODE* child : aNode->m_Children )
wxDataViewModel::ValueChanged( ToItem( child ), 0 );
// Comment items can come and go depening on exclusion state and comment content.
//
const std::shared_ptr<RC_ITEM> rcItem = aNode->m_RcItem;
MARKER_BASE* marker = rcItem ? rcItem->GetParent() : nullptr;
if( marker )
{
bool needsCommentNode = marker->IsExcluded() && !marker->GetComment().IsEmpty();
RC_TREE_NODE* commentNode = aNode->m_Children.back();
if( commentNode && commentNode->m_Type != RC_TREE_NODE::COMMENT )
commentNode = nullptr;
if( needsCommentNode && !commentNode )
{
commentNode = new RC_TREE_NODE( aNode, rcItem, RC_TREE_NODE::COMMENT );
wxDataViewItemArray newItems;
newItems.push_back( ToItem( commentNode ) );
aNode->m_Children.push_back( commentNode );
ItemsAdded( markerItem, newItems );
}
else if( commentNode && !needsCommentNode )
{
wxDataViewItemArray deletedItems;
deletedItems.push_back( ToItem( commentNode ) );
aNode->m_Children.erase( aNode->m_Children.end() - 1 );
ItemsDeleted( markerItem, deletedItems );
}
}
}

View File

@ -43,6 +43,7 @@
#include <confirm.h>
#include <common.h>
#include <widgets/wx_html_report_box.h>
#include <dialogs/dialog_text_entry.h>
#include <wx/ffile.h>
#include <wx/filedlg.h>
#include <wx/hyperlink.h>
@ -599,14 +600,34 @@ void DIALOG_ERC::OnERCItemRClick( wxDataViewEvent& aEvent )
default: listName = _( "appropriate" ); break;
}
enum MENU_IDS
{
ID_EDIT_EXCLUSION_COMMENT = 4467,
ID_REMOVE_EXCLUSION,
ID_REMOVE_EXCLUSION_ALL,
ID_ADD_EXCLUSION,
ID_ADD_EXCLUSION_ALL,
ID_EDIT_PIN_CONFLICT_MAP,
ID_EDIT_CONNECTION_GRID,
ID_SET_SEVERITY_TO_ERROR,
ID_SET_SEVERITY_TO_WARNING,
ID_SET_SEVERITY_TO_IGNORE,
ID_EDIT_SEVERITIES,
};
if( rcItem->GetParent()->IsExcluded() )
{
menu.Append( 1, _( "Remove exclusion for this violation" ),
menu.Append( ID_EDIT_EXCLUSION_COMMENT,
_( "Edit exclusion comment..." ) );
menu.Append( ID_REMOVE_EXCLUSION,
_( "Remove exclusion for this violation" ),
wxString::Format( _( "It will be placed back in the %s list" ), listName ) );
}
else
{
menu.Append( 2, _( "Exclude this violation" ),
menu.Append( ID_ADD_EXCLUSION,
_( "Exclude this violation..." ),
wxString::Format( _( "It will be excluded from the %s list" ), listName ) );
}
@ -619,18 +640,21 @@ void DIALOG_ERC::OnERCItemRClick( wxDataViewEvent& aEvent )
}
else if( settings.GetSeverity( rcItem->GetErrorCode() ) == RPT_SEVERITY_WARNING )
{
menu.Append( 4, wxString::Format( _( "Change severity to Error for all '%s' violations" ),
rcItem->GetErrorText() ),
menu.Append( ID_SET_SEVERITY_TO_ERROR,
wxString::Format( _( "Change severity to Error for all '%s' violations" ),
rcItem->GetErrorText() ),
_( "Violation severities can also be edited in the Schematic Setup... dialog" ) );
}
else
{
menu.Append( 5, wxString::Format( _( "Change severity to Warning for all '%s' violations" ),
rcItem->GetErrorText() ),
menu.Append( ID_SET_SEVERITY_TO_WARNING,
wxString::Format( _( "Change severity to Warning for all '%s' violations" ),
rcItem->GetErrorText() ),
_( "Violation severities can also be edited in the Schematic Setup... dialog" ) );
}
menu.Append( 6, wxString::Format( _( "Ignore all '%s' violations" ), rcItem->GetErrorText() ),
menu.Append( ID_SET_SEVERITY_TO_IGNORE,
wxString::Format( _( "Ignore all '%s' violations" ), rcItem->GetErrorText() ),
_( "Violations will not be checked or reported" ) );
menu.AppendSeparator();
@ -638,17 +662,21 @@ void DIALOG_ERC::OnERCItemRClick( wxDataViewEvent& aEvent )
if( rcItem->GetErrorCode() == ERCE_PIN_TO_PIN_WARNING
|| rcItem->GetErrorCode() == ERCE_PIN_TO_PIN_ERROR )
{
menu.Append( 7, _( "Edit pin-to-pin conflict map..." ) );
menu.Append( ID_EDIT_PIN_CONFLICT_MAP,
_( "Edit pin-to-pin conflict map..." ),
_( "Open the Schematic Setup... dialog" ) );
}
else
{
menu.Append( 8, _( "Edit violation severities..." ),
menu.Append( ID_EDIT_SEVERITIES,
_( "Edit violation severities..." ),
_( "Open the Schematic Setup... dialog" ) );
}
if( rcItem->GetErrorCode() == ERCE_ENDPOINT_OFF_GRID )
{
menu.Append( 9, _( "Edit connection grid spacing..." ),
menu.Append( ID_EDIT_CONNECTION_GRID,
_( "Edit connection grid spacing..." ),
_( "Open the Schematic Setup... dialog" ) );
}
@ -656,11 +684,26 @@ void DIALOG_ERC::OnERCItemRClick( wxDataViewEvent& aEvent )
switch( GetPopupMenuSelectionFromUser( menu ) )
{
case 1:
{
SCH_MARKER* marker = dynamic_cast<SCH_MARKER*>( node->m_RcItem->GetParent() );
case ID_EDIT_EXCLUSION_COMMENT:
if( SCH_MARKER* marker = dynamic_cast<SCH_MARKER*>( node->m_RcItem->GetParent() ) )
{
WX_TEXT_ENTRY_DIALOG dlg( this, _( "Optional comment:" ), _( "Exclusion Comment" ),
marker->GetComment(), true );
if( marker )
if( dlg.ShowModal() == wxID_CANCEL )
break;
marker->SetExcluded( true, dlg.GetValue() );
// Update view
static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->ValueChanged( node );
modified = true;
}
break;
case ID_REMOVE_EXCLUSION:
if( SCH_MARKER* marker = dynamic_cast<SCH_MARKER*>( node->m_RcItem->GetParent() ) )
{
marker->SetExcluded( false );
m_parent->GetCanvas()->GetView()->Update( marker );
@ -669,16 +712,20 @@ void DIALOG_ERC::OnERCItemRClick( wxDataViewEvent& aEvent )
static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->ValueChanged( node );
modified = true;
}
}
break;
case 2:
{
SCH_MARKER* marker = dynamic_cast<SCH_MARKER*>( node->m_RcItem->GetParent() );
if( marker )
case ID_ADD_EXCLUSION:
if( SCH_MARKER* marker = dynamic_cast<SCH_MARKER*>( node->m_RcItem->GetParent() ) )
{
marker->SetExcluded( true );
WX_TEXT_ENTRY_DIALOG dlg( this, _( "Optional comment:" ), _( "Exclusion Comment" ),
wxEmptyString, true );
if( dlg.ShowModal() == wxID_CANCEL )
break;
marker->SetExcluded( true, dlg.GetValue() );
m_parent->GetCanvas()->GetView()->Update( marker );
// Update view
@ -689,10 +736,10 @@ void DIALOG_ERC::OnERCItemRClick( wxDataViewEvent& aEvent )
modified = true;
}
}
break;
case 4:
case ID_SET_SEVERITY_TO_ERROR:
settings.SetSeverity( rcItem->GetErrorCode(), RPT_SEVERITY_ERROR );
for( SCH_ITEM* item : m_parent->GetScreen()->Items().OfType( SCH_MARKER_T ) )
@ -708,7 +755,7 @@ void DIALOG_ERC::OnERCItemRClick( wxDataViewEvent& aEvent )
modified = true;
break;
case 5:
case ID_SET_SEVERITY_TO_WARNING:
settings.SetSeverity( rcItem->GetErrorCode(), RPT_SEVERITY_WARNING );
for( SCH_ITEM* item : m_parent->GetScreen()->Items().OfType( SCH_MARKER_T ) )
@ -724,7 +771,7 @@ void DIALOG_ERC::OnERCItemRClick( wxDataViewEvent& aEvent )
modified = true;
break;
case 6:
case ID_SET_SEVERITY_TO_IGNORE:
{
settings.SetSeverity( rcItem->GetErrorCode(), RPT_SEVERITY_IGNORE );
@ -740,15 +787,15 @@ void DIALOG_ERC::OnERCItemRClick( wxDataViewEvent& aEvent )
}
break;
case 7:
case ID_EDIT_PIN_CONFLICT_MAP:
m_parent->ShowSchematicSetupDialog( _( "Pin Conflicts Map" ) );
break;
case 8:
case ID_EDIT_SEVERITIES:
m_parent->ShowSchematicSetupDialog( _( "Violation Severity" ) );
break;
case 9:
case ID_EDIT_CONNECTION_GRID:
m_parent->ShowSchematicSetupDialog( _( "Formatting" ) );
break;
}

View File

@ -376,6 +376,12 @@ void ERC_TREE_MODEL::GetValue( wxVariant& aVariant, wxDataViewItem const& aItem,
msg = getItemDesc( schEditFrame->GetItem( ercItem->GetAuxItem3ID() ),
schEditFrame->GetCurrentSheet() );
break;
case RC_TREE_NODE::COMMENT:
if( marker )
msg = marker->GetComment();
break;
}
msg.Replace( wxS( "\n" ), wxS( " " ) );

View File

@ -148,7 +148,7 @@ bool ERC_REPORT::WriteJsonReport( const wxString& aFullFileName )
switch( severity )
{
case RPT_SEVERITY_ERROR: err_count++; break;
case RPT_SEVERITY_ERROR: err_count++; break;
case RPT_SEVERITY_WARNING: warn_count++; break;
default: break;
}

View File

@ -149,8 +149,8 @@ ERC_SETTINGS::ERC_SETTINGS( JSON_SETTINGS* aParent, const std::string& aPath ) :
{
nlohmann::json js = nlohmann::json::array();
for( const auto& entry : m_ErcExclusions )
js.push_back( entry );
for( const wxString& entry : m_ErcExclusions )
js.push_back( { entry, m_ErcExclusionComments[ entry ] } );
return js;
},
@ -163,10 +163,16 @@ ERC_SETTINGS::ERC_SETTINGS( JSON_SETTINGS* aParent, const std::string& aPath ) :
for( const nlohmann::json& entry : aObj )
{
if( entry.empty() )
continue;
m_ErcExclusions.insert( entry.get<wxString>() );
if( entry.is_array() )
{
wxString serialized = entry[0].get<wxString>();
m_ErcExclusions.insert( serialized );
m_ErcExclusionComments[ serialized ] = entry[1].get<wxString>();
}
else if( entry.is_string() )
{
m_ErcExclusions.insert( entry.get<wxString>() );
}
}
},
{} ) );

View File

@ -172,8 +172,9 @@ public:
public:
std::map<int, SEVERITY> m_ERCSeverities;
std::set<wxString> m_ErcExclusions;
std::map<int, SEVERITY> m_ERCSeverities;
std::set<wxString> m_ErcExclusions; // Serialized excluded ERC markers
std::map<wxString, wxString> m_ErcExclusionComments; // Map from serialization to comment
PIN_ERROR m_PinMap[ELECTRICAL_PINTYPES_TOTAL][ELECTRICAL_PINTYPES_TOTAL];

View File

@ -27,6 +27,7 @@
#include <widgets/msgpanel.h>
#include <bitmaps.h>
#include <base_units.h>
#include <eda_draw_frame.h>
#include <erc_settings.h>
#include <sch_marker.h>
#include <schematic.h>
@ -272,7 +273,52 @@ const BOX2I SCH_MARKER::GetBoundingBox() const
void SCH_MARKER::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
{
aList.emplace_back( _( "Electrical Rule Check Error" ), m_rcItem->GetErrorMessage() );
aList.emplace_back( _( "Type" ), _( "Marker" ) );
aList.emplace_back( _( "Violation" ), m_rcItem->GetErrorMessage() );
switch( GetSeverity() )
{
case RPT_SEVERITY_IGNORE:
aList.emplace_back( _( "Severity" ), _( "Ignore" ) );
break;
case RPT_SEVERITY_WARNING:
aList.emplace_back( _( "Severity" ), _( "Warning" ) );
break;
case RPT_SEVERITY_ERROR:
aList.emplace_back( _( "Severity" ), _( "Error" ) );
break;
default:
break;
}
if( GetMarkerType() == MARKER_DRAWING_SHEET )
{
aList.emplace_back( _( "Drawing Sheet" ), wxEmptyString );
}
else
{
wxString mainText;
wxString auxText;
EDA_ITEM* mainItem = nullptr;
EDA_ITEM* auxItem = nullptr;
if( m_rcItem->GetMainItemID() != niluuid )
mainItem = aFrame->GetItem( m_rcItem->GetMainItemID() );
if( m_rcItem->GetAuxItemID() != niluuid )
auxItem = aFrame->GetItem( m_rcItem->GetAuxItemID() );
if( mainItem )
mainText = mainItem->GetItemDescription( aFrame );
if( auxItem )
auxText = auxItem->GetItemDescription( aFrame );
aList.emplace_back( mainText, auxText );
}
if( IsExcluded() )
aList.emplace_back( _( "Excluded" ), m_comment );
}

View File

@ -349,7 +349,7 @@ std::vector<SCH_MARKER*> SCHEMATIC::ResolveERCExclusions()
if( it != settings.m_ErcExclusions.end() )
{
marker->SetExcluded( true );
marker->SetExcluded( true, settings.m_ErcExclusionComments[serialized] );
settings.m_ErcExclusions.erase( it );
}
}
@ -363,7 +363,7 @@ std::vector<SCH_MARKER*> SCHEMATIC::ResolveERCExclusions()
if( marker )
{
marker->SetExcluded( true );
marker->SetExcluded( true, settings.m_ErcExclusionComments[serialized] );
newMarkers.push_back( marker );
}
}
@ -818,6 +818,7 @@ void SCHEMATIC::RecordERCExclusions()
ERC_SETTINGS& ercSettings = ErcSettings();
ercSettings.m_ErcExclusions.clear();
ercSettings.m_ErcExclusionComments.clear();
for( unsigned i = 0; i < sheetList.size(); i++ )
{
@ -826,7 +827,11 @@ void SCHEMATIC::RecordERCExclusions()
SCH_MARKER* marker = static_cast<SCH_MARKER*>( item );
if( marker->IsExcluded() )
ercSettings.m_ErcExclusions.insert( marker->Serialize() );
{
wxString serialized = marker->Serialize();
ercSettings.m_ErcExclusions.insert( serialized );
ercSettings.m_ErcExclusionComments[ serialized ] = marker->GetComment();
}
}
}
}

View File

@ -695,9 +695,10 @@ public:
int m_MinSilkTextHeight; // Min text height for silkscreen layers
int m_MinSilkTextThickness; // Min text thickness for silkscreen layers
std::shared_ptr<DRC_ENGINE> m_DRCEngine;
std::map<int, SEVERITY> m_DRCSeverities; // Map from DRCErrorCode to SEVERITY
std::set<wxString> m_DrcExclusions;
std::shared_ptr<DRC_ENGINE> m_DRCEngine;
std::map<int, SEVERITY> m_DRCSeverities; // Map from DRCErrorCode to SEVERITY
std::set<wxString> m_DrcExclusions; // Serialized excluded DRC markers
std::map<wxString, wxString> m_DrcExclusionComments; // Map from serialization to comment
// When smoothing the zone's outline there's the question of external fillets (that is, those
// applied to concave corners). While it seems safer to never have copper extend outside the

View File

@ -40,7 +40,7 @@ class WX_TEXT_ENTRY_DIALOG : public WX_TEXT_ENTRY_DIALOG_BASE
{
public:
WX_TEXT_ENTRY_DIALOG( wxWindow* aParent, const wxString& aLabel, const wxString& aCaption,
const wxString& aDefaultValue = wxEmptyString );
const wxString& aDefaultValue = wxEmptyString, bool aExtraWidth = false );
WX_TEXT_ENTRY_DIALOG( wxWindow* aParent, const wxString& aLabel, const wxString& aCaption,

View File

@ -96,7 +96,13 @@ public:
enum MARKER_T GetMarkerType() const { return m_markerType; }
bool IsExcluded() const { return m_excluded; }
void SetExcluded( bool aExcluded ) { m_excluded = aExcluded; }
void SetExcluded( bool aExcluded, const wxString& aComment = wxEmptyString )
{
m_excluded = aExcluded;
m_comment = aComment;
}
wxString GetComment() const { return m_comment; }
virtual SEVERITY GetSeverity() const { return RPT_SEVERITY_UNDEFINED; }
@ -131,6 +137,7 @@ public:
protected:
MARKER_T m_markerType; // The type of marker (useful to filter markers)
bool m_excluded; // User has excluded this specific error
wxString m_comment; // User-supplied comment (generally for exclusions)
std::shared_ptr<RC_ITEM> m_rcItem;
int m_scalingFactor; // Scaling factor to convert corners coordinates

View File

@ -195,7 +195,15 @@ protected:
class RC_TREE_NODE
{
public:
enum NODE_TYPE { MARKER, MAIN_ITEM, AUX_ITEM, AUX_ITEM2, AUX_ITEM3 };
enum NODE_TYPE
{
MARKER,
MAIN_ITEM,
AUX_ITEM,
AUX_ITEM2,
AUX_ITEM3,
COMMENT
};
RC_TREE_NODE( RC_TREE_NODE* aParent, const std::shared_ptr<RC_ITEM>& aRcItem, NODE_TYPE aType ) :
m_Type( aType ),
@ -280,7 +288,7 @@ public:
bool GetAttr( wxDataViewItem const& aItem, unsigned int aCol,
wxDataViewItemAttr& aAttr ) const override;
void ValueChanged( const RC_TREE_NODE* aNode );
void ValueChanged( RC_TREE_NODE* aNode );
void DeleteCurrentItem( bool aDeep );

View File

@ -328,7 +328,7 @@ std::vector<PCB_MARKER*> BOARD::ResolveDRCExclusions( bool aCreateMarkers )
if( it != m_designSettings->m_DrcExclusions.end() )
{
marker->SetExcluded( true );
marker->SetExcluded( true, m_designSettings->m_DrcExclusionComments[serialized] );
m_designSettings->m_DrcExclusions.erase( it );
}
}
@ -357,7 +357,7 @@ std::vector<PCB_MARKER*> BOARD::ResolveDRCExclusions( bool aCreateMarkers )
if( marker )
{
marker->SetExcluded( true );
marker->SetExcluded( true, m_designSettings->m_DrcExclusionComments[serialized] );
newMarkers.push_back( marker );
}
}
@ -2738,10 +2738,15 @@ bool BOARD::operator==( const BOARD_ITEM& aItem ) const
void BOARD::RecordDRCExclusions()
{
m_designSettings->m_DrcExclusions.clear();
m_designSettings->m_DrcExclusionComments.clear();
for( PCB_MARKER* marker : m_markers )
{
if( marker->IsExcluded() )
m_designSettings->m_DrcExclusions.insert( marker->Serialize() );
{
wxString serialized = marker->Serialize();
m_designSettings->m_DrcExclusions.insert( serialized );
m_designSettings->m_DrcExclusionComments[ serialized ] = marker->GetComment();
}
}
}

View File

@ -336,8 +336,8 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS( JSON_SETTINGS* aParent, const std:
{
nlohmann::json js = nlohmann::json::array();
for( const auto& entry : m_DrcExclusions )
js.push_back( entry );
for( const wxString& entry : m_DrcExclusions )
js.push_back( { entry, m_DrcExclusionComments[ entry ] } );
return js;
},
@ -350,10 +350,16 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS( JSON_SETTINGS* aParent, const std:
for( const nlohmann::json& entry : aObj )
{
if( entry.empty() )
continue;
m_DrcExclusions.insert( entry.get<wxString>() );
if( entry.is_array() )
{
wxString serialized = entry[0].get<wxString>();
m_DrcExclusions.insert( serialized );
m_DrcExclusionComments[ serialized ] = entry[1].get<wxString>();
}
else if( entry.is_string() )
{
m_DrcExclusions.insert( entry.get<wxString>() );
}
}
},
{} ) );
@ -938,6 +944,7 @@ void BOARD_DESIGN_SETTINGS::initFromOther( const BOARD_DESIGN_SETTINGS& aOther )
m_MinSilkTextThickness = aOther.m_MinSilkTextThickness;
m_DRCSeverities = aOther.m_DRCSeverities;
m_DrcExclusions = aOther.m_DrcExclusions;
m_DrcExclusionComments = aOther.m_DrcExclusionComments;
m_ZoneKeepExternalFillets = aOther.m_ZoneKeepExternalFillets;
m_MaxError = aOther.m_MaxError;
m_SolderMaskExpansion = aOther.m_SolderMaskExpansion;
@ -1025,6 +1032,7 @@ bool BOARD_DESIGN_SETTINGS::operator==( const BOARD_DESIGN_SETTINGS& aOther ) co
if( m_MinSilkTextThickness != aOther.m_MinSilkTextThickness ) return false;
if( m_DRCSeverities != aOther.m_DRCSeverities ) return false;
if( m_DrcExclusions != aOther.m_DrcExclusions ) return false;
if( m_DrcExclusionComments != aOther.m_DrcExclusionComments ) return false;
if( m_ZoneKeepExternalFillets != aOther.m_ZoneKeepExternalFillets ) return false;
if( m_MaxError != aOther.m_MaxError ) return false;
if( m_SolderMaskExpansion != aOther.m_SolderMaskExpansion ) return false;

View File

@ -47,6 +47,7 @@
#include <widgets/progress_reporter_base.h>
#include <widgets/wx_html_report_box.h>
#include <dialogs/panel_setup_rules_base.h>
#include <dialogs/dialog_text_entry.h>
#include <tools/drc_tool.h>
#include <tools/zone_filler_tool.h>
#include <tools/board_inspection_tool.h>
@ -579,7 +580,6 @@ void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent )
std::shared_ptr<CONNECTIVITY_DATA> conn = m_currentBoard->GetConnectivity();
wxString listName;
wxMenu menu;
wxString msg;
switch( bds().m_DRCSeverities[ rcItem->GetErrorCode() ] )
{
@ -588,67 +588,107 @@ void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent )
default: listName = _( "appropriate" ); break;
}
enum MENU_IDS
{
ID_EDIT_EXCLUSION_COMMENT = 4467,
ID_REMOVE_EXCLUSION,
ID_REMOVE_EXCLUSION_ALL,
ID_ADD_EXCLUSION,
ID_ADD_EXCLUSION_ALL,
ID_INSPECT_VIOLATION,
ID_SET_SEVERITY_TO_ERROR,
ID_SET_SEVERITY_TO_WARNING,
ID_SET_SEVERITY_TO_IGNORE,
ID_EDIT_SEVERITIES
};
if( rcItem->GetParent()->IsExcluded() )
{
menu.Append( 1, _( "Remove exclusion for this violation" ),
menu.Append( ID_EDIT_EXCLUSION_COMMENT,
_( "Edit exclusion comment..." ) );
menu.Append( ID_REMOVE_EXCLUSION,
_( "Remove exclusion for this violation" ),
wxString::Format( _( "It will be placed back in the %s list" ), listName ) );
if( drcItem->GetViolatingRule() && !drcItem->GetViolatingRule()->m_Implicit )
{
msg.Printf( _( "Remove all exclusions for violations of rule '%s'" ),
drcItem->GetViolatingRule()->m_Name );
menu.Append( 11, msg );
menu.Append( ID_REMOVE_EXCLUSION_ALL,
wxString::Format( _( "Remove all exclusions for violations of rule '%s'" ),
drcItem->GetViolatingRule()->m_Name ),
wxString::Format( _( "They will be placed back in the %s list" ), listName ) );
}
}
else
{
menu.Append( 2, _( "Exclude this violation" ),
menu.Append( ID_ADD_EXCLUSION,
_( "Exclude this violation..." ),
wxString::Format( _( "It will be excluded from the %s list" ), listName ) );
if( drcItem->GetViolatingRule() && !drcItem->GetViolatingRule()->m_Implicit )
{
msg.Printf( _( "Exclude all violations of rule '%s'" ),
drcItem->GetViolatingRule()->m_Name );
menu.Append( 21, msg );
menu.Append( ID_ADD_EXCLUSION_ALL,
wxString::Format( _( "Exclude all violations of rule '%s'..." ),
drcItem->GetViolatingRule()->m_Name ),
wxString::Format( _( "They will be excluded from the %s list" ), listName ) );
}
}
wxString inspectDRCErrorMenuText = inspectionTool->InspectDRCErrorMenuText( rcItem );
if( !inspectDRCErrorMenuText.IsEmpty() )
menu.Append( 3, inspectDRCErrorMenuText );
menu.Append( ID_INSPECT_VIOLATION, inspectDRCErrorMenuText );
menu.AppendSeparator();
if( bds().m_DRCSeverities[ rcItem->GetErrorCode() ] == RPT_SEVERITY_WARNING )
{
msg.Printf( _( "Change severity to Error for all '%s' violations" ),
rcItem->GetErrorText(),
_( "Violation severities can also be edited in the Board Setup... dialog" ) );
menu.Append( 4, msg );
menu.Append( ID_SET_SEVERITY_TO_ERROR,
wxString::Format( _( "Change severity to Error for all '%s' violations" ),
rcItem->GetErrorText() ),
_( "Violation severities can also be edited in the Board Setup... dialog" ) );
}
else
{
msg.Printf( _( "Change severity to Warning for all '%s' violations" ),
rcItem->GetErrorText(),
_( "Violation severities can also be edited in the Board Setup... dialog" ) );
menu.Append( 5, msg );
menu.Append( ID_SET_SEVERITY_TO_WARNING,
wxString::Format( _( "Change severity to Warning for all '%s' violations" ),
rcItem->GetErrorText() ),
_( "Violation severities can also be edited in the Board Setup... dialog" ) );
}
msg.Printf( _( "Ignore all '%s' violations" ),
rcItem->GetErrorText(),
_( "Violations will not be checked or reported" ) );
menu.Append( 6, msg );
menu.Append( ID_SET_SEVERITY_TO_IGNORE,
wxString::Format( _( "Ignore all '%s' violations" ), rcItem->GetErrorText() ),
_( "Violations will not be checked or reported" ) );
menu.AppendSeparator();
menu.Append( 7, _( "Edit violation severities..." ), _( "Open the Board Setup... dialog" ) );
menu.Append( ID_EDIT_SEVERITIES,
_( "Edit violation severities..." ),
_( "Open the Board Setup... dialog" ) );
bool modified = false;
switch( GetPopupMenuSelectionFromUser( menu ) )
{
case 1:
case ID_EDIT_EXCLUSION_COMMENT:
if( PCB_MARKER* marker = dynamic_cast<PCB_MARKER*>( node->m_RcItem->GetParent() ) )
{
WX_TEXT_ENTRY_DIALOG dlg( this, _( "Optional comment:" ), _( "Exclusion Comment" ),
marker->GetComment(), true );
if( dlg.ShowModal() == wxID_CANCEL )
break;
marker->SetExcluded( true, dlg.GetValue() );
// Update view
static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->ValueChanged( node );
modified = true;
}
break;
case ID_REMOVE_EXCLUSION:
if( PCB_MARKER* marker = dynamic_cast<PCB_MARKER*>( rcItem->GetParent() ) )
{
marker->SetExcluded( false );
@ -670,10 +710,16 @@ void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent )
break;
case 2:
case ID_ADD_EXCLUSION:
if( PCB_MARKER* marker = dynamic_cast<PCB_MARKER*>( rcItem->GetParent() ) )
{
marker->SetExcluded( true );
WX_TEXT_ENTRY_DIALOG dlg( this, _( "Optional comment:" ), _( "Exclusion Comment" ),
wxEmptyString, true );
if( dlg.ShowModal() == wxID_CANCEL )
break;
marker->SetExcluded( true, dlg.GetValue() );
if( rcItem->GetErrorCode() == DRCE_UNCONNECTED_ITEMS )
{
@ -696,7 +742,7 @@ void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent )
break;
case 11:
case ID_REMOVE_EXCLUSION_ALL:
for( PCB_MARKER* marker : m_frame->GetBoard()->Markers() )
{
DRC_ITEM* candidateDrcItem = static_cast<DRC_ITEM*>( marker->GetRCItem().get() );
@ -710,7 +756,7 @@ void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent )
modified = true;
break;
case 21:
case ID_ADD_EXCLUSION_ALL:
for( PCB_MARKER* marker : m_frame->GetBoard()->Markers() )
{
DRC_ITEM* candidateDrcItem = static_cast<DRC_ITEM*>( marker->GetRCItem().get() );
@ -724,11 +770,11 @@ void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent )
modified = true;
break;
case 3:
case ID_INSPECT_VIOLATION:
inspectionTool->InspectDRCError( node->m_RcItem );
break;
case 4:
case ID_SET_SEVERITY_TO_ERROR:
bds().m_DRCSeverities[ rcItem->GetErrorCode() ] = RPT_SEVERITY_ERROR;
for( PCB_MARKER* marker : m_frame->GetBoard()->Markers() )
@ -742,7 +788,7 @@ void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent )
modified = true;
break;
case 5:
case ID_SET_SEVERITY_TO_WARNING:
bds().m_DRCSeverities[ rcItem->GetErrorCode() ] = RPT_SEVERITY_WARNING;
for( PCB_MARKER* marker : m_frame->GetBoard()->Markers() )
@ -756,7 +802,7 @@ void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent )
modified = true;
break;
case 6:
case ID_SET_SEVERITY_TO_IGNORE:
{
bds().m_DRCSeverities[ rcItem->GetErrorCode() ] = RPT_SEVERITY_IGNORE;
@ -787,7 +833,7 @@ void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent )
break;
}
case 7:
case ID_EDIT_SEVERITIES:
m_frame->ShowBoardSetupDialog( _( "Violation Severity" ) );
break;
}
@ -930,10 +976,10 @@ void DIALOG_DRC::PrevMarker()
{
switch( m_Notebook->GetSelection() )
{
case 0: m_markersTreeModel->PrevMarker(); break;
case 1: m_unconnectedTreeModel->PrevMarker(); break;
case 2: m_fpWarningsTreeModel->PrevMarker(); break;
case 3: break;
case 0: m_markersTreeModel->PrevMarker(); break;
case 1: m_unconnectedTreeModel->PrevMarker(); break;
case 2: m_fpWarningsTreeModel->PrevMarker(); break;
case 3: break;
}
}
}
@ -945,10 +991,10 @@ void DIALOG_DRC::NextMarker()
{
switch( m_Notebook->GetSelection() )
{
case 0: m_markersTreeModel->NextMarker(); break;
case 1: m_unconnectedTreeModel->NextMarker(); break;
case 2: m_fpWarningsTreeModel->NextMarker(); break;
case 3: break;
case 0: m_markersTreeModel->NextMarker(); break;
case 1: m_unconnectedTreeModel->NextMarker(); break;
case 2: m_fpWarningsTreeModel->NextMarker(); break;
case 3: break;
}
}
}

View File

@ -234,6 +234,9 @@ void PCB_MARKER::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_
aList.emplace_back( mainText, auxText );
}
if( IsExcluded() )
aList.emplace_back( _( "Excluded" ), m_comment );
}