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 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 
101  if( !footprint )
102  {
103  msg = _( "No footprint loaded." );
104  return;
105  }
106 
107  OUTLINE_ERROR_HANDLER errorHandler =
108  [&]( const wxString& aMsg, BOARD_ITEM* aItemA, BOARD_ITEM* aItemB, const wxPoint& aPt )
109  {
110  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MALFORMED_COURTYARD );
111 
112  drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + aMsg );
113  drcItem->SetItems( aItemA, aItemB );
114 
115  PCB_MARKER* marker = new PCB_MARKER( drcItem, aPt );
116  board->Add( marker );
117  m_frame->GetCanvas()->GetView()->Add( marker );
118  };
119 
120  footprint->BuildPolyCourtyards( &errorHandler );
121 
122 
123  const std::function<void( const wxString& msg )> typeWarning =
124  [&]( const wxString& aMsg )
125  {
126  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_FOOTPRINT_TYPE_MISMATCH );
127 
128  drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + aMsg );
129  drcItem->SetItems( footprint );
130 
131  PCB_MARKER* marker = new PCB_MARKER( drcItem, wxPoint( 0, 0 ) );
132  board->Add( marker );
133  m_frame->GetCanvas()->GetView()->Add( marker );
134  };
135 
136  const std::function<void( const wxString& msg, const wxPoint& position )> tstHoleInTHPad =
137  [&]( const wxString& aMsg, const wxPoint& aPosition )
138  {
139  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_PAD_TH_WITH_NO_HOLE );
140 
141  drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + aMsg );
142  drcItem->SetItems( footprint );
143 
144  PCB_MARKER* marker = new PCB_MARKER( drcItem, aPosition );
145  board->Add( marker );
146  m_frame->GetCanvas()->GetView()->Add( marker );
147  };
148 
149  footprint->CheckFootprintAttributes( &typeWarning );
150  footprint->CheckFootprintTHPadNoHoles( &tstHoleInTHPad );
151  m_checksRun = true;
152 
154 
155  refreshEditor();
156 }
157 
158 
160 {
161  m_markersTreeModel->SetProvider( aProvider );
163 }
164 
165 
166 void DIALOG_FOOTPRINT_CHECKER::OnRunChecksClick( wxCommandEvent& aEvent )
167 {
168  m_checksRun = false;
169 
170  runChecks();
171 }
172 
173 
174 void DIALOG_FOOTPRINT_CHECKER::OnSelectItem( wxDataViewEvent& aEvent )
175 {
176  BOARD* board = m_frame->GetBoard();
177  RC_TREE_NODE* node = RC_TREE_MODEL::ToNode( aEvent.GetItem() );
178  const KIID& itemID = node ? RC_TREE_MODEL::ToUUID( aEvent.GetItem() ) : niluuid;
179  BOARD_ITEM* item = board->GetItem( itemID );
180 
181  if( node && item )
182  {
183  PCB_LAYER_ID principalLayer = item->GetLayer();
184  LSET violationLayers;
185  std::shared_ptr<RC_ITEM> rc_item = node->m_RcItem;
186 
187  if( rc_item->GetErrorCode() == DRCE_MALFORMED_COURTYARD )
188  {
189  BOARD_ITEM* a = board->GetItem( rc_item->GetMainItemID() );
190 
191  if( a && ( a->GetFlags() & MALFORMED_B_COURTYARD ) > 0
192  && ( a->GetFlags() & MALFORMED_F_COURTYARD ) == 0 )
193  {
194  principalLayer = B_CrtYd;
195  }
196  else
197  {
198  principalLayer = F_CrtYd;
199  }
200  }
201  else if (rc_item->GetErrorCode() == DRCE_INVALID_OUTLINE )
202  {
203  principalLayer = Edge_Cuts;
204  }
205  else
206  {
207  BOARD_ITEM* a = board->GetItem( rc_item->GetMainItemID() );
208  BOARD_ITEM* b = board->GetItem( rc_item->GetAuxItemID() );
209  BOARD_ITEM* c = board->GetItem( rc_item->GetAuxItem2ID() );
210  BOARD_ITEM* d = board->GetItem( rc_item->GetAuxItem3ID() );
211 
212  if( a || b || c || d )
213  violationLayers = LSET::AllLayersMask();
214 
215  if( a )
216  violationLayers &= a->GetLayerSet();
217 
218  if( b )
219  violationLayers &= b->GetLayerSet();
220 
221  if( c )
222  violationLayers &= c->GetLayerSet();
223 
224  if( d )
225  violationLayers &= d->GetLayerSet();
226  }
227 
228  if( violationLayers.count() )
229  principalLayer = violationLayers.Seq().front();
230  else
231  violationLayers.set( principalLayer );
232 
233  WINDOW_THAWER thawer( m_frame );
234 
235  m_frame->FocusOnItem( item );
236  m_frame->GetCanvas()->Refresh();
237 
238  if( ( violationLayers & board->GetVisibleLayers() ) == 0 )
239  {
240  m_frame->GetAppearancePanel()->SetLayerVisible( principalLayer, true );
241  m_frame->GetCanvas()->Refresh();
242  }
243 
244  if( board->GetVisibleLayers().test( principalLayer ) )
245  m_frame->SetActiveLayer( principalLayer );
246  }
247 
248  aEvent.Skip();
249 }
250 
251 
253 {
254  if( m_markersDataView->GetCurrentItem().IsOk() )
255  {
256  // turn control over to m_frame, hide this DIALOG_FOOTPRINT_CHECKER window,
257  // no destruction so we can preserve listbox cursor
258  if( !IsModal() )
259  Show( false );
260  }
261 
262  // Do not skip aVent here: this is not useful, and Pcbnew crashes
263  // if skipped (at least on Windows)
264 }
265 
266 
267 void DIALOG_FOOTPRINT_CHECKER::OnSeverity( wxCommandEvent& aEvent )
268 {
269  int flag = 0;
270 
271  if( aEvent.GetEventObject() == m_showAll )
273  else if( aEvent.GetEventObject() == m_showErrors )
275  else if( aEvent.GetEventObject() == m_showWarnings )
277  else if( aEvent.GetEventObject() == m_showExclusions )
279 
280  if( aEvent.IsChecked() )
281  m_severities |= flag;
282  else if( aEvent.GetEventObject() == m_showAll )
284  else
285  m_severities &= ~flag;
286 
287  syncCheckboxes();
288 
289  // Set the provider's severity levels through the TreeModel so that the old tree
290  // can be torn down before the severity changes.
291  //
292  // It's not clear this is required, but we've had a lot of issues with wxDataView
293  // being cranky on various platforms.
294 
296 
298 }
299 
300 
301 void DIALOG_FOOTPRINT_CHECKER::OnCancelClick( wxCommandEvent& aEvent )
302 {
303  m_frame->FocusOnItem( nullptr );
304 
305  SetReturnCode( wxID_CANCEL );
306 
307  // Leave the tool to destroy (or not) the dialog
309  tool->DestroyCheckerDialog();
310 }
311 
312 
313 void DIALOG_FOOTPRINT_CHECKER::OnClose( wxCloseEvent& aEvent )
314 {
315  wxCommandEvent dummy;
316  OnCancelClick( dummy );
317 }
318 
319 
321 {
322  WINDOW_THAWER thawer( m_frame );
323 
324  m_frame->GetCanvas()->Refresh();
325 }
326 
327 
328 void DIALOG_FOOTPRINT_CHECKER::OnDeleteOneClick( wxCommandEvent& aEvent )
329 {
330  // Clear the selection. It may be the selected DRC marker.
332 
334 
335  // redraw the pcb
336  refreshEditor();
337 
339 }
340 
341 
342 void DIALOG_FOOTPRINT_CHECKER::OnDeleteAllClick( wxCommandEvent& event )
343 {
345 
346  m_checksRun = false;
347  refreshEditor();
349 }
350 
351 
353 {
354  // Clear current selection list to avoid selection of deleted items
356 
357  m_markersTreeModel->DeleteItems( false, true, true );
358 }
359 
360 
362 {
363  // Collect counts:
364 
365  int numErrors = 0;
366  int numWarnings = 0;
367  int numExcluded = 0;
368 
369  if( m_markersProvider )
370  {
374  }
375 
376  // Update badges:
377 
378  if( !m_checksRun && numErrors == 0 )
379  numErrors = -1;
380 
381  if( !m_checksRun && numWarnings == 0 )
382  numWarnings = -1;
383 
384  m_errorsBadge->SetMaximumNumber( numErrors );
386 
387  m_warningsBadge->SetMaximumNumber( numWarnings );
389 
390  m_exclusionsBadge->SetMaximumNumber( numExcluded );
392 }
393 
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:2022
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:459
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:292
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:2077
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:2108
void OnClose(wxCloseEvent &event) override
void DeleteCurrentItem(bool aDeep)
Definition: rc_item.cpp:453
RC_ITEMS_PROVIDER * m_markersProvider
void SetSeverities(int aSeverities)
Definition: rc_item.cpp:298
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:504
std::shared_ptr< RC_ITEM > m_RcItem
Definition: rc_item.h:195
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
Definition: board.h:317
static RC_TREE_NODE * ToNode(wxDataViewItem aItem)
Definition: rc_item.h:210
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:787
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:155
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:190
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:140
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:145