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:323
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.
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
void Flush(bool aSort=false)
Forces updating the HTML page, after the report is built in lazy mode If aSort = true,...
wxConfigBase * KifaceSettings() const
Definition: kiface_i.h:103
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...
unsigned GetCount() const
Function GetCount.
Definition: pcb_netlist.h:256
Class REPORTER is a pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:61
void OnTestFootprintsClick(wxCommandEvent &event) override
const wxString & GetFileName() const
Definition: class_board.h:238
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
VTBL_ENTRY const wxString AbsolutePath(const wxString &aFileName) const
Function AbsolutePath fixes up aFileName if it is relative to the project's directory to be an absolu...
Definition: project.cpp:385
This file contains miscellaneous commonly used macros and functions.
TOOL_MANAGER * GetToolManager() const
Return the tool manager instance, if any.
Definition: draw_frame.h:941
wxString MessageTextFromValue(EDA_UNITS_T aUnits, int aValue, bool aUseMils)
Definition: base_units.cpp:125
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
#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
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
#define NETLIST_DELETESHORTINGTRACKS_KEY
void OnOpenNetlistClick(wxCommandEvent &event) override
wxString NetlistFileWildcard()
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
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.
const wxString & GetReference() const
Definition: pcb_netlist.h:151
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Function GetConnectivity() returns list of missing connections between components/tracks.
Definition: class_board.h:297
const wxString & GetReference() const
Function GetReference.
Definition: class_module.h:462
Definition of file extensions used in Kicad.
Helper dialog and control classes.
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
wxString GetLastNetListRead()
Get the last net list read with the net list dialog box.
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
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)
MODULE * FindModuleByReference(const wxString &aReference) const
Function FindModuleByReference searches for a MODULE within this board with the given reference desig...
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_UNDEFINED)=0
Function Report is a pure virtual function to override in the derived object.
const wxString & GetValue() const
Function GetValue.
Definition: class_module.h:487
MODULE * Next() const
Definition: class_module.h:122
const wxString & GetValue() const
Definition: pcb_netlist.h:153
COMPONENT * GetComponentByReference(const wxString &aReference)
Function GetComponentByReference returns a COMPONENT by aReference.
Module description (excepted pads)
#define NETLIST_UPDATEFOOTPRINTS_KEY
BOARD * GetBoard() const
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,...
EDA_UNITS_T m_units
Definition: dialog_shim.h:173
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Function DisplayInfoMessage displays an informational message box with aMessage.
Definition: confirm.cpp:275
#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:293
const wxPoint GetPosition() const override
Definition: class_module.h:183
bool IsEmpty() const
Definition: class_board.h:273
#define ERR_CNT_MAX