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 4 fixed netlist formats:
28 * Pcbnew
29 * ORCADPCB2
30 * CADSTAR
31 * SPICE
32 * and up to CUSTOMPANEL_COUNTMAX user programmable formats. These external converters are
33 * referred to as plugins, but they are really just external binaries.
34 */
35
36#include <pgm_base.h>
37#include <kiface_base.h>
38#include <gestfich.h>
40#include <sch_edit_frame.h>
41#include <netlist.h>
44#include <invoke_sch_dialog.h>
46#include <eeschema_settings.h>
47#include <schematic.h>
48#include <paths.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/regex.h>
55#include <wx/txtstrm.h>
56
57#include <thread>
58
59
60#define CUSTOMPANEL_COUNTMAX 8 // Max number of netlist plugins
61
62
63/* panel (notebook page) identifiers
64 * if modified, fix also the DEFINED_NETLISTS_COUNT value
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) */
76 PANELCUSTOMBASE /* First auxiliary panel (custom netlists).
77 * others use PANELCUSTOMBASE+1, PANELCUSTOMBASE+2.. */
78};
79
80// The count of panels for internally defined netlist formats
81// (the max count of panel is DEFINED_NETLISTS_COUNT+CUSTOMPANEL_COUNTMAX)
82#define DEFINED_NETLISTS_COUNT 6
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 // opt to reformat passive component values (e.g. 1M -> 1Meg):
109 wxCheckBox* m_CurSheetAsRoot;
110 wxCheckBox* m_SaveAllVoltages;
111 wxCheckBox* m_SaveAllCurrents;
115 wxTextCtrl* m_TitleStringCtrl;
116 wxBoxSizer* m_LeftBoxSizer;
117 wxBoxSizer* m_RightBoxSizer;
119 wxBoxSizer* m_LowBoxSizer;
120
121 bool IsCustom() const { return m_custom; }
122
123private:
125
127};
128
129
130/* Dialog frame for creating netlists */
132{
133public:
136
137private:
138 void InstallCustomPages();
139 EXPORT_NETLIST_PAGE* AddOneCustomPage( const wxString& aTitle, const wxString& aCommandString,
140 NETLIST_TYPE_ID aNetTypeId );
141 void InstallPageSpice();
143
144 bool TransferDataFromWindow() override;
145 bool NetlistUpdateOpt();
146
148
149 // Called when changing the notebook page (and therefore the current netlist format)
150 void OnNetlistTypeSelection( wxNotebookEvent& event ) override;
151
155 void OnAddGenerator( wxCommandEvent& event ) override;
156
160 void OnDelGenerator( wxCommandEvent& event ) override;
161
166
176 bool FilenamePrms( NETLIST_TYPE_ID aType, wxString* aExt, wxString* aWildCard );
177
178public:
181};
182
183
185{
186public:
188
189 const wxString GetGeneratorTitle() { return m_textCtrlName->GetValue(); }
190 const wxString GetGeneratorTCommandLine() { return m_textCtrlCommand->GetValue(); }
191
192 bool TransferDataFromWindow() override;
193
194private:
195 /*
196 * Browse plugin files, and set m_CommandStringCtrl field
197 */
198 void OnBrowseGenerators( wxCommandEvent& event ) override;
199
201};
202
203
204/* Event id for notebook page buttons: */
213
214
215EXPORT_NETLIST_PAGE::EXPORT_NETLIST_PAGE( wxNotebook* aParent, const wxString& aTitle,
216 NETLIST_TYPE_ID aIdNetType, bool aCustom ) :
217 wxPanel( aParent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL )
218{
219 m_IdNetType = aIdNetType;
220 m_pageNetFmtName = aTitle;
221 m_CommandStringCtrl = nullptr;
222 m_CurSheetAsRoot = nullptr;
223 m_TitleStringCtrl = nullptr;
224 m_SaveAllVoltages = nullptr;
225 m_SaveAllCurrents = nullptr;
226 m_SaveAllDissipations = nullptr;
228 m_custom = aCustom;
229
230 aParent->AddPage( this, aTitle, false );
231
232 wxBoxSizer* MainBoxSizer = new wxBoxSizer( wxVERTICAL );
233 SetSizer( MainBoxSizer );
234 wxBoxSizer* UpperBoxSizer = new wxBoxSizer( wxHORIZONTAL );
235 m_LowBoxSizer = new wxBoxSizer( wxVERTICAL );
236 MainBoxSizer->Add( UpperBoxSizer, 0, wxGROW | wxALL, 5 );
237 MainBoxSizer->Add( m_LowBoxSizer, 0, wxGROW | wxALL, 5 );
238
239 m_LeftBoxSizer = new wxBoxSizer( wxVERTICAL );
240 m_RightBoxSizer = new wxBoxSizer( wxVERTICAL );
241 m_RightOptionsBoxSizer = new wxBoxSizer( wxVERTICAL );
242 UpperBoxSizer->Add( m_LeftBoxSizer, 0, wxGROW | wxALL, 5 );
243 UpperBoxSizer->Add( m_RightBoxSizer, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
244 UpperBoxSizer->Add( m_RightOptionsBoxSizer, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
245}
246
247
250{
251 m_Parent = parent;
252
254
255 for( EXPORT_NETLIST_PAGE*& page : m_PanelNetType )
256 page = nullptr;
257
258 // Add notebook pages:
259 EXPORT_NETLIST_PAGE* page = nullptr;
260 wxStaticText* label = nullptr;
261
262 page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "KiCad" ), NET_TYPE_PCBNEW, false );
263 label = new wxStaticText( page, wxID_ANY, _( "Export netlist in legacy KiCad format" ) );
264 page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
266
267 page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "OrcadPCB2" ), NET_TYPE_ORCADPCB2, false );
268 label = new wxStaticText( page, wxID_ANY, _( "Export netlist in OrcadPCB2 format" ) );
269 page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
271
272 page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "Allegro" ), NET_TYPE_ALLEGRO, false );
273 label = new wxStaticText( page, wxID_ANY, _( "Export netlist in Allegro format" ) );
274 page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
276
277 page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "PADS" ), NET_TYPE_PADS, false );
278 label = new wxStaticText( page, wxID_ANY, _( "Export netlist in PADS 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
290
291 SetupStandardButtons( { { wxID_OK, _( "Export Netlist" ) },
292 { wxID_CANCEL, _( "Close" ) } } );
293
294 for( int ii = 0; (ii < 4 + CUSTOMPANEL_COUNTMAX) && m_PanelNetType[ii]; ++ii )
295 {
296 if( m_PanelNetType[ii]->GetPageNetFmtName() == settings.m_NetFormatName )
297 {
298 m_NoteBook->ChangeSelection( ii );
299 break;
300 }
301 }
302
303 // Now all widgets have the size fixed, call FinishDialogSettings
305
307}
308
309
311{
313 new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "Spice" ), NET_TYPE_SPICE, false );
314
316
317 wxStaticText* label = new wxStaticText( page, wxID_ANY, _( "Export netlist in SPICE format" ) );
318 page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
319
320 page->m_CurSheetAsRoot = new wxCheckBox( page, ID_CUR_SHEET_AS_ROOT,
321 _( "Use current sheet as root" ) );
322 page->m_CurSheetAsRoot->SetToolTip( _( "Export netlist only for the current sheet" ) );
323 page->m_CurSheetAsRoot->SetValue( settings.m_SpiceCurSheetAsRoot );
324 page->m_LeftBoxSizer->Add( page->m_CurSheetAsRoot, 0, wxGROW | wxBOTTOM | wxRIGHT, 5 );
325
326 page->m_SaveAllVoltages = new wxCheckBox( page, ID_SAVE_ALL_VOLTAGES,
327 _( "Save all voltages" ) );
328 page->m_SaveAllVoltages->SetToolTip( _( "Write a directive to save all voltages (.save all)" ) );
329 page->m_SaveAllVoltages->SetValue( settings.m_SpiceSaveAllVoltages );
330 page->m_LeftBoxSizer->Add( page->m_SaveAllVoltages, 0, wxBOTTOM | wxRIGHT, 5 );
331
332 page->m_SaveAllCurrents = new wxCheckBox( page, ID_SAVE_ALL_CURRENTS,
333 _( "Save all currents" ) );
334 page->m_SaveAllCurrents->SetToolTip( _( "Write a directive to save all currents (.probe alli)" ) );
335 page->m_SaveAllCurrents->SetValue( settings.m_SpiceSaveAllCurrents );
336 page->m_LeftBoxSizer->Add( page->m_SaveAllCurrents, 0, wxBOTTOM | wxRIGHT, 5 );
337
338 page->m_SaveAllDissipations = new wxCheckBox( page, ID_SAVE_ALL_DISSIPATIONS,
339 _( "Save all power dissipations" ) );
340 page->m_SaveAllDissipations->SetToolTip( _( "Write directives to save power dissipation of all items (.probe p(<item>))" ) );
341 page->m_SaveAllDissipations->SetValue( settings.m_SpiceSaveAllDissipations );
342 page->m_LeftBoxSizer->Add( page->m_SaveAllDissipations, 0, wxBOTTOM | wxRIGHT, 5 );
343
344
345 page->m_RunExternalSpiceCommand = new wxCheckBox( page, ID_RUN_SIMULATOR,
346 _( "Run external simulator command:" ) );
347 wxString simulatorCommand = settings.m_SpiceCommandString;
348 page->m_RunExternalSpiceCommand->SetToolTip( _( "Enter the command line to run SPICE\n"
349 "Usually '<path to SPICE binary> \"%I\"'\n"
350 "%I will be replaced by the netlist filepath" ) );
351 page->m_LowBoxSizer->Add( page->m_RunExternalSpiceCommand, 0,
352 wxGROW | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
353
354 page->m_CommandStringCtrl = new wxTextCtrl( page, -1, simulatorCommand,
355 wxDefaultPosition, wxDefaultSize );
356
357 page->m_CommandStringCtrl->SetInsertionPoint( 1 );
358 page->m_LowBoxSizer->Add( page->m_CommandStringCtrl, 0,
359 wxGROW | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
360}
361
362
364{
366 new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "Spice Model" ), NET_TYPE_SPICE_MODEL, false );
367
369
370 wxStaticText* label = new wxStaticText( page, wxID_ANY, _( "Export netlist as a SPICE .subckt model" ) );
371 page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
372
373 page->m_CurSheetAsRoot = new wxCheckBox( page, ID_CUR_SHEET_AS_ROOT,
374 _( "Use current sheet as root" ) );
375 page->m_CurSheetAsRoot->SetToolTip( _( "Export netlist only for the current sheet" ) );
376 page->m_CurSheetAsRoot->SetValue( settings.m_SpiceModelCurSheetAsRoot );
377 page->m_LeftBoxSizer->Add( page->m_CurSheetAsRoot, 0, wxGROW | wxBOTTOM | wxRIGHT, 5 );
378}
379
380
382{
383 EXPORT_NETLIST_PAGE* currPage;
384 EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
385 wxASSERT( cfg );
386
387 if( cfg )
388 {
389 for( size_t i = 0; i < CUSTOMPANEL_COUNTMAX && i < cfg->m_NetlistPanel.plugins.size(); i++ )
390 {
391 // pairs of (title, command) are stored
392 wxString title = cfg->m_NetlistPanel.plugins[i].name;
393
394 if( i >= cfg->m_NetlistPanel.plugins.size() )
395 break; // No more panel to install
396
397 wxString command = cfg->m_NetlistPanel.plugins[i].command;
398
399 currPage = AddOneCustomPage( title, command,
400 static_cast<NETLIST_TYPE_ID>( NET_TYPE_CUSTOM1 + i ) );
401
402 m_PanelNetType[PANELCUSTOMBASE + i] = currPage;
403 }
404 }
405}
406
407
409 const wxString& aCommandString,
410 NETLIST_TYPE_ID aNetTypeId )
411{
412 EXPORT_NETLIST_PAGE* currPage = new EXPORT_NETLIST_PAGE( m_NoteBook, aTitle, aNetTypeId, true );
413
414 currPage->m_LowBoxSizer->Add( new wxStaticText( currPage, -1, _( "Title:" ) ), 0,
415 wxGROW | wxLEFT | wxRIGHT | wxTOP, 5 );
416
417 currPage->m_TitleStringCtrl = new wxTextCtrl( currPage, -1, aTitle,
418 wxDefaultPosition, wxDefaultSize );
419
420 currPage->m_TitleStringCtrl->SetInsertionPoint( 1 );
421 currPage->m_LowBoxSizer->Add( currPage->m_TitleStringCtrl, 0,
422 wxGROW | wxTOP | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
423
424 currPage->m_LowBoxSizer->Add( new wxStaticText( currPage, -1, _( "Netlist command:" ) ), 0,
425 wxGROW | wxLEFT | wxRIGHT | wxTOP, 5 );
426
427 currPage->m_CommandStringCtrl = new wxTextCtrl( currPage, -1, aCommandString,
428 wxDefaultPosition, wxDefaultSize );
429
430 currPage->m_CommandStringCtrl->SetInsertionPoint( 1 );
431 currPage->m_LowBoxSizer->Add( currPage->m_CommandStringCtrl, 0,
432 wxGROW | wxTOP | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
433
434 return currPage;
435}
436
437
439{
441}
442
443
445{
446 bool changed = false;
447
448 bool saveAllVoltages = m_PanelNetType[ PANELSPICE ]->m_SaveAllVoltages->IsChecked();
449 bool saveAllCurrents = m_PanelNetType[ PANELSPICE ]->m_SaveAllCurrents->IsChecked();
450 bool saveAllDissipations = m_PanelNetType[ PANELSPICE ]->m_SaveAllDissipations->IsChecked();
451 wxString spiceCmdString = m_PanelNetType[ PANELSPICE ]->m_CommandStringCtrl->GetValue();
452 bool curSheetAsRoot = m_PanelNetType[ PANELSPICE ]->m_CurSheetAsRoot->GetValue();
453 bool spiceModelCurSheetAsRoot = m_PanelNetType[ PANELSPICEMODEL ]->m_CurSheetAsRoot->GetValue();
454
456 wxString netFormatName = m_PanelNetType[m_NoteBook->GetSelection()]->GetPageNetFmtName();
457
458 changed |= ( settings.m_SpiceSaveAllVoltages != saveAllVoltages );
459 changed |= ( settings.m_SpiceSaveAllCurrents != saveAllCurrents );
460 changed |= ( settings.m_SpiceSaveAllDissipations != saveAllDissipations );
461 changed |= ( settings.m_SpiceCommandString != spiceCmdString );
462 changed |= ( settings.m_SpiceCurSheetAsRoot != curSheetAsRoot );
463 changed |= ( settings.m_SpiceModelCurSheetAsRoot != spiceModelCurSheetAsRoot );
464 changed |= ( settings.m_NetFormatName != netFormatName );
465
466 settings.m_SpiceSaveAllVoltages = saveAllVoltages;
467 settings.m_SpiceSaveAllCurrents = saveAllCurrents;
468 settings.m_SpiceSaveAllDissipations = saveAllDissipations;
469 settings.m_SpiceCommandString = spiceCmdString;
470 settings.m_SpiceCurSheetAsRoot = curSheetAsRoot;
471 settings.m_SpiceModelCurSheetAsRoot = spiceModelCurSheetAsRoot;
472 settings.m_NetFormatName = netFormatName;
473
474 return changed;
475}
476
477
479{
480 wxFileName fn;
481 wxString fileWildcard;
482 wxString fileExt;
483 wxString title = _( "Save Netlist File" );
484
485 if( NetlistUpdateOpt() )
487
488 EXPORT_NETLIST_PAGE* currPage;
489 currPage = (EXPORT_NETLIST_PAGE*) m_NoteBook->GetCurrentPage();
490
491 bool runExternalSpiceCommand = false;
492 unsigned netlist_opt = 0;
493
494 // Calculate the netlist filename
496 FilenamePrms( currPage->m_IdNetType, &fileExt, &fileWildcard );
497
498 // Set some parameters
499 switch( currPage->m_IdNetType )
500 {
501 case NET_TYPE_SPICE:
502 // Set spice netlist options:
504
505 if( currPage->m_SaveAllVoltages->GetValue() )
507
508 if( currPage->m_SaveAllCurrents->GetValue() )
510
511 if( currPage->m_SaveAllDissipations->GetValue() )
513
514 if( currPage->m_CurSheetAsRoot->GetValue() )
516
517 runExternalSpiceCommand = currPage->m_RunExternalSpiceCommand->GetValue();
518 break;
519
521 if( currPage->m_CurSheetAsRoot->GetValue() )
523
524 break;
525
526 case NET_TYPE_CADSTAR:
527 break;
528
529 case NET_TYPE_PCBNEW:
530 break;
531
533 break;
534
535 case NET_TYPE_ALLEGRO:
536 break;
537
538 case NET_TYPE_PADS:
539 break;
540
541 default: // custom, NET_TYPE_CUSTOM1 and greater
542 {
543 title.Printf( _( "%s Export" ), currPage->m_TitleStringCtrl->GetValue() );
544 break;
545 }
546 }
547
548 wxString fullpath;
549
550 if( runExternalSpiceCommand )
551 {
552 fn.SetExt( FILEEXT::SpiceFileExtension );
553 fullpath = fn.GetFullPath();
554 }
555 else
556 {
557 fn.SetExt( fileExt );
558
559 if( fn.GetPath().IsEmpty() )
560 fn.SetPath( wxPathOnly( Prj().GetProjectFullName() ) );
561
562 wxString fullname = fn.GetFullName();
563 wxString path = fn.GetPath();
564
565 // full name does not and should not include the path, per wx docs.
566 wxFileDialog dlg( this, title, path, fullname, fileWildcard, wxFD_SAVE );
567
568 if( dlg.ShowModal() == wxID_CANCEL )
569 return false;
570
571 fullpath = dlg.GetPath(); // directory + filename
572 }
573
575 REPORTER& reporter = m_MessagesBox->Reporter();
576
577 if( currPage->m_CommandStringCtrl )
578 m_Parent->SetNetListerCommand( currPage->m_CommandStringCtrl->GetValue() );
579 else
580 m_Parent->SetNetListerCommand( wxEmptyString );
581
582 if( !m_Parent->ReadyToNetlist( _( "Exporting netlist requires a fully annotated schematic." ) ) )
583 return false;
584
585 m_Parent->WriteNetListFile( currPage->m_IdNetType, fullpath, netlist_opt, &reporter );
586
587 if( runExternalSpiceCommand )
588 {
589 // Build the command line
590 wxString commandLine = m_Parent->Schematic().Settings().m_SpiceCommandString;
591 commandLine.Replace( wxS( "%I" ), fullpath, true );
592 commandLine.Trim( true ).Trim( false );
593
594 if( !commandLine.IsEmpty() )
595 {
596 wxProcess* process = new wxProcess( GetEventHandler(), wxID_ANY );
597 process->Redirect();
598 wxExecute( commandLine, wxEXEC_ASYNC, process );
599
600 reporter.ReportHead( commandLine, RPT_SEVERITY_ACTION );
601 process->Activate();
602
603 std::this_thread::sleep_for( std::chrono::seconds( 1 ) ); // give the process time to start and output any data or errors
604
605 if( process->IsInputAvailable() )
606 {
607 wxInputStream* in = process->GetInputStream();
608 wxTextInputStream textstream( *in );
609
610 while( in->CanRead() )
611 {
612 wxString line = textstream.ReadLine();
613
614 if( !line.IsEmpty() )
615 reporter.Report( line, RPT_SEVERITY_INFO );
616 }
617 }
618
619 if( process->IsErrorAvailable() )
620 {
621 wxInputStream* err = process->GetErrorStream();
622 wxTextInputStream textstream( *err );
623
624 while( err->CanRead() )
625 {
626 wxString line = textstream.ReadLine();
627
628 if( !line.IsEmpty() )
629 {
630 if( line.EndsWith( wxS( "failed with error 2!" ) ) ) // ENOENT
631 {
632 reporter.Report( _( "external simulator not found" ), RPT_SEVERITY_ERROR );
633 reporter.Report( _( "Note: command line is usually: "
634 "<tt>&lt;path to SPICE binary&gt; \"%I\"</tt>" ),
636 }
637 else if( line.EndsWith( wxS( "failed with error 8!" ) ) ) // ENOEXEC
638 {
639 reporter.Report( _( "external simulator has the wrong format or "
640 "architecture" ), RPT_SEVERITY_ERROR );
641 }
642 else if( line.EndsWith( "failed with error 13!" ) ) // EACCES
643 {
644 reporter.Report( _( "permission denied" ), RPT_SEVERITY_ERROR );
645 }
646 else
647 {
648 reporter.Report( line, RPT_SEVERITY_ERROR );
649 }
650 }
651 }
652 }
653
654 process->CloseOutput();
655 process->Detach();
656
657 // Do not delete process, it will delete itself when it terminates
658 }
659 }
660
662
663 return !runExternalSpiceCommand;
664}
665
666
667bool DIALOG_EXPORT_NETLIST::FilenamePrms( NETLIST_TYPE_ID aType, wxString * aExt, wxString * aWildCard )
668{
669 wxString fileExt;
670 wxString fileWildcard;
671 bool ret = true;
672
673 switch( aType )
674 {
675 case NET_TYPE_SPICE:
677 fileWildcard = FILEEXT::SpiceNetlistFileWildcard();
678 break;
679
680 case NET_TYPE_CADSTAR:
683 break;
684
688 break;
689
690 case NET_TYPE_PCBNEW:
692 fileWildcard = FILEEXT::NetlistFileWildcard();
693 break;
694
695 case NET_TYPE_ALLEGRO:
698 break;
699
700 case NET_TYPE_PADS:
702 fileWildcard = FILEEXT::PADSNetlistFileWildcard();
703 break;
704
705
706 default: // custom, NET_TYPE_CUSTOM1 and greater
707 fileWildcard = FILEEXT::AllFilesWildcard();
708 ret = false;
709 }
710
711 if( aExt )
712 *aExt = fileExt;
713
714 if( aWildCard )
715 *aWildCard = fileWildcard;
716
717 return ret;
718}
719
720
722{
723 if( NetlistUpdateOpt() )
725
726 EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
727 wxASSERT( cfg );
728
729 if( !cfg )
730 return;
731
732 cfg->m_NetlistPanel.plugins.clear();
733
734 // Update existing custom pages
735 for( int ii = 0; ii < CUSTOMPANEL_COUNTMAX; ii++ )
736 {
738
739 if( currPage == nullptr )
740 break;
741
742 wxString title = currPage->m_TitleStringCtrl->GetValue();
743 wxString command = currPage->m_CommandStringCtrl->GetValue();
744
745 if( title.IsEmpty() || command.IsEmpty() )
746 continue;
747
748 cfg->m_NetlistPanel.plugins.emplace_back( title, wxEmptyString );
749 cfg->m_NetlistPanel.plugins.back().command = command;
750 }
751}
752
753
754void DIALOG_EXPORT_NETLIST::OnDelGenerator( wxCommandEvent& event )
755{
756 EXPORT_NETLIST_PAGE* currPage = (EXPORT_NETLIST_PAGE*) m_NoteBook->GetCurrentPage();
757
758 if( !currPage->IsCustom() )
759 return;
760
761 currPage->m_CommandStringCtrl->SetValue( wxEmptyString );
762 currPage->m_TitleStringCtrl->SetValue( wxEmptyString );
763
765
766 if( IsQuasiModal() )
768 else
769 EndDialog( NET_PLUGIN_CHANGE );
770}
771
772
773void DIALOG_EXPORT_NETLIST::OnAddGenerator( wxCommandEvent& event )
774{
776
777 if( dlg.ShowModal() != wxID_OK )
778 return;
779
780 // Creates a new custom plugin page
781 wxString title = dlg.GetGeneratorTitle();
782
783 // Verify it does not exists
784 int netTypeId = PANELCUSTOMBASE; // the first not used type id
785 EXPORT_NETLIST_PAGE* currPage;
786
787 for( int ii = 0; ii < CUSTOMPANEL_COUNTMAX; ii++ )
788 {
789 netTypeId = PANELCUSTOMBASE + ii;
790 currPage = m_PanelNetType[ii + PANELCUSTOMBASE];
791
792 if( currPage == nullptr )
793 break;
794
795 if( currPage->GetPageNetFmtName() == title )
796 {
797 wxMessageBox( _("This plugin already exists.") );
798 return;
799 }
800 }
801
802 wxString cmd = dlg.GetGeneratorTCommandLine();
803 currPage = AddOneCustomPage( title,cmd, (NETLIST_TYPE_ID)netTypeId );
804 m_PanelNetType[netTypeId] = currPage;
806
807 if( IsQuasiModal() )
809 else
810 EndDialog( NET_PLUGIN_CHANGE );
811}
812
813
816{
817 m_Parent = parent;
819 GetSizer()->SetSizeHints( this );
820}
821
822
824{
825 if( !wxDialog::TransferDataFromWindow() )
826 return false;
827
828 if( m_textCtrlCommand->GetValue() == wxEmptyString )
829 {
830 wxMessageBox( _( "You must provide a netlist generator command string" ) );
831 return false;
832 }
833
834 if( m_textCtrlName->GetValue() == wxEmptyString )
835 {
836 wxMessageBox( _( "You must provide a netlist generator title" ) );
837 return false;
838 }
839
840 return true;
841}
842
843
845{
846 wxString FullFileName, Path;
847
848#ifndef __WXMAC__
849 Path = Pgm().GetExecutablePath();
850#else
851 Path = PATHS::GetOSXKicadDataDir() + wxT( "/plugins" );
852#endif
853
854 FullFileName = wxFileSelector( _( "Generator File" ), Path, FullFileName,
855 wxEmptyString, wxFileSelectorDefaultWildcardStr,
856 wxFD_OPEN, this );
857
858 if( FullFileName.IsEmpty() )
859 return;
860
861 // Creates a default command line, suitable for external tool xslproc or python, based on
862 // the plugin extension ("xsl" or "exe" or "py")
863 wxString cmdLine;
864 wxFileName fn( FullFileName );
865 wxString ext = fn.GetExt();
866
867 if( ext == wxT( "xsl" ) )
868 cmdLine.Printf( wxT( "xsltproc -o \"%%O\" \"%s\" \"%%I\"" ), FullFileName );
869 else if( ext == wxT( "exe" ) || ext.IsEmpty() )
870 cmdLine.Printf( wxT( "\"%s\" > \"%%O\" < \"%%I\"" ), FullFileName );
871 else if( ext == wxT( "py" ) || ext.IsEmpty() )
872 cmdLine.Printf( wxT( "python \"%s\" \"%%I\" \"%%O\"" ), FullFileName );
873 else
874 cmdLine.Printf( wxT( "\"%s\"" ), FullFileName );
875
876 m_textCtrlCommand->SetValue( cmdLine );
877
878 // We need a title for this panel
879 // Propose a default value if empty ( i.e. the short filename of the script)
880 if( m_textCtrlName->GetValue().IsEmpty() )
881 m_textCtrlName->SetValue( fn.GetName() );
882}
883
884
886{
887 EXPORT_NETLIST_PAGE* currPage = (EXPORT_NETLIST_PAGE*) m_NoteBook->GetCurrentPage();
888
889 if( currPage == nullptr )
890 return;
891
892 m_buttonDelGenerator->Enable( currPage->IsCustom() );
893}
894
895
897{
898 DIALOG_EXPORT_NETLIST dlg( aCaller );
899
900 int ret = dlg.ShowModal();
901 aCaller->SaveProjectLocalSettings();
902
903 return ret;
904}
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
void OnAddGenerator(wxCommandEvent &event) override
Add a new panel for a new netlist plugin.
void OnNetlistTypeSelection(wxNotebookEvent &event) override
EXPORT_NETLIST_PAGE * m_PanelNetType[DEFINED_NETLISTS_COUNT+CUSTOMPANEL_COUNTMAX]
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 *parent)
void SetupStandardButtons(std::map< int, wxString > aLabels={})
bool IsQuasiModal() const
Definition: dialog_shim.h:107
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
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:1038
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:71
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:108
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
These settings were stored in SCH_BASE_FRAME previously.
wxString GetFileName() const override
Helper to retrieve the filename from the root sheet screen.
Definition: schematic.cpp:281
SCHEMATIC_SETTINGS & Settings() const
Definition: schematic.cpp:287
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)
@ PANELSPICEMODEL
@ 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
#define DEFINED_NETLISTS_COUNT
#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:1057
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: pgm_base.cpp:1059
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.