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, see <https://www.gnu.org/licenses/>.
20 */
21
22/* Functions relative to the dialog creating the netlist for Pcbnew. The dialog is a notebook
23 * with 7 fixed netlist formats:
24 * Pcbnew
25 * ORCADPCB2
26 * Allegro
27 * CADSTAR
28 * Pads
29 * SPICE
30 * SPICE model
31 * and up to CUSTOMPANEL_COUNTMAX user programmable formats. These external converters are
32 * referred to as plugins, but they are really just external binaries.
33 */
34
35#include <properties/property.h>
36#include <pgm_base.h>
37#include <kiface_base.h>
38#include <string_utils.h>
39#include <gestfich.h>
41#include <sch_edit_frame.h>
44#include <invoke_sch_dialog.h>
46#include <paths.h>
48#include <kiplatform/ui.h>
49
50#include <eeschema_id.h>
51#include <wx/checkbox.h>
52#include <wx/filedlg.h>
53#include <wx/msgdlg.h>
54#include <wx/process.h>
55#include <wx/regex.h>
56#include <wx/txtstrm.h>
57#include <wx/utils.h>
58
59#include <thread>
60#include <vector>
62
63
64namespace
65{
66std::vector<wxString> SplitCommandLine( const wxString& aCommand )
67{
68 std::vector<wxString> args;
69 wxString current;
70 bool inSingle = false;
71 bool inDouble = false;
72 bool argStarted = false;
73
74 for( wxUniChar c : aCommand )
75 {
76 if( c == '"' && !inSingle )
77 {
78 inDouble = !inDouble;
79 argStarted = true;
80 continue;
81 }
82
83 if( c == '\'' && !inDouble )
84 {
85 inSingle = !inSingle;
86 argStarted = true;
87 continue;
88 }
89
90 if( ( c == ' ' || c == '\t' || c == '\n' || c == '\r' ) && !inSingle && !inDouble )
91 {
92 if( argStarted || !current.IsEmpty() )
93 {
94 args.emplace_back( current );
95 current.clear();
96 argStarted = false;
97 }
98
99 continue;
100 }
101
102 current.Append( c );
103 argStarted = true;
104 }
105
106 if( argStarted || !current.IsEmpty() )
107 args.emplace_back( current );
108
109 return args;
110}
111} // namespace
112
113
114#define CUSTOMPANEL_COUNTMAX 8 // Max number of netlist plugins
115
116/*
117 * PANEL_NETLIST_INDEX values are used as index in m_PanelNetType[]
118 */
120{
121 PANELPCBNEW = 0, /* Handle Netlist format Pcbnew */
122 PANELORCADPCB2, /* Handle Netlist format OracdPcb2 */
123 PANELALLEGRO, /* Handle Netlist format Allegro */
124 PANELCADSTAR, /* Handle Netlist format CadStar */
125 PANELPADS, /* Handle Netlist format PADS */
126 PANELSPICE, /* Handle Netlist format Spice */
127 PANELSPICEMODEL, /* Handle Netlist format Spice Model (subcircuit) */
129
130 /* First auxiliary panel (custom netlists). Subsequent ones use PANELCUSTOMBASE+1,
131 * PANELCUSTOMBASE+2, etc., up to PANELCUSTOMBASE+CUSTOMPANEL_COUNTMAX-1 */
133};
134
135
136/* wxPanels for creating the NoteBook pages for each netlist format: */
137class EXPORT_NETLIST_PAGE : public wxPanel
138{
139public:
149 EXPORT_NETLIST_PAGE( wxNotebook* aParent, const wxString& aTitle, NETLIST_TYPE_ID aIdNetType, bool aCustom );
151
155 const wxString GetPageNetFmtName() { return m_pageNetFmtName; }
156
157 bool IsCustom() const { return m_custom; }
158
159public:
161
162 // opt to reformat passive component values (e.g. 1M -> 1Meg):
163 wxCheckBox* m_CurSheetAsRoot;
164 wxCheckBox* m_SaveAllVoltages;
165 wxCheckBox* m_SaveAllCurrents;
167 wxCheckBox* m_SaveAllEvents;
170 wxTextCtrl* m_TitleStringCtrl;
171 wxBoxSizer* m_LeftBoxSizer;
172 wxBoxSizer* m_RightBoxSizer;
174 wxBoxSizer* m_LowBoxSizer;
175
176private:
179};
180
181
183{
184public:
186
187 const wxString GetGeneratorTitle() { return m_textCtrlName->GetValue(); }
188 const wxString GetGeneratorTCommandLine() { return m_textCtrlCommand->GetValue(); }
189
190 bool TransferDataFromWindow() override;
191
192private:
196 void OnBrowseGenerators( wxCommandEvent& event ) override;
197
199};
200
201
202/* Event id for notebook page buttons: */
212
213
214EXPORT_NETLIST_PAGE::EXPORT_NETLIST_PAGE( wxNotebook* aParent, const wxString& aTitle,
215 NETLIST_TYPE_ID aIdNetType, bool aCustom ) :
216 wxPanel( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ),
217 m_IdNetType( aIdNetType ),
218 m_CurSheetAsRoot( nullptr ),
219 m_SaveAllVoltages( nullptr ),
220 m_SaveAllCurrents( nullptr ),
221 m_SaveAllDissipations( nullptr ),
222 m_SaveAllEvents( nullptr ),
223 m_RunExternalSpiceCommand( nullptr ),
224 m_CommandStringCtrl( nullptr ),
225 m_TitleStringCtrl( nullptr ),
226 m_pageNetFmtName( aTitle ),
227 m_custom( aCustom )
228{
229 aParent->AddPage( this, aTitle, false );
230
231 wxBoxSizer* MainBoxSizer = new wxBoxSizer( wxVERTICAL );
232 SetSizer( MainBoxSizer );
233 wxBoxSizer* UpperBoxSizer = new wxBoxSizer( wxHORIZONTAL );
234 m_LowBoxSizer = new wxBoxSizer( wxVERTICAL );
235 MainBoxSizer->Add( UpperBoxSizer, 0, wxEXPAND | wxALL, 5 );
236 MainBoxSizer->Add( m_LowBoxSizer, 0, wxEXPAND | wxALL, 5 );
237
238 m_LeftBoxSizer = new wxBoxSizer( wxVERTICAL );
239 m_RightBoxSizer = new wxBoxSizer( wxVERTICAL );
240 m_RightOptionsBoxSizer = new wxBoxSizer( wxVERTICAL );
241 UpperBoxSizer->Add( m_LeftBoxSizer, 0, wxEXPAND | wxALL, 5 );
242 UpperBoxSizer->Add( m_RightBoxSizer, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
243 UpperBoxSizer->Add( m_RightOptionsBoxSizer, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
244}
245
246
248 DIALOG_EXPORT_NETLIST( aEditFrame, aEditFrame )
249{
250}
251
252
254 JOB_EXPORT_SCH_NETLIST* aJob ) :
256 m_job( aJob )
257{
258 m_editFrame = aEditFrame;
259
260 // Initialize the array of netlist pages
262
263 // Add notebook pages:
264 EXPORT_NETLIST_PAGE* page = nullptr;
265 wxStaticText* label = nullptr;
266
267 page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "KiCad" ), NET_TYPE_PCBNEW, false );
268 label = new wxStaticText( page, wxID_ANY, _( "Export netlist in KiCad format" ) );
269 page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
271
272 page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "OrcadPCB2" ), NET_TYPE_ORCADPCB2, false );
273 label = new wxStaticText( page, wxID_ANY, _( "Export netlist in OrcadPCB2 format" ) );
274 page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
276
277 page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "Allegro" ), NET_TYPE_ALLEGRO, false );
278 label = new wxStaticText( page, wxID_ANY, _( "Export netlist in Allegro format" ) );
279 page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
281
282 page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "CadStar" ), NET_TYPE_CADSTAR, false );
283 label = new wxStaticText( page, wxID_ANY, _( "Export netlist in CadStar format" ) );
284 page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
286
287 page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "PADS" ), NET_TYPE_PADS, false );
288 label = new wxStaticText( page, wxID_ANY, _( "Export netlist in PADS format" ) );
289 page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
291
294
295 if( !m_job )
296 {
297 m_outputPath->Hide();
300
301 SetupStandardButtons( { { wxID_OK, _( "Export Netlist" ) },
302 { wxID_CANCEL, _( "Close" ) } } );
303 }
304 else
305 {
306 SetTitle( m_job->GetSettingsDialogTitle() );
307
308 m_MessagesBox->Hide();
309 m_outputPath->SetValue( m_job->GetConfiguredOutputPath() );
310
312
313 // custom netlist (external invokes, not supported)
314 for( int ii = 0; ii < DEFINED_NETLISTS_COUNT + CUSTOMPANEL_COUNTMAX; ++ii )
315 {
316 if( EXPORT_NETLIST_PAGE* candidate = m_PanelNetType[ii] )
317 {
318 if( candidate->GetPageNetFmtName() == JOB_EXPORT_SCH_NETLIST::GetFormatNameMap()[m_job->format] )
319 {
320 m_NoteBook->ChangeSelection( ii );
321 break;
322 }
323 }
324 }
325
326 m_buttonAddGenerator->Hide();
327 m_buttonDelGenerator->Hide();
328 }
329
330 // DIALOG_SHIM needs a unique hash_key because classname will be the same for both job and
331 // non-job versions.
332 m_hash_key = TO_UTF8( GetTitle() );
333
334 // Now all widgets have the size fixed, call FinishDialogSettings
336
338}
339
340
342{
343 EXPORT_NETLIST_PAGE* pg = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "SPICE" ), NET_TYPE_SPICE, false );
344
345 wxStaticText* label = new wxStaticText( pg, wxID_ANY, _( "Export netlist in SPICE format" ) );
346 pg->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
347
348 pg->m_CurSheetAsRoot = new wxCheckBox( pg, ID_CUR_SHEET_AS_ROOT, _( "Use current sheet as root" ) );
349 pg->m_CurSheetAsRoot->SetToolTip( _( "Export netlist only for the current sheet" ) );
350 pg->m_LeftBoxSizer->Add( pg->m_CurSheetAsRoot, 0, wxGROW | wxBOTTOM | wxRIGHT, 5 );
351
352 pg->m_SaveAllVoltages = new wxCheckBox( pg, ID_SAVE_ALL_VOLTAGES, _( "Save all voltages" ) );
353 pg->m_SaveAllVoltages->SetToolTip( _( "Write a directive to save all voltages (.save all)" ) );
354 pg->m_LeftBoxSizer->Add( pg->m_SaveAllVoltages, 0, wxBOTTOM | wxRIGHT, 5 );
355
356 pg->m_SaveAllCurrents = new wxCheckBox( pg, ID_SAVE_ALL_CURRENTS, _( "Save all currents" ) );
357 pg->m_SaveAllCurrents->SetToolTip( _( "Write a directive to save all currents (.probe alli)" ) );
358 pg->m_LeftBoxSizer->Add( pg->m_SaveAllCurrents, 0, wxBOTTOM | wxRIGHT, 5 );
359
360 pg->m_SaveAllDissipations = new wxCheckBox( pg, ID_SAVE_ALL_DISSIPATIONS, _( "Save all power dissipations" ) );
361 pg->m_SaveAllDissipations->SetToolTip( _( "Write directives to save power dissipation of all items "
362 "(.probe p(<item>))" ) );
363 pg->m_LeftBoxSizer->Add( pg->m_SaveAllDissipations, 0, wxBOTTOM | wxRIGHT, 5 );
364
365 pg->m_SaveAllEvents = new wxCheckBox( pg, ID_SAVE_ALL_EVENTS, _( "Save all digital event data" ) );
366 pg->m_SaveAllEvents->SetToolTip( _( "If not set, write a directive to prevent the saving of digital event data "
367 "(esave none)" ) );
368 pg->m_LeftBoxSizer->Add( pg->m_SaveAllEvents, 0, wxBOTTOM | wxRIGHT, 5 );
369
370
371 pg->m_RunExternalSpiceCommand = new wxCheckBox( pg, ID_RUN_SIMULATOR, _( "Run external simulator command:" ) );
372 pg->m_RunExternalSpiceCommand->SetToolTip( _( "Enter the command line to run SPICE\n"
373 "Usually '<path to SPICE binary> \"%I\"'\n"
374 "%I will be replaced by the netlist filepath" ) );
375 pg->m_LowBoxSizer->Add( pg->m_RunExternalSpiceCommand, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
376
377 pg->m_CommandStringCtrl = new wxTextCtrl( pg, wxID_ANY, wxT( "spice \"%I\"" ) );
378
379 pg->m_CommandStringCtrl->SetInsertionPoint( 1 );
380 pg->m_LowBoxSizer->Add( pg->m_CommandStringCtrl, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
381
383}
384
385
387{
388 auto* pg = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "SPICE Model" ), NET_TYPE_SPICE_MODEL, false );
389
390 wxStaticText* label = new wxStaticText( pg, wxID_ANY, _( "Export netlist as a SPICE .subckt model" ) );
391 pg->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
392
393 pg->m_CurSheetAsRoot = new wxCheckBox( pg, ID_CUR_SHEET_AS_ROOT, _( "Use current sheet as root" ) );
394 pg->m_CurSheetAsRoot->SetToolTip( _( "Export netlist only for the current sheet" ) );
395 pg->m_LeftBoxSizer->Add( pg->m_CurSheetAsRoot, 0, wxEXPAND | wxBOTTOM | wxRIGHT, 5 );
396
398}
399
400
402{
403 EXPORT_NETLIST_PAGE* currPage;
404 EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
405 wxCHECK( cfg, /* void */ );
406
407 for( size_t i = 0; i < CUSTOMPANEL_COUNTMAX && i < cfg->m_NetlistPanel.plugins.size(); i++ )
408 {
409 // pairs of (title, command) are stored
410 currPage = AddOneCustomPage( cfg->m_NetlistPanel.plugins[i].name,
411 cfg->m_NetlistPanel.plugins[i].command,
412 static_cast<NETLIST_TYPE_ID>( NET_TYPE_CUSTOM1 + i ) );
413
414 m_PanelNetType[PANELCUSTOMBASE + i] = currPage;
415 }
416}
417
418
420 const wxString& aCommandString,
421 NETLIST_TYPE_ID aNetTypeId )
422{
423 EXPORT_NETLIST_PAGE* pg = new EXPORT_NETLIST_PAGE( m_NoteBook, aTitle, aNetTypeId, true );
424
425 pg->m_LowBoxSizer->Add( new wxStaticText( pg, wxID_ANY, _( "Title:" ) ), 0,
426 wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 5 );
427
428 pg->m_LowBoxSizer->AddSpacer( 2 );
429
430 pg->m_TitleStringCtrl = new wxTextCtrl( pg, wxID_ANY, aTitle );
431
432 pg->m_TitleStringCtrl->SetInsertionPoint( 1 );
433 pg->m_LowBoxSizer->Add( pg->m_TitleStringCtrl, 0, wxEXPAND | wxLEFT | wxRIGHT, 5 );
434
435 pg->m_LowBoxSizer->AddSpacer( 10 );
436
437 pg->m_LowBoxSizer->Add( new wxStaticText( pg, wxID_ANY, _( "Netlist command:" ) ), 0,
438 wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 5 );
439
440 pg->m_LowBoxSizer->AddSpacer( 2 );
441
442 pg->m_CommandStringCtrl = new wxTextCtrl( pg, wxID_ANY, aCommandString );
443
444 pg->m_CommandStringCtrl->SetInsertionPoint( 1 );
445 pg->m_LowBoxSizer->Add( pg->m_CommandStringCtrl, 0, wxEXPAND | wxLEFT | wxRIGHT, 5 );
446
447 return pg;
448}
449
450
452{
454}
455
456
458{
459 wxFileName fn;
460 wxString fileWildcard;
461 wxString fileExt;
462 wxString title = _( "Save Netlist File" );
463
464 if( m_job )
465 {
466 for( const auto& [format, name] : JOB_EXPORT_SCH_NETLIST::GetFormatNameMap() )
467 {
468 if( name == m_PanelNetType[m_NoteBook->GetSelection()]->GetPageNetFmtName() )
469 {
470 m_job->format = format;
471 break;
472 }
473 }
474
475 m_job->SetConfiguredOutputPath( m_outputPath->GetValue() );
476 m_job->m_spiceSaveAllVoltages = m_PanelNetType[ PANELSPICE ]->m_SaveAllVoltages->IsChecked();
477 m_job->m_spiceSaveAllCurrents = m_PanelNetType[ PANELSPICE ]->m_SaveAllCurrents->IsChecked();
478 m_job->m_spiceSaveAllDissipations = m_PanelNetType[ PANELSPICE ]->m_SaveAllDissipations->IsChecked();
479 m_job->m_spiceSaveAllEvents = m_PanelNetType[ PANELSPICE ]->m_SaveAllEvents->IsChecked();
480
481 return true;
482 }
483
484 EXPORT_NETLIST_PAGE* currPage;
485 currPage = (EXPORT_NETLIST_PAGE*) m_NoteBook->GetCurrentPage();
486
487 bool runExternalSpiceCommand = false;
488 unsigned netlist_opt = 0;
489
490 // Calculate the netlist filename
491 fn = m_editFrame->Schematic().GetFileName();
492 FilenamePrms( currPage->m_IdNetType, &fileExt, &fileWildcard );
493
494 // Set some parameters
495 switch( currPage->m_IdNetType )
496 {
497 case NET_TYPE_SPICE:
498 // Set spice netlist options:
500
501 if( currPage->m_SaveAllVoltages->GetValue() )
503
504 if( currPage->m_SaveAllCurrents->GetValue() )
506
507 if( currPage->m_SaveAllDissipations->GetValue() )
509
510 if( currPage->m_SaveAllEvents->GetValue() )
512
513 if( currPage->m_CurSheetAsRoot->GetValue() )
515
516 runExternalSpiceCommand = currPage->m_RunExternalSpiceCommand->GetValue();
517 break;
518
520 if( currPage->m_CurSheetAsRoot->GetValue() )
522
523 break;
524
525 case NET_TYPE_CADSTAR:
526 break;
527
528 case NET_TYPE_PCBNEW:
529 break;
530
532 break;
533
534 case NET_TYPE_ALLEGRO:
535 break;
536
537 case NET_TYPE_PADS:
538 break;
539
540 default: // custom, NET_TYPE_CUSTOM1 and greater
541 title.Printf( _( "%s Export" ), currPage->m_TitleStringCtrl->GetValue() );
542 break;
543 }
544
545 wxString fullpath;
546
547 if( runExternalSpiceCommand )
548 {
549 fn.SetExt( FILEEXT::SpiceFileExtension );
550 fullpath = fn.GetFullPath();
551 }
552 else
553 {
554 fn.SetExt( fileExt );
555
556 if( fn.GetPath().IsEmpty() )
557 fn.SetPath( wxPathOnly( Prj().GetProjectFullName() ) );
558
559 wxString fullname = fn.GetFullName();
560 wxString path = fn.GetPath();
561
562 // full name does not and should not include the path, per wx docs.
563 wxFileDialog dlg( this, title, path, fullname, fileWildcard, wxFD_SAVE );
564
566
567 if( dlg.ShowModal() == wxID_CANCEL )
568 return false;
569
570 fullpath = dlg.GetPath(); // directory + filename
571 }
572
573 m_editFrame->ClearMsgPanel();
574 REPORTER& reporter = m_MessagesBox->Reporter();
575
576 if( currPage->m_CommandStringCtrl )
577 m_editFrame->SetNetListerCommand( currPage->m_CommandStringCtrl->GetValue() );
578 else
579 m_editFrame->SetNetListerCommand( wxEmptyString );
580
581 if( !m_editFrame->ReadyToNetlist( _( "Exporting netlist requires a fully annotated schematic." ) ) )
582 return false;
583
584 m_editFrame->WriteNetListFile( currPage->m_IdNetType, fullpath, netlist_opt, &reporter );
585
586 if( runExternalSpiceCommand )
587 {
588 // Build the command line
589 wxString commandLine = m_PanelNetType[ PANELSPICE ]->m_CommandStringCtrl->GetValue();
590 commandLine.Replace( wxS( "%I" ), fullpath, true );
591 commandLine.Trim( true ).Trim( false );
592
593 if( !commandLine.IsEmpty() )
594 {
595 std::vector<wxString> argsStrings = SplitCommandLine( commandLine );
596
597 if( !argsStrings.empty() )
598 {
599 std::vector<const wxChar*> argv;
600 argv.reserve( argsStrings.size() + 1 );
601
602 for( wxString& arg : argsStrings )
603 argv.emplace_back( arg.wc_str() );
604
605 argv.emplace_back( nullptr );
606
607 wxExecuteEnv env;
608 wxGetEnvMap( &env.env );
609
610 const ENV_VAR_MAP& envVars = Pgm().GetLocalEnvVariables();
611
612 for( const auto& [key, value] : envVars )
613 {
614 if( !value.GetValue().IsEmpty() )
615 env.env[key] = value.GetValue();
616 }
617
618 wxFileName netlistFile( fullpath );
619
620 if( !netlistFile.IsAbsolute() )
621 netlistFile.MakeAbsolute( Prj().GetProjectPath() );
622 else
623 netlistFile.MakeAbsolute();
624
625 wxString cwd = netlistFile.GetPath();
626
627 if( cwd.IsEmpty() )
628 cwd = Prj().GetProjectPath();
629
630 env.cwd = cwd;
631
632 wxProcess* process = new wxProcess( GetEventHandler(), wxID_ANY );
633 process->Redirect();
634
635 long pid = wxExecute( argv.data(), wxEXEC_ASYNC, process, &env );
636
637 reporter.ReportHead( commandLine, RPT_SEVERITY_ACTION );
638
639 if( pid <= 0 )
640 {
641 reporter.Report( _( "external simulator not found" ), RPT_SEVERITY_ERROR );
642 reporter.Report( _( "Note: command line is usually: "
643 "<tt>&lt;path to SPICE binary&gt; \"%I\"</tt>" ),
645 delete process;
646 }
647 else
648 {
649 process->Activate();
650
651 std::this_thread::sleep_for( std::chrono::seconds( 1 ) ); // give the process time to start and output any data or errors
652
653 if( process->IsInputAvailable() )
654 {
655 wxInputStream* in = process->GetInputStream();
656 wxTextInputStream textstream( *in );
657
658 while( in->CanRead() )
659 {
660 wxString line = textstream.ReadLine();
661
662 if( !line.IsEmpty() )
663 reporter.Report( line, RPT_SEVERITY_INFO );
664 }
665 }
666
667 if( process->IsErrorAvailable() )
668 {
669 wxInputStream* err = process->GetErrorStream();
670 wxTextInputStream textstream( *err );
671
672 while( err->CanRead() )
673 {
674 wxString line = textstream.ReadLine();
675
676 if( !line.IsEmpty() )
677 {
678 if( line.EndsWith( wxS( "failed with error 2!" ) ) ) // ENOENT
679 {
680 reporter.Report( _( "external simulator not found" ), RPT_SEVERITY_ERROR );
681 reporter.Report( _( "Note: command line is usually: "
682 "<tt>&lt;path to SPICE binary&gt; \"%I\"</tt>" ),
684 }
685 else if( line.EndsWith( wxS( "failed with error 8!" ) ) ) // ENOEXEC
686 {
687 reporter.Report( _( "external simulator has the wrong format or "
688 "architecture" ), RPT_SEVERITY_ERROR );
689 }
690 else if( line.EndsWith( "failed with error 13!" ) ) // EACCES
691 {
692 reporter.Report( _( "permission denied" ), RPT_SEVERITY_ERROR );
693 }
694 else
695 {
696 reporter.Report( line, RPT_SEVERITY_ERROR );
697 }
698 }
699 }
700 }
701
702 process->CloseOutput();
703 process->Detach();
704
705 // Do not delete process, it will delete itself when it terminates
706 }
707 }
708 }
709 }
710
712
713 return !runExternalSpiceCommand;
714}
715
716
717bool DIALOG_EXPORT_NETLIST::FilenamePrms( NETLIST_TYPE_ID aType, wxString * aExt, wxString * aWildCard )
718{
719 wxString fileExt;
720 wxString fileWildcard;
721 bool ret = true;
722
723 switch( aType )
724 {
725 case NET_TYPE_SPICE:
727 fileWildcard = FILEEXT::SpiceNetlistFileWildcard();
728 break;
729
730 case NET_TYPE_CADSTAR:
733 break;
734
738 break;
739
740 case NET_TYPE_PCBNEW:
742 fileWildcard = FILEEXT::NetlistFileWildcard();
743 break;
744
745 case NET_TYPE_ALLEGRO:
748 break;
749
750 case NET_TYPE_PADS:
752 fileWildcard = FILEEXT::PADSNetlistFileWildcard();
753 break;
754
755
756 default: // custom, NET_TYPE_CUSTOM1 and greater
757 fileWildcard = FILEEXT::AllFilesWildcard();
758 ret = false;
759 }
760
761 if( aExt )
762 *aExt = fileExt;
763
764 if( aWildCard )
765 *aWildCard = fileWildcard;
766
767 return ret;
768}
769
770
772{
773 EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
774 wxCHECK( cfg, /* void */ );
775
776 cfg->m_NetlistPanel.plugins.clear();
777
778 // Update existing custom pages
779 for( int ii = PANELCUSTOMBASE; ii < PANELCUSTOMBASE + CUSTOMPANEL_COUNTMAX; ++ii )
780 {
781 if( EXPORT_NETLIST_PAGE* currPage = m_PanelNetType[ii] )
782 {
783 wxString title = currPage->m_TitleStringCtrl->GetValue();
784 wxString command = currPage->m_CommandStringCtrl->GetValue();
785
786 if( title.IsEmpty() || command.IsEmpty() )
787 continue;
788
789 cfg->m_NetlistPanel.plugins.emplace_back( title, wxEmptyString );
790 cfg->m_NetlistPanel.plugins.back().command = command;
791 }
792 }
793}
794
795
796void DIALOG_EXPORT_NETLIST::OnDelGenerator( wxCommandEvent& event )
797{
798 EXPORT_NETLIST_PAGE* currPage = (EXPORT_NETLIST_PAGE*) m_NoteBook->GetCurrentPage();
799
800 if( !currPage->IsCustom() )
801 return;
802
803 currPage->m_CommandStringCtrl->SetValue( wxEmptyString );
804 currPage->m_TitleStringCtrl->SetValue( wxEmptyString );
805
807
808 if( IsQuasiModal() )
810 else
811 EndDialog( NET_PLUGIN_CHANGE );
812}
813
814
815void DIALOG_EXPORT_NETLIST::OnAddGenerator( wxCommandEvent& event )
816{
818
819 if( dlg.ShowModal() != wxID_OK )
820 return;
821
822 wxString title = dlg.GetGeneratorTitle();
823 wxString cmd = dlg.GetGeneratorTCommandLine();
824
825 // Verify it does not exists
826 for( int ii = PANELCUSTOMBASE; ii < PANELCUSTOMBASE + CUSTOMPANEL_COUNTMAX; ++ii )
827 {
828 if( m_PanelNetType[ii] && m_PanelNetType[ii]->GetPageNetFmtName() == title )
829 {
830 wxMessageBox( _( "This plugin already exists." ) );
831 return;
832 }
833 }
834
835 // Find the first empty slot
836 int netTypeId = PANELCUSTOMBASE;
837
838 while( m_PanelNetType[netTypeId] )
839 {
840 netTypeId++;
841
842 if( netTypeId == PANELCUSTOMBASE + CUSTOMPANEL_COUNTMAX )
843 {
844 wxMessageBox( _( "Maximum number of plugins already added to dialog." ) );
845 return;
846 }
847 }
848
849 m_PanelNetType[netTypeId] = AddOneCustomPage( title, cmd, (NETLIST_TYPE_ID)netTypeId );
850
852
853 if( IsQuasiModal() )
855 else
856 EndDialog( NET_PLUGIN_CHANGE );
857}
858
859
869
870
872{
873 if( !wxDialog::TransferDataFromWindow() )
874 return false;
875
876 if( m_textCtrlName->GetValue() == wxEmptyString )
877 {
878 wxMessageBox( _( "You must provide a netlist generator title" ) );
879 return false;
880 }
881
882 return true;
883}
884
885
887{
888 wxString FullFileName, Path;
889
890#ifndef __WXMAC__
891 Path = Pgm().GetExecutablePath();
892#else
893 Path = PATHS::GetOSXKicadDataDir() + wxT( "/plugins" );
894#endif
895
896 FullFileName = wxFileSelector( _( "Generator File" ), Path, FullFileName, wxEmptyString,
897 wxFileSelectorDefaultWildcardStr, wxFD_OPEN, this );
898
899 if( FullFileName.IsEmpty() )
900 return;
901
902 // Creates a default command line, suitable for external tool xslproc or python, based on
903 // the plugin extension ("xsl" or "exe" or "py")
904 wxString cmdLine;
905 wxFileName fn( FullFileName );
906 wxString ext = fn.GetExt();
907
908 if( ext == wxT( "xsl" ) )
909 cmdLine.Printf( wxT( "xsltproc -o \"%%O\" \"%s\" \"%%I\"" ), FullFileName );
910 else if( ext == wxT( "exe" ) || ext.IsEmpty() )
911 cmdLine.Printf( wxT( "\"%s\" > \"%%O\" < \"%%I\"" ), FullFileName );
912 else if( ext == wxT( "py" ) || ext.IsEmpty() )
913 cmdLine.Printf( wxT( "python \"%s\" \"%%I\" \"%%O\"" ), FullFileName );
914 else
915 cmdLine.Printf( wxT( "\"%s\"" ), FullFileName );
916
917 m_textCtrlCommand->SetValue( cmdLine );
918
919 // We need a title for this panel
920 // Propose a default value if empty ( i.e. the short filename of the script)
921 if( m_textCtrlName->GetValue().IsEmpty() )
922 m_textCtrlName->SetValue( fn.GetName() );
923}
924
925
927{
928 EXPORT_NETLIST_PAGE* currPage = (EXPORT_NETLIST_PAGE*) m_NoteBook->GetCurrentPage();
929
930 if( currPage == nullptr )
931 return;
932
933 m_buttonDelGenerator->Enable( currPage->IsCustom() );
934}
935
936
938{
939 DIALOG_EXPORT_NETLIST dlg( aCaller );
940
941 int ret = dlg.ShowModal();
942 aCaller->SaveProjectLocalSettings();
943
944 return ret;
945}
const char * name
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
DIALOG_EXPORT_NETLIST_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Export Netlist"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
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)
std::vector< EXPORT_NETLIST_PAGE * > m_PanelNetType
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
bool IsQuasiModal() const
Definition dialog_shim.h:90
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
int ShowModal() override
PANEL_NETLIST m_NetlistPanel
const wxString GetPageNetFmtName()
~EXPORT_NETLIST_PAGE()=default
EXPORT_NETLIST_PAGE(wxNotebook *aParent, const wxString &aTitle, NETLIST_TYPE_ID aIdNetType, bool aCustom)
Create a setup page for one netlist format.
static std::map< JOB_EXPORT_SCH_NETLIST::FORMAT, wxString > & GetFormatNameMap()
APP_SETTINGS_BASE * KifaceSettings() const
Definition kiface_base.h:91
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
NETLIST_DIALOG_ADD_GENERATOR_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Add Script-based Netlist Exporter"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
NETLIST_DIALOG_ADD_GENERATOR(DIALOG_EXPORT_NETLIST *parent)
void OnBrowseGenerators(wxCommandEvent &event) override
Browse plugin files, and set m_CommandStringCtrl field.
virtual ENV_VAR_MAP & GetLocalEnvVariables() const
Definition pgm_base.cpp:774
virtual const wxString & GetExecutablePath() const
Definition pgm_base.cpp:854
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition project.cpp:183
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:71
Schematic editor (Eeschema) main window.
void SaveProjectLocalSettings() override
Save changes to the project settings to the project (.pro) file.
@ DEFINED_NETLISTS_COUNT
@ ID_SAVE_ALL_VOLTAGES
@ ID_SAVE_ALL_CURRENTS
@ ID_CUR_SHEET_AS_ROOT
@ ID_SAVE_ALL_DISSIPATIONS
#define CUSTOMPANEL_COUNTMAX
int InvokeDialogNetList(SCH_EDIT_FRAME *aCaller)
#define _(s)
NETLIST_TYPE_ID
netlist types
@ ID_END_EESCHEMA_ID_LIST
Definition eeschema_id.h:70
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()
std::map< wxString, ENV_VAR_ITEM > ENV_VAR_MAP
#define NET_PLUGIN_CHANGE
Create and shows DIALOG_EXPORT_NETLIST and returns whatever DIALOG_EXPORT_NETLIST::ShowModal() return...
void AllowNetworkFileSystems(wxDialog *aDialog)
Configure a file dialog to show network and virtual file systems.
Definition wxgtk/ui.cpp:448
static PGM_BASE * process
PGM_BASE & Pgm()
The global program "get" accessor.
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.
std::vector< NETLIST_PLUGIN_SETTINGS > plugins
std::string path
IbisParser parser & reporter
Definition of file extensions used in Kicad.