KiCad PCB EDA Suite
pcbnew/dialogs/dialog_netlist.cpp
Go to the documentation of this file.
1 
6 /*
7  * This program source code file is part of KiCad, a free EDA CAD application.
8  *
9  * Copyright (C) 1992-2017 KiCad Developers, see change_log.txt for contributors.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, you may find one here:
23  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
24  * or you may search the http://www.gnu.org website for the version 2 license,
25  * or you may write to the Free Software Foundation, Inc.,
26  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
27  */
28 
29 #include <fctsys.h>
30 #include <project.h>
31 #include <kiface_i.h>
32 #include <confirm.h>
33 #include <macros.h>
34 #include <dialog_helpers.h>
35 #include <html_messagebox.h>
36 #include <base_units.h>
37 #include <pcb_edit_frame.h>
38 #include <pcb_netlist.h>
39 #include <netlist_reader.h>
40 #include <reporter.h>
41 #include <bitmaps.h>
42 
43 #include <board_design_settings.h>
44 #include <class_board.h>
45 #include <class_module.h>
48 
49 #include <dialog_netlist.h>
50 #include <wx_html_report_panel.h>
51 
52 #define NETLIST_FILTER_MESSAGES_KEY wxT("NetlistReportFilterMsg")
53 #define NETLIST_UPDATEFOOTPRINTS_KEY wxT("NetlistUpdateFootprints")
54 #define NETLIST_DELETESHORTINGTRACKS_KEY wxT("NetlistDeleteShortingTracks")
55 #define NETLIST_DELETEEXTRAFOOTPRINTS_KEY wxT("NetlistDeleteExtraFootprints")
56 #define NETLIST_DELETESINGLEPADNETS_KEY wxT("NetlistDeleteSinglePadNets")
57 
59 {
60  wxString netlistName = GetLastNetListRead();
61 
62  DIALOG_NETLIST dlg( this, netlistName );
63 
64  dlg.ShowModal();
65 
66  // Save project settings if needed.
67  // Project settings are saved in the corresponding <board name>.pro file
68  bool configChanged = !GetLastNetListRead().IsEmpty() && ( netlistName != GetLastNetListRead() );
69 
70  if( configChanged && !GetBoard()->GetFileName().IsEmpty() )
71  {
72  wxFileName fn = Prj().AbsolutePath( GetBoard()->GetFileName() );
73  fn.SetExt( ProjectFileExtension );
74  wxString path = fn.GetFullPath();
75  Prj().ConfigSave( Kiface().KifaceSearch(), GROUP_PCB, GetProjectFileParameters(), path );
76  }
77 }
78 
79 
80 DIALOG_NETLIST::DIALOG_NETLIST( PCB_EDIT_FRAME* aParent, const wxString & aNetlistFullFilename )
81  : DIALOG_NETLIST_BASE( aParent ),
82  m_parent( aParent ),
83  m_initialized( false )
84 {
86 
87  m_NetlistFilenameCtrl->SetValue( aNetlistFullFilename );
88  m_browseButton->SetBitmap( KiBitmap( folder_xpm ) );
89 
94 
95  m_MessageWindow->SetLabel( _("Changes To Be Applied") );
97 
98  // We use a sdbSizer to get platform-dependent ordering of the action buttons, but
99  // that requires us to correct the button labels here.
100  m_sdbSizer1OK->SetLabel( _( "Update PCB" ) );
101  m_sdbSizer1Apply->SetLabel( _( "Rebuild Ratsnest" ) );
102  m_sdbSizer1Cancel->SetLabel( _( "Close" ) );
103  m_buttonsSizer->Layout();
104 
105  m_sdbSizer1OK->SetDefault();
107 
108  m_initialized = true;
109  loadNetlist( true );
110 }
111 
113 {
119 }
120 
121 
122 void DIALOG_NETLIST::OnOpenNetlistClick( wxCommandEvent& event )
123 {
124  wxString dirPath = wxFileName( Prj().GetProjectFullName() ).GetPath();
125 
126  wxString filename = m_parent->GetLastNetListRead();
127 
128  if( !filename.IsEmpty() )
129  {
130  wxFileName fn = filename;
131  dirPath = fn.GetPath();
132  filename = fn.GetFullName();
133  }
134 
135  wxFileDialog FilesDialog( this, _( "Select Netlist" ), dirPath, filename,
136  NetlistFileWildcard(), wxFD_DEFAULT_STYLE | wxFD_FILE_MUST_EXIST );
137 
138  if( FilesDialog.ShowModal() != wxID_OK )
139  return;
140 
141  m_NetlistFilenameCtrl->SetValue( FilesDialog.GetPath() );
143 }
144 
145 void DIALOG_NETLIST::OnUpdatePCB( wxCommandEvent& event )
146 {
147  wxFileName fn = m_NetlistFilenameCtrl->GetValue();
148 
149  if( !fn.IsOk() )
150  {
151  wxMessageBox( _("Please, choose a valid netlist file.") );
152  return;
153  }
154 
155  if( !fn.FileExists() )
156  {
157  wxMessageBox( _("The netlist file does not exist.") );
158  return;
159  }
160 
161  // Give the user a chance to bail out when making changes from a netlist.
162  if( m_parent->GetBoard()->IsEmpty()
163  || IsOK( this, _( "The changes made cannot be undone. Are you sure you want to update the PCB?" ) ) )
164  {
165  m_MessageWindow->SetLabel( _( "Changes Applied To PCB" ) );
166  loadNetlist( false );
167 
168  m_sdbSizer1Cancel->SetDefault();
169  }
170 }
171 
172 
173 void DIALOG_NETLIST::OnTestFootprintsClick( wxCommandEvent& event )
174 {
175  if( m_parent->GetBoard()->m_Modules == nullptr )
176  {
177  DisplayInfoMessage( this, _( "No footprints." ) );
178  return;
179  }
180 
181  // Lists of duplicates, missing references and not in netlist footprints:
182  std::vector <MODULE*> duplicate;
183  wxArrayString missing;
184  std::vector <MODULE*> notInNetlist;
185  wxString netlistFilename = m_NetlistFilenameCtrl->GetValue();
186 
187  if( !verifyFootprints( netlistFilename, wxEmptyString, duplicate, missing, notInNetlist ) )
188  return;
189 
190  #define ERR_CNT_MAX 100 // Max number of errors to output in dialog
191  // to avoid a too long message list
192 
193  wxString list; // The messages to display
194 
195  m_parent->SetLastNetListRead( netlistFilename );
196 
197  int err_cnt = 0;
198 
199  // Search for duplicate footprints.
200  if( duplicate.size() == 0 )
201  list << wxT("<p><b>") << _( "No duplicate." ) << wxT("</b></p>");
202  else
203  {
204  list << wxT("<p><b>") << _( "Duplicates:" ) << wxT("</b></p>");
205 
206  for( unsigned ii = 0; ii < duplicate.size(); ii++ )
207  {
208  MODULE* module = duplicate[ii];
209 
210  if( module->GetReference().IsEmpty() )
211  list << wxT("<br>") << wxT("[noref)");
212  else
213  list << wxT("<br>") << module->GetReference();
214 
215  list << wxT(" (<i>") << module->GetValue() << wxT("</i>)");
216  list << wxT(" @ ");
217  list << MessageTextFromValue( m_units, module->GetPosition().x ),
218  list << wxT(", ") << MessageTextFromValue( m_units, module->GetPosition().y ),
219  err_cnt++;
220 
221  if( ERR_CNT_MAX < err_cnt )
222  break;
223  }
224  }
225 
226  // Search for missing modules on board.
227  if( missing.size() == 0 )
228  list << wxT("<p><b>") << _( "No missing footprints." ) << wxT("</b></p>");
229  else
230  {
231  list << wxT("<p><b>") << _( "Missing:" ) << wxT("</b></p>");
232 
233  for( unsigned ii = 0; ii < missing.size(); ii += 2 )
234  {
235  list << wxT("<br>") << missing[ii];
236  list << wxT(" (<i>") << missing[ii+1] << wxT("</i>)");
237  err_cnt++;
238 
239  if( ERR_CNT_MAX < err_cnt )
240  break;
241  }
242  }
243 
244 
245  // Search for modules found on board but not in net list.
246  if( notInNetlist.size() == 0 )
247  list << wxT( "<p><b>" ) << _( "No extra footprints." ) << wxT( "</b></p>" );
248  else
249  {
250  list << wxT( "<p><b>" ) << _( "Not in Netlist:" ) << wxT( "</b></p>" );
251 
252  for( unsigned ii = 0; ii < notInNetlist.size(); ii++ )
253  {
254  MODULE* module = notInNetlist[ii];
255 
256  if( module->GetReference().IsEmpty() )
257  list << wxT( "<br>" ) << wxT( "[noref)" );
258  else
259  list << wxT( "<br>" ) << module->GetReference() ;
260 
261  list << wxT( " (<i>" ) << module->GetValue() << wxT( "</i>)" );
262  list << wxT( " @ " );
263  list << MessageTextFromValue( m_units, module->GetPosition().x ),
264  list << wxT( ", " ) << MessageTextFromValue( m_units, module->GetPosition().y ),
265  err_cnt++;
266 
267  if( ERR_CNT_MAX < err_cnt )
268  break;
269  }
270  }
271 
272  if( ERR_CNT_MAX < err_cnt )
273  {
274  list << wxT( "<p><b>" )
275  << _( "Too many errors: some are skipped" )
276  << wxT( "</b></p>" );
277  }
278 
279  HTML_MESSAGE_BOX dlg( this, _( "Check footprints" ) );
280  dlg.AddHTML_Text( list );
281  dlg.ShowModal();
282 }
283 
284 
285 void DIALOG_NETLIST::OnFilenameKillFocus( wxFocusEvent& event )
286 {
288 }
289 
290 
292 {
293  if( m_initialized )
294  {
295  wxFileName fn = m_NetlistFilenameCtrl->GetValue();
296  if( fn.IsOk() )
297  {
298  if( fn.FileExists() )
299  {
300  loadNetlist( true );
301  }
302  else
303  {
305  REPORTER& reporter = m_MessageWindow->Reporter();
306  reporter.Report( _("The netlist file does not exist."), REPORTER::RPT_ERROR );
307  }
308  }
309  }
310 }
311 
312 
313 void DIALOG_NETLIST::OnMatchChanged( wxCommandEvent& event )
314 {
315  if( m_initialized )
316  loadNetlist( true );
317 }
318 
319 
320 void DIALOG_NETLIST::OnOptionChanged( wxCommandEvent& event )
321 {
322  if( m_initialized )
323  loadNetlist( true );
324 }
325 
326 
327 void DIALOG_NETLIST::OnCompileRatsnestClick( wxCommandEvent& event )
328 {
329  // Rebuild the board connectivity:
330  auto board = m_parent->GetBoard();
331  board->GetConnectivity()->RecalculateRatsnest();
332 }
333 
334 
335 void DIALOG_NETLIST::OnUpdateUIValidNetlistFile( wxUpdateUIEvent& aEvent )
336 {
337  aEvent.Enable( !m_NetlistFilenameCtrl->GetValue().IsEmpty() );
338 }
339 
340 
341 bool DIALOG_NETLIST::verifyFootprints( const wxString& aNetlistFilename,
342  const wxString & aCmpFilename,
343  std::vector< MODULE* >& aDuplicates,
344  wxArrayString& aMissing,
345  std::vector< MODULE* >& aNotInNetlist )
346 {
347  wxString msg;
348  MODULE* module;
349  MODULE* nextModule;
350  NETLIST netlist;
351  wxBusyCursor dummy; // Shows an hourglass while calculating.
352  NETLIST_READER* netlistReader;
353  COMPONENT* component;
354 
355  try
356  {
357  netlistReader = NETLIST_READER::GetNetlistReader( &netlist, aNetlistFilename,
358  aCmpFilename );
359 
360  if( netlistReader == NULL )
361  {
362  msg.Printf( _( "Cannot open netlist file \"%s\"." ), GetChars( aNetlistFilename ) );
363  wxMessageBox( msg, _( "Netlist Load Error." ), wxOK | wxICON_ERROR );
364  return false;
365  }
366 
367  std::unique_ptr< NETLIST_READER > nlr( netlistReader );
368  netlistReader->LoadNetlist();
369  }
370  catch( const IO_ERROR& ioe )
371  {
372  msg.Printf( _( "Error loading netlist file:\n%s" ), ioe.What().GetData() );
373  wxMessageBox( msg, _( "Netlist Load Error" ), wxOK | wxICON_ERROR );
374  return false;
375  }
376 
377  BOARD* pcb = m_parent->GetBoard();
378 
379  // Search for duplicate footprints.
380  module = pcb->m_Modules;
381 
382  for( ; module != NULL; module = module->Next() )
383  {
384  nextModule = module->Next();
385 
386  for( ; nextModule != NULL; nextModule = nextModule->Next() )
387  {
388  if( module->GetReference().CmpNoCase( nextModule->GetReference() ) == 0 )
389  {
390  aDuplicates.push_back( module );
391  break;
392  }
393  }
394  }
395 
396  // Search for component footprints in the netlist but not on the board.
397  for( unsigned ii = 0; ii < netlist.GetCount(); ii++ )
398  {
399  component = netlist.GetComponent( ii );
400 
401  module = pcb->FindModuleByReference( component->GetReference() );
402 
403  if( module == NULL )
404  {
405  aMissing.Add( component->GetReference() );
406  aMissing.Add( component->GetValue() );
407  }
408  }
409 
410  // Search for component footprints found on board but not in netlist.
411  module = pcb->m_Modules;
412 
413  for( ; module != NULL; module = module->Next() )
414  {
415 
416  component = netlist.GetComponentByReference( module->GetReference() );
417 
418  if( component == NULL )
419  aNotInNetlist.push_back( module );
420  }
421 
422  return true;
423 }
424 
425 
426 void DIALOG_NETLIST::loadNetlist( bool aDryRun )
427 {
428  wxString netlistFileName = m_NetlistFilenameCtrl->GetValue();
429  wxFileName fn = netlistFileName;
430 
431  if( !fn.IsOk() || !fn.FileExists() )
432  return;
433 
435  REPORTER& reporter = m_MessageWindow->Reporter();
436 
437  wxBusyCursor busy;
438 
439  wxString msg;
440  msg.Printf( _( "Reading netlist file \"%s\".\n" ), GetChars( netlistFileName ) );
441  reporter.ReportHead( msg, REPORTER::RPT_INFO );
442 
443  if( m_matchByTimestamp->GetSelection() == 0 )
444  msg = _( "Using time stamps to match components and footprints.\n" );
445  else
446  msg = _( "Using references to match components and footprints.\n" );
447 
448  reporter.ReportHead( msg, REPORTER::RPT_INFO );
449  m_MessageWindow->SetLazyUpdate( true ); // Use lazy update to speed the creation of the report
450  // (the window is not updated for each message)
451 
452  m_parent->ReadPcbNetlist( netlistFileName, wxEmptyString, reporter,
453  m_cbUpdateFootprints->GetValue(),
454  m_cbDeleteShortingTracks->GetValue(),
455  m_cbDeleteExtraFootprints->GetValue(),
456  m_matchByTimestamp->GetSelection() == 0,
457  m_cbDeleteSinglePadNets->GetValue(),
458  aDryRun );
459 
460  // The creation of the report was made without window update: the full page must be displayed
461  m_MessageWindow->Flush( true );
462 }
463 
464 
void SetVisibleSeverities(int aSeverities)
Set the visible severity filter.
void SetLazyUpdate(bool aLazyUpdate)
Sets the lasy update.
VTBL_ENTRY void ConfigSave(const SEARCH_STACK &aSList, const wxString &aGroupName, const PARAM_CFG_ARRAY &aParams, const wxString &aFileName=wxEmptyString)
Function ConfigSave saves the current "project" parameters into the wxConfigBase* derivative...
Definition: project.cpp:318
PARAM_CFG_ARRAY GetProjectFileParameters()
Function GetProjectFileParameters returns a project file parameter list for Pcbnew.
void OnMatchChanged(wxCommandEvent &event) override
PCB_EDIT_FRAME * m_parent
Implementation of conversion functions that require both schematic and board internal units...
This file is part of the common library.
Class DIALOG_NETLIST_BASE.
const std::string ProjectFileExtension
void SetLastNetListRead(const wxString &aNetListFile)
Set the last net list successfully read by the net list dialog box.
Class BOARD to handle a board.
wxConfigBase * m_config
MODULE * Next() const
Definition: class_module.h:123
void Flush(bool aSort=false)
Forces updating the HTML page, after the report is built in lazy mode If aSort = true, the body messages will be ordered by severity
void FinishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
static NETLIST_READER * GetNetlistReader(NETLIST *aNetlist, const wxString &aNetlistFileName, const wxString &aCompFootprintFileName=wxEmptyString)
Function GetNetlistReader attempts to determine the net list file type of aNetlistFileName and return...
MODULE * FindModuleByReference(const wxString &aReference) const
Function FindModuleByReference searches for a MODULE within this board with the given reference desig...
BOARD * GetBoard() const
const wxString & GetValue() const
Function GetValue.
Definition: class_module.h:497
Class REPORTER is a pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:61
void OnTestFootprintsClick(wxCommandEvent &event) override
void OnFilenameKillFocus(wxFocusEvent &event) override
#define NETLIST_DELETEEXTRAFOOTPRINTS_KEY
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
Definition: kicad.cpp:52
This file contains miscellaneous commonly used macros and functions.
wxString MessageTextFromValue(EDA_UNITS_T aUnits, int aValue, bool aUseMils)
Definition: base_units.cpp:125
const wxString & GetReference() const
Definition: pcb_netlist.h:151
const wxString & GetValue() const
Definition: pcb_netlist.h:153
virtual REPORTER & ReportHead(const wxString &aText, SEVERITY aSeverity=RPT_UNDEFINED)
Function ReportHead Places the report at the beginning of the list for objects that support ordering...
Definition: reporter.h:118
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Construct a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:79
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
#define NETLIST_DELETESINGLEPADNETS_KEY
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_INSERT) override
>
virtual void LoadNetlist()=0
Function LoadNetlist loads the contents of the netlist file into aNetlist.
#define NETLIST_FILTER_MESSAGES_KEY
Class NETLIST stores all of information read from a netlist along with the flags used to update the N...
Definition: pcb_netlist.h:214
#define NETLIST_DELETESHORTINGTRACKS_KEY
void OnOpenNetlistClick(wxCommandEvent &event) override
const wxString & GetFileName() const
Definition: class_board.h:237
wxString NetlistFileWildcard()
bool IsEmpty() const
Definition: class_board.h:272
REPORTER & Reporter()
returns the reporter object that reports to this panel
void OnOptionChanged(wxCommandEvent &event) override
Subclass of DIALOG_DISPLAY_HTML_TEXT_BASE, which is generated by wxFormBuilder.
VTBL_ENTRY const wxString AbsolutePath(const wxString &aFileName) const
Function AbsolutePath fixes up aFileName if it is relative to the project&#39;s directory to be an absolu...
Definition: project.cpp:380
The common library.
Helper dialog and control classes.
wxConfigBase * KifaceSettings() const
Definition: kiface_i.h:103
Class NETLIST_READER is a pure virtual class to derive a specific type of netlist reader from...
void ReadPcbNetlist(const wxString &aNetlistFileName, const wxString &aCmpFileName, REPORTER &aReporter, bool aChangeFootprint, bool aDeleteBadTracks, bool aDeleteExtraFootprints, bool aSelectByTimestamp, bool aDeleteSinglePadNets, bool aIsDryRun)
Function ReadPcbNetlist reads aNetlistFileName and updates the footprints (load missing footprints an...
Definition: netlist.cpp:58
Class HTML_MESSAGE_BOX.
Class COMPONENT is used to store components and all of their related information found in a netlist...
Definition: pcb_netlist.h:83
WX_HTML_REPORT_PANEL * m_MessageWindow
COMPONENT * GetComponent(unsigned aIndex)
Function GetComponent returns the COMPONENT at aIndex.
Definition: pcb_netlist.h:265
void OnUpdatePCB(wxCommandEvent &event) override
wxString GetLastNetListRead()
Get the last net list read with the net list dialog box.
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:92
void Clear()
clears the report panel
static LIB_PART * dummy()
Used when a LIB_PART is not found in library to draw a dummy shape This component is a 400 mils squar...
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:170
const wxString & GetReference() const
Function GetReference.
Definition: class_module.h:463
DLIST< MODULE > m_Modules
Definition: class_board.h:248
void AddHTML_Text(const wxString &message)
Function AddHTML_Text adds html text (without any change) to message list.
void OnUpdateUIValidNetlistFile(wxUpdateUIEvent &aEvent) override
Class PCB_EDIT_FRAME is the main frame for Pcbnew.
void OnCompileRatsnestClick(wxCommandEvent &event) override
DIALOG_NETLIST(PCB_EDIT_FRAME *aParent, const wxString &aNetlistFullFilename)
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_UNDEFINED)=0
Function Report is a pure virtual function to override in the derived object.
COMPONENT * GetComponentByReference(const wxString &aReference)
Function GetComponentByReference returns a COMPONENT by aReference.
Module description (excepted pads)
#define NETLIST_UPDATEFOOTPRINTS_KEY
bool verifyFootprints(const wxString &aNetlistFilename, const wxString &aCmpFilename, std::vector< MODULE * > &aDuplicate, wxArrayString &aMissing, std::vector< MODULE * > &aNotInNetlist)
Function verifyFootprints compares the netlist to the board and builds a list of duplicate, missing, and extra footprints.
EDA_UNITS_T m_units
Definition: dialog_shim.h:172
unsigned GetCount() const
Function GetCount.
Definition: pcb_netlist.h:256
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Function DisplayInfoMessage displays an informational message box with aMessage.
Definition: confirm.cpp:277
#define GROUP_PCB
Names of sub sections where to store project info in *.pro project config files.
Definition: config_params.h:43
void SetLabel(const wxString &aLabel) override
sets the frame label
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:76
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Function IsOK displays a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:295
const wxPoint GetPosition() const override
Definition: class_module.h:184
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Function GetConnectivity() returns list of missing connections between components/tracks.
Definition: class_board.h:296
#define ERR_CNT_MAX