KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_export_netlist.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2013-2017 Jean-Pierre Charras, [email protected]
5 * Copyright (C) 2013 Wayne Stambaugh <[email protected]>
6 * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26/* Functions relative to the dialog creating the netlist for Pcbnew. The dialog is a notebook
27 * with 7 fixed netlist formats:
28 * Pcbnew
29 * ORCADPCB2
30 * Allegro
31 * CADSTAR
32 * Pads
33 * SPICE
34 * SPICE model
35 * and up to CUSTOMPANEL_COUNTMAX user programmable formats. These external converters are
36 * referred to as plugins, but they are really just external binaries.
37 */
38
39#include <pgm_base.h>
40#include <kiface_base.h>
41#include <gestfich.h>
43#include <sch_edit_frame.h>
46#include <invoke_sch_dialog.h>
48#include <eeschema_settings.h>
49#include <schematic.h>
50#include <paths.h>
52
53#include <eeschema_id.h>
54#include <wx/checkbox.h>
55#include <wx/filedlg.h>
56#include <wx/msgdlg.h>
57#include <wx/regex.h>
58#include <wx/txtstrm.h>
59
60#include <thread>
61
62
63#define CUSTOMPANEL_COUNTMAX 8 // Max number of netlist plugins
64
65/*
66 * PANEL_NETLIST_INDEX values are used as index in m_PanelNetType[]
67 */
69{
70 PANELPCBNEW = 0, /* Handle Netlist format Pcbnew */
71 PANELORCADPCB2, /* Handle Netlist format OracdPcb2 */
72 PANELALLEGRO, /* Handle Netlist format Allegro */
73 PANELCADSTAR, /* Handle Netlist format CadStar */
74 PANELPADS, /* Handle Netlist format PADS */
75 PANELSPICE, /* Handle Netlist format Spice */
76 PANELSPICEMODEL, /* Handle Netlist format Spice Model (subcircuit) */
78
79 /* First auxiliary panel (custom netlists). Subsequent ones use PANELCUSTOMBASE+1,
80 * PANELCUSTOMBASE+2, etc., up to PANELCUSTOMBASE+CUSTOMPANEL_COUNTMAX-1 */
82};
83
84
85std::map<JOB_EXPORT_SCH_NETLIST::FORMAT, wxString> jobNetlistNameLookup =
86{
88 { JOB_EXPORT_SCH_NETLIST::FORMAT::ORCADPCB2, wxT( "OrcadPCB2" ) },
89 { JOB_EXPORT_SCH_NETLIST::FORMAT::ALLEGRO, wxT( "Allegro" ) },
90 { JOB_EXPORT_SCH_NETLIST::FORMAT::PADS, wxT( "CadStar" ) },
91 { JOB_EXPORT_SCH_NETLIST::FORMAT::SPICE, wxT( "SPICE" ) },
92 { JOB_EXPORT_SCH_NETLIST::FORMAT::SPICEMODEL, wxT( "SPICE Model" ) }
93};
94
95/* wxPanels for creating the NoteBook pages for each netlist format: */
96class EXPORT_NETLIST_PAGE : public wxPanel
97{
98
99public:
109 EXPORT_NETLIST_PAGE( wxNotebook* aParent, const wxString& aTitle,
110 NETLIST_TYPE_ID aIdNetType, bool aCustom );
112
116 const wxString GetPageNetFmtName() { return m_pageNetFmtName; }
117
119 // opt to reformat passive component values (e.g. 1M -> 1Meg):
120 wxCheckBox* m_CurSheetAsRoot;
121 wxCheckBox* m_SaveAllVoltages;
122 wxCheckBox* m_SaveAllCurrents;
124 wxCheckBox* m_SaveAllEvents;
127 wxTextCtrl* m_TitleStringCtrl;
128 wxBoxSizer* m_LeftBoxSizer;
129 wxBoxSizer* m_RightBoxSizer;
131 wxBoxSizer* m_LowBoxSizer;
132
133 bool IsCustom() const { return m_custom; }
134
135private:
137
139};
140
141
143{
144public:
146
147 const wxString GetGeneratorTitle() { return m_textCtrlName->GetValue(); }
148 const wxString GetGeneratorTCommandLine() { return m_textCtrlCommand->GetValue(); }
149
150 bool TransferDataFromWindow() override;
151
152private:
153 /*
154 * Browse plugin files, and set m_CommandStringCtrl field
155 */
156 void OnBrowseGenerators( wxCommandEvent& event ) override;
157
159};
160
161
162/* Event id for notebook page buttons: */
172
173
174EXPORT_NETLIST_PAGE::EXPORT_NETLIST_PAGE( wxNotebook* aParent, const wxString& aTitle,
175 NETLIST_TYPE_ID aIdNetType, bool aCustom ) :
176 wxPanel( aParent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL )
177{
178 m_IdNetType = aIdNetType;
179 m_pageNetFmtName = aTitle;
180 m_CommandStringCtrl = nullptr;
181 m_CurSheetAsRoot = nullptr;
182 m_TitleStringCtrl = nullptr;
183 m_SaveAllVoltages = nullptr;
184 m_SaveAllCurrents = nullptr;
185 m_SaveAllDissipations = nullptr;
186 m_SaveAllEvents = nullptr;
188 m_custom = aCustom;
189
190 aParent->AddPage( this, aTitle, false );
191
192 wxBoxSizer* MainBoxSizer = new wxBoxSizer( wxVERTICAL );
193 SetSizer( MainBoxSizer );
194 wxBoxSizer* UpperBoxSizer = new wxBoxSizer( wxHORIZONTAL );
195 m_LowBoxSizer = new wxBoxSizer( wxVERTICAL );
196 MainBoxSizer->Add( UpperBoxSizer, 0, wxGROW | wxALL, 5 );
197 MainBoxSizer->Add( m_LowBoxSizer, 0, wxGROW | wxALL, 5 );
198
199 m_LeftBoxSizer = new wxBoxSizer( wxVERTICAL );
200 m_RightBoxSizer = new wxBoxSizer( wxVERTICAL );
201 m_RightOptionsBoxSizer = new wxBoxSizer( wxVERTICAL );
202 UpperBoxSizer->Add( m_LeftBoxSizer, 0, wxGROW | wxALL, 5 );
203 UpperBoxSizer->Add( m_RightBoxSizer, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
204 UpperBoxSizer->Add( m_RightOptionsBoxSizer, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
205}
206
207
209 DIALOG_EXPORT_NETLIST( aEditFrame, aEditFrame )
210{
211
212}
213
214
216 JOB_EXPORT_SCH_NETLIST* aJob ) :
218 m_job( aJob )
219{
220 m_editFrame = aEditFrame;
221
222 // Initialize the array of netlist pages
224
226
227 // Add notebook pages:
228 EXPORT_NETLIST_PAGE* page = nullptr;
229 wxStaticText* label = nullptr;
230
231 page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "KiCad" ), NET_TYPE_PCBNEW, false );
232 label = new wxStaticText( page, wxID_ANY, _( "Export netlist in legacy KiCad format" ) );
233 page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
235
236 page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "OrcadPCB2" ), NET_TYPE_ORCADPCB2, false );
237 label = new wxStaticText( page, wxID_ANY, _( "Export netlist in OrcadPCB2 format" ) );
238 page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
240
241 page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "Allegro" ), NET_TYPE_ALLEGRO, false );
242 label = new wxStaticText( page, wxID_ANY, _( "Export netlist in Allegro format" ) );
243 page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
245
246 page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "PADS" ), NET_TYPE_PADS, false );
247 label = new wxStaticText( page, wxID_ANY, _( "Export netlist in PADS format" ) );
248 page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
250
251 page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "CadStar" ), NET_TYPE_CADSTAR, false );
252 label = new wxStaticText( page, wxID_ANY, _( "Export netlist in CadStar format" ) );
253 page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
255
258
259 wxString selectedPageFormatName;
260 if( !m_job )
261 {
262 m_outputPath->Hide();
265
266 SetupStandardButtons( { { wxID_OK, _( "Export Netlist" ) },
267 { wxID_CANCEL, _( "Close" ) } } );
268
269 selectedPageFormatName = settings.m_NetFormatName;
270 }
271 else
272 {
273 m_MessagesBox->Hide();
274 m_outputPath->SetValue( m_job->GetOutputPath() );
275
276 SetupStandardButtons( { { wxID_OK, _( "Save" ) },
277 { wxID_CANCEL, _( "Close" ) } } );
278
279 // custom netlist (external invokes, not supported)
280 auto it = jobNetlistNameLookup.find( m_job->format );
281
282 if( it != jobNetlistNameLookup.end() )
283 selectedPageFormatName = it->second;
284
285 m_buttonAddGenerator->Hide();
286 m_buttonDelGenerator->Hide();
287 }
288
289 for( int ii = 0; ii < DEFINED_NETLISTS_COUNT + CUSTOMPANEL_COUNTMAX; ++ii )
290 {
291 if( EXPORT_NETLIST_PAGE* candidate = m_PanelNetType[ii] )
292 {
293 if( candidate->GetPageNetFmtName() == selectedPageFormatName )
294 {
295 m_NoteBook->ChangeSelection( ii );
296 break;
297 }
298 }
299 }
300
301 // Now all widgets have the size fixed, call FinishDialogSettings
303
305}
306
307
309{
311 new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "SPICE" ), NET_TYPE_SPICE, false );
312
314
315 wxStaticText* label = new wxStaticText( page, wxID_ANY, _( "Export netlist in SPICE format" ) );
316 page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
317
318 page->m_CurSheetAsRoot = new wxCheckBox( page, ID_CUR_SHEET_AS_ROOT,
319 _( "Use current sheet as root" ) );
320 page->m_CurSheetAsRoot->SetToolTip( _( "Export netlist only for the current sheet" ) );
321 page->m_CurSheetAsRoot->SetValue( settings.m_SpiceCurSheetAsRoot );
322 page->m_LeftBoxSizer->Add( page->m_CurSheetAsRoot, 0, wxGROW | wxBOTTOM | wxRIGHT, 5 );
323
324 page->m_SaveAllVoltages = new wxCheckBox( page, ID_SAVE_ALL_VOLTAGES,
325 _( "Save all voltages" ) );
326 page->m_SaveAllVoltages->SetToolTip( _( "Write a directive to save all voltages (.save all)" ) );
327 page->m_SaveAllVoltages->SetValue( settings.m_SpiceSaveAllVoltages );
328 page->m_LeftBoxSizer->Add( page->m_SaveAllVoltages, 0, wxBOTTOM | wxRIGHT, 5 );
329
330 page->m_SaveAllCurrents = new wxCheckBox( page, ID_SAVE_ALL_CURRENTS,
331 _( "Save all currents" ) );
332 page->m_SaveAllCurrents->SetToolTip( _( "Write a directive to save all currents (.probe alli)" ) );
333 page->m_SaveAllCurrents->SetValue( settings.m_SpiceSaveAllCurrents );
334 page->m_LeftBoxSizer->Add( page->m_SaveAllCurrents, 0, wxBOTTOM | wxRIGHT, 5 );
335
336 page->m_SaveAllDissipations = new wxCheckBox( page, ID_SAVE_ALL_DISSIPATIONS,
337 _( "Save all power dissipations" ) );
338 page->m_SaveAllDissipations->SetToolTip( _( "Write directives to save power dissipation of all items (.probe p(<item>))" ) );
339 page->m_SaveAllDissipations->SetValue( settings.m_SpiceSaveAllDissipations );
340 page->m_LeftBoxSizer->Add( page->m_SaveAllDissipations, 0, wxBOTTOM | wxRIGHT, 5 );
341
342 page->m_SaveAllEvents = new wxCheckBox( page, ID_SAVE_ALL_EVENTS,
343 _( "Save all digital event data" ) );
344 page->m_SaveAllEvents->SetToolTip( _( "If not set, write a directive to prevent the saving of digital event data (esave none)" ) );
345 page->m_SaveAllEvents->SetValue( settings.m_SpiceSaveAllEvents );
346 page->m_LeftBoxSizer->Add( page->m_SaveAllEvents, 0, wxBOTTOM | wxRIGHT, 5 );
347
348
349 page->m_RunExternalSpiceCommand = new wxCheckBox( page, ID_RUN_SIMULATOR,
350 _( "Run external simulator command:" ) );
351 wxString simulatorCommand = settings.m_SpiceCommandString;
352 page->m_RunExternalSpiceCommand->SetToolTip( _( "Enter the command line to run SPICE\n"
353 "Usually '<path to SPICE binary> \"%I\"'\n"
354 "%I will be replaced by the netlist filepath" ) );
355 page->m_LowBoxSizer->Add( page->m_RunExternalSpiceCommand, 0,
356 wxGROW | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
357
358 page->m_CommandStringCtrl = new wxTextCtrl( page, -1, simulatorCommand,
359 wxDefaultPosition, wxDefaultSize );
360
361 page->m_CommandStringCtrl->SetInsertionPoint( 1 );
362 page->m_LowBoxSizer->Add( page->m_CommandStringCtrl, 0,
363 wxGROW | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
364}
365
366
368{
370 new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "SPICE Model" ), NET_TYPE_SPICE_MODEL, false );
371
373
374 wxStaticText* label = new wxStaticText( page, wxID_ANY, _( "Export netlist as a SPICE .subckt model" ) );
375 page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
376
377 page->m_CurSheetAsRoot = new wxCheckBox( page, ID_CUR_SHEET_AS_ROOT,
378 _( "Use current sheet as root" ) );
379 page->m_CurSheetAsRoot->SetToolTip( _( "Export netlist only for the current sheet" ) );
380 page->m_CurSheetAsRoot->SetValue( settings.m_SpiceModelCurSheetAsRoot );
381 page->m_LeftBoxSizer->Add( page->m_CurSheetAsRoot, 0, wxGROW | wxBOTTOM | wxRIGHT, 5 );
382}
383
384
386{
387 EXPORT_NETLIST_PAGE* currPage;
388 EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
389 wxCHECK( cfg, /* void */ );
390
391 for( size_t i = 0; i < CUSTOMPANEL_COUNTMAX && i < cfg->m_NetlistPanel.plugins.size(); i++ )
392 {
393 // pairs of (title, command) are stored
394 currPage = AddOneCustomPage( cfg->m_NetlistPanel.plugins[i].name,
395 cfg->m_NetlistPanel.plugins[i].command,
396 static_cast<NETLIST_TYPE_ID>( NET_TYPE_CUSTOM1 + i ) );
397
398 m_PanelNetType[PANELCUSTOMBASE + i] = currPage;
399 }
400}
401
402
404 const wxString& aCommandString,
405 NETLIST_TYPE_ID aNetTypeId )
406{
407 EXPORT_NETLIST_PAGE* currPage = new EXPORT_NETLIST_PAGE( m_NoteBook, aTitle, aNetTypeId, true );
408
409 currPage->m_LowBoxSizer->Add( new wxStaticText( currPage, -1, _( "Title:" ) ), 0,
410 wxGROW | wxLEFT | wxRIGHT | wxTOP, 5 );
411
412 currPage->m_TitleStringCtrl = new wxTextCtrl( currPage, -1, aTitle,
413 wxDefaultPosition, wxDefaultSize );
414
415 currPage->m_TitleStringCtrl->SetInsertionPoint( 1 );
416 currPage->m_LowBoxSizer->Add( currPage->m_TitleStringCtrl, 0,
417 wxGROW | wxTOP | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
418
419 currPage->m_LowBoxSizer->Add( new wxStaticText( currPage, -1, _( "Netlist command:" ) ), 0,
420 wxGROW | wxLEFT | wxRIGHT | wxTOP, 5 );
421
422 currPage->m_CommandStringCtrl = new wxTextCtrl( currPage, -1, aCommandString,
423 wxDefaultPosition, wxDefaultSize );
424
425 currPage->m_CommandStringCtrl->SetInsertionPoint( 1 );
426 currPage->m_LowBoxSizer->Add( currPage->m_CommandStringCtrl, 0,
427 wxGROW | wxTOP | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
428
429 return currPage;
430}
431
432
434{
436}
437
438
440{
441 bool changed = false;
442 bool saveAllVoltages = m_PanelNetType[ PANELSPICE ]->m_SaveAllVoltages->IsChecked();
443 bool saveAllCurrents = m_PanelNetType[ PANELSPICE ]->m_SaveAllCurrents->IsChecked();
444 bool saveAllDissipations = m_PanelNetType[ PANELSPICE ]->m_SaveAllDissipations->IsChecked();
445 bool saveAllEvents = m_PanelNetType[ PANELSPICE ]->m_SaveAllEvents->IsChecked();
446 wxString spiceCmdString = m_PanelNetType[ PANELSPICE ]->m_CommandStringCtrl->GetValue();
447 bool curSheetAsRoot = m_PanelNetType[ PANELSPICE ]->m_CurSheetAsRoot->GetValue();
448 bool spiceModelCurSheetAsRoot = m_PanelNetType[ PANELSPICEMODEL ]->m_CurSheetAsRoot->GetValue();
449
450 if( !m_job )
451 {
453 wxString netFormatName = m_PanelNetType[m_NoteBook->GetSelection()]->GetPageNetFmtName();
454
455 changed |= ( settings.m_SpiceSaveAllVoltages != saveAllVoltages );
456 changed |= ( settings.m_SpiceSaveAllCurrents != saveAllCurrents );
457 changed |= ( settings.m_SpiceSaveAllDissipations != saveAllDissipations );
458 changed |= ( settings.m_SpiceSaveAllEvents != saveAllEvents );
459 changed |= ( settings.m_SpiceCommandString != spiceCmdString );
460 changed |= ( settings.m_SpiceCurSheetAsRoot != curSheetAsRoot );
461 changed |= ( settings.m_SpiceModelCurSheetAsRoot != spiceModelCurSheetAsRoot );
462 changed |= ( settings.m_NetFormatName != netFormatName );
463
464 settings.m_SpiceSaveAllVoltages = saveAllVoltages;
465 settings.m_SpiceSaveAllCurrents = saveAllCurrents;
466 settings.m_SpiceSaveAllDissipations = saveAllDissipations;
467 settings.m_SpiceSaveAllEvents = saveAllEvents;
468 settings.m_SpiceCommandString = spiceCmdString;
469 settings.m_SpiceCurSheetAsRoot = curSheetAsRoot;
470 settings.m_SpiceModelCurSheetAsRoot = spiceModelCurSheetAsRoot;
471 settings.m_NetFormatName = netFormatName;
472 }
473 else
474 {
475 for (auto i = jobNetlistNameLookup.begin(); i != jobNetlistNameLookup.end(); ++i)
476 {
477 if( i->second == m_PanelNetType[m_NoteBook->GetSelection()]->GetPageNetFmtName() )
478 {
479 m_job->format = i->first;
480 break;
481 }
482 }
483
484 m_job->SetOutputPath( m_outputPath->GetValue() );
485 m_job->m_spiceSaveAllVoltages = saveAllVoltages;
486 m_job->m_spiceSaveAllCurrents = saveAllCurrents;
487 m_job->m_spiceSaveAllDissipations = saveAllDissipations;
488 m_job->m_spiceSaveAllEvents = saveAllEvents;
489 }
490
491 return changed;
492}
493
494
496{
497 wxFileName fn;
498 wxString fileWildcard;
499 wxString fileExt;
500 wxString title = _( "Save Netlist File" );
501
502
503 if (m_job)
504 {
506 return true;
507 }
508 else
509 {
510 if( NetlistUpdateOpt() )
512 }
513
514
515 EXPORT_NETLIST_PAGE* currPage;
516 currPage = (EXPORT_NETLIST_PAGE*) m_NoteBook->GetCurrentPage();
517
518 bool runExternalSpiceCommand = false;
519 unsigned netlist_opt = 0;
520
521 // Calculate the netlist filename
523 FilenamePrms( currPage->m_IdNetType, &fileExt, &fileWildcard );
524
525 // Set some parameters
526 switch( currPage->m_IdNetType )
527 {
528 case NET_TYPE_SPICE:
529 // Set spice netlist options:
531
532 if( currPage->m_SaveAllVoltages->GetValue() )
534
535 if( currPage->m_SaveAllCurrents->GetValue() )
537
538 if( currPage->m_SaveAllDissipations->GetValue() )
540
541 if( currPage->m_SaveAllEvents->GetValue() )
543
544 if( currPage->m_CurSheetAsRoot->GetValue() )
546
547 runExternalSpiceCommand = currPage->m_RunExternalSpiceCommand->GetValue();
548 break;
549
551 if( currPage->m_CurSheetAsRoot->GetValue() )
553
554 break;
555
556 case NET_TYPE_CADSTAR:
557 break;
558
559 case NET_TYPE_PCBNEW:
560 break;
561
563 break;
564
565 case NET_TYPE_ALLEGRO:
566 break;
567
568 case NET_TYPE_PADS:
569 break;
570
571 default: // custom, NET_TYPE_CUSTOM1 and greater
572 {
573 title.Printf( _( "%s Export" ), currPage->m_TitleStringCtrl->GetValue() );
574 break;
575 }
576 }
577
578 wxString fullpath;
579
580 if( runExternalSpiceCommand )
581 {
582 fn.SetExt( FILEEXT::SpiceFileExtension );
583 fullpath = fn.GetFullPath();
584 }
585 else
586 {
587 fn.SetExt( fileExt );
588
589 if( fn.GetPath().IsEmpty() )
590 fn.SetPath( wxPathOnly( Prj().GetProjectFullName() ) );
591
592 wxString fullname = fn.GetFullName();
593 wxString path = fn.GetPath();
594
595 // full name does not and should not include the path, per wx docs.
596 wxFileDialog dlg( this, title, path, fullname, fileWildcard, wxFD_SAVE );
597
598 if( dlg.ShowModal() == wxID_CANCEL )
599 return false;
600
601 fullpath = dlg.GetPath(); // directory + filename
602 }
603
605 REPORTER& reporter = m_MessagesBox->Reporter();
606
607 if( currPage->m_CommandStringCtrl )
608 m_editFrame->SetNetListerCommand( currPage->m_CommandStringCtrl->GetValue() );
609 else
610 m_editFrame->SetNetListerCommand( wxEmptyString );
611
613 _( "Exporting netlist requires a fully annotated schematic." ) ) )
614 return false;
615
616 m_editFrame->WriteNetListFile( currPage->m_IdNetType, fullpath, netlist_opt, &reporter );
617
618 if( runExternalSpiceCommand )
619 {
620 // Build the command line
621 wxString commandLine = m_editFrame->Schematic().Settings().m_SpiceCommandString;
622 commandLine.Replace( wxS( "%I" ), fullpath, true );
623 commandLine.Trim( true ).Trim( false );
624
625 if( !commandLine.IsEmpty() )
626 {
627 wxProcess* process = new wxProcess( GetEventHandler(), wxID_ANY );
628 process->Redirect();
629 wxExecute( commandLine, wxEXEC_ASYNC, process );
630
631 reporter.ReportHead( commandLine, RPT_SEVERITY_ACTION );
632 process->Activate();
633
634 std::this_thread::sleep_for( std::chrono::seconds( 1 ) ); // give the process time to start and output any data or errors
635
636 if( process->IsInputAvailable() )
637 {
638 wxInputStream* in = process->GetInputStream();
639 wxTextInputStream textstream( *in );
640
641 while( in->CanRead() )
642 {
643 wxString line = textstream.ReadLine();
644
645 if( !line.IsEmpty() )
646 reporter.Report( line, RPT_SEVERITY_INFO );
647 }
648 }
649
650 if( process->IsErrorAvailable() )
651 {
652 wxInputStream* err = process->GetErrorStream();
653 wxTextInputStream textstream( *err );
654
655 while( err->CanRead() )
656 {
657 wxString line = textstream.ReadLine();
658
659 if( !line.IsEmpty() )
660 {
661 if( line.EndsWith( wxS( "failed with error 2!" ) ) ) // ENOENT
662 {
663 reporter.Report( _( "external simulator not found" ), RPT_SEVERITY_ERROR );
664 reporter.Report( _( "Note: command line is usually: "
665 "<tt>&lt;path to SPICE binary&gt; \"%I\"</tt>" ),
667 }
668 else if( line.EndsWith( wxS( "failed with error 8!" ) ) ) // ENOEXEC
669 {
670 reporter.Report( _( "external simulator has the wrong format or "
671 "architecture" ), RPT_SEVERITY_ERROR );
672 }
673 else if( line.EndsWith( "failed with error 13!" ) ) // EACCES
674 {
675 reporter.Report( _( "permission denied" ), RPT_SEVERITY_ERROR );
676 }
677 else
678 {
679 reporter.Report( line, RPT_SEVERITY_ERROR );
680 }
681 }
682 }
683 }
684
685 process->CloseOutput();
686 process->Detach();
687
688 // Do not delete process, it will delete itself when it terminates
689 }
690 }
691
693
694 return !runExternalSpiceCommand;
695}
696
697
698bool DIALOG_EXPORT_NETLIST::FilenamePrms( NETLIST_TYPE_ID aType, wxString * aExt, wxString * aWildCard )
699{
700 wxString fileExt;
701 wxString fileWildcard;
702 bool ret = true;
703
704 switch( aType )
705 {
706 case NET_TYPE_SPICE:
708 fileWildcard = FILEEXT::SpiceNetlistFileWildcard();
709 break;
710
711 case NET_TYPE_CADSTAR:
714 break;
715
719 break;
720
721 case NET_TYPE_PCBNEW:
723 fileWildcard = FILEEXT::NetlistFileWildcard();
724 break;
725
726 case NET_TYPE_ALLEGRO:
729 break;
730
731 case NET_TYPE_PADS:
733 fileWildcard = FILEEXT::PADSNetlistFileWildcard();
734 break;
735
736
737 default: // custom, NET_TYPE_CUSTOM1 and greater
738 fileWildcard = FILEEXT::AllFilesWildcard();
739 ret = false;
740 }
741
742 if( aExt )
743 *aExt = fileExt;
744
745 if( aWildCard )
746 *aWildCard = fileWildcard;
747
748 return ret;
749}
750
751
753{
754 if( NetlistUpdateOpt() )
756
757 EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
758 wxCHECK( cfg, /* void */ );
759
760 cfg->m_NetlistPanel.plugins.clear();
761
762 // Update existing custom pages
763 for( int ii = PANELCUSTOMBASE; ii < PANELCUSTOMBASE + CUSTOMPANEL_COUNTMAX; ++ii )
764 {
765 if( EXPORT_NETLIST_PAGE* currPage = m_PanelNetType[ii] )
766 {
767 wxString title = currPage->m_TitleStringCtrl->GetValue();
768 wxString command = currPage->m_CommandStringCtrl->GetValue();
769
770 if( title.IsEmpty() || command.IsEmpty() )
771 continue;
772
773 cfg->m_NetlistPanel.plugins.emplace_back( title, wxEmptyString );
774 cfg->m_NetlistPanel.plugins.back().command = command;
775 }
776 }
777}
778
779
780void DIALOG_EXPORT_NETLIST::OnDelGenerator( wxCommandEvent& event )
781{
782 EXPORT_NETLIST_PAGE* currPage = (EXPORT_NETLIST_PAGE*) m_NoteBook->GetCurrentPage();
783
784 if( !currPage->IsCustom() )
785 return;
786
787 currPage->m_CommandStringCtrl->SetValue( wxEmptyString );
788 currPage->m_TitleStringCtrl->SetValue( wxEmptyString );
789
791
792 if( IsQuasiModal() )
794 else
795 EndDialog( NET_PLUGIN_CHANGE );
796}
797
798
799void DIALOG_EXPORT_NETLIST::OnAddGenerator( wxCommandEvent& event )
800{
802
803 if( dlg.ShowModal() != wxID_OK )
804 return;
805
806 wxString title = dlg.GetGeneratorTitle();
807 wxString cmd = dlg.GetGeneratorTCommandLine();
808
809 // Verify it does not exists
810 for( int ii = PANELCUSTOMBASE; ii < PANELCUSTOMBASE + CUSTOMPANEL_COUNTMAX; ++ii )
811 {
812 if( m_PanelNetType[ii] && m_PanelNetType[ii]->GetPageNetFmtName() == title )
813 {
814 wxMessageBox( _( "This plugin already exists." ) );
815 return;
816 }
817 }
818
819 // Find the first empty slot
820 int netTypeId = PANELCUSTOMBASE;
821
822 while( m_PanelNetType[netTypeId] )
823 {
824 netTypeId++;
825
826 if( netTypeId == PANELCUSTOMBASE + CUSTOMPANEL_COUNTMAX )
827 {
828 wxMessageBox( _( "Maximum number of plugins already added to dialog." ) );
829 return;
830 }
831 }
832
833 m_PanelNetType[netTypeId] = AddOneCustomPage( title, cmd, (NETLIST_TYPE_ID)netTypeId );
835
836 if( IsQuasiModal() )
838 else
839 EndDialog( NET_PLUGIN_CHANGE );
840}
841
842
845{
846 m_Parent = parent;
848 GetSizer()->SetSizeHints( this );
849}
850
851
853{
854 if( !wxDialog::TransferDataFromWindow() )
855 return false;
856
857 if( m_textCtrlCommand->GetValue() == wxEmptyString )
858 {
859 wxMessageBox( _( "You must provide a netlist generator command string" ) );
860 return false;
861 }
862
863 if( m_textCtrlName->GetValue() == wxEmptyString )
864 {
865 wxMessageBox( _( "You must provide a netlist generator title" ) );
866 return false;
867 }
868
869 return true;
870}
871
872
874{
875 wxString FullFileName, Path;
876
877#ifndef __WXMAC__
878 Path = Pgm().GetExecutablePath();
879#else
880 Path = PATHS::GetOSXKicadDataDir() + wxT( "/plugins" );
881#endif
882
883 FullFileName = wxFileSelector( _( "Generator File" ), Path, FullFileName,
884 wxEmptyString, wxFileSelectorDefaultWildcardStr,
885 wxFD_OPEN, this );
886
887 if( FullFileName.IsEmpty() )
888 return;
889
890 // Creates a default command line, suitable for external tool xslproc or python, based on
891 // the plugin extension ("xsl" or "exe" or "py")
892 wxString cmdLine;
893 wxFileName fn( FullFileName );
894 wxString ext = fn.GetExt();
895
896 if( ext == wxT( "xsl" ) )
897 cmdLine.Printf( wxT( "xsltproc -o \"%%O\" \"%s\" \"%%I\"" ), FullFileName );
898 else if( ext == wxT( "exe" ) || ext.IsEmpty() )
899 cmdLine.Printf( wxT( "\"%s\" > \"%%O\" < \"%%I\"" ), FullFileName );
900 else if( ext == wxT( "py" ) || ext.IsEmpty() )
901 cmdLine.Printf( wxT( "python \"%s\" \"%%I\" \"%%O\"" ), FullFileName );
902 else
903 cmdLine.Printf( wxT( "\"%s\"" ), FullFileName );
904
905 m_textCtrlCommand->SetValue( cmdLine );
906
907 // We need a title for this panel
908 // Propose a default value if empty ( i.e. the short filename of the script)
909 if( m_textCtrlName->GetValue().IsEmpty() )
910 m_textCtrlName->SetValue( fn.GetName() );
911}
912
913
915{
916 EXPORT_NETLIST_PAGE* currPage = (EXPORT_NETLIST_PAGE*) m_NoteBook->GetCurrentPage();
917
918 if( currPage == nullptr )
919 return;
920
921 m_buttonDelGenerator->Enable( currPage->IsCustom() );
922}
923
924
926{
927 DIALOG_EXPORT_NETLIST dlg( aCaller );
928
929 int ret = dlg.ShowModal();
930 aCaller->SaveProjectLocalSettings();
931
932 return ret;
933}
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
Class DIALOG_EXPORT_NETLIST_BASE.
WX_HTML_REPORT_PANEL * m_MessagesBox
void OnDelGenerator(wxCommandEvent &event) override
Remove a panel relative to a netlist plugin.
void WriteCurrentNetlistSetup()
Write the current netlist options setup in the configuration.
EXPORT_NETLIST_PAGE * AddOneCustomPage(const wxString &aTitle, const wxString &aCommandString, NETLIST_TYPE_ID aNetTypeId)
bool TransferDataFromWindow() override
std::vector< EXPORT_NETLIST_PAGE * > m_PanelNetType
SCH_EDIT_FRAME * m_editFrame
JOB_EXPORT_SCH_NETLIST * m_job
void OnAddGenerator(wxCommandEvent &event) override
Add a new panel for a new netlist plugin.
void OnNetlistTypeSelection(wxNotebookEvent &event) override
bool FilenamePrms(NETLIST_TYPE_ID aType, wxString *aExt, wxString *aWildCard)
Return the filename extension and the wildcard string for this page or a void name if there is no def...
DIALOG_EXPORT_NETLIST(SCH_EDIT_FRAME *aEditFrame)
void SetupStandardButtons(std::map< int, wxString > aLabels={})
bool IsQuasiModal() const
Definition: dialog_shim.h:111
void EndQuasiModal(int retCode)
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
virtual void ClearMsgPanel()
Clear all messages from the message panel.
PANEL_NETLIST m_NetlistPanel
const wxString GetPageNetFmtName()
EXPORT_NETLIST_PAGE(wxNotebook *aParent, const wxString &aTitle, NETLIST_TYPE_ID aIdNetType, bool aCustom)
Create a setup page for one netlist format.
wxCheckBox * m_RunExternalSpiceCommand
void SetOutputPath(const wxString &aPath)
Definition: job.cpp:130
wxString GetOutputPath() const
Definition: job.h:120
APP_SETTINGS_BASE * KifaceSettings() const
Definition: kiface_base.h:95
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
Class NETLIST_DIALOG_ADD_GENERATOR_BASE.
NETLIST_DIALOG_ADD_GENERATOR(DIALOG_EXPORT_NETLIST *parent)
void OnBrowseGenerators(wxCommandEvent &event) override
virtual const wxString & GetExecutablePath() const
Definition: pgm_base.cpp:1039
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:72
virtual REPORTER & ReportHead(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Places the report at the beginning of the list for objects that support ordering.
Definition: reporter.h:109
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
These are loaded from Eeschema settings but then overwritten by the project settings.
wxString GetFileName() const override
Helper to retrieve the filename from the root sheet screen.
Definition: schematic.cpp:308
SCHEMATIC_SETTINGS & Settings() const
Definition: schematic.cpp:314
Schematic editor (Eeschema) main window.
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag and update other data struc...
void SaveProjectLocalSettings() override
Save changes to the project settings to the project (.pro) file.
bool ReadyToNetlist(const wxString &aAnnotateMessage)
Check if we are ready to write a netlist file for the current schematic.
bool WriteNetListFile(int aFormat, const wxString &aFullFileName, unsigned aNetlistOptions, REPORTER *aReporter=nullptr)
Create a netlist file.
SCHEMATIC & Schematic() const
void SetNetListerCommand(const wxString &aCommand)
std::map< JOB_EXPORT_SCH_NETLIST::FORMAT, wxString > jobNetlistNameLookup
@ PANELSPICEMODEL
@ DEFINED_NETLISTS_COUNT
@ PANELORCADPCB2
@ PANELCUSTOMBASE
@ ID_RUN_SIMULATOR
@ ID_SAVE_ALL_VOLTAGES
@ ID_SAVE_ALL_CURRENTS
@ ID_CUR_SHEET_AS_ROOT
@ ID_SAVE_ALL_DISSIPATIONS
@ ID_CREATE_NETLIST
@ ID_SAVE_ALL_EVENTS
#define CUSTOMPANEL_COUNTMAX
int InvokeDialogNetList(SCH_EDIT_FRAME *aCaller)
#define _(s)
@ ID_END_EESCHEMA_ID_LIST
Definition: eeschema_id.h:71
static const std::string CadstarNetlistFileExtension
static const std::string NetlistFileExtension
static const std::string OrCadPcb2NetlistFileExtension
static const std::string SpiceFileExtension
static const std::string PADSNetlistFileExtension
static const std::string AllegroNetlistFileExtension
static wxString SpiceNetlistFileWildcard()
static wxString OrCadPcb2NetlistFileWildcard()
static wxString AllFilesWildcard()
static wxString AllegroNetlistFileWildcard()
static wxString CadstarNetlistFileWildcard()
static wxString PADSNetlistFileWildcard()
static wxString NetlistFileWildcard()
#define NET_PLUGIN_CHANGE
Create and shows DIALOG_EXPORT_NETLIST and returns whatever DIALOG_EXPORT_NETLIST::ShowModal() return...
NETLIST_TYPE_ID
netlist types
Definition: netlist.h:35
@ NET_TYPE_CADSTAR
Definition: netlist.h:40
@ NET_TYPE_ORCADPCB2
Definition: netlist.h:39
@ NET_TYPE_SPICE
Definition: netlist.h:41
@ NET_TYPE_ALLEGRO
Definition: netlist.h:43
@ NET_TYPE_SPICE_MODEL
Definition: netlist.h:42
@ NET_TYPE_PCBNEW
Definition: netlist.h:38
@ NET_TYPE_PADS
Definition: netlist.h:44
@ NET_TYPE_CUSTOM1
Definition: netlist.h:45
static PGM_BASE * process
Definition: pgm_base.cpp:1058
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: pgm_base.cpp:1060
see class PGM_BASE
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_INFO
@ RPT_SEVERITY_ACTION
std::vector< NETLIST_PLUGIN_SETTINGS > plugins
Definition of file extensions used in Kicad.