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 #include <tool/tool_manager.h>
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  m_runDragCommand( false )
85 {
87 
88  m_NetlistFilenameCtrl->SetValue( aNetlistFullFilename );
89  m_browseButton->SetBitmap( KiBitmap( folder_xpm ) );
90 
95 
96  m_MessageWindow->SetLabel( _("Changes To Be Applied") );
98 
99  // We use a sdbSizer to get platform-dependent ordering of the action buttons, but
100  // that requires us to correct the button labels here.
101  m_sdbSizer1OK->SetLabel( _( "Update PCB" ) );
102  m_sdbSizer1Apply->SetLabel( _( "Rebuild Ratsnest" ) );
103  m_sdbSizer1Cancel->SetLabel( _( "Close" ) );
104  m_buttonsSizer->Layout();
105 
106  m_sdbSizer1OK->SetDefault();
108 
109  m_initialized = true;
110  loadNetlist( true );
111 }
112 
114 {
120 
121  if( m_runDragCommand )
122  m_parent->GetToolManager()->InvokeTool( "pcbnew.InteractiveEdit" );
123 }
124 
125 
126 void DIALOG_NETLIST::OnOpenNetlistClick( wxCommandEvent& event )
127 {
128  wxString dirPath = wxFileName( Prj().GetProjectFullName() ).GetPath();
129 
130  wxString filename = m_parent->GetLastNetListRead();
131 
132  if( !filename.IsEmpty() )
133  {
134  wxFileName fn = filename;
135  dirPath = fn.GetPath();
136  filename = fn.GetFullName();
137  }
138 
139  wxFileDialog FilesDialog( this, _( "Select Netlist" ), dirPath, filename,
140  NetlistFileWildcard(), wxFD_DEFAULT_STYLE | wxFD_FILE_MUST_EXIST );
141 
142  if( FilesDialog.ShowModal() != wxID_OK )
143  return;
144 
145  m_NetlistFilenameCtrl->SetValue( FilesDialog.GetPath() );
147 }
148 
149 void DIALOG_NETLIST::OnUpdatePCB( wxCommandEvent& event )
150 {
151  wxFileName fn = m_NetlistFilenameCtrl->GetValue();
152 
153  if( !fn.IsOk() )
154  {
155  wxMessageBox( _("Please, choose a valid netlist file.") );
156  return;
157  }
158 
159  if( !fn.FileExists() )
160  {
161  wxMessageBox( _("The netlist file does not exist.") );
162  return;
163  }
164 
165  // Give the user a chance to bail out when making changes from a netlist.
166  if( m_parent->GetBoard()->IsEmpty()
167  || IsOK( this, _( "The changes made cannot be undone. Are you sure you want to update the PCB?" ) ) )
168  {
169  m_MessageWindow->SetLabel( _( "Changes Applied To PCB" ) );
170  loadNetlist( false );
171 
172  m_sdbSizer1Cancel->SetDefault();
173  }
174 }
175 
176 
177 void DIALOG_NETLIST::OnTestFootprintsClick( wxCommandEvent& event )
178 {
179  if( m_parent->GetBoard()->m_Modules == nullptr )
180  {
181  DisplayInfoMessage( this, _( "No footprints." ) );
182  return;
183  }
184 
185  // Lists of duplicates, missing references and not in netlist footprints:
186  std::vector <MODULE*> duplicate;
187  wxArrayString missing;
188  std::vector <MODULE*> notInNetlist;
189  wxString netlistFilename = m_NetlistFilenameCtrl->GetValue();
190 
191  if( !verifyFootprints( netlistFilename, wxEmptyString, duplicate, missing, notInNetlist ) )
192  return;
193 
194  #define ERR_CNT_MAX 100 // Max number of errors to output in dialog
195  // to avoid a too long message list
196 
197  wxString list; // The messages to display
198 
199  m_parent->SetLastNetListRead( netlistFilename );
200 
201  int err_cnt = 0;
202 
203  // Search for duplicate footprints.
204  if( duplicate.size() == 0 )
205  list << wxT("<p><b>") << _( "No duplicate." ) << wxT("</b></p>");
206  else
207  {
208  list << wxT("<p><b>") << _( "Duplicates:" ) << wxT("</b></p>");
209 
210  for( unsigned ii = 0; ii < duplicate.size(); ii++ )
211  {
212  MODULE* module = duplicate[ii];
213 
214  if( module->GetReference().IsEmpty() )
215  list << wxT("<br>") << wxT("[noref)");
216  else
217  list << wxT("<br>") << module->GetReference();
218 
219  list << wxT(" (<i>") << module->GetValue() << wxT("</i>)");
220  list << wxT(" @ ");
221  list << MessageTextFromValue( m_units, module->GetPosition().x ),
222  list << wxT(", ") << MessageTextFromValue( m_units, module->GetPosition().y ),
223  err_cnt++;
224 
225  if( ERR_CNT_MAX < err_cnt )
226  break;
227  }
228  }
229 
230  // Search for missing modules on board.
231  if( missing.size() == 0 )
232  list << wxT("<p><b>") << _( "No missing footprints." ) << wxT("</b></p>");
233  else
234  {
235  list << wxT("<p><b>") << _( "Missing:" ) << wxT("</b></p>");
236 
237  for( unsigned ii = 0; ii < missing.size(); ii += 2 )
238  {
239  list << wxT("<br>") << missing[ii];
240  list << wxT(" (<i>") << missing[ii+1] << wxT("</i>)");
241  err_cnt++;
242 
243  if( ERR_CNT_MAX < err_cnt )
244  break;
245  }
246  }
247 
248 
249  // Search for modules found on board but not in net list.
250  if( notInNetlist.size() == 0 )
251  list << wxT( "<p><b>" ) << _( "No extra footprints." ) << wxT( "</b></p>" );
252  else
253  {
254  list << wxT( "<p><b>" ) << _( "Not in Netlist:" ) << wxT( "</b></p>" );
255 
256  for( unsigned ii = 0; ii < notInNetlist.size(); ii++ )
257  {
258  MODULE* module = notInNetlist[ii];
259 
260  if( module->GetReference().IsEmpty() )
261  list << wxT( "<br>" ) << wxT( "[noref)" );
262  else
263  list << wxT( "<br>" ) << module->GetReference() ;
264 
265  list << wxT( " (<i>" ) << module->GetValue() << wxT( "</i>)" );
266  list << wxT( " @ " );
267  list << MessageTextFromValue( m_units, module->GetPosition().x ),
268  list << wxT( ", " ) << MessageTextFromValue( m_units, module->GetPosition().y ),
269  err_cnt++;
270 
271  if( ERR_CNT_MAX < err_cnt )
272  break;
273  }
274  }
275 
276  if( ERR_CNT_MAX < err_cnt )
277  {
278  list << wxT( "<p><b>" )
279  << _( "Too many errors: some are skipped" )
280  << wxT( "</b></p>" );
281  }
282 
283  HTML_MESSAGE_BOX dlg( this, _( "Check footprints" ) );
284  dlg.AddHTML_Text( list );
285  dlg.ShowModal();
286 }
287 
288 
289 void DIALOG_NETLIST::OnFilenameKillFocus( wxFocusEvent& event )
290 {
292 }
293 
294 
296 {
297  if( m_initialized )
298  {
299  wxFileName fn = m_NetlistFilenameCtrl->GetValue();
300  if( fn.IsOk() )
301  {
302  if( fn.FileExists() )
303  {
304  loadNetlist( true );
305  }
306  else
307  {
309  REPORTER& reporter = m_MessageWindow->Reporter();
310  reporter.Report( _("The netlist file does not exist."), REPORTER::RPT_ERROR );
311  }
312  }
313  }
314 }
315 
316 
317 void DIALOG_NETLIST::OnMatchChanged( wxCommandEvent& event )
318 {
319  if( m_initialized )
320  loadNetlist( true );
321 }
322 
323 
324 void DIALOG_NETLIST::OnOptionChanged( wxCommandEvent& event )
325 {
326  if( m_initialized )
327  loadNetlist( true );
328 }
329 
330 
331 void DIALOG_NETLIST::OnCompileRatsnestClick( wxCommandEvent& event )
332 {
333  // Rebuild the board connectivity:
334  auto board = m_parent->GetBoard();
335  board->GetConnectivity()->RecalculateRatsnest();
336 }
337 
338 
339 void DIALOG_NETLIST::OnUpdateUIValidNetlistFile( wxUpdateUIEvent& aEvent )
340 {
341  aEvent.Enable( !m_NetlistFilenameCtrl->GetValue().IsEmpty() );
342 }
343 
344 
345 bool DIALOG_NETLIST::verifyFootprints( const wxString& aNetlistFilename,
346  const wxString & aCmpFilename,
347  std::vector< MODULE* >& aDuplicates,
348  wxArrayString& aMissing,
349  std::vector< MODULE* >& aNotInNetlist )
350 {
351  wxString msg;
352  MODULE* module;
353  MODULE* nextModule;
354  NETLIST netlist;
355  wxBusyCursor dummy; // Shows an hourglass while calculating.
356  NETLIST_READER* netlistReader;
357  COMPONENT* component;
358 
359  try
360  {
361  netlistReader = NETLIST_READER::GetNetlistReader( &netlist, aNetlistFilename,
362  aCmpFilename );
363 
364  if( netlistReader == NULL )
365  {
366  msg.Printf( _( "Cannot open netlist file \"%s\"." ), GetChars( aNetlistFilename ) );
367  wxMessageBox( msg, _( "Netlist Load Error." ), wxOK | wxICON_ERROR );
368  return false;
369  }
370 
371  std::unique_ptr< NETLIST_READER > nlr( netlistReader );
372  netlistReader->LoadNetlist();
373  }
374  catch( const IO_ERROR& ioe )
375  {
376  msg.Printf( _( "Error loading netlist file:\n%s" ), ioe.What().GetData() );
377  wxMessageBox( msg, _( "Netlist Load Error" ), wxOK | wxICON_ERROR );
378  return false;
379  }
380 
381  BOARD* pcb = m_parent->GetBoard();
382 
383  // Search for duplicate footprints.
384  module = pcb->m_Modules;
385 
386  for( ; module != NULL; module = module->Next() )
387  {
388  nextModule = module->Next();
389 
390  for( ; nextModule != NULL; nextModule = nextModule->Next() )
391  {
392  if( module->GetReference().CmpNoCase( nextModule->GetReference() ) == 0 )
393  {
394  aDuplicates.push_back( module );
395  break;
396  }
397  }
398  }
399 
400  // Search for component footprints in the netlist but not on the board.
401  for( unsigned ii = 0; ii < netlist.GetCount(); ii++ )
402  {
403  component = netlist.GetComponent( ii );
404 
405  module = pcb->FindModuleByReference( component->GetReference() );
406 
407  if( module == NULL )
408  {
409  aMissing.Add( component->GetReference() );
410  aMissing.Add( component->GetValue() );
411  }
412  }
413 
414  // Search for component footprints found on board but not in netlist.
415  module = pcb->m_Modules;
416 
417  for( ; module != NULL; module = module->Next() )
418  {
419 
420  component = netlist.GetComponentByReference( module->GetReference() );
421 
422  if( component == NULL )
423  aNotInNetlist.push_back( module );
424  }
425 
426  return true;
427 }
428 
429 
430 void DIALOG_NETLIST::loadNetlist( bool aDryRun )
431 {
432  wxString netlistFileName = m_NetlistFilenameCtrl->GetValue();
433  wxFileName fn = netlistFileName;
434 
435  if( !fn.IsOk() || !fn.FileExists() )
436  return;
437 
439  REPORTER& reporter = m_MessageWindow->Reporter();
440 
441  wxBusyCursor busy;
442 
443  wxString msg;
444  msg.Printf( _( "Reading netlist file \"%s\".\n" ), GetChars( netlistFileName ) );
445  reporter.ReportHead( msg, REPORTER::RPT_INFO );
446 
447  if( m_matchByTimestamp->GetSelection() == 0 )
448  msg = _( "Using time stamps to match components and footprints.\n" );
449  else
450  msg = _( "Using references to match components and footprints.\n" );
451 
452  reporter.ReportHead( msg, REPORTER::RPT_INFO );
453  m_MessageWindow->SetLazyUpdate( true ); // Use lazy update to speed the creation of the report
454  // (the window is not updated for each message)
455 
456  m_parent->ReadPcbNetlist( netlistFileName, wxEmptyString, reporter,
457  m_cbUpdateFootprints->GetValue(),
458  m_cbDeleteShortingTracks->GetValue(),
459  m_cbDeleteExtraFootprints->GetValue(),
460  m_matchByTimestamp->GetSelection() == 0,
461  m_cbDeleteSinglePadNets->GetValue(),
462  aDryRun, &m_runDragCommand );
463 
464  // The creation of the report was made without window update: the full page must be displayed
465  m_MessageWindow->Flush( true );
466 }
467 
468 
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:122
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:496
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
bool InvokeTool(TOOL_ID aToolId)
Function InvokeTool() Calls a tool by sending a tool activation event to tool of given ID...
#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:120
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:238
wxString NetlistFileWildcard()
bool IsEmpty() const
Definition: class_board.h:273
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
Definition of file extensions used in Kicad.
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...
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
void ReadPcbNetlist(const wxString &aNetlistFileName, const wxString &aCmpFileName, REPORTER &aReporter, bool aChangeFootprint, bool aDeleteBadTracks, bool aDeleteExtraFootprints, bool aSelectByTimestamp, bool aDeleteSinglePadNets, bool aIsDryRun, bool *runDragCommand)
Function ReadPcbNetlist reads aNetlistFileName and updates the footprints (load missing footprints an...
Definition: netlist.cpp:58
COMPONENT * GetComponent(unsigned aIndex)
Function GetComponent returns the COMPONENT at aIndex.
Definition: pcb_netlist.h:265
void OnUpdatePCB(wxCommandEvent &event) override
TOOL_MANAGER * GetToolManager() const
Return the tool manager instance, if any.
Definition: draw_frame.h:931
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:171
const wxString & GetReference() const
Function GetReference.
Definition: class_module.h:462
DLIST< MODULE > m_Modules
Definition: class_board.h:249
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:183
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Function GetConnectivity() returns list of missing connections between components/tracks.
Definition: class_board.h:297
#define ERR_CNT_MAX