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>
46 #include <connectivity_data.h>
48 
49 #include <dialog_netlist.h>
50 #include <wx_html_report_panel.h>
51 
52 #define NETLIST_SILENTMODE_KEY wxT("SilentMode")
53 #define NETLIST_FILTER_MESSAGES_KEY wxT("NetlistReportFilterMsg")
54 #define NETLIST_DELETESINGLEPADNETS_KEY wxT("NetlistDeleteSinglePadNets")
55 
57 {
58  /* Setup the netlist file name to the last netlist file read,
59  * or the board file name if the last filename is empty or last file not existing.
60  */
61  wxString netlistName = GetLastNetListRead();
62 
63  wxFileName fn = netlistName;
64 
65  if( !fn.IsOk() || !fn.FileExists() )
66  {
67  fn = GetBoard()->GetFileName();
68  fn.SetExt( NetlistFileExtension );
69 
70  if( fn.GetName().IsEmpty() )
71  netlistName.Clear();
72  else
73  netlistName = fn.GetFullPath();
74  }
75 
76  DIALOG_NETLIST dlg( this, DC, netlistName );
77 
78  dlg.ShowModal();
79 
80  // Save project settings if needed.
81  // Project settings are saved in the corresponding <board name>.pro file
82  bool configChanged = !GetLastNetListRead().IsEmpty() && ( netlistName != GetLastNetListRead() );
83 
84  if( configChanged && !GetBoard()->GetFileName().IsEmpty()
85  && IsOK( this, _( "The project configuration has changed. Do you want to save it?" ) ) )
86  {
87  fn = Prj().AbsolutePath( GetBoard()->GetFileName() );
88  fn.SetExt( ProjectFileExtension );
89 
90  wxString pro_name = fn.GetFullPath();
91 
92  Prj().ConfigSave( Kiface().KifaceSearch(), GROUP_PCB,
93  GetProjectFileParameters(), pro_name );
94  }
95 }
96 
97 
99  const wxString & aNetlistFullFilename )
100  : DIALOG_NETLIST_BASE( aParent )
101 {
102  m_parent = aParent;
103  m_dc = aDC;
105 
107  bool tmp = m_config->Read( NETLIST_DELETESINGLEPADNETS_KEY, 0l );
108  m_rbSingleNets->SetSelection( tmp == 0 ? 0 : 1);
109  m_browseButton->SetBitmap( KiBitmap( browse_files_xpm ) );
110  m_NetlistFilenameCtrl->SetValue( aNetlistFullFilename );
111  m_checkBoxSilentMode->SetValue( m_silentMode );
112 
113  int severities = m_config->Read( NETLIST_FILTER_MESSAGES_KEY, -1l );
114  m_MessageWindow->SetVisibleSeverities( severities );
115 
116  // Update sizes and sizers:
117  m_MessageWindow->MsgPanelSetMinSize( wxSize( -1, 160 ) );
118  GetSizer()->SetSizeHints( this );
119 }
120 
122 {
123  m_config->Write( NETLIST_SILENTMODE_KEY, (long) m_silentMode );
125  (long) m_rbSingleNets->GetSelection() );
128 }
129 
130 
131 void DIALOG_NETLIST::OnOpenNetlistClick( wxCommandEvent& event )
132 {
133  wxString lastPath = wxFileName( Prj().GetProjectFullName() ).GetPath();
134 
135  wxString lastNetlistRead = m_parent->GetLastNetListRead();
136 
137  if( !lastNetlistRead.IsEmpty() && !wxFileName::FileExists( lastNetlistRead ) )
138  {
139  lastNetlistRead = wxEmptyString;
140  }
141  else
142  {
143  wxFileName fn = lastNetlistRead;
144  lastPath = fn.GetPath();
145  lastNetlistRead = fn.GetFullName();
146  }
147 
148  wxLogDebug( wxT( "Last net list read path '%s', file name '%s'." ),
149  GetChars( lastPath ), GetChars( lastNetlistRead ) );
150 
151  wxFileDialog FilesDialog( this, _( "Select Netlist" ), lastPath, lastNetlistRead,
152  NetlistFileWildcard(), wxFD_DEFAULT_STYLE | wxFD_FILE_MUST_EXIST );
153 
154  if( FilesDialog.ShowModal() != wxID_OK )
155  return;
156 
157  m_NetlistFilenameCtrl->SetValue( FilesDialog.GetPath() );
158 }
159 
160 void DIALOG_NETLIST::OnReadNetlistFileClick( wxCommandEvent& event )
161 {
162  wxString netlistFileName = m_NetlistFilenameCtrl->GetValue();
163  wxFileName fn = netlistFileName;
164 
165  if( !fn.IsOk() )
166  {
167  wxMessageBox( _("Please, choose a valid netlist file") );
168  return;
169  }
170 
171  if( !fn.FileExists() )
172  {
173  wxMessageBox( _("The netlist file does not exist") );
174  return;
175  }
176 
177  // Give the user a chance to bail out when making changes from a netlist.
178  if( !m_checkDryRun->GetValue() && !m_silentMode
179  && !m_parent->GetBoard()->IsEmpty()
180  && !IsOK( this, _( "The changes made by reading the netlist cannot be undone. Are you "
181  "sure you want to read the netlist?" ) ) )
182  return;
183 
185  REPORTER& reporter = m_MessageWindow->Reporter();
186 
187  wxBusyCursor busy;
188 
189  wxString msg;
190  msg.Printf( _( "Reading netlist file \"%s\".\n" ), GetChars( netlistFileName ) );
191  reporter.ReportHead( msg, REPORTER::RPT_INFO );
192 
193  if( m_Select_By_Timestamp->GetSelection() == 1 )
194  msg = _( "Using time stamps to match components and footprints.\n" );
195  else
196  msg = _( "Using references to match components and footprints.\n" );
197 
198  reporter.ReportHead( msg, REPORTER::RPT_INFO );
199  m_MessageWindow->SetLazyUpdate( true ); // use a "lazy" update to speed up the creation of the report
200  // (The window is not updated for each message)
201 
202  m_parent->ReadPcbNetlist( netlistFileName, wxEmptyString, &reporter,
203  m_ChangeExistingFootprintCtrl->GetSelection() == 1,
204  m_DeleteBadTracks->GetSelection() == 1,
205  m_RemoveExtraFootprintsCtrl->GetSelection() == 1,
206  m_Select_By_Timestamp->GetSelection() == 1,
207  m_rbSingleNets->GetSelection() == 1,
208  m_checkDryRun->GetValue() );
209  // The creation of the report was made without window update:
210  // the full page must be displayed
211  m_MessageWindow->Flush( true );
212 }
213 
214 
215 void DIALOG_NETLIST::OnTestFootprintsClick( wxCommandEvent& event )
216 {
217  if( m_parent->GetBoard()->m_Modules == NULL )
218  {
219  DisplayInfoMessage( this, _( "No footprints" ) );
220  return;
221  }
222 
223  // Lists of duplicates, missing references and not in netlist footprints:
224  std::vector <MODULE*> duplicate;
225  wxArrayString missing;
226  std::vector <MODULE*> notInNetlist;
227  wxString netlistFilename = m_NetlistFilenameCtrl->GetValue();
228 
229  if( !verifyFootprints( netlistFilename, wxEmptyString, duplicate, missing, notInNetlist ) )
230  return;
231 
232  #define ERR_CNT_MAX 100 // Max number of errors to output in dialog
233  // to avoid a too long message list
234 
235  wxString list; // The messages to display
236 
237  m_parent->SetLastNetListRead( netlistFilename );
238 
239  int err_cnt = 0;
240 
241  // Search for duplicate footprints.
242  if( duplicate.size() == 0 )
243  list << wxT("<p><b>") << _( "No duplicate." ) << wxT("</b></p>");
244  else
245  {
246  list << wxT("<p><b>") << _( "Duplicates:" ) << wxT("</b></p>");
247 
248  for( unsigned ii = 0; ii < duplicate.size(); ii++ )
249  {
250  MODULE* module = duplicate[ii];
251 
252  if( module->GetReference().IsEmpty() )
253  list << wxT("<br>") << wxT("[noref)");
254  else
255  list << wxT("<br>") << module->GetReference();
256 
257  list << wxT(" (<i>") << module->GetValue() << wxT("</i>)");
258  list << wxT(" @ ");
259  list << CoordinateToString( module->GetPosition().x ),
260  list << wxT(", ") << CoordinateToString( module->GetPosition().y ),
261  err_cnt++;
262 
263  if( ERR_CNT_MAX < err_cnt )
264  break;
265  }
266  }
267 
268  // Search for missing modules on board.
269  if( missing.size() == 0 )
270  list << wxT("<p><b>") << _( "No missing footprints." ) << wxT("</b></p>");
271  else
272  {
273  list << wxT("<p><b>") << _( "Missing:" ) << wxT("</b></p>");
274 
275  for( unsigned ii = 0; ii < missing.size(); ii += 2 )
276  {
277  list << wxT("<br>") << missing[ii];
278  list << wxT(" (<i>") << missing[ii+1] << wxT("</i>)");
279  err_cnt++;
280 
281  if( ERR_CNT_MAX < err_cnt )
282  break;
283  }
284  }
285 
286 
287  // Search for modules found on board but not in net list.
288  if( notInNetlist.size() == 0 )
289  list << wxT( "<p><b>" ) << _( "No extra footprints." ) << wxT( "</b></p>" );
290  else
291  {
292  list << wxT( "<p><b>" ) << _( "Not in Netlist:" ) << wxT( "</b></p>" );
293 
294  for( unsigned ii = 0; ii < notInNetlist.size(); ii++ )
295  {
296  MODULE* module = notInNetlist[ii];
297 
298  if( module->GetReference().IsEmpty() )
299  list << wxT( "<br>" ) << wxT( "[noref)" );
300  else
301  list << wxT( "<br>" ) << module->GetReference() ;
302 
303  list << wxT( " (<i>" ) << module->GetValue() << wxT( "</i>)" );
304  list << wxT( " @ " );
305  list << CoordinateToString( module->GetPosition().x ),
306  list << wxT( ", " ) << CoordinateToString( module->GetPosition().y ),
307  err_cnt++;
308 
309  if( ERR_CNT_MAX < err_cnt )
310  break;
311  }
312  }
313 
314  if( ERR_CNT_MAX < err_cnt )
315  {
316  list << wxT( "<p><b>" )
317  << _( "Too many errors: some are skipped" )
318  << wxT( "</b></p>" );
319  }
320 
321  HTML_MESSAGE_BOX dlg( this, _( "Check footprints" ) );
322  dlg.AddHTML_Text( list );
323  dlg.ShowModal();
324 }
325 
326 
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 
343 void DIALOG_NETLIST::OnCancelClick( wxCommandEvent& event )
344 {
345  EndModal( wxID_CANCEL );
346 }
347 
348 
349 void DIALOG_NETLIST::OnUpdateUIValidNetlistFile( wxUpdateUIEvent& aEvent )
350 {
351  aEvent.Enable( !m_NetlistFilenameCtrl->GetValue().IsEmpty() );
352 }
353 
354 
355 bool DIALOG_NETLIST::verifyFootprints( const wxString& aNetlistFilename,
356  const wxString & aCmpFilename,
357  std::vector< MODULE* >& aDuplicates,
358  wxArrayString& aMissing,
359  std::vector< MODULE* >& aNotInNetlist )
360 {
361  wxString msg;
362  MODULE* module;
363  MODULE* nextModule;
364  NETLIST netlist;
365  wxBusyCursor dummy; // Shows an hourglass while calculating.
366  NETLIST_READER* netlistReader;
367  COMPONENT* component;
368 
369  try
370  {
371  netlistReader = NETLIST_READER::GetNetlistReader( &netlist, aNetlistFilename,
372  aCmpFilename );
373 
374  if( netlistReader == NULL )
375  {
376  msg.Printf( _( "Cannot open netlist file \"%s\"." ), GetChars( aNetlistFilename ) );
377  wxMessageBox( msg, _( "Netlist Load Error." ), wxOK | wxICON_ERROR );
378  return false;
379  }
380 
381  std::unique_ptr< NETLIST_READER > nlr( netlistReader );
382  netlistReader->LoadNetlist();
383  }
384  catch( const IO_ERROR& ioe )
385  {
386  msg.Printf( _( "Error loading netlist file:\n%s" ), ioe.What().GetData() );
387  wxMessageBox( msg, _( "Netlist Load Error" ), wxOK | wxICON_ERROR );
388  return false;
389  }
390 
391  BOARD* pcb = m_parent->GetBoard();
392 
393  // Search for duplicate footprints.
394  module = pcb->m_Modules;
395 
396  for( ; module != NULL; module = module->Next() )
397  {
398  nextModule = module->Next();
399 
400  for( ; nextModule != NULL; nextModule = nextModule->Next() )
401  {
402  if( module->GetReference().CmpNoCase( nextModule->GetReference() ) == 0 )
403  {
404  aDuplicates.push_back( module );
405  break;
406  }
407  }
408  }
409 
410  // Search for component footprints in the netlist but not on the board.
411  for( unsigned ii = 0; ii < netlist.GetCount(); ii++ )
412  {
413  component = netlist.GetComponent( ii );
414 
415  module = pcb->FindModuleByReference( component->GetReference() );
416 
417  if( module == NULL )
418  {
419  aMissing.Add( component->GetReference() );
420  aMissing.Add( component->GetValue() );
421  }
422  }
423 
424  // Search for component footprints found on board but not in netlist.
425  module = pcb->m_Modules;
426 
427  for( ; module != NULL; module = module->Next() )
428  {
429 
430  component = netlist.GetComponentByReference( module->GetReference() );
431 
432  if( component == NULL )
433  aNotInNetlist.push_back( module );
434  }
435 
436  return true;
437 }
void SetVisibleSeverities(int aSeverities)
Set the visible severity filter.
wxString CoordinateToString(int aValue, bool aConvertToMils)
Function CoordinateToString is a helper to convert the integer coordinate aValue to a string in inche...
Definition: base_units.cpp:118
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.
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.
void SetLastNetListRead(const wxString &aNetListFile)
Set the last net list successfully read by the net list dialog box.
const wxString ProjectFileExtension
DIALOG_NETLIST(PCB_EDIT_FRAME *aParent, wxDC *aDC, const wxString &aNetlistFullFilename)
Class BOARD to handle a board.
wxConfigBase * m_config
MODULE * Next() const
Definition: class_module.h:121
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
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:486
Class REPORTER is a pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:61
void OnTestFootprintsClick(wxCommandEvent &event) override
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
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
Definition: kicad.cpp:52
This file contains miscellaneous commonly used macros and functions.
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)
Function KiBitmap constructs a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:78
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
>
const wxString NetlistFileExtension
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
void OnOpenNetlistClick(wxCommandEvent &event) override
const wxString & GetFileName() const
Definition: class_board.h:234
wxString NetlistFileWildcard()
bool IsEmpty() const
Definition: class_board.h:269
REPORTER & Reporter()
returns the reporter object that reports to this panel
#define NETLIST_SILENTMODE_KEY
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:383
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...
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
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:169
const wxString & GetReference() const
Function GetReference.
Definition: class_module.h:458
DLIST< MODULE > m_Modules
Definition: class_board.h:245
void AddHTML_Text(const wxString &message)
Function AddHTML_Text adds html text (without any change) to message list.
void OnCancelClick(wxCommandEvent &event) override
void OnUpdateUIValidNetlistFile(wxUpdateUIEvent &aEvent) override
Class PCB_EDIT_FRAME is the main frame for Pcbnew.
void OnCompileRatsnestClick(wxCommandEvent &event) override
void MsgPanelSetMinSize(const wxSize &aMinSize)
Set the min size of the area which displays html messages:
COMPONENT * GetComponentByReference(const wxString &aReference)
Function GetComponentByReference returns a COMPONENT by aReference.
Module description (excepted pads)
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.
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:216
#define GROUP_PCB
Names of sub sections where to store project info in *.pro project config files.
Definition: config_params.h:43
void OnReadNetlistFileClick(wxCommandEvent &event) override
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:47
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Function IsOK displays a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:233
const wxPoint GetPosition() const override
Definition: class_module.h:182
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Function GetConnectivity() returns list of missing connections between components/tracks.
Definition: class_board.h:291
#define ERR_CNT_MAX