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-2013 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 <wxPcbStruct.h>
38 #include <pcb_netlist.h>
39 #include <netlist_reader.h>
40 #include <reporter.h>
41 
43 #include <class_board.h>
44 #include <class_module.h>
45 #include <connectivity.h>
47 
48 #include <dialog_netlist.h>
49 #include <wx_html_report_panel.h>
50 
51 #define NETLIST_SILENTMODE_KEY wxT("SilentMode")
52 #define NETLIST_FILTER_MESSAGES_KEY wxT("NetlistReportFilterMsg")
53 #define NETLIST_DELETESINGLEPADNETS_KEY wxT("NetlistDeleteSinglePadNets")
54 
56 {
57  /* Setup the netlist file name to the last netlist file read,
58  * or the board file name if the last filename is empty or last file not existing.
59  */
60  wxString netlistName = GetLastNetListRead();
61 
62  wxFileName fn = netlistName;
63 
64  if( !fn.IsOk() || !fn.FileExists() )
65  {
66  fn = GetBoard()->GetFileName();
67  fn.SetExt( NetlistFileExtension );
68 
69  if( fn.GetName().IsEmpty() )
70  netlistName.Clear();
71  else
72  netlistName = fn.GetFullPath();
73  }
74 
75  DIALOG_NETLIST dlg( this, DC, netlistName );
76 
77  dlg.ShowModal();
78 
79  // Save project settings if needed.
80  // Project settings are saved in the corresponding <board name>.pro file
81  bool configChanged = !GetLastNetListRead().IsEmpty() && ( netlistName != GetLastNetListRead() );
82 
83  if( configChanged && !GetBoard()->GetFileName().IsEmpty()
84  && IsOK( NULL, _( "The project configuration has changed. Do you want to save it?" ) ) )
85  {
86  fn = Prj().AbsolutePath( GetBoard()->GetFileName() );
87  fn.SetExt( ProjectFileExtension );
88 
89  wxString pro_name = fn.GetFullPath();
90 
91  Prj().ConfigSave( Kiface().KifaceSearch(), GROUP_PCB,
92  GetProjectFileParameters(), pro_name );
93  }
94 }
95 
96 
98  const wxString & aNetlistFullFilename )
99  : DIALOG_NETLIST_FBP( aParent )
100 {
101  m_parent = aParent;
102  m_dc = aDC;
104 
106  bool tmp = m_config->Read( NETLIST_DELETESINGLEPADNETS_KEY, 0l );
107  m_rbSingleNets->SetSelection( tmp == 0 ? 0 : 1);
108  m_NetlistFilenameCtrl->SetValue( aNetlistFullFilename );
109  m_checkBoxSilentMode->SetValue( m_silentMode );
110 
111  int severities = m_config->Read( NETLIST_FILTER_MESSAGES_KEY, -1l );
112  m_MessageWindow->SetVisibleSeverities( severities );
113 
114  // Update sizes and sizers:
115  m_MessageWindow->MsgPanelSetMinSize( wxSize( -1, 150 ) );
116  GetSizer()->SetSizeHints( this );
117 }
118 
120 {
121  m_config->Write( NETLIST_SILENTMODE_KEY, (long) m_silentMode );
123  (long) m_rbSingleNets->GetSelection() );
126 }
127 
128 
129 void DIALOG_NETLIST::OnOpenNetlistClick( wxCommandEvent& event )
130 {
131  wxString lastPath = wxFileName( Prj().GetProjectFullName() ).GetPath();
132 
133  wxString lastNetlistRead = m_parent->GetLastNetListRead();
134 
135  if( !lastNetlistRead.IsEmpty() && !wxFileName::FileExists( lastNetlistRead ) )
136  {
137  lastNetlistRead = wxEmptyString;
138  }
139  else
140  {
141  wxFileName fn = lastNetlistRead;
142  lastPath = fn.GetPath();
143  lastNetlistRead = fn.GetFullName();
144  }
145 
146  wxLogDebug( wxT( "Last net list read path '%s', file name '%s'." ),
147  GetChars( lastPath ), GetChars( lastNetlistRead ) );
148 
149  wxFileDialog FilesDialog( this, _( "Select Netlist" ), lastPath, lastNetlistRead,
150  NetlistFileWildcard, wxFD_DEFAULT_STYLE | wxFD_FILE_MUST_EXIST );
151 
152  if( FilesDialog.ShowModal() != wxID_OK )
153  return;
154 
155  m_NetlistFilenameCtrl->SetValue( FilesDialog.GetPath() );
156 }
157 
158 void DIALOG_NETLIST::OnReadNetlistFileClick( wxCommandEvent& event )
159 {
160  wxString netlistFileName = m_NetlistFilenameCtrl->GetValue();
161  wxFileName fn = netlistFileName;
162 
163  if( !fn.IsOk() )
164  {
165  wxMessageBox( _("Please, choose a valid netlist file") );
166  return;
167  }
168 
169  if( !fn.FileExists() )
170  {
171  wxMessageBox( _("The netlist file does not exist") );
172  return;
173  }
174 
175  // Give the user a chance to bail out when making changes from a netlist.
176  if( !m_checkDryRun->GetValue() && !m_silentMode
177  && !m_parent->GetBoard()->IsEmpty()
178  && !IsOK( NULL, _( "The changes made by reading the netlist cannot be undone. Are you "
179  "sure you want to read the netlist?" ) ) )
180  return;
181 
183  REPORTER& reporter = m_MessageWindow->Reporter();
184 
185  wxBusyCursor busy;
186 
187  wxString msg;
188  msg.Printf( _( "Reading netlist file \"%s\".\n" ), GetChars( netlistFileName ) );
189  reporter.Report( msg, REPORTER::RPT_INFO );
190 
191  if( m_Select_By_Timestamp->GetSelection() == 1 )
192  msg = _( "Using time stamps to match components and footprints.\n" );
193  else
194  msg = _( "Using references to match components and footprints.\n" );
195 
196  reporter.Report( msg, REPORTER::RPT_INFO );
197  m_MessageWindow->SetLazyUpdate( true ); // use a "lazy" update to speed up the creation of the report
198  // (The window is not updated for each message)
199 
200  m_parent->ReadPcbNetlist( netlistFileName, wxEmptyString, &reporter,
201  m_ChangeExistingFootprintCtrl->GetSelection() == 1,
202  m_DeleteBadTracks->GetSelection() == 1,
203  m_RemoveExtraFootprintsCtrl->GetSelection() == 1,
204  m_Select_By_Timestamp->GetSelection() == 1,
205  m_rbSingleNets->GetSelection() == 1,
206  m_checkDryRun->GetValue() );
207  // The creation of the report was made without window update:
208  // the full page must be displayed
210 }
211 
212 
213 void DIALOG_NETLIST::OnTestFootprintsClick( wxCommandEvent& event )
214 {
215  if( m_parent->GetBoard()->m_Modules == NULL )
216  {
217  DisplayInfoMessage( this, _( "No footprints" ) );
218  return;
219  }
220 
221  // Lists of duplicates, missing references and not in netlist footprints:
222  std::vector <MODULE*> duplicate;
223  wxArrayString missing;
224  std::vector <MODULE*> notInNetlist;
225  wxString netlistFilename = m_NetlistFilenameCtrl->GetValue();
226 
227  if( !verifyFootprints( netlistFilename, wxEmptyString, duplicate, missing, notInNetlist ) )
228  return;
229 
230  #define ERR_CNT_MAX 100 // Max number of errors to output in dialog
231  // to avoid a too long message list
232 
233  wxString list; // The messages to display
234 
235  m_parent->SetLastNetListRead( netlistFilename );
236 
237  int err_cnt = 0;
238 
239  // Search for duplicate footprints.
240  if( duplicate.size() == 0 )
241  list << wxT("<p><b>") << _( "No duplicate." ) << wxT("</b></p>");
242  else
243  {
244  list << wxT("<p><b>") << _( "Duplicates:" ) << wxT("</b></p>");
245 
246  for( unsigned ii = 0; ii < duplicate.size(); ii++ )
247  {
248  MODULE* module = duplicate[ii];
249 
250  if( module->GetReference().IsEmpty() )
251  list << wxT("<br>") << wxT("[noref)");
252  else
253  list << wxT("<br>") << module->GetReference();
254 
255  list << wxT(" (<i>") << module->GetValue() << wxT("</i>)");
256  list << wxT(" @ ");
257  list << CoordinateToString( module->GetPosition().x ),
258  list << wxT(", ") << CoordinateToString( module->GetPosition().y ),
259  err_cnt++;
260 
261  if( ERR_CNT_MAX < err_cnt )
262  break;
263  }
264  }
265 
266  // Search for missing modules on board.
267  if( missing.size() == 0 )
268  list << wxT("<p><b>") << _( "No missing footprints." ) << wxT("</b></p>");
269  else
270  {
271  list << wxT("<p><b>") << _( "Missing:" ) << wxT("</b></p>");
272 
273  for( unsigned ii = 0; ii < missing.size(); ii += 2 )
274  {
275  list << wxT("<br>") << missing[ii];
276  list << wxT(" (<i>") << missing[ii+1] << wxT("</i>)");
277  err_cnt++;
278 
279  if( ERR_CNT_MAX < err_cnt )
280  break;
281  }
282  }
283 
284 
285  // Search for modules found on board but not in net list.
286  if( notInNetlist.size() == 0 )
287  list << wxT( "<p><b>" ) << _( "No extra footprints." ) << wxT( "</b></p>" );
288  else
289  {
290  list << wxT( "<p><b>" ) << _( "Not in Netlist:" ) << wxT( "</b></p>" );
291 
292  for( unsigned ii = 0; ii < notInNetlist.size(); ii++ )
293  {
294  MODULE* module = notInNetlist[ii];
295 
296  if( module->GetReference().IsEmpty() )
297  list << wxT( "<br>" ) << wxT( "[noref)" );
298  else
299  list << wxT( "<br>" ) << module->GetReference() ;
300 
301  list << wxT( " (<i>" ) << module->GetValue() << wxT( "</i>)" );
302  list << wxT( " @ " );
303  list << CoordinateToString( module->GetPosition().x ),
304  list << wxT( ", " ) << CoordinateToString( module->GetPosition().y ),
305  err_cnt++;
306 
307  if( ERR_CNT_MAX < err_cnt )
308  break;
309  }
310  }
311 
312  if( ERR_CNT_MAX < err_cnt )
313  {
314  list << wxT( "<p><b>" )
315  << _( "Too many errors: some are skipped" )
316  << wxT( "</b></p>" );
317  }
318 
319  HTML_MESSAGE_BOX dlg( this, _( "Check footprints" ) );
320  dlg.AddHTML_Text( list );
321  dlg.ShowModal();
322 }
323 
324 
329 void DIALOG_NETLIST::OnCompileRatsnestClick( wxCommandEvent& event )
330 {
331  // Rebuild the board connectivity:
332  auto board = m_parent->GetBoard();
333  board->GetConnectivity()->RecalculateRatsnest();
334 }
335 
336 
341 void DIALOG_NETLIST::OnCancelClick( wxCommandEvent& event )
342 {
343  EndModal( wxID_CANCEL );
344 }
345 
346 
347 void DIALOG_NETLIST::OnSaveMessagesToFile( wxCommandEvent& aEvent )
348 {
349  wxFileName fn;
350 
351  if( !m_parent->GetLastNetListRead().IsEmpty() )
352  {
354  fn.SetExt( wxT( "txt" ) );
355  }
356  else
357  {
358  fn = wxPathOnly( Prj().GetProjectFullName() );
359  }
360 
361  wxFileDialog dlg( this, _( "Save contents of message window" ), fn.GetPath(), fn.GetName(),
362  TextWildcard, wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
363 
364  if( dlg.ShowModal() != wxID_OK )
365  return;
366 
367  fn = dlg.GetPath();
368 
369  if( fn.GetExt().IsEmpty() )
370  fn.SetExt( wxT( "txt" ) );
371 
372  wxFile f( fn.GetFullPath(), wxFile::write );
373 
374  if( !f.IsOpened() )
375  {
376  wxString msg;
377 
378  msg.Printf( _( "Cannot write message contents to file \"%s\"." ),
379  GetChars( fn.GetFullPath() ) );
380  wxMessageBox( msg, _( "File Write Error" ), wxOK | wxICON_ERROR, this );
381  return;
382  }
383 }
384 
385 
386 void DIALOG_NETLIST::OnUpdateUISaveMessagesToFile( wxUpdateUIEvent& aEvent )
387 {
388  //aEvent.Enable( !m_MessageWindow->IsEmpty() );
389 }
390 
391 
392 void DIALOG_NETLIST::OnUpdateUIValidNetlistFile( wxUpdateUIEvent& aEvent )
393 {
394  aEvent.Enable( !m_NetlistFilenameCtrl->GetValue().IsEmpty() );
395 }
396 
397 
398 bool DIALOG_NETLIST::verifyFootprints( const wxString& aNetlistFilename,
399  const wxString & aCmpFilename,
400  std::vector< MODULE* >& aDuplicates,
401  wxArrayString& aMissing,
402  std::vector< MODULE* >& aNotInNetlist )
403 {
404  wxString msg;
405  MODULE* module;
406  MODULE* nextModule;
407  NETLIST netlist;
408  wxBusyCursor dummy; // Shows an hourglass while calculating.
409  NETLIST_READER* netlistReader;
410  COMPONENT* component;
411 
412  try
413  {
414  netlistReader = NETLIST_READER::GetNetlistReader( &netlist, aNetlistFilename,
415  aCmpFilename );
416 
417  if( netlistReader == NULL )
418  {
419  msg.Printf( _( "Cannot open netlist file \"%s\"." ), GetChars( aNetlistFilename ) );
420  wxMessageBox( msg, _( "Netlist Load Error." ), wxOK | wxICON_ERROR );
421  return false;
422  }
423 
424  std::unique_ptr< NETLIST_READER > nlr( netlistReader );
425  netlistReader->LoadNetlist();
426  }
427  catch( const IO_ERROR& ioe )
428  {
429  msg.Printf( _( "Error loading netlist file:\n%s" ), ioe.What().GetData() );
430  wxMessageBox( msg, _( "Netlist Load Error" ), wxOK | wxICON_ERROR );
431  return false;
432  }
433 
434  BOARD* pcb = m_parent->GetBoard();
435 
436  // Search for duplicate footprints.
437  module = pcb->m_Modules;
438 
439  for( ; module != NULL; module = module->Next() )
440  {
441  nextModule = module->Next();
442 
443  for( ; nextModule != NULL; nextModule = nextModule->Next() )
444  {
445  if( module->GetReference().CmpNoCase( nextModule->GetReference() ) == 0 )
446  {
447  aDuplicates.push_back( module );
448  break;
449  }
450  }
451  }
452 
453  // Search for component footprints in the netlist but not on the board.
454  for( unsigned ii = 0; ii < netlist.GetCount(); ii++ )
455  {
456  component = netlist.GetComponent( ii );
457 
458  module = pcb->FindModuleByReference( component->GetReference() );
459 
460  if( module == NULL )
461  {
462  aMissing.Add( component->GetReference() );
463  aMissing.Add( component->GetValue() );
464  }
465  }
466 
467  // Search for component footprints found on board but not in netlist.
468  module = pcb->m_Modules;
469 
470  for( ; module != NULL; module = module->Next() )
471  {
472 
473  component = netlist.GetComponentByReference( module->GetReference() );
474 
475  if( component == NULL )
476  aNotInNetlist.push_back( module );
477  }
478 
479  return true;
480 }
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:117
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:307
void OnSaveMessagesToFile(wxCommandEvent &aEvent) override
PARAM_CFG_ARRAY GetProjectFileParameters()
Function GetProjectFileParameters returns a project file parameter list for Pcbnew.
wxCheckBox * m_checkBoxSilentMode
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 wxString ProjectFileExtension
void SetLastNetListRead(const wxString &aNetListFile)
Set the last net list successfully read by the net list dialog box.
Definition: pcbframe.cpp:981
DIALOG_NETLIST(PCB_EDIT_FRAME *aParent, wxDC *aDC, const wxString &aNetlistFullFilename)
Class BOARD to handle a board.
wxConfigBase * m_config
const wxPoint & GetPosition() const override
Definition: class_module.h:155
MODULE * Next() const
Definition: class_module.h:100
const wxString NetlistFileExtension
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:447
wxRadioBox * m_rbSingleNets
wxRadioBox * m_RemoveExtraFootprintsCtrl
Class REPORTER is a pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:61
void OnTestFootprintsClick(wxCommandEvent &event) override
const wxString TextWildcard
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...
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:149
const wxString & GetValue() const
Definition: pcb_netlist.h:151
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:205
void OnOpenNetlistClick(wxCommandEvent &event) override
const wxString & GetFileName() const
Definition: class_board.h:234
bool IsEmpty() const
Definition: class_board.h:268
REPORTER & Reporter()
returns the reporter object that reports to this panel
const wxString NetlistFileWildcard
#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's directory to be an absolu...
Definition: project.cpp:371
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 DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString aExtraInfo)
Function DisplayInfoMessage displays an informational message box with aMessage.
Definition: confirm.cpp:102
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
COMPONENT * GetComponent(unsigned aIndex)
Function GetComponent returns the COMPONENT at aIndex.
Definition: pcb_netlist.h:256
wxString GetLastNetListRead()
Get the last net list read with the net list dialog box.
Definition: pcbframe.cpp:966
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
wxRadioBox * m_DeleteBadTracks
void Flush()
Forces updating the HTML page, after the report is built in lazy mode
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:419
DLIST< MODULE > m_Modules
Definition: class_board.h:245
wxTextCtrl * m_NetlistFilenameCtrl
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
void OnCompileRatsnestClick(wxCommandEvent &event) override
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_UNDEFINED)=0
Function Report is a pure virtual function to override in the derived object.
wxRadioBox * m_ChangeExistingFootprintCtrl
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.
void OnUpdateUISaveMessagesToFile(wxUpdateUIEvent &aEvent) override
Module description (excepted pads)
Class DIALOG_NETLIST_FBP.
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.
wxCheckBox * m_checkDryRun
unsigned GetCount() const
Function GetCount.
Definition: pcb_netlist.h:247
#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:129
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Function GetConnectivity() returns list of missing connections between components/tracks.
Definition: class_board.h:290
WX_HTML_REPORT_PANEL * m_MessageWindow
#define ERR_CNT_MAX
wxRadioBox * m_Select_By_Timestamp