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>
44#include <netlist.h>
47#include <invoke_sch_dialog.h>
49#include <eeschema_settings.h>
50#include <schematic.h>
51#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
85/* wxPanels for creating the NoteBook pages for each netlist format: */
86class EXPORT_NETLIST_PAGE : public wxPanel
87{
88
89public:
99 EXPORT_NETLIST_PAGE( wxNotebook* aParent, const wxString& aTitle,
100 NETLIST_TYPE_ID aIdNetType, bool aCustom );
102
106 const wxString GetPageNetFmtName() { return m_pageNetFmtName; }
107
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
132/* Dialog frame for creating netlists */
134{
135public:
138
139private:
140 void InstallCustomPages();
141 EXPORT_NETLIST_PAGE* AddOneCustomPage( const wxString& aTitle, const wxString& aCommandString,
142 NETLIST_TYPE_ID aNetTypeId );
143 void InstallPageSpice();
145
146 bool TransferDataFromWindow() override;
147 bool NetlistUpdateOpt();
148
150
151 // Called when changing the notebook page (and therefore the current netlist format)
152 void OnNetlistTypeSelection( wxNotebookEvent& event ) override;
153
157 void OnAddGenerator( wxCommandEvent& event ) override;
158
162 void OnDelGenerator( wxCommandEvent& event ) override;
163
168
178 bool FilenamePrms( NETLIST_TYPE_ID aType, wxString* aExt, wxString* aWildCard );
179
180public:
183};
184
185
187{
188public:
190
191 const wxString GetGeneratorTitle() { return m_textCtrlName->GetValue(); }
192 const wxString GetGeneratorTCommandLine() { return m_textCtrlCommand->GetValue(); }
193
194 bool TransferDataFromWindow() override;
195
196private:
197 /*
198 * Browse plugin files, and set m_CommandStringCtrl field
199 */
200 void OnBrowseGenerators( wxCommandEvent& event ) override;
201
203};
204
205
206/* Event id for notebook page buttons: */
216
217
218EXPORT_NETLIST_PAGE::EXPORT_NETLIST_PAGE( wxNotebook* aParent, const wxString& aTitle,
219 NETLIST_TYPE_ID aIdNetType, bool aCustom ) :
220 wxPanel( aParent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL )
221{
222 m_IdNetType = aIdNetType;
223 m_pageNetFmtName = aTitle;
224 m_CommandStringCtrl = nullptr;
225 m_CurSheetAsRoot = nullptr;
226 m_TitleStringCtrl = nullptr;
227 m_SaveAllVoltages = nullptr;
228 m_SaveAllCurrents = nullptr;
229 m_SaveAllDissipations = nullptr;
230 m_SaveAllEvents = nullptr;
232 m_custom = aCustom;
233
234 aParent->AddPage( this, aTitle, false );
235
236 wxBoxSizer* MainBoxSizer = new wxBoxSizer( wxVERTICAL );
237 SetSizer( MainBoxSizer );
238 wxBoxSizer* UpperBoxSizer = new wxBoxSizer( wxHORIZONTAL );
239 m_LowBoxSizer = new wxBoxSizer( wxVERTICAL );
240 MainBoxSizer->Add( UpperBoxSizer, 0, wxGROW | wxALL, 5 );
241 MainBoxSizer->Add( m_LowBoxSizer, 0, wxGROW | wxALL, 5 );
242
243 m_LeftBoxSizer = new wxBoxSizer( wxVERTICAL );
244 m_RightBoxSizer = new wxBoxSizer( wxVERTICAL );
245 m_RightOptionsBoxSizer = new wxBoxSizer( wxVERTICAL );
246 UpperBoxSizer->Add( m_LeftBoxSizer, 0, wxGROW | wxALL, 5 );
247 UpperBoxSizer->Add( m_RightBoxSizer, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
248 UpperBoxSizer->Add( m_RightOptionsBoxSizer, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
249}
250
251
254{
255 m_Parent = parent;
256
258
259 for( EXPORT_NETLIST_PAGE*& page : m_PanelNetType )
260 page = nullptr;
261
262 // Add notebook pages:
263 EXPORT_NETLIST_PAGE* page = nullptr;
264 wxStaticText* label = nullptr;
265
266 page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "KiCad" ), NET_TYPE_PCBNEW, false );
267 label = new wxStaticText( page, wxID_ANY, _( "Export netlist in legacy KiCad format" ) );
268 page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
270
271 page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "OrcadPCB2" ), NET_TYPE_ORCADPCB2, false );
272 label = new wxStaticText( page, wxID_ANY, _( "Export netlist in OrcadPCB2 format" ) );
273 page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
275
276 page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "Allegro" ), NET_TYPE_ALLEGRO, false );
277 label = new wxStaticText( page, wxID_ANY, _( "Export netlist in Allegro format" ) );
278 page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
280
281 page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "PADS" ), NET_TYPE_PADS, false );
282 label = new wxStaticText( page, wxID_ANY, _( "Export netlist in PADS format" ) );
283 page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
285
286 page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "CadStar" ), NET_TYPE_CADSTAR, false );
287 label = new wxStaticText( page, wxID_ANY, _( "Export netlist in CadStar format" ) );
288 page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
290
294
295 SetupStandardButtons( { { wxID_OK, _( "Export Netlist" ) },
296 { wxID_CANCEL, _( "Close" ) } } );
297
298 for( int ii = 0; ii < DEFINED_NETLISTS_COUNT + CUSTOMPANEL_COUNTMAX; ++ii )
299 {
300 if( EXPORT_NETLIST_PAGE* candidate = m_PanelNetType[ii] )
301 {
302 if( candidate->GetPageNetFmtName() == settings.m_NetFormatName )
303 {
304 m_NoteBook->ChangeSelection( ii );
305 break;
306 }
307 }
308 }
309
310 // Now all widgets have the size fixed, call FinishDialogSettings
312
314}
315
316
318{
320 new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "SPICE" ), NET_TYPE_SPICE, false );
321
323
324 wxStaticText* label = new wxStaticText( page, wxID_ANY, _( "Export netlist in SPICE format" ) );
325 page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
326
327 page->m_CurSheetAsRoot = new wxCheckBox( page, ID_CUR_SHEET_AS_ROOT,
328 _( "Use current sheet as root" ) );
329 page->m_CurSheetAsRoot->SetToolTip( _( "Export netlist only for the current sheet" ) );
330 page->m_CurSheetAsRoot->SetValue( settings.m_SpiceCurSheetAsRoot );
331 page->m_LeftBoxSizer->Add( page->m_CurSheetAsRoot, 0, wxGROW | wxBOTTOM | wxRIGHT, 5 );
332
333 page->m_SaveAllVoltages = new wxCheckBox( page, ID_SAVE_ALL_VOLTAGES,
334 _( "Save all voltages" ) );
335 page->m_SaveAllVoltages->SetToolTip( _( "Write a directive to save all voltages (.save all)" ) );
336 page->m_SaveAllVoltages->SetValue( settings.m_SpiceSaveAllVoltages );
337 page->m_LeftBoxSizer->Add( page->m_SaveAllVoltages, 0, wxBOTTOM | wxRIGHT, 5 );
338
339 page->m_SaveAllCurrents = new wxCheckBox( page, ID_SAVE_ALL_CURRENTS,
340 _( "Save all currents" ) );
341 page->m_SaveAllCurrents->SetToolTip( _( "Write a directive to save all currents (.probe alli)" ) );
342 page->m_SaveAllCurrents->SetValue( settings.m_SpiceSaveAllCurrents );
343 page->m_LeftBoxSizer->Add( page->m_SaveAllCurrents, 0, wxBOTTOM | wxRIGHT, 5 );
344
345 page->m_SaveAllDissipations = new wxCheckBox( page, ID_SAVE_ALL_DISSIPATIONS,
346 _( "Save all power dissipations" ) );
347 page->m_SaveAllDissipations->SetToolTip( _( "Write directives to save power dissipation of all items (.probe p(<item>))" ) );
348 page->m_SaveAllDissipations->SetValue( settings.m_SpiceSaveAllDissipations );
349 page->m_LeftBoxSizer->Add( page->m_SaveAllDissipations, 0, wxBOTTOM | wxRIGHT, 5 );
350
351 page->m_SaveAllEvents = new wxCheckBox( page, ID_SAVE_ALL_EVENTS,
352 _( "Save all digital event data" ) );
353 page->m_SaveAllEvents->SetToolTip( _( "If not set, write a directive to prevent the saving of digital event data (esave none)" ) );
354 page->m_SaveAllEvents->SetValue( settings.m_SpiceSaveAllEvents );
355 page->m_LeftBoxSizer->Add( page->m_SaveAllEvents, 0, wxBOTTOM | wxRIGHT, 5 );
356
357
358 page->m_RunExternalSpiceCommand = new wxCheckBox( page, ID_RUN_SIMULATOR,
359 _( "Run external simulator command:" ) );
360 wxString simulatorCommand = settings.m_SpiceCommandString;
361 page->m_RunExternalSpiceCommand->SetToolTip( _( "Enter the command line to run SPICE\n"
362 "Usually '<path to SPICE binary> \"%I\"'\n"
363 "%I will be replaced by the netlist filepath" ) );
364 page->m_LowBoxSizer->Add( page->m_RunExternalSpiceCommand, 0,
365 wxGROW | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
366
367 page->m_CommandStringCtrl = new wxTextCtrl( page, -1, simulatorCommand,
368 wxDefaultPosition, wxDefaultSize );
369
370 page->m_CommandStringCtrl->SetInsertionPoint( 1 );
371 page->m_LowBoxSizer->Add( page->m_CommandStringCtrl, 0,
372 wxGROW | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
373}
374
375
377{
379 new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "SPICE Model" ), NET_TYPE_SPICE_MODEL, false );
380
382
383 wxStaticText* label = new wxStaticText( page, wxID_ANY, _( "Export netlist as a SPICE .subckt model" ) );
384 page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
385
386 page->m_CurSheetAsRoot = new wxCheckBox( page, ID_CUR_SHEET_AS_ROOT,
387 _( "Use current sheet as root" ) );
388 page->m_CurSheetAsRoot->SetToolTip( _( "Export netlist only for the current sheet" ) );
389 page->m_CurSheetAsRoot->SetValue( settings.m_SpiceModelCurSheetAsRoot );
390 page->m_LeftBoxSizer->Add( page->m_CurSheetAsRoot, 0, wxGROW | wxBOTTOM | wxRIGHT, 5 );
391}
392
393
395{
396 EXPORT_NETLIST_PAGE* currPage;
397 EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
398 wxCHECK( cfg, /* void */ );
399
400 for( size_t i = 0; i < CUSTOMPANEL_COUNTMAX && i < cfg->m_NetlistPanel.plugins.size(); i++ )
401 {
402 // pairs of (title, command) are stored
403 currPage = AddOneCustomPage( cfg->m_NetlistPanel.plugins[i].name,
404 cfg->m_NetlistPanel.plugins[i].command,
405 static_cast<NETLIST_TYPE_ID>( NET_TYPE_CUSTOM1 + i ) );
406
407 m_PanelNetType[PANELCUSTOMBASE + i] = currPage;
408 }
409}
410
411
413 const wxString& aCommandString,
414 NETLIST_TYPE_ID aNetTypeId )
415{
416 EXPORT_NETLIST_PAGE* currPage = new EXPORT_NETLIST_PAGE( m_NoteBook, aTitle, aNetTypeId, true );
417
418 currPage->m_LowBoxSizer->Add( new wxStaticText( currPage, -1, _( "Title:" ) ), 0,
419 wxGROW | wxLEFT | wxRIGHT | wxTOP, 5 );
420
421 currPage->m_TitleStringCtrl = new wxTextCtrl( currPage, -1, aTitle,
422 wxDefaultPosition, wxDefaultSize );
423
424 currPage->m_TitleStringCtrl->SetInsertionPoint( 1 );
425 currPage->m_LowBoxSizer->Add( currPage->m_TitleStringCtrl, 0,
426 wxGROW | wxTOP | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
427
428 currPage->m_LowBoxSizer->Add( new wxStaticText( currPage, -1, _( "Netlist command:" ) ), 0,
429 wxGROW | wxLEFT | wxRIGHT | wxTOP, 5 );
430
431 currPage->m_CommandStringCtrl = new wxTextCtrl( currPage, -1, aCommandString,
432 wxDefaultPosition, wxDefaultSize );
433
434 currPage->m_CommandStringCtrl->SetInsertionPoint( 1 );
435 currPage->m_LowBoxSizer->Add( currPage->m_CommandStringCtrl, 0,
436 wxGROW | wxTOP | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
437
438 return currPage;
439}
440
441
443{
445}
446
447
449{
450 bool changed = false;
451
452 bool saveAllVoltages = m_PanelNetType[ PANELSPICE ]->m_SaveAllVoltages->IsChecked();
453 bool saveAllCurrents = m_PanelNetType[ PANELSPICE ]->m_SaveAllCurrents->IsChecked();
454 bool saveAllDissipations = m_PanelNetType[ PANELSPICE ]->m_SaveAllDissipations->IsChecked();
455 bool saveAllEvents = m_PanelNetType[ PANELSPICE ]->m_SaveAllEvents->IsChecked();
456 wxString spiceCmdString = m_PanelNetType[ PANELSPICE ]->m_CommandStringCtrl->GetValue();
457 bool curSheetAsRoot = m_PanelNetType[ PANELSPICE ]->m_CurSheetAsRoot->GetValue();
458 bool spiceModelCurSheetAsRoot = m_PanelNetType[ PANELSPICEMODEL ]->m_CurSheetAsRoot->GetValue();
459
461 wxString netFormatName = m_PanelNetType[m_NoteBook->GetSelection()]->GetPageNetFmtName();
462
463 changed |= ( settings.m_SpiceSaveAllVoltages != saveAllVoltages );
464 changed |= ( settings.m_SpiceSaveAllCurrents != saveAllCurrents );
465 changed |= ( settings.m_SpiceSaveAllDissipations != saveAllDissipations );
466 changed |= ( settings.m_SpiceSaveAllEvents != saveAllEvents );
467 changed |= ( settings.m_SpiceCommandString != spiceCmdString );
468 changed |= ( settings.m_SpiceCurSheetAsRoot != curSheetAsRoot );
469 changed |= ( settings.m_SpiceModelCurSheetAsRoot != spiceModelCurSheetAsRoot );
470 changed |= ( settings.m_NetFormatName != netFormatName );
471
472 settings.m_SpiceSaveAllVoltages = saveAllVoltages;
473 settings.m_SpiceSaveAllCurrents = saveAllCurrents;
474 settings.m_SpiceSaveAllDissipations = saveAllDissipations;
475 settings.m_SpiceSaveAllEvents = saveAllEvents;
476 settings.m_SpiceCommandString = spiceCmdString;
477 settings.m_SpiceCurSheetAsRoot = curSheetAsRoot;
478 settings.m_SpiceModelCurSheetAsRoot = spiceModelCurSheetAsRoot;
479 settings.m_NetFormatName = netFormatName;
480
481 return changed;
482}
483
484
486{
487 wxFileName fn;
488 wxString fileWildcard;
489 wxString fileExt;
490 wxString title = _( "Save Netlist File" );
491
492 if( NetlistUpdateOpt() )
494
495 EXPORT_NETLIST_PAGE* currPage;
496 currPage = (EXPORT_NETLIST_PAGE*) m_NoteBook->GetCurrentPage();
497
498 bool runExternalSpiceCommand = false;
499 unsigned netlist_opt = 0;
500
501 // Calculate the netlist filename
503 FilenamePrms( currPage->m_IdNetType, &fileExt, &fileWildcard );
504
505 // Set some parameters
506 switch( currPage->m_IdNetType )
507 {
508 case NET_TYPE_SPICE:
509 // Set spice netlist options:
511
512 if( currPage->m_SaveAllVoltages->GetValue() )
514
515 if( currPage->m_SaveAllCurrents->GetValue() )
517
518 if( currPage->m_SaveAllDissipations->GetValue() )
520
521 if( currPage->m_SaveAllEvents->GetValue() )
523
524 if( currPage->m_CurSheetAsRoot->GetValue() )
526
527 runExternalSpiceCommand = currPage->m_RunExternalSpiceCommand->GetValue();
528 break;
529
531 if( currPage->m_CurSheetAsRoot->GetValue() )
533
534 break;
535
536 case NET_TYPE_CADSTAR:
537 break;
538
539 case NET_TYPE_PCBNEW:
540 break;
541
543 break;
544
545 case NET_TYPE_ALLEGRO:
546 break;
547
548 case NET_TYPE_PADS:
549 break;
550
551 default: // custom, NET_TYPE_CUSTOM1 and greater
552 {
553 title.Printf( _( "%s Export" ), currPage->m_TitleStringCtrl->GetValue() );
554 break;
555 }
556 }
557
558 wxString fullpath;
559
560 if( runExternalSpiceCommand )
561 {
562 fn.SetExt( FILEEXT::SpiceFileExtension );
563 fullpath = fn.GetFullPath();
564 }
565 else
566 {
567 fn.SetExt( fileExt );
568
569 if( fn.GetPath().IsEmpty() )
570 fn.SetPath( wxPathOnly( Prj().GetProjectFullName() ) );
571
572 wxString fullname = fn.GetFullName();
573 wxString path = fn.GetPath();
574
575 // full name does not and should not include the path, per wx docs.
576 wxFileDialog dlg( this, title, path, fullname, fileWildcard, wxFD_SAVE );
577
578 if( dlg.ShowModal() == wxID_CANCEL )
579 return false;
580
581 fullpath = dlg.GetPath(); // directory + filename
582 }
583
585 REPORTER& reporter = m_MessagesBox->Reporter();
586
587 if( currPage->m_CommandStringCtrl )
588 m_Parent->SetNetListerCommand( currPage->m_CommandStringCtrl->GetValue() );
589 else
590 m_Parent->SetNetListerCommand( wxEmptyString );
591
592 if( !m_Parent->ReadyToNetlist( _( "Exporting netlist requires a fully annotated schematic." ) ) )
593 return false;
594
595 m_Parent->WriteNetListFile( currPage->m_IdNetType, fullpath, netlist_opt, &reporter );
596
597 if( runExternalSpiceCommand )
598 {
599 // Build the command line
600 wxString commandLine = m_Parent->Schematic().Settings().m_SpiceCommandString;
601 commandLine.Replace( wxS( "%I" ), fullpath, true );
602 commandLine.Trim( true ).Trim( false );
603
604 if( !commandLine.IsEmpty() )
605 {
606 wxProcess* process = new wxProcess( GetEventHandler(), wxID_ANY );
607 process->Redirect();
608 wxExecute( commandLine, wxEXEC_ASYNC, process );
609
610 reporter.ReportHead( commandLine, RPT_SEVERITY_ACTION );
611 process->Activate();
612
613 std::this_thread::sleep_for( std::chrono::seconds( 1 ) ); // give the process time to start and output any data or errors
614
615 if( process->IsInputAvailable() )
616 {
617 wxInputStream* in = process->GetInputStream();
618 wxTextInputStream textstream( *in );
619
620 while( in->CanRead() )
621 {
622 wxString line = textstream.ReadLine();
623
624 if( !line.IsEmpty() )
625 reporter.Report( line, RPT_SEVERITY_INFO );
626 }
627 }
628
629 if( process->IsErrorAvailable() )
630 {
631 wxInputStream* err = process->GetErrorStream();
632 wxTextInputStream textstream( *err );
633
634 while( err->CanRead() )
635 {
636 wxString line = textstream.ReadLine();
637
638 if( !line.IsEmpty() )
639 {
640 if( line.EndsWith( wxS( "failed with error 2!" ) ) ) // ENOENT
641 {
642 reporter.Report( _( "external simulator not found" ), RPT_SEVERITY_ERROR );
643 reporter.Report( _( "Note: command line is usually: "
644 "<tt>&lt;path to SPICE binary&gt; \"%I\"</tt>" ),
646 }
647 else if( line.EndsWith( wxS( "failed with error 8!" ) ) ) // ENOEXEC
648 {
649 reporter.Report( _( "external simulator has the wrong format or "
650 "architecture" ), RPT_SEVERITY_ERROR );
651 }
652 else if( line.EndsWith( "failed with error 13!" ) ) // EACCES
653 {
654 reporter.Report( _( "permission denied" ), RPT_SEVERITY_ERROR );
655 }
656 else
657 {
658 reporter.Report( line, RPT_SEVERITY_ERROR );
659 }
660 }
661 }
662 }
663
664 process->CloseOutput();
665 process->Detach();
666
667 // Do not delete process, it will delete itself when it terminates
668 }
669 }
670
672
673 return !runExternalSpiceCommand;
674}
675
676
677bool DIALOG_EXPORT_NETLIST::FilenamePrms( NETLIST_TYPE_ID aType, wxString * aExt, wxString * aWildCard )
678{
679 wxString fileExt;
680 wxString fileWildcard;
681 bool ret = true;
682
683 switch( aType )
684 {
685 case NET_TYPE_SPICE:
687 fileWildcard = FILEEXT::SpiceNetlistFileWildcard();
688 break;
689
690 case NET_TYPE_CADSTAR:
693 break;
694
698 break;
699
700 case NET_TYPE_PCBNEW:
702 fileWildcard = FILEEXT::NetlistFileWildcard();
703 break;
704
705 case NET_TYPE_ALLEGRO:
708 break;
709
710 case NET_TYPE_PADS:
712 fileWildcard = FILEEXT::PADSNetlistFileWildcard();
713 break;
714
715
716 default: // custom, NET_TYPE_CUSTOM1 and greater
717 fileWildcard = FILEEXT::AllFilesWildcard();
718 ret = false;
719 }
720
721 if( aExt )
722 *aExt = fileExt;
723
724 if( aWildCard )
725 *aWildCard = fileWildcard;
726
727 return ret;
728}
729
730
732{
733 if( NetlistUpdateOpt() )
735
736 EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
737 wxCHECK( cfg, /* void */ );
738
739 cfg->m_NetlistPanel.plugins.clear();
740
741 // Update existing custom pages
742 for( int ii = PANELCUSTOMBASE; ii < PANELCUSTOMBASE + CUSTOMPANEL_COUNTMAX; ++ii )
743 {
744 if( EXPORT_NETLIST_PAGE* currPage = m_PanelNetType[ii] )
745 {
746 wxString title = currPage->m_TitleStringCtrl->GetValue();
747 wxString command = currPage->m_CommandStringCtrl->GetValue();
748
749 if( title.IsEmpty() || command.IsEmpty() )
750 continue;
751
752 cfg->m_NetlistPanel.plugins.emplace_back( title, wxEmptyString );
753 cfg->m_NetlistPanel.plugins.back().command = command;
754 }
755 }
756}
757
758
759void DIALOG_EXPORT_NETLIST::OnDelGenerator( wxCommandEvent& event )
760{
761 EXPORT_NETLIST_PAGE* currPage = (EXPORT_NETLIST_PAGE*) m_NoteBook->GetCurrentPage();
762
763 if( !currPage->IsCustom() )
764 return;
765
766 currPage->m_CommandStringCtrl->SetValue( wxEmptyString );
767 currPage->m_TitleStringCtrl->SetValue( wxEmptyString );
768
770
771 if( IsQuasiModal() )
773 else
774 EndDialog( NET_PLUGIN_CHANGE );
775}
776
777
778void DIALOG_EXPORT_NETLIST::OnAddGenerator( wxCommandEvent& event )
779{
781
782 if( dlg.ShowModal() != wxID_OK )
783 return;
784
785 wxString title = dlg.GetGeneratorTitle();
786 wxString cmd = dlg.GetGeneratorTCommandLine();
787
788 // Verify it does not exists
789 for( int ii = PANELCUSTOMBASE; ii < PANELCUSTOMBASE + CUSTOMPANEL_COUNTMAX; ++ii )
790 {
791 if( m_PanelNetType[ii] && m_PanelNetType[ii]->GetPageNetFmtName() == title )
792 {
793 wxMessageBox( _( "This plugin already exists." ) );
794 return;
795 }
796 }
797
798 // Find the first empty slot
799 int netTypeId = PANELCUSTOMBASE;
800
801 while( m_PanelNetType[netTypeId] )
802 {
803 netTypeId++;
804
805 if( netTypeId == PANELCUSTOMBASE + CUSTOMPANEL_COUNTMAX )
806 {
807 wxMessageBox( _( "Maximum number of plugins already added to dialog." ) );
808 return;
809 }
810 }
811
812 m_PanelNetType[netTypeId] = AddOneCustomPage( title, cmd, (NETLIST_TYPE_ID)netTypeId );
814
815 if( IsQuasiModal() )
817 else
818 EndDialog( NET_PLUGIN_CHANGE );
819}
820
821
824{
825 m_Parent = parent;
827 GetSizer()->SetSizeHints( this );
828}
829
830
832{
833 if( !wxDialog::TransferDataFromWindow() )
834 return false;
835
836 if( m_textCtrlCommand->GetValue() == wxEmptyString )
837 {
838 wxMessageBox( _( "You must provide a netlist generator command string" ) );
839 return false;
840 }
841
842 if( m_textCtrlName->GetValue() == wxEmptyString )
843 {
844 wxMessageBox( _( "You must provide a netlist generator title" ) );
845 return false;
846 }
847
848 return true;
849}
850
851
853{
854 wxString FullFileName, Path;
855
856#ifndef __WXMAC__
857 Path = Pgm().GetExecutablePath();
858#else
859 Path = PATHS::GetOSXKicadDataDir() + wxT( "/plugins" );
860#endif
861
862 FullFileName = wxFileSelector( _( "Generator File" ), Path, FullFileName,
863 wxEmptyString, wxFileSelectorDefaultWildcardStr,
864 wxFD_OPEN, this );
865
866 if( FullFileName.IsEmpty() )
867 return;
868
869 // Creates a default command line, suitable for external tool xslproc or python, based on
870 // the plugin extension ("xsl" or "exe" or "py")
871 wxString cmdLine;
872 wxFileName fn( FullFileName );
873 wxString ext = fn.GetExt();
874
875 if( ext == wxT( "xsl" ) )
876 cmdLine.Printf( wxT( "xsltproc -o \"%%O\" \"%s\" \"%%I\"" ), FullFileName );
877 else if( ext == wxT( "exe" ) || ext.IsEmpty() )
878 cmdLine.Printf( wxT( "\"%s\" > \"%%O\" < \"%%I\"" ), FullFileName );
879 else if( ext == wxT( "py" ) || ext.IsEmpty() )
880 cmdLine.Printf( wxT( "python \"%s\" \"%%I\" \"%%O\"" ), FullFileName );
881 else
882 cmdLine.Printf( wxT( "\"%s\"" ), FullFileName );
883
884 m_textCtrlCommand->SetValue( cmdLine );
885
886 // We need a title for this panel
887 // Propose a default value if empty ( i.e. the short filename of the script)
888 if( m_textCtrlName->GetValue().IsEmpty() )
889 m_textCtrlName->SetValue( fn.GetName() );
890}
891
892
894{
895 EXPORT_NETLIST_PAGE* currPage = (EXPORT_NETLIST_PAGE*) m_NoteBook->GetCurrentPage();
896
897 if( currPage == nullptr )
898 return;
899
900 m_buttonDelGenerator->Enable( currPage->IsCustom() );
901}
902
903
905{
906 DIALOG_EXPORT_NETLIST dlg( aCaller );
907
908 int ret = dlg.ShowModal();
909 aCaller->SaveProjectLocalSettings();
910
911 return ret;
912}
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: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
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 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:291
SCHEMATIC_SETTINGS & Settings() const
Definition: schematic.cpp:297
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
@ 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: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.