KiCad PCB EDA Suite
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 (C) 2020-2022 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 <pcb_marker.h>
31 #include <footprint_edit_frame.h>
34 
35 
38  m_frame( aParent ),
39  m_checksRun( false ),
40  m_markersProvider( nullptr ),
42 {
44  m_markersDataView->AssociateModel( m_markersTreeModel );
45 
47 
48  // We use a sdbSizer to get platform-dependent ordering of the action buttons, but
49  // that requires us to correct the button labels here.
50  m_sdbSizerOK->SetLabel( _( "Run Checks" ) );
51  m_sdbSizerCancel->SetLabel( _( "Close" ) );
52 
53  m_sdbSizerOK->SetDefault();
54  m_sdbSizer->Layout();
55 
57 
59 }
60 
61 
63 {
64  m_markersTreeModel->DecRef();
65 }
66 
67 
69 {
70  return true;
71 }
72 
73 
75 {
76  return true;
77 }
78 
79 
80 // Don't globally define this; different facilities use different definitions of "ALL"
82 
83 
85 {
86  m_showAll->SetValue( m_severities == RPT_SEVERITY_ALL );
90 }
91 
92 
94 {
95  BOARD* board = m_frame->GetBoard();
96  FOOTPRINT* footprint = board->GetFirstFootprint();
97  wxString msg;
98 
100 
102 
103  if( !footprint )
104  {
105  msg = _( "No footprint loaded." );
106  return;
107  }
108 
109  OUTLINE_ERROR_HANDLER errorHandler =
110  [&]( const wxString& aMsg, BOARD_ITEM* aItemA, BOARD_ITEM* aItemB, const wxPoint& aPt )
111  {
112  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MALFORMED_COURTYARD );
113 
114  drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + aMsg );
115  drcItem->SetItems( aItemA, aItemB );
116 
117  PCB_MARKER* marker = new PCB_MARKER( drcItem, aPt );
118  board->Add( marker );
119  m_frame->GetCanvas()->GetView()->Add( marker );
120  };
121 
122  footprint->BuildPolyCourtyards( &errorHandler );
123 
124 
125  const std::function<void( const wxString& msg )> typeWarning =
126  [&]( const wxString& aMsg )
127  {
128  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_FOOTPRINT_TYPE_MISMATCH );
129 
130  drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + aMsg );
131  drcItem->SetItems( footprint );
132 
133  PCB_MARKER* marker = new PCB_MARKER( drcItem, wxPoint( 0, 0 ) );
134  board->Add( marker );
135  m_frame->GetCanvas()->GetView()->Add( marker );
136  };
137 
138  const std::function<void( const wxString& msg, const wxPoint& position )> tstHoleInTHPad =
139  [&]( const wxString& aMsg, const wxPoint& aPosition )
140  {
141  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_PAD_TH_WITH_NO_HOLE );
142 
143  drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + aMsg );
144  drcItem->SetItems( footprint );
145 
146  PCB_MARKER* marker = new PCB_MARKER( drcItem, aPosition );
147  board->Add( marker );
148  m_frame->GetCanvas()->GetView()->Add( marker );
149  };
150 
151  footprint->CheckFootprintAttributes( &typeWarning );
152  footprint->CheckFootprintTHPadNoHoles( &tstHoleInTHPad );
153  m_checksRun = true;
154 
156 
157  refreshEditor();
158 }
159 
160 
162 {
163  m_markersProvider = aProvider;
164  m_markersTreeModel->SetProvider( aProvider );
166 }
167 
168 
169 void DIALOG_FOOTPRINT_CHECKER::OnRunChecksClick( wxCommandEvent& aEvent )
170 {
171  m_checksRun = false;
172 
173  runChecks();
174 }
175 
176 
177 void DIALOG_FOOTPRINT_CHECKER::OnSelectItem( wxDataViewEvent& aEvent )
178 {
179  BOARD* board = m_frame->GetBoard();
180  RC_TREE_NODE* node = RC_TREE_MODEL::ToNode( aEvent.GetItem() );
181  const KIID& itemID = node ? RC_TREE_MODEL::ToUUID( aEvent.GetItem() ) : niluuid;
182  BOARD_ITEM* item = board->GetItem( itemID );
183 
184  if( node && item )
185  {
186  PCB_LAYER_ID principalLayer = item->GetLayer();
187  LSET violationLayers;
188  std::shared_ptr<RC_ITEM> rc_item = node->m_RcItem;
189 
190  if( rc_item->GetErrorCode() == DRCE_MALFORMED_COURTYARD )
191  {
192  BOARD_ITEM* a = board->GetItem( rc_item->GetMainItemID() );
193 
194  if( a && ( a->GetFlags() & MALFORMED_B_COURTYARD ) > 0
195  && ( a->GetFlags() & MALFORMED_F_COURTYARD ) == 0 )
196  {
197  principalLayer = B_CrtYd;
198  }
199  else
200  {
201  principalLayer = F_CrtYd;
202  }
203  }
204  else if (rc_item->GetErrorCode() == DRCE_INVALID_OUTLINE )
205  {
206  principalLayer = Edge_Cuts;
207  }
208  else
209  {
210  BOARD_ITEM* a = board->GetItem( rc_item->GetMainItemID() );
211  BOARD_ITEM* b = board->GetItem( rc_item->GetAuxItemID() );
212  BOARD_ITEM* c = board->GetItem( rc_item->GetAuxItem2ID() );
213  BOARD_ITEM* d = board->GetItem( rc_item->GetAuxItem3ID() );
214 
215  if( a || b || c || d )
216  violationLayers = LSET::AllLayersMask();
217 
218  if( a )
219  violationLayers &= a->GetLayerSet();
220 
221  if( b )
222  violationLayers &= b->GetLayerSet();
223 
224  if( c )
225  violationLayers &= c->GetLayerSet();
226 
227  if( d )
228  violationLayers &= d->GetLayerSet();
229  }
230 
231  if( violationLayers.count() )
232  principalLayer = violationLayers.Seq().front();
233  else
234  violationLayers.set( principalLayer );
235 
236  WINDOW_THAWER thawer( m_frame );
237 
238  m_frame->FocusOnItem( item );
239  m_frame->GetCanvas()->Refresh();
240 
241  if( ( violationLayers & board->GetVisibleLayers() ) == 0 )
242  {
243  m_frame->GetAppearancePanel()->SetLayerVisible( principalLayer, true );
244  m_frame->GetCanvas()->Refresh();
245  }
246 
247  if( board->GetVisibleLayers().test( principalLayer ) )
248  m_frame->SetActiveLayer( principalLayer );
249  }
250 
251  aEvent.Skip();
252 }
253 
254 
256 {
257  if( m_markersDataView->GetCurrentItem().IsOk() )
258  {
259  // turn control over to m_frame, hide this DIALOG_FOOTPRINT_CHECKER window,
260  // no destruction so we can preserve listbox cursor
261  if( !IsModal() )
262  Show( false );
263  }
264 
265  // Do not skip aVent here: this is not useful, and Pcbnew crashes
266  // if skipped (at least on Windows)
267 }
268 
269 
270 void DIALOG_FOOTPRINT_CHECKER::OnSeverity( wxCommandEvent& aEvent )
271 {
272  int flag = 0;
273 
274  if( aEvent.GetEventObject() == m_showAll )
276  else if( aEvent.GetEventObject() == m_showErrors )
278  else if( aEvent.GetEventObject() == m_showWarnings )
280  else if( aEvent.GetEventObject() == m_showExclusions )
282 
283  if( aEvent.IsChecked() )
284  m_severities |= flag;
285  else if( aEvent.GetEventObject() == m_showAll )
287  else
288  m_severities &= ~flag;
289 
290  syncCheckboxes();
291 
292  // Set the provider's severity levels through the TreeModel so that the old tree
293  // can be torn down before the severity changes.
294  //
295  // It's not clear this is required, but we've had a lot of issues with wxDataView
296  // being cranky on various platforms.
297 
299 
301 }
302 
303 
304 void DIALOG_FOOTPRINT_CHECKER::OnCancelClick( wxCommandEvent& aEvent )
305 {
306  m_frame->FocusOnItem( nullptr );
307 
308  SetReturnCode( wxID_CANCEL );
309 
310  // Leave the tool to destroy (or not) the dialog
312  tool->DestroyCheckerDialog();
313 }
314 
315 
316 void DIALOG_FOOTPRINT_CHECKER::OnClose( wxCloseEvent& aEvent )
317 {
318  wxCommandEvent dummy;
319  OnCancelClick( dummy );
320 }
321 
322 
324 {
325  WINDOW_THAWER thawer( m_frame );
326 
327  m_frame->GetCanvas()->Refresh();
328 }
329 
330 
331 void DIALOG_FOOTPRINT_CHECKER::OnDeleteOneClick( wxCommandEvent& aEvent )
332 {
333  // Clear the selection. It may be the selected DRC marker.
335 
337 
338  // redraw the pcb
339  refreshEditor();
340 
342 }
343 
344 
345 void DIALOG_FOOTPRINT_CHECKER::OnDeleteAllClick( wxCommandEvent& event )
346 {
348 
349  m_checksRun = false;
350  refreshEditor();
352 }
353 
354 
356 {
357  // Clear current selection list to avoid selection of deleted items
359 
360  m_markersTreeModel->DeleteItems( false, true, true );
361 }
362 
363 
365 {
366  // Collect counts:
367 
368  int numErrors = 0;
369  int numWarnings = 0;
370  int numExcluded = 0;
371 
372  if( m_markersProvider )
373  {
377  }
378 
379  // Update badges:
380 
381  if( !m_checksRun && numErrors == 0 )
382  numErrors = -1;
383 
384  if( !m_checksRun && numWarnings == 0 )
385  numWarnings = -1;
386 
387  m_errorsBadge->SetMaximumNumber( numErrors );
389 
390  m_warningsBadge->SetMaximumNumber( numWarnings );
392 
393  m_exclusionsBadge->SetMaximumNumber( numExcluded );
395 }
396 
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:59
void BuildPolyCourtyards(OUTLINE_ERROR_HANDLER *aErrorHandler=nullptr)
Build complex polygons of the courtyard areas from graphic items on the courtyard layers.
Definition: footprint.cpp:2040
BOARD_ITEM * GetItem(const KIID &aID) const
Definition: board.cpp:845
void DeleteItems(bool aCurrentOnly, bool aIncludeExclusions, bool aDeep)
Deletes the current item or all items.
Definition: rc_item.cpp:467
Module editor specific tools.
KIID niluuid(0)
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
Definition: drc_item.cpp:266
void OnDeleteAllClick(wxCommandEvent &event) override
#define MALFORMED_B_COURTYARD
void SetProvider(RC_ITEMS_PROVIDER *aProvider)
Definition: rc_item.cpp:294
void SetActiveLayer(PCB_LAYER_ID aLayer) override
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:49
static int RPT_SEVERITY_ALL
void OnDeleteOneClick(wxCommandEvent &event) override
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
#define MALFORMED_F_COURTYARD
void CheckFootprintAttributes(const std::function< void(const wxString &msg)> *aErrorHandler)
Test if footprint attributes for type (SMD/Through hole/Other) match the expected type based on the p...
Definition: footprint.cpp:2095
void UpdateNumber(int aNumber, SEVERITY aSeverity)
Update the number displayed on the badge.
LSET GetVisibleLayers() const
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:481
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:143
static KIID ToUUID(wxDataViewItem aItem)
Definition: rc_item.cpp:147
FOOTPRINT_EDIT_FRAME * m_frame
virtual int GetCount(int aSeverity=-1) const =0
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:411
APPEARANCE_CONTROLS * GetAppearancePanel()
void CheckFootprintTHPadNoHoles(const std::function< void(const wxString &msg, const wxPoint &position)> *aErrorHandler)
Test if footprint attributes for type (SMD/Through hole/Other) match the expected type based on the p...
Definition: footprint.cpp:2126
void OnClose(wxCloseEvent &event) override
void DeleteCurrentItem(bool aDeep)
Definition: rc_item.cpp:461
RC_ITEMS_PROVIDER * m_markersProvider
void SetSeverities(int aSeverities)
Definition: rc_item.cpp:300
Provide an abstract interface of a RC_ITEM* list manager.
Definition: rc_item.h:45
static LIB_SYMBOL * dummy()
Used to draw a dummy shape when a LIB_SYMBOL is not found in library.
Definition: sch_symbol.cpp:72
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT) override
Adds an item to the container.
Definition: board.cpp:608
Definition: kiid.h:44
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:516
std::shared_ptr< RC_ITEM > m_RcItem
Definition: rc_item.h:197
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
Definition: board.h:318
static RC_TREE_NODE * ToNode(wxDataViewItem aItem)
Definition: rc_item.h:212
BOARD_DRC_ITEMS_PROVIDER is an implementation of the RC_ITEMS_PROVIDER interface which uses a BOARD i...
void OnRunChecksClick(wxCommandEvent &aEvent) override
#define _(s)
static LSET AllLayersMask()
Definition: lset.cpp:796
virtual KIGFX::PCB_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
bool Show(bool show) override
void FocusOnItem(BOARD_ITEM *aItem, PCB_LAYER_ID aLayer=UNDEFINED_LAYER)
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:154
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
Class DIALOG_FOOTPRINT_CHECKER_BASE.
void OnSelectItem(wxDataViewEvent &event) override
void SetMarkersProvider(RC_ITEMS_PROVIDER *aProvider)
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:191
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:65
void OnCancelClick(wxCommandEvent &aEvent) override
DIALOG_FOOTPRINT_CHECKER(FOOTPRINT_EDIT_FRAME *aParent)
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
Update the board display after modifying it by a python script (note: it is automatically called by a...
void OnSeverity(wxCommandEvent &aEvent) override
const std::function< void(const wxString &msg, BOARD_ITEM *itemA, BOARD_ITEM *itemB, const wxPoint &pt)> OUTLINE_ERROR_HANDLER
void SetLayerVisible(LAYER_NUM aLayer, bool isVisible)
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1) override
Add a VIEW_ITEM to the view.
Definition: pcb_view.cpp:58
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:54
BOARD * GetBoard() const
void OnLeftDClickItem(wxMouseEvent &event) override
void SetMaximumNumber(int aMax)
Set the maximum number to be shown on the badge.
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:143
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:148