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 The 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 <string_utils.h>
42#include <gestfich.h>
44#include <sch_edit_frame.h>
47#include <invoke_sch_dialog.h>
49#include <paths.h>
51
52#include <eeschema_id.h>
53#include <wx/checkbox.h>
54#include <wx/filedlg.h>
55#include <wx/msgdlg.h>
56#include <wx/regex.h>
57#include <wx/txtstrm.h>
58
59#include <thread>
60
61
62#define CUSTOMPANEL_COUNTMAX 8 // Max number of netlist plugins
63
64/*
65 * PANEL_NETLIST_INDEX values are used as index in m_PanelNetType[]
66 */
68{
69 PANELPCBNEW = 0, /* Handle Netlist format Pcbnew */
70 PANELORCADPCB2, /* Handle Netlist format OracdPcb2 */
71 PANELALLEGRO, /* Handle Netlist format Allegro */
72 PANELCADSTAR, /* Handle Netlist format CadStar */
73 PANELPADS, /* Handle Netlist format PADS */
74 PANELSPICE, /* Handle Netlist format Spice */
75 PANELSPICEMODEL, /* Handle Netlist format Spice Model (subcircuit) */
77
78 /* First auxiliary panel (custom netlists). Subsequent ones use PANELCUSTOMBASE+1,
79 * PANELCUSTOMBASE+2, etc., up to PANELCUSTOMBASE+CUSTOMPANEL_COUNTMAX-1 */
81};
82
83
84/* wxPanels for creating the NoteBook pages for each netlist format: */
85class EXPORT_NETLIST_PAGE : public wxPanel
86{
87
88public:
98 EXPORT_NETLIST_PAGE( wxNotebook* aParent, const wxString& aTitle,
99 NETLIST_TYPE_ID aIdNetType, bool aCustom );
101
105 const wxString GetPageNetFmtName() { return m_pageNetFmtName; }
106
108
109 // opt to reformat passive component values (e.g. 1M -> 1Meg):
110 wxCheckBox* m_CurSheetAsRoot;
111 wxCheckBox* m_SaveAllVoltages;
112 wxCheckBox* m_SaveAllCurrents;
114 wxCheckBox* m_SaveAllEvents;
117 wxTextCtrl* m_TitleStringCtrl;
118 wxBoxSizer* m_LeftBoxSizer;
119 wxBoxSizer* m_RightBoxSizer;
121 wxBoxSizer* m_LowBoxSizer;
122
123 bool IsCustom() const { return m_custom; }
124
125private:
127
129};
130
131
133{
134public:
136
137 const wxString GetGeneratorTitle() { return m_textCtrlName->GetValue(); }
138 const wxString GetGeneratorTCommandLine() { return m_textCtrlCommand->GetValue(); }
139
140 bool TransferDataFromWindow() override;
141
142private:
146 void OnBrowseGenerators( wxCommandEvent& event ) override;
147
149};
150
151
152/* Event id for notebook page buttons: */
162
163
164EXPORT_NETLIST_PAGE::EXPORT_NETLIST_PAGE( wxNotebook* aParent, const wxString& aTitle,
165 NETLIST_TYPE_ID aIdNetType, bool aCustom ) :
166 wxPanel( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL )
167{
168 m_IdNetType = aIdNetType;
169 m_pageNetFmtName = aTitle;
170 m_CommandStringCtrl = nullptr;
171 m_CurSheetAsRoot = nullptr;
172 m_TitleStringCtrl = nullptr;
173 m_SaveAllVoltages = nullptr;
174 m_SaveAllCurrents = nullptr;
175 m_SaveAllDissipations = nullptr;
176 m_SaveAllEvents = nullptr;
178 m_custom = aCustom;
179
180 aParent->AddPage( this, aTitle, false );
181
182 wxBoxSizer* MainBoxSizer = new wxBoxSizer( wxVERTICAL );
183 SetSizer( MainBoxSizer );
184 wxBoxSizer* UpperBoxSizer = new wxBoxSizer( wxHORIZONTAL );
185 m_LowBoxSizer = new wxBoxSizer( wxVERTICAL );
186 MainBoxSizer->Add( UpperBoxSizer, 0, wxEXPAND | wxALL, 5 );
187 MainBoxSizer->Add( m_LowBoxSizer, 0, wxEXPAND | wxALL, 5 );
188
189 m_LeftBoxSizer = new wxBoxSizer( wxVERTICAL );
190 m_RightBoxSizer = new wxBoxSizer( wxVERTICAL );
191 m_RightOptionsBoxSizer = new wxBoxSizer( wxVERTICAL );
192 UpperBoxSizer->Add( m_LeftBoxSizer, 0, wxEXPAND | wxALL, 5 );
193 UpperBoxSizer->Add( m_RightBoxSizer, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
194 UpperBoxSizer->Add( m_RightOptionsBoxSizer, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
195}
196
197
199 DIALOG_EXPORT_NETLIST( aEditFrame, aEditFrame )
200{
201}
202
203
205 JOB_EXPORT_SCH_NETLIST* aJob ) :
207 m_job( aJob )
208{
209 m_editFrame = aEditFrame;
210
211 // Initialize the array of netlist pages
213
215
216 // Add notebook pages:
217 EXPORT_NETLIST_PAGE* page = nullptr;
218 wxStaticText* label = nullptr;
219
220 page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "KiCad" ), NET_TYPE_PCBNEW, false );
221 label = new wxStaticText( page, wxID_ANY, _( "Export netlist in KiCad format" ) );
222 page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
224
225 page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "OrcadPCB2" ), NET_TYPE_ORCADPCB2, false );
226 label = new wxStaticText( page, wxID_ANY, _( "Export netlist in OrcadPCB2 format" ) );
227 page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
229
230 page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "Allegro" ), NET_TYPE_ALLEGRO, false );
231 label = new wxStaticText( page, wxID_ANY, _( "Export netlist in Allegro format" ) );
232 page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
234
235 page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "PADS" ), NET_TYPE_PADS, false );
236 label = new wxStaticText( page, wxID_ANY, _( "Export netlist in PADS format" ) );
237 page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
239
240 page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "CadStar" ), NET_TYPE_CADSTAR, false );
241 label = new wxStaticText( page, wxID_ANY, _( "Export netlist in CadStar format" ) );
242 page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
244
247
248 wxString selectedPageFormatName;
249
250 if( !m_job )
251 {
252 m_outputPath->Hide();
255
256 SetupStandardButtons( { { wxID_OK, _( "Export Netlist" ) },
257 { wxID_CANCEL, _( "Close" ) } } );
258
259 selectedPageFormatName = settings.m_NetFormatName;
260 }
261 else
262 {
263 SetTitle( m_job->GetSettingsDialogTitle() );
264
265 m_MessagesBox->Hide();
267
269
270 // custom netlist (external invokes, not supported)
271 selectedPageFormatName = JOB_EXPORT_SCH_NETLIST::GetFormatNameMap()[m_job->format];
272
273 m_buttonAddGenerator->Hide();
274 m_buttonDelGenerator->Hide();
275 }
276
277 // DIALOG_SHIM needs a unique hash_key because classname will be the same for both job and
278 // non-job versions (which have different sizes).
279 m_hash_key = TO_UTF8( GetTitle() );
280
281 for( int ii = 0; ii < DEFINED_NETLISTS_COUNT + CUSTOMPANEL_COUNTMAX; ++ii )
282 {
283 if( EXPORT_NETLIST_PAGE* candidate = m_PanelNetType[ii] )
284 {
285 if( candidate->GetPageNetFmtName() == selectedPageFormatName )
286 {
287 m_NoteBook->ChangeSelection( ii );
288 break;
289 }
290 }
291 }
292
293 // Now all widgets have the size fixed, call FinishDialogSettings
295
297}
298
299
301{
302 auto* pg = m_PanelNetType[PANELSPICE] = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "SPICE" ),
303 NET_TYPE_SPICE, false );
304
306
307 wxStaticText* label = new wxStaticText( pg, wxID_ANY, _( "Export netlist in SPICE format" ) );
308 pg->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
309
310 pg->m_CurSheetAsRoot = new wxCheckBox( pg, ID_CUR_SHEET_AS_ROOT,
311 _( "Use current sheet as root" ) );
312 pg->m_CurSheetAsRoot->SetToolTip( _( "Export netlist only for the current sheet" ) );
313 pg->m_CurSheetAsRoot->SetValue( settings.m_SpiceCurSheetAsRoot );
314 pg->m_LeftBoxSizer->Add( pg->m_CurSheetAsRoot, 0, wxGROW | wxBOTTOM | wxRIGHT, 5 );
315
316 pg->m_SaveAllVoltages = new wxCheckBox( pg, ID_SAVE_ALL_VOLTAGES, _( "Save all voltages" ) );
317 pg->m_SaveAllVoltages->SetToolTip( _( "Write a directive to save all voltages (.save all)" ) );
318 pg->m_SaveAllVoltages->SetValue( settings.m_SpiceSaveAllVoltages );
319 pg->m_LeftBoxSizer->Add( pg->m_SaveAllVoltages, 0, wxBOTTOM | wxRIGHT, 5 );
320
321 pg->m_SaveAllCurrents = new wxCheckBox( pg, ID_SAVE_ALL_CURRENTS, _( "Save all currents" ) );
322 pg->m_SaveAllCurrents->SetToolTip( _( "Write a directive to save all currents (.probe alli)" ) );
323 pg->m_SaveAllCurrents->SetValue( settings.m_SpiceSaveAllCurrents );
324 pg->m_LeftBoxSizer->Add( pg->m_SaveAllCurrents, 0, wxBOTTOM | wxRIGHT, 5 );
325
326 pg->m_SaveAllDissipations = new wxCheckBox( pg, ID_SAVE_ALL_DISSIPATIONS,
327 _( "Save all power dissipations" ) );
328 pg->m_SaveAllDissipations->SetToolTip( _( "Write directives to save power dissipation of all "
329 "items (.probe p(<item>))" ) );
330 pg->m_SaveAllDissipations->SetValue( settings.m_SpiceSaveAllDissipations );
331 pg->m_LeftBoxSizer->Add( pg->m_SaveAllDissipations, 0, wxBOTTOM | wxRIGHT, 5 );
332
333 pg->m_SaveAllEvents = new wxCheckBox( pg, ID_SAVE_ALL_EVENTS,
334 _( "Save all digital event data" ) );
335 pg->m_SaveAllEvents->SetToolTip( _( "If not set, write a directive to prevent the saving of "
336 "digital event data (esave none)" ) );
337 pg->m_SaveAllEvents->SetValue( settings.m_SpiceSaveAllEvents );
338 pg->m_LeftBoxSizer->Add( pg->m_SaveAllEvents, 0, wxBOTTOM | wxRIGHT, 5 );
339
340
341 pg->m_RunExternalSpiceCommand = new wxCheckBox( pg, ID_RUN_SIMULATOR,
342 _( "Run external simulator command:" ) );
343 wxString simulatorCommand = settings.m_SpiceCommandString;
344 pg->m_RunExternalSpiceCommand->SetToolTip( _( "Enter the command line to run SPICE\n"
345 "Usually '<path to SPICE binary> \"%I\"'\n"
346 "%I will be replaced by the netlist filepath" ) );
347 pg->m_LowBoxSizer->Add( pg->m_RunExternalSpiceCommand, 0,
348 wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
349
350 pg->m_CommandStringCtrl = new wxTextCtrl( pg, -1, simulatorCommand,
351 wxDefaultPosition, wxDefaultSize );
352
353 pg->m_CommandStringCtrl->SetInsertionPoint( 1 );
354 pg->m_LowBoxSizer->Add( pg->m_CommandStringCtrl, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
355}
356
357
359{
361 wxT( "SPICE Model" ),
363 false );
364
366
367 wxStaticText* label = new wxStaticText( pg, wxID_ANY,
368 _( "Export netlist as a SPICE .subckt model" ) );
369 pg->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
370
371 pg->m_CurSheetAsRoot = new wxCheckBox( pg, ID_CUR_SHEET_AS_ROOT,
372 _( "Use current sheet as root" ) );
373 pg->m_CurSheetAsRoot->SetToolTip( _( "Export netlist only for the current sheet" ) );
374 pg->m_CurSheetAsRoot->SetValue( settings.m_SpiceModelCurSheetAsRoot );
375 pg->m_LeftBoxSizer->Add( pg->m_CurSheetAsRoot, 0, wxEXPAND | wxBOTTOM | wxRIGHT, 5 );
376}
377
378
380{
381 EXPORT_NETLIST_PAGE* currPage;
382 EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
383 wxCHECK( cfg, /* void */ );
384
385 for( size_t i = 0; i < CUSTOMPANEL_COUNTMAX && i < cfg->m_NetlistPanel.plugins.size(); i++ )
386 {
387 // pairs of (title, command) are stored
388 currPage = AddOneCustomPage( cfg->m_NetlistPanel.plugins[i].name,
389 cfg->m_NetlistPanel.plugins[i].command,
390 static_cast<NETLIST_TYPE_ID>( NET_TYPE_CUSTOM1 + i ) );
391
392 m_PanelNetType[PANELCUSTOMBASE + i] = currPage;
393 }
394}
395
396
398 const wxString& aCommandString,
399 NETLIST_TYPE_ID aNetTypeId )
400{
401 EXPORT_NETLIST_PAGE* pg = new EXPORT_NETLIST_PAGE( m_NoteBook, aTitle, aNetTypeId, true );
402
403 pg->m_LowBoxSizer->Add( new wxStaticText( pg, wxID_ANY, _( "Title:" ) ), 0,
404 wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 5 );
405
406 pg->m_LowBoxSizer->AddSpacer( 2 );
407
408 pg->m_TitleStringCtrl = new wxTextCtrl( pg, wxID_ANY, aTitle );
409
410 pg->m_TitleStringCtrl->SetInsertionPoint( 1 );
411 pg->m_LowBoxSizer->Add( pg->m_TitleStringCtrl, 0, wxEXPAND | wxLEFT | wxRIGHT, 5 );
412
413 pg->m_LowBoxSizer->AddSpacer( 10 );
414
415 pg->m_LowBoxSizer->Add( new wxStaticText( pg, wxID_ANY, _( "Netlist command:" ) ), 0,
416 wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 5 );
417
418 pg->m_LowBoxSizer->AddSpacer( 2 );
419
420 pg->m_CommandStringCtrl = new wxTextCtrl( pg, wxID_ANY, aCommandString );
421
422 pg->m_CommandStringCtrl->SetInsertionPoint( 1 );
423 pg->m_LowBoxSizer->Add( pg->m_CommandStringCtrl, 0, wxEXPAND | wxLEFT | wxRIGHT, 5 );
424
425 return pg;
426}
427
428
430{
432}
433
434
436{
437 bool changed = false;
438 bool saveAllVoltages = m_PanelNetType[ PANELSPICE ]->m_SaveAllVoltages->IsChecked();
439 bool saveAllCurrents = m_PanelNetType[ PANELSPICE ]->m_SaveAllCurrents->IsChecked();
440 bool saveAllDissipations = m_PanelNetType[ PANELSPICE ]->m_SaveAllDissipations->IsChecked();
441 bool saveAllEvents = m_PanelNetType[ PANELSPICE ]->m_SaveAllEvents->IsChecked();
442 wxString spiceCmdString = m_PanelNetType[ PANELSPICE ]->m_CommandStringCtrl->GetValue();
443 bool curSheetAsRoot = m_PanelNetType[ PANELSPICE ]->m_CurSheetAsRoot->GetValue();
444 bool spiceModelCurSheetAsRoot = m_PanelNetType[ PANELSPICEMODEL ]->m_CurSheetAsRoot->GetValue();
445
446 if( !m_job )
447 {
449 wxString netFormatName = m_PanelNetType[m_NoteBook->GetSelection()]->GetPageNetFmtName();
450
451 changed |= ( settings.m_SpiceSaveAllVoltages != saveAllVoltages );
452 changed |= ( settings.m_SpiceSaveAllCurrents != saveAllCurrents );
453 changed |= ( settings.m_SpiceSaveAllDissipations != saveAllDissipations );
454 changed |= ( settings.m_SpiceSaveAllEvents != saveAllEvents );
455 changed |= ( settings.m_SpiceCommandString != spiceCmdString );
456 changed |= ( settings.m_SpiceCurSheetAsRoot != curSheetAsRoot );
457 changed |= ( settings.m_SpiceModelCurSheetAsRoot != spiceModelCurSheetAsRoot );
458 changed |= ( settings.m_NetFormatName != netFormatName );
459
460 settings.m_SpiceSaveAllVoltages = saveAllVoltages;
461 settings.m_SpiceSaveAllCurrents = saveAllCurrents;
462 settings.m_SpiceSaveAllDissipations = saveAllDissipations;
463 settings.m_SpiceSaveAllEvents = saveAllEvents;
464 settings.m_SpiceCommandString = spiceCmdString;
465 settings.m_SpiceCurSheetAsRoot = curSheetAsRoot;
466 settings.m_SpiceModelCurSheetAsRoot = spiceModelCurSheetAsRoot;
467 settings.m_NetFormatName = netFormatName;
468 }
469 else
470 {
471 for( const auto& [format, name] : JOB_EXPORT_SCH_NETLIST::GetFormatNameMap() )
472 {
473 if( name == m_PanelNetType[m_NoteBook->GetSelection()]->GetPageNetFmtName() )
474 {
475 m_job->format = format;
476 break;
477 }
478 }
479
481 m_job->m_spiceSaveAllVoltages = saveAllVoltages;
482 m_job->m_spiceSaveAllCurrents = saveAllCurrents;
483 m_job->m_spiceSaveAllDissipations = saveAllDissipations;
484 m_job->m_spiceSaveAllEvents = saveAllEvents;
485 }
486
487 return changed;
488}
489
490
492{
493 wxFileName fn;
494 wxString fileWildcard;
495 wxString fileExt;
496 wxString title = _( "Save Netlist File" );
497
498 if( m_job )
499 {
501 return true;
502 }
503 else
504 {
505 if( NetlistUpdateOpt() )
507 }
508
509 EXPORT_NETLIST_PAGE* currPage;
510 currPage = (EXPORT_NETLIST_PAGE*) m_NoteBook->GetCurrentPage();
511
512 bool runExternalSpiceCommand = false;
513 unsigned netlist_opt = 0;
514
515 // Calculate the netlist filename
517 FilenamePrms( currPage->m_IdNetType, &fileExt, &fileWildcard );
518
519 // Set some parameters
520 switch( currPage->m_IdNetType )
521 {
522 case NET_TYPE_SPICE:
523 // Set spice netlist options:
525
526 if( currPage->m_SaveAllVoltages->GetValue() )
528
529 if( currPage->m_SaveAllCurrents->GetValue() )
531
532 if( currPage->m_SaveAllDissipations->GetValue() )
534
535 if( currPage->m_SaveAllEvents->GetValue() )
537
538 if( currPage->m_CurSheetAsRoot->GetValue() )
540
541 runExternalSpiceCommand = currPage->m_RunExternalSpiceCommand->GetValue();
542 break;
543
545 if( currPage->m_CurSheetAsRoot->GetValue() )
547
548 break;
549
550 case NET_TYPE_CADSTAR:
551 break;
552
553 case NET_TYPE_PCBNEW:
554 break;
555
557 break;
558
559 case NET_TYPE_ALLEGRO:
560 break;
561
562 case NET_TYPE_PADS:
563 break;
564
565 default: // custom, NET_TYPE_CUSTOM1 and greater
566 title.Printf( _( "%s Export" ), currPage->m_TitleStringCtrl->GetValue() );
567 break;
568 }
569
570 wxString fullpath;
571
572 if( runExternalSpiceCommand )
573 {
574 fn.SetExt( FILEEXT::SpiceFileExtension );
575 fullpath = fn.GetFullPath();
576 }
577 else
578 {
579 fn.SetExt( fileExt );
580
581 if( fn.GetPath().IsEmpty() )
582 fn.SetPath( wxPathOnly( Prj().GetProjectFullName() ) );
583
584 wxString fullname = fn.GetFullName();
585 wxString path = fn.GetPath();
586
587 // full name does not and should not include the path, per wx docs.
588 wxFileDialog dlg( this, title, path, fullname, fileWildcard, wxFD_SAVE );
589
590 if( dlg.ShowModal() == wxID_CANCEL )
591 return false;
592
593 fullpath = dlg.GetPath(); // directory + filename
594 }
595
597 REPORTER& reporter = m_MessagesBox->Reporter();
598
599 if( currPage->m_CommandStringCtrl )
600 m_editFrame->SetNetListerCommand( currPage->m_CommandStringCtrl->GetValue() );
601 else
602 m_editFrame->SetNetListerCommand( wxEmptyString );
603
605 _( "Exporting netlist requires a fully annotated schematic." ) ) )
606 return false;
607
608 m_editFrame->WriteNetListFile( currPage->m_IdNetType, fullpath, netlist_opt, &reporter );
609
610 if( runExternalSpiceCommand )
611 {
612 // Build the command line
613 wxString commandLine = m_editFrame->Schematic().Settings().m_SpiceCommandString;
614 commandLine.Replace( wxS( "%I" ), fullpath, true );
615 commandLine.Trim( true ).Trim( false );
616
617 if( !commandLine.IsEmpty() )
618 {
619 wxProcess* process = new wxProcess( GetEventHandler(), wxID_ANY );
620 process->Redirect();
621 wxExecute( commandLine, wxEXEC_ASYNC, process );
622
623 reporter.ReportHead( commandLine, RPT_SEVERITY_ACTION );
624 process->Activate();
625
626 std::this_thread::sleep_for( std::chrono::seconds( 1 ) ); // give the process time to start and output any data or errors
627
628 if( process->IsInputAvailable() )
629 {
630 wxInputStream* in = process->GetInputStream();
631 wxTextInputStream textstream( *in );
632
633 while( in->CanRead() )
634 {
635 wxString line = textstream.ReadLine();
636
637 if( !line.IsEmpty() )
638 reporter.Report( line, RPT_SEVERITY_INFO );
639 }
640 }
641
642 if( process->IsErrorAvailable() )
643 {
644 wxInputStream* err = process->GetErrorStream();
645 wxTextInputStream textstream( *err );
646
647 while( err->CanRead() )
648 {
649 wxString line = textstream.ReadLine();
650
651 if( !line.IsEmpty() )
652 {
653 if( line.EndsWith( wxS( "failed with error 2!" ) ) ) // ENOENT
654 {
655 reporter.Report( _( "external simulator not found" ), RPT_SEVERITY_ERROR );
656 reporter.Report( _( "Note: command line is usually: "
657 "<tt>&lt;path to SPICE binary&gt; \"%I\"</tt>" ),
659 }
660 else if( line.EndsWith( wxS( "failed with error 8!" ) ) ) // ENOEXEC
661 {
662 reporter.Report( _( "external simulator has the wrong format or "
663 "architecture" ), RPT_SEVERITY_ERROR );
664 }
665 else if( line.EndsWith( "failed with error 13!" ) ) // EACCES
666 {
667 reporter.Report( _( "permission denied" ), RPT_SEVERITY_ERROR );
668 }
669 else
670 {
671 reporter.Report( line, RPT_SEVERITY_ERROR );
672 }
673 }
674 }
675 }
676
677 process->CloseOutput();
678 process->Detach();
679
680 // Do not delete process, it will delete itself when it terminates
681 }
682 }
683
685
686 return !runExternalSpiceCommand;
687}
688
689
690bool DIALOG_EXPORT_NETLIST::FilenamePrms( NETLIST_TYPE_ID aType, wxString * aExt, wxString * aWildCard )
691{
692 wxString fileExt;
693 wxString fileWildcard;
694 bool ret = true;
695
696 switch( aType )
697 {
698 case NET_TYPE_SPICE:
700 fileWildcard = FILEEXT::SpiceNetlistFileWildcard();
701 break;
702
703 case NET_TYPE_CADSTAR:
706 break;
707
711 break;
712
713 case NET_TYPE_PCBNEW:
715 fileWildcard = FILEEXT::NetlistFileWildcard();
716 break;
717
718 case NET_TYPE_ALLEGRO:
721 break;
722
723 case NET_TYPE_PADS:
725 fileWildcard = FILEEXT::PADSNetlistFileWildcard();
726 break;
727
728
729 default: // custom, NET_TYPE_CUSTOM1 and greater
730 fileWildcard = FILEEXT::AllFilesWildcard();
731 ret = false;
732 }
733
734 if( aExt )
735 *aExt = fileExt;
736
737 if( aWildCard )
738 *aWildCard = fileWildcard;
739
740 return ret;
741}
742
743
745{
746 if( NetlistUpdateOpt() )
748
749 EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
750 wxCHECK( cfg, /* void */ );
751
752 cfg->m_NetlistPanel.plugins.clear();
753
754 // Update existing custom pages
755 for( int ii = PANELCUSTOMBASE; ii < PANELCUSTOMBASE + CUSTOMPANEL_COUNTMAX; ++ii )
756 {
757 if( EXPORT_NETLIST_PAGE* currPage = m_PanelNetType[ii] )
758 {
759 wxString title = currPage->m_TitleStringCtrl->GetValue();
760 wxString command = currPage->m_CommandStringCtrl->GetValue();
761
762 if( title.IsEmpty() || command.IsEmpty() )
763 continue;
764
765 cfg->m_NetlistPanel.plugins.emplace_back( title, wxEmptyString );
766 cfg->m_NetlistPanel.plugins.back().command = command;
767 }
768 }
769}
770
771
772void DIALOG_EXPORT_NETLIST::OnDelGenerator( wxCommandEvent& event )
773{
774 EXPORT_NETLIST_PAGE* currPage = (EXPORT_NETLIST_PAGE*) m_NoteBook->GetCurrentPage();
775
776 if( !currPage->IsCustom() )
777 return;
778
779 currPage->m_CommandStringCtrl->SetValue( wxEmptyString );
780 currPage->m_TitleStringCtrl->SetValue( wxEmptyString );
781
783
784 // Override m_NetFormatName written in WriteCurrentNetlistSetup()
786 settings.m_NetFormatName = m_NoteBook->GetPageText( m_NoteBook->GetSelection() - 1 );
787
788 if( IsQuasiModal() )
790 else
791 EndDialog( NET_PLUGIN_CHANGE );
792}
793
794
795void DIALOG_EXPORT_NETLIST::OnAddGenerator( wxCommandEvent& event )
796{
798
799 if( dlg.ShowModal() != wxID_OK )
800 return;
801
802 wxString title = dlg.GetGeneratorTitle();
803 wxString cmd = dlg.GetGeneratorTCommandLine();
804
805 // Verify it does not exists
806 for( int ii = PANELCUSTOMBASE; ii < PANELCUSTOMBASE + CUSTOMPANEL_COUNTMAX; ++ii )
807 {
808 if( m_PanelNetType[ii] && m_PanelNetType[ii]->GetPageNetFmtName() == title )
809 {
810 wxMessageBox( _( "This plugin already exists." ) );
811 return;
812 }
813 }
814
815 // Find the first empty slot
816 int netTypeId = PANELCUSTOMBASE;
817
818 while( m_PanelNetType[netTypeId] )
819 {
820 netTypeId++;
821
822 if( netTypeId == PANELCUSTOMBASE + CUSTOMPANEL_COUNTMAX )
823 {
824 wxMessageBox( _( "Maximum number of plugins already added to dialog." ) );
825 return;
826 }
827 }
828
829 m_PanelNetType[netTypeId] = AddOneCustomPage( title, cmd, (NETLIST_TYPE_ID)netTypeId );
830
832
833 // Override m_NetFormatName written in WriteCurrentNetlistSetup()
835 settings.m_NetFormatName = title;
836
837 if( IsQuasiModal() )
839 else
840 EndDialog( NET_PLUGIN_CHANGE );
841}
842
843
846{
847 m_Parent = parent;
849
852}
853
854
856{
857 if( !wxDialog::TransferDataFromWindow() )
858 return false;
859
860 if( m_textCtrlName->GetValue() == wxEmptyString )
861 {
862 wxMessageBox( _( "You must provide a netlist generator title" ) );
863 return false;
864 }
865
866 return true;
867}
868
869
871{
872 wxString FullFileName, Path;
873
874#ifndef __WXMAC__
875 Path = Pgm().GetExecutablePath();
876#else
877 Path = PATHS::GetOSXKicadDataDir() + wxT( "/plugins" );
878#endif
879
880 FullFileName = wxFileSelector( _( "Generator File" ), Path, FullFileName,
881 wxEmptyString, wxFileSelectorDefaultWildcardStr,
882 wxFD_OPEN, this );
883
884 if( FullFileName.IsEmpty() )
885 return;
886
887 // Creates a default command line, suitable for external tool xslproc or python, based on
888 // the plugin extension ("xsl" or "exe" or "py")
889 wxString cmdLine;
890 wxFileName fn( FullFileName );
891 wxString ext = fn.GetExt();
892
893 if( ext == wxT( "xsl" ) )
894 cmdLine.Printf( wxT( "xsltproc -o \"%%O\" \"%s\" \"%%I\"" ), FullFileName );
895 else if( ext == wxT( "exe" ) || ext.IsEmpty() )
896 cmdLine.Printf( wxT( "\"%s\" > \"%%O\" < \"%%I\"" ), FullFileName );
897 else if( ext == wxT( "py" ) || ext.IsEmpty() )
898 cmdLine.Printf( wxT( "python \"%s\" \"%%I\" \"%%O\"" ), FullFileName );
899 else
900 cmdLine.Printf( wxT( "\"%s\"" ), FullFileName );
901
902 m_textCtrlCommand->SetValue( cmdLine );
903
904 // We need a title for this panel
905 // Propose a default value if empty ( i.e. the short filename of the script)
906 if( m_textCtrlName->GetValue().IsEmpty() )
907 m_textCtrlName->SetValue( fn.GetName() );
908}
909
910
912{
913 EXPORT_NETLIST_PAGE* currPage = (EXPORT_NETLIST_PAGE*) m_NoteBook->GetCurrentPage();
914
915 if( currPage == nullptr )
916 return;
917
918 m_buttonDelGenerator->Enable( currPage->IsCustom() );
919}
920
921
923{
924 DIALOG_EXPORT_NETLIST dlg( aCaller );
925
926 int ret = dlg.ShowModal();
927 aCaller->SaveProjectLocalSettings();
928
929 return ret;
930}
const char * name
Definition: DXF_plotter.cpp:59
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={})
std::string m_hash_key
Definition: dialog_shim.h:230
bool IsQuasiModal() const
Definition: dialog_shim.h:113
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...
wxWindow * m_initialFocusTarget
Definition: dialog_shim.h:240
int ShowModal() override
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
static std::map< JOB_EXPORT_SCH_NETLIST::FORMAT, wxString > & GetFormatNameMap()
wxString GetSettingsDialogTitle() const override
void SetConfiguredOutputPath(const wxString &aPath)
Sets the configured output path for the job, this path is always saved to file.
Definition: job.cpp:153
wxString GetConfiguredOutputPath() const
Returns the configured output path for the job.
Definition: job.h:226
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
Browse plugin files, and set m_CommandStringCtrl field.
virtual const wxString & GetExecutablePath() const
Definition: pgm_base.cpp:1050
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:306
SCHEMATIC_SETTINGS & Settings() const
Definition: schematic.cpp:312
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)
REPORTER & Reporter()
Return the reporter object that reports to this panel.
@ 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:1070
PGM_BASE & Pgm()
The global program "get" accessor.
Definition: pgm_base.cpp:1073
see class PGM_BASE
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_INFO
@ RPT_SEVERITY_ACTION
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: string_utils.h:398
std::vector< NETLIST_PLUGIN_SETTINGS > plugins
Definition of file extensions used in Kicad.