KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_footprint_checker.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
26#include <tool/tool_manager.h>
27#include <tools/pcb_actions.h>
28#include <footprint.h>
29#include <pad.h>
30#include <pcb_marker.h>
31#include <drc/drc_item.h>
35
36
37static FOOTPRINT* g_lastFootprint = nullptr;
38static bool g_lastChecksRun = false;
39
40
43 m_frame( aParent ),
44 m_checksRun( false ),
45 m_centerMarkerOnIdle( nullptr )
46{
47 m_markersProvider = std::make_shared<DRC_ITEMS_PROVIDER>( m_frame->GetBoard(), MARKER_BASE::MARKER_DRC );
48
50 m_markersDataView->AssociateModel( m_markersTreeModel );
51
54
55 SetupStandardButtons( { { wxID_OK, _( "Run Checks" ) },
56 { wxID_CANCEL, _( "Close" ) } } );
57
59}
60
61
63{
65
68
69 m_markersTreeModel->DecRef();
70}
71
72
74{
77}
78
79
81{
82 updateData();
83 return true;
84}
85
86
88{
89 BOARD* board = m_frame->GetBoard();
90 FOOTPRINT* footprint = board->GetFirstFootprint();
91 wxString msg;
92
94
95 if( !footprint )
96 {
97 msg = _( "No footprint loaded." );
98 return;
99 }
100
101 auto errorHandler =
102 [&]( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB, const BOARD_ITEM* aItemC,
103 int aErrorCode, const wxString& aMsg, const VECTOR2I& aPt )
104 {
105 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( aErrorCode );
106
107 if( !aMsg.IsEmpty() )
108 drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + aMsg );
109
110 drcItem->SetItems( aItemA, aItemB, aItemC );
111
112 PCB_MARKER* marker = new PCB_MARKER( drcItem, aPt );
113 board->Add( marker );
114 m_frame->GetCanvas()->GetView()->Add( marker );
115 };
116
117 OUTLINE_ERROR_HANDLER outlineErrorHandler =
118 [&]( const wxString& aMsg, BOARD_ITEM* aItemA, BOARD_ITEM* aItemB, const VECTOR2I& aPt )
119 {
120 if( !aItemA ) // If we only have a single item, make sure it's A
121 std::swap( aItemA, aItemB );
122
123 errorHandler( aItemA, aItemB, nullptr, DRCE_MALFORMED_COURTYARD, aMsg, aPt );
124 };
125
126 footprint->BuildCourtyardCaches( &outlineErrorHandler );
127
128 if( !footprint->AllowMissingCourtyard()
129 && footprint->GetCourtyard( F_CrtYd ).OutlineCount() == 0
130 && footprint->GetCourtyard( B_CrtYd ).OutlineCount() == 0 )
131 {
132 errorHandler( footprint, nullptr, nullptr, DRCE_MISSING_COURTYARD, wxEmptyString, { 0, 0 } );
133 }
134
135 footprint->CheckFootprintAttributes(
136 [&]( const wxString& aMsg )
137 {
138 errorHandler( footprint, nullptr, nullptr, DRCE_FOOTPRINT_TYPE_MISMATCH, aMsg, { 0, 0 } );
139 } );
140
141 footprint->CheckPads( m_frame,
142 [&]( const PAD* aPad, int aErrorCode, const wxString& aMsg )
143 {
144 errorHandler( aPad, nullptr, nullptr, aErrorCode, aMsg, aPad->GetPosition() );
145 } );
146
147 footprint->CheckShortingPads(
148 [&]( const PAD* aPadA, const PAD* aPadB, int aErrorCode, const VECTOR2I& aPosition )
149 {
150 errorHandler( aPadA, aPadB, nullptr, aErrorCode, wxEmptyString, aPosition );
151 } );
152
153 if( footprint->IsNetTie() )
154 {
155 footprint->CheckNetTiePadGroups(
156 [&]( const wxString& aMsg )
157 {
158 errorHandler( footprint, nullptr, nullptr, DRCE_FOOTPRINT, aMsg, { 0, 0 } );
159 } );
160
161 footprint->CheckNetTies(
162 [&]( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB, const BOARD_ITEM* aItemC,
163 const VECTOR2I& aPt )
164 {
165 errorHandler( aItemA, aItemB, aItemC, DRCE_SHORTING_ITEMS, wxEmptyString, aPt );
166 } );
167 }
168
169 footprint->CheckClippedSilk(
170 [&]( BOARD_ITEM* aItemA, BOARD_ITEM* aItemB, const VECTOR2I& aPt )
171 {
172 errorHandler( aItemA, aItemB, nullptr, DRCE_SILK_MASK_CLEARANCE, wxEmptyString, aPt );
173 } );
174
175 m_checksRun = true;
176 updateData();
178}
179
180
182{
184
185 // wxWidgets on some platforms fails to correctly ensure that a selected item is
186 // visible, so we have to do it in a separate idle event.
187 m_centerMarkerOnIdle = aMarker;
188 Bind( wxEVT_IDLE, &DIALOG_FOOTPRINT_CHECKER::centerMarkerIdleHandler, this );
189}
190
191
193{
194 if( m_markersTreeModel->GetView()->IsFrozen() )
195 return;
196
198 m_centerMarkerOnIdle = nullptr;
199 Unbind( wxEVT_IDLE, &DIALOG_FOOTPRINT_CHECKER::centerMarkerIdleHandler, this );
200}
201
202
203void DIALOG_FOOTPRINT_CHECKER::OnRunChecksClick( wxCommandEvent& aEvent )
204{
205 m_checksRun = false;
206 runChecks();
207}
208
209
210void DIALOG_FOOTPRINT_CHECKER::OnSelectItem( wxDataViewEvent& aEvent )
211{
212 BOARD* board = m_frame->GetBoard();
213 RC_TREE_NODE* node = RC_TREE_MODEL::ToNode( aEvent.GetItem() );
214 const KIID& itemID = node ? RC_TREE_MODEL::ToUUID( aEvent.GetItem() ) : niluuid;
215 BOARD_ITEM* item = board->ResolveItem( itemID, true );
216
218 {
219 // we already came from a cross-probe of the marker in the document; don't go around in circles
220 aEvent.Skip();
221 return;
222 }
223
224 if( node && item )
225 {
226 PCB_LAYER_ID principalLayer = UNDEFINED_LAYER;
227 LSET violationLayers;
228 std::shared_ptr<RC_ITEM> rc_item = node->m_RcItem;
229
230 if( item->GetLayerSet().count() > 0 )
231 principalLayer = item->GetLayerSet().Seq().front();
232
233 if( rc_item->GetErrorCode() == DRCE_MALFORMED_COURTYARD )
234 {
235 BOARD_ITEM* a = board->ResolveItem( rc_item->GetMainItemID(), true );
236
237 if( a && ( a->GetFlags() & MALFORMED_B_COURTYARD ) > 0
238 && ( a->GetFlags() & MALFORMED_F_COURTYARD ) == 0 )
239 {
240 principalLayer = B_CrtYd;
241 }
242 else
243 {
244 principalLayer = F_CrtYd;
245 }
246 }
247 else if (rc_item->GetErrorCode() == DRCE_INVALID_OUTLINE )
248 {
249 principalLayer = Edge_Cuts;
250 }
251 else
252 {
253 BOARD_ITEM* a = board->ResolveItem( rc_item->GetMainItemID(), true );
254 BOARD_ITEM* b = board->ResolveItem( rc_item->GetAuxItemID(), true );
255 BOARD_ITEM* c = board->ResolveItem( rc_item->GetAuxItem2ID(), true );
256 BOARD_ITEM* d = board->ResolveItem( rc_item->GetAuxItem3ID(), true );
257
258 if( a || b || c || d )
259 violationLayers = LSET::AllLayersMask();
260
261 if( a )
262 violationLayers &= a->GetLayerSet();
263
264 if( b )
265 violationLayers &= b->GetLayerSet();
266
267 if( c )
268 violationLayers &= c->GetLayerSet();
269
270 if( d )
271 violationLayers &= d->GetLayerSet();
272 }
273
274 if( violationLayers.count() )
275 principalLayer = violationLayers.Seq().front();
276 else if( principalLayer >= 0 )
277 violationLayers.set( principalLayer );
278
279 WINDOW_THAWER thawer( m_frame );
280
281 m_frame->FocusOnItem( item );
283
284 if( ( violationLayers & board->GetVisibleLayers() ).none() )
285 {
286 m_frame->GetAppearancePanel()->SetLayerVisible( principalLayer, true );
288 }
289
290 if( board->GetVisibleLayers().test( principalLayer ) )
291 m_frame->SetActiveLayer( principalLayer );
292 }
293
294 aEvent.Skip();
295}
296
297
299{
300 if( m_markersDataView->GetCurrentItem().IsOk() )
301 {
302 // turn control over to m_frame, hide this DIALOG_FOOTPRINT_CHECKER window,
303 // no destruction so we can preserve listbox cursor
304 if( !IsModal() )
305 Show( false );
306 }
307
308 // Do not skip event here: this is not useful, and Pcbnew crashes if skipped (at least on MSW)
309}
310
311
313{
314 int severities = 0;
315
316 if( m_showErrors->GetValue() )
317 severities |= RPT_SEVERITY_ERROR;
318
319 if( m_showWarnings->GetValue() )
320 severities |= RPT_SEVERITY_WARNING;
321
322 if( m_showExclusions->GetValue() )
323 severities |= RPT_SEVERITY_EXCLUSION;
324
325 return severities;
326}
327
328
329void DIALOG_FOOTPRINT_CHECKER::OnSeverity( wxCommandEvent& aEvent )
330{
331 if( aEvent.GetEventObject() == m_showAll )
332 {
333 m_showErrors->SetValue( true );
334 m_showWarnings->SetValue( aEvent.IsChecked() );
335 m_showExclusions->SetValue( aEvent.IsChecked() );
336 }
337
338 updateData();
339}
340
341
342void DIALOG_FOOTPRINT_CHECKER::OnCancelClick( wxCommandEvent& aEvent )
343{
345
346 SetReturnCode( wxID_CANCEL );
347
348 // Leave the tool to destroy (or not) the dialog
350 tool->DestroyCheckerDialog();
351}
352
353
354void DIALOG_FOOTPRINT_CHECKER::OnClose( wxCloseEvent& aEvent )
355{
356 wxCommandEvent dummy;
358}
359
360
362{
363 WINDOW_THAWER thawer( m_frame );
364
366}
367
368
369void DIALOG_FOOTPRINT_CHECKER::OnDeleteOneClick( wxCommandEvent& aEvent )
370{
371 // Clear the selection. It may be the selected DRC marker.
373
375
376 // redraw the pcb
378
380}
381
382
384{
386
387 m_checksRun = false;
390}
391
392
394{
395 // Clear current selection list to avoid selection of deleted items
397
398 m_markersTreeModel->DeleteItems( false, true, false );
399 m_frame->GetBoard()->DeleteMARKERs( true, true );
400}
401
402
404{
405 // Collect counts:
406
407 int numErrors = 0;
408 int numWarnings = 0;
409 int numExcluded = 0;
410
412 {
413 numErrors += m_markersProvider->GetCount( RPT_SEVERITY_ERROR );
414 numWarnings += m_markersProvider->GetCount( RPT_SEVERITY_WARNING );
415 numExcluded += m_markersProvider->GetCount( RPT_SEVERITY_EXCLUSION );
416 }
417
418 // Update badges:
419
420 if( !m_checksRun && numErrors == 0 )
421 numErrors = -1;
422
423 if( !m_checksRun && numWarnings == 0 )
424 numWarnings = -1;
425
426 m_errorsBadge->SetMaximumNumber( numErrors );
428
429 m_warningsBadge->SetMaximumNumber( numWarnings );
431
432 m_exclusionsBadge->SetMaximumNumber( numExcluded );
434}
435
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: actions.h:221
void SetLayerVisible(int aLayer, bool isVisible)
BASE_SET & set(size_t pos)
Definition: base_set.h:116
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:79
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:252
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:317
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition: board.cpp:1147
const LSET & GetVisibleLayers() const
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:921
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
Definition: board.h:489
void DeleteMARKERs()
Delete all MARKERS from the board.
Definition: board.cpp:1530
BOARD_ITEM * ResolveItem(const KIID &aID, bool aAllowNullptrReturn=false) const
Definition: board.cpp:1583
Class DIALOG_FOOTPRINT_CHECKER_BASE.
void centerMarkerIdleHandler(wxIdleEvent &aEvent)
void OnCancelClick(wxCommandEvent &aEvent) override
void OnDeleteAllClick(wxCommandEvent &event) override
void OnClose(wxCloseEvent &event) override
FOOTPRINT_EDIT_FRAME * m_frame
std::shared_ptr< RC_ITEMS_PROVIDER > m_markersProvider
void OnSeverity(wxCommandEvent &aEvent) override
DIALOG_FOOTPRINT_CHECKER(FOOTPRINT_EDIT_FRAME *aParent)
void OnRunChecksClick(wxCommandEvent &aEvent) override
void OnSelectItem(wxDataViewEvent &event) override
void SelectMarker(const PCB_MARKER *aMarker)
void OnDeleteOneClick(wxCommandEvent &event) override
void OnLeftDClickItem(wxMouseEvent &event) override
const PCB_MARKER * m_centerMarkerOnIdle
bool Show(bool show) override
void SetupStandardButtons(std::map< int, wxString > aLabels={})
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
Definition: drc_item.cpp:393
virtual void ClearFocus()
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:145
Module editor specific tools.
void SetActiveLayer(PCB_LAYER_ID aLayer) override
void CheckClippedSilk(const std::function< void(BOARD_ITEM *aItemA, BOARD_ITEM *aItemB, const VECTOR2I &aPt)> &aErrorHandler)
Definition: footprint.cpp:3573
void CheckNetTies(const std::function< void(const BOARD_ITEM *aItem, const BOARD_ITEM *bItem, const BOARD_ITEM *cItem, const VECTOR2I &)> &aErrorHandler)
Check for un-allowed shorting of pads in net-tie footprints.
Definition: footprint.cpp:3439
void CheckPads(UNITS_PROVIDER *aUnitsProvider, const std::function< void(const PAD *, int, const wxString &)> &aErrorHandler)
Run non-board-specific DRC checks on footprint's pads.
Definition: footprint.cpp:3352
bool AllowMissingCourtyard() const
Definition: footprint.h:296
void BuildCourtyardCaches(OUTLINE_ERROR_HANDLER *aErrorHandler=nullptr)
Build complex polygons of the courtyard areas from graphic items on the courtyard layers.
Definition: footprint.cpp:3081
bool IsNetTie() const
Definition: footprint.h:306
void CheckShortingPads(const std::function< void(const PAD *, const PAD *, int aErrorCode, const VECTOR2I &)> &aErrorHandler)
Check for overlapping, different-numbered, non-net-tie pads.
Definition: footprint.cpp:3370
void CheckNetTiePadGroups(const std::function< void(const wxString &)> &aErrorHandler)
Sanity check net-tie pad groups.
Definition: footprint.cpp:3550
const SHAPE_POLY_SET & GetCourtyard(PCB_LAYER_ID aLayer) const
Used in DRC to test the courtyard area (a complex polygon).
Definition: footprint.cpp:3058
void CheckFootprintAttributes(const std::function< void(const wxString &)> &aErrorHandler)
Test if footprint attributes for type (SMD/Through hole/Other) match the expected type based on the p...
Definition: footprint.cpp:3327
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1) override
Add a VIEW_ITEM to the view.
Definition: pcb_view.cpp:57
Definition: kiid.h:49
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:37
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:296
static const LSET & AllLayersMask()
Definition: lset.cpp:624
void SetMaximumNumber(int aMax)
Set the maximum number to be shown on the badge.
void UpdateNumber(int aNumber, SEVERITY aSeverity)
Update the number displayed on the badge.
Definition: pad.h:54
VECTOR2I GetPosition() const override
Definition: pad.h:208
APPEARANCE_CONTROLS * GetAppearancePanel()
void FocusOnItem(EDA_ITEM *aItem) override
Focus on a particular canvas item.
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
BOARD * GetBoard() const
virtual KIGFX::PCB_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
void SelectMarker(const MARKER_BASE *aMarker)
Definition: rc_item.cpp:739
const wxDataViewCtrl * GetView() const
Definition: rc_item.h:248
static RC_TREE_NODE * ToNode(wxDataViewItem aItem)
Definition: rc_item.h:243
void Update(std::shared_ptr< RC_ITEMS_PROVIDER > aProvider, int aSeverities)
Definition: rc_item.cpp:361
void DeleteItems(bool aCurrentOnly, bool aIncludeExclusions, bool aDeep)
Delete the current item or all items.
Definition: rc_item.cpp:573
void DeleteCurrentItem(bool aDeep)
Definition: rc_item.cpp:567
void CenterMarker(const MARKER_BASE *aMarker)
Definition: rc_item.cpp:754
static KIID ToUUID(wxDataViewItem aItem)
Definition: rc_item.cpp:217
std::shared_ptr< RC_ITEM > m_RcItem
Definition: rc_item.h:228
int OutlineCount() const
Return the number of outlines in the set.
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:55
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:150
const std::function< void(const wxString &msg, BOARD_ITEM *itemA, BOARD_ITEM *itemB, const VECTOR2I &pt)> OUTLINE_ERROR_HANDLER
static bool g_lastChecksRun
static FOOTPRINT * g_lastFootprint
@ DRCE_SILK_MASK_CLEARANCE
Definition: drc_item.h:96
@ DRCE_INVALID_OUTLINE
Definition: drc_item.h:72
@ DRCE_MISSING_COURTYARD
Definition: drc_item.h:66
@ DRCE_SHORTING_ITEMS
Definition: drc_item.h:40
@ DRCE_MALFORMED_COURTYARD
Definition: drc_item.h:67
@ DRCE_FOOTPRINT_TYPE_MISMATCH
Definition: drc_item.h:81
@ DRCE_FOOTPRINT
Definition: drc_item.h:85
#define _(s)
#define MALFORMED_F_COURTYARD
#define MALFORMED_B_COURTYARD
KIID niluuid(0)
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ F_CrtYd
Definition: layer_ids.h:116
@ Edge_Cuts
Definition: layer_ids.h:112
@ B_CrtYd
Definition: layer_ids.h:115
@ UNDEFINED_LAYER
Definition: layer_ids.h:61
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_EXCLUSION
std::vector< FAB_LAYER_COLOR > dummy