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