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 
56 
58 }
59 
60 
62 {
63  m_markersTreeModel->DecRef();
64 }
65 
66 
68 {
69  runChecks();
70 
71  return true;
72 }
73 
74 
76 {
77  return true;
78 }
79 
80 
81 // Don't globally define this; different facilities use different definitions of "ALL"
83 
84 
86 {
87  m_showAll->SetValue( m_severities == RPT_SEVERITY_ALL );
91 }
92 
93 
95 {
96  BOARD* board = m_frame->GetBoard();
97  FOOTPRINT* footprint = board->GetFirstFootprint();
98  wxString msg;
99 
101 
102  if( !footprint )
103  {
104  msg = _( "No footprint loaded." );
105  return;
106  }
107 
108  OUTLINE_ERROR_HANDLER errorHandler =
109  [&]( const wxString& aMsg, BOARD_ITEM* aItemA, BOARD_ITEM* aItemB, const wxPoint& aPt )
110  {
111  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MALFORMED_COURTYARD );
112 
113  drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + aMsg );
114  drcItem->SetItems( aItemA, aItemB );
115 
116  PCB_MARKER* marker = new PCB_MARKER( drcItem, aPt );
117  board->Add( marker );
118  m_frame->GetCanvas()->GetView()->Add( marker );
119  };
120 
121  footprint->BuildPolyCourtyards( &errorHandler );
122 
123  m_checksRun = true;
124 
126 
127  refreshEditor();
128 }
129 
130 
132 {
133  m_markersTreeModel->SetProvider( aProvider );
135 }
136 
137 
138 void DIALOG_FOOTPRINT_CHECKER::OnRunChecksClick( wxCommandEvent& aEvent )
139 {
140  m_checksRun = false;
141 
142  runChecks();
143 }
144 
145 
146 void DIALOG_FOOTPRINT_CHECKER::OnSelectItem( wxDataViewEvent& aEvent )
147 {
148  BOARD* board = m_frame->GetBoard();
149  RC_TREE_NODE* node = RC_TREE_MODEL::ToNode( aEvent.GetItem() );
150  const KIID& itemID = node ? RC_TREE_MODEL::ToUUID( aEvent.GetItem() ) : niluuid;
151  BOARD_ITEM* item = board->GetItem( itemID );
152 
153  if( node && item )
154  {
155  PCB_LAYER_ID principalLayer = item->GetLayer();
156  LSET violationLayers;
157  std::shared_ptr<RC_ITEM> rc_item = node->m_RcItem;
158 
159  if( rc_item->GetErrorCode() == DRCE_MALFORMED_COURTYARD )
160  {
161  BOARD_ITEM* a = board->GetItem( rc_item->GetMainItemID() );
162 
163  if( a && ( a->GetFlags() & MALFORMED_B_COURTYARD ) > 0
164  && ( a->GetFlags() & MALFORMED_F_COURTYARD ) == 0 )
165  {
166  principalLayer = B_CrtYd;
167  }
168  else
169  {
170  principalLayer = F_CrtYd;
171  }
172  }
173  else if (rc_item->GetErrorCode() == DRCE_INVALID_OUTLINE )
174  {
175  principalLayer = Edge_Cuts;
176  }
177  else
178  {
179  BOARD_ITEM* a = board->GetItem( rc_item->GetMainItemID() );
180  BOARD_ITEM* b = board->GetItem( rc_item->GetAuxItemID() );
181  BOARD_ITEM* c = board->GetItem( rc_item->GetAuxItem2ID() );
182  BOARD_ITEM* d = board->GetItem( rc_item->GetAuxItem3ID() );
183 
184  if( a || b || c || d )
185  violationLayers = LSET::AllLayersMask();
186 
187  if( a )
188  violationLayers &= a->GetLayerSet();
189 
190  if( b )
191  violationLayers &= b->GetLayerSet();
192 
193  if( c )
194  violationLayers &= c->GetLayerSet();
195 
196  if( d )
197  violationLayers &= d->GetLayerSet();
198  }
199 
200  if( violationLayers.count() )
201  principalLayer = violationLayers.Seq().front();
202  else
203  violationLayers.set( principalLayer );
204 
205  WINDOW_THAWER thawer( m_frame );
206 
207  m_frame->FocusOnItem( item );
208  m_frame->GetCanvas()->Refresh();
209 
210  if( ( violationLayers & board->GetVisibleLayers() ) == 0 )
211  {
212  m_frame->GetAppearancePanel()->SetLayerVisible( principalLayer, true );
213  m_frame->GetCanvas()->Refresh();
214  }
215 
216  if( board->GetVisibleLayers().test( principalLayer ) )
217  m_frame->SetActiveLayer( principalLayer );
218  }
219 
220  aEvent.Skip();
221 }
222 
223 
225 {
226  if( m_markersDataView->GetCurrentItem().IsOk() )
227  {
228  // turn control over to m_frame, hide this DIALOG_FOOTPRINT_CHECKER window,
229  // no destruction so we can preserve listbox cursor
230  if( !IsModal() )
231  Show( false );
232  }
233 
234  // Do not skip aVent here: this is not useful, and Pcbnew crashes
235  // if skipped (at least on Windows)
236 }
237 
238 
239 void DIALOG_FOOTPRINT_CHECKER::OnSeverity( wxCommandEvent& aEvent )
240 {
241  int flag = 0;
242 
243  if( aEvent.GetEventObject() == m_showAll )
245  else if( aEvent.GetEventObject() == m_showErrors )
247  else if( aEvent.GetEventObject() == m_showWarnings )
249  else if( aEvent.GetEventObject() == m_showExclusions )
251 
252  if( aEvent.IsChecked() )
253  m_severities |= flag;
254  else if( aEvent.GetEventObject() == m_showAll )
256  else
257  m_severities &= ~flag;
258 
259  syncCheckboxes();
260 
261  // Set the provider's severity levels through the TreeModel so that the old tree
262  // can be torn down before the severity changes.
263  //
264  // It's not clear this is required, but we've had a lot of issues with wxDataView
265  // being cranky on various platforms.
266 
268 
270 }
271 
272 
273 void DIALOG_FOOTPRINT_CHECKER::OnCancelClick( wxCommandEvent& aEvent )
274 {
275  m_frame->FocusOnItem( nullptr );
276 
277  SetReturnCode( wxID_CANCEL );
278 
279  // Leave the tool to destroy (or not) the dialog
281  tool->DestroyCheckerDialog();
282 }
283 
284 
285 void DIALOG_FOOTPRINT_CHECKER::OnClose( wxCloseEvent& aEvent )
286 {
287  wxCommandEvent dummy;
288  OnCancelClick( dummy );
289 }
290 
291 
293 {
294  WINDOW_THAWER thawer( m_frame );
295 
296  m_frame->GetCanvas()->Refresh();
297 }
298 
299 
300 void DIALOG_FOOTPRINT_CHECKER::OnDeleteOneClick( wxCommandEvent& aEvent )
301 {
302  // Clear the selection. It may be the selected DRC marker.
304 
306 
307  // redraw the pcb
308  refreshEditor();
309 
311 }
312 
313 
314 void DIALOG_FOOTPRINT_CHECKER::OnDeleteAllClick( wxCommandEvent& event )
315 {
317 
318  m_checksRun = false;
319  refreshEditor();
321 }
322 
323 
325 {
326  // Clear current selection list to avoid selection of deleted items
328 
329  m_markersTreeModel->DeleteItems( false, true, true );
330 }
331 
332 
334 {
335  // Collect counts:
336 
337  int numErrors = 0;
338  int numWarnings = 0;
339  int numExcluded = 0;
340 
341  if( m_markersProvider )
342  {
346  }
347 
348  // Update badges:
349 
350  if( !m_checksRun && numErrors == 0 )
351  numErrors = -1;
352 
353  if( !m_checksRun && numWarnings == 0 )
354  numWarnings = -1;
355 
356  m_errorsBadge->SetMaximumNumber( numErrors );
358 
359  m_warningsBadge->SetMaximumNumber( numWarnings );
361 
362  m_exclusionsBadge->SetMaximumNumber( numExcluded );
364 }
365 
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:1945
BOARD_ITEM * GetItem(const KIID &aID) const
Definition: board.cpp:867
void DeleteItems(bool aCurrentOnly, bool aIncludeExclusions, bool aDeep)
Deletes the current item or all items.
Definition: rc_item.cpp:456
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:253
void OnDeleteAllClick(wxCommandEvent &event) override
#define MALFORMED_B_COURTYARD
void SetProvider(RC_ITEMS_PROVIDER *aProvider)
Definition: rc_item.cpp:289
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:80
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 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:479
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:143
functions to convert a shape built with DRAWSEGMENTS to a polygon.
static KIID ToUUID(wxDataViewItem aItem)
Definition: rc_item.cpp:144
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 OnClose(wxCloseEvent &event) override
void DeleteCurrentItem(bool aDeep)
Definition: rc_item.cpp:450
RC_ITEMS_PROVIDER * m_markersProvider
void SetSeverities(int aSeverities)
Definition: rc_item.cpp:295
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:71
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT) override
Adds an item to the container.
Definition: board.cpp:606
Definition: kiid.h:44
PCB_LAYER_ID
A quick note on layer IDs:
LSET is a set of PCB_LAYER_IDs.
std::shared_ptr< RC_ITEM > m_RcItem
Definition: rc_item.h:190
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:205
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
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
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:171
void FocusOnItem(BOARD_ITEM *aItem)
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:176