kicad/eeschema/dialogs/dialog_export_netlist.cpp

873 lines
30 KiB
C++
Raw Normal View History

2011-12-16 20:12:49 +00:00
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013-2017 Jean-Pierre Charras, jp.charras@wanadoo.fr
* Copyright (C) 2013 Wayne Stambaugh <stambaughw@gmail.com>
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
2011-12-16 20:12:49 +00:00
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/* Functions relative to the dialog creating the netlist for Pcbnew. The dialog is a notebook
* with 4 fixed netlist formats:
* Pcbnew
* ORCADPCB2
* CADSTAR
* SPICE
* and up to CUSTOMPANEL_COUNTMAX user programmable formats. These external converters are
* referred to as plugins, but they are really just external binaries.
*/
* KIWAY Milestone A): Make major modules into DLL/DSOs. ! The initial testing of this commit should be done using a Debug build so that all the wxASSERT()s are enabled. Also, be sure and keep enabled the USE_KIWAY_DLLs option. The tree won't likely build without it. Turning it off is senseless anyways. If you want stable code, go back to a prior version, the one tagged with "stable". * Relocate all functionality out of the wxApp derivative into more finely targeted purposes: a) DLL/DSO specific b) PROJECT specific c) EXE or process specific d) configuration file specific data e) configuration file manipulations functions. All of this functionality was blended into an extremely large wxApp derivative and that was incompatible with the desire to support multiple concurrently loaded DLL/DSO's ("KIFACE")s and multiple concurrently open projects. An amazing amount of organization come from simply sorting each bit of functionality into the proper box. * Switch to wxConfigBase from wxConfig everywhere except instantiation. * Add classes KIWAY, KIFACE, KIFACE_I, SEARCH_STACK, PGM_BASE, PGM_KICAD, PGM_SINGLE_TOP, * Remove "Return" prefix on many function names. * Remove obvious comments from CMakeLists.txt files, and from else() and endif()s. * Fix building boost for use in a DSO on linux. * Remove some of the assumptions in the CMakeLists.txt files that windows had to be the host platform when building windows binaries. * Reduce the number of wxStrings being constructed at program load time via static construction. * Pass wxConfigBase* to all SaveSettings() and LoadSettings() functions so that these functions are useful even when the wxConfigBase comes from another source, as is the case in the KICAD_MANAGER_FRAME. * Move the setting of the KIPRJMOD environment variable into class PROJECT, so that it can be moved into a project variable soon, and out of FP_LIB_TABLE. * Add the KIWAY_PLAYER which is associated with a particular PROJECT, and all its child wxFrames and wxDialogs now have a Kiway() member function which returns a KIWAY& that that window tree branch is in support of. This is like wxWindows DNA in that child windows get this member with proper value at time of construction. * Anticipate some of the needs for milestones B) and C) and make code adjustments now in an effort to reduce work in those milestones. * No testing has been done for python scripting, since milestone C) has that being largely reworked and re-thought-out.
2014-03-20 00:42:08 +00:00
#include <pgm_base.h>
2021-09-14 22:45:14 +00:00
#include <kiface_base.h>
#include <gestfich.h>
2022-11-18 15:27:53 +00:00
#include <widgets/wx_html_report_panel.h>
2018-01-30 10:49:51 +00:00
#include <sch_edit_frame.h>
#include <netlist.h>
#include <dialogs/dialog_export_netlist_base.h>
#include <wildcards_and_files_ext.h>
2013-06-27 20:34:30 +00:00
#include <invoke_sch_dialog.h>
#include <netlist_exporters/netlist_exporter_spice.h>
#include <eeschema_settings.h>
#include <schematic.h>
#include <paths.h>
#include <eeschema_id.h>
2021-06-03 11:49:49 +00:00
#include <wx/checkbox.h>
#include <wx/filedlg.h>
#include <wx/msgdlg.h>
2021-06-03 11:49:49 +00:00
#include <wx/regex.h>
#include <wx/txtstrm.h>
2023-11-27 23:03:06 +00:00
#include <thread>
2013-06-27 20:34:30 +00:00
#define CUSTOMPANEL_COUNTMAX 8 // Max number of netlist plugins
2023-07-08 07:51:23 +00:00
/* panel (notebook page) identifiers
* if modified, fix also the DEFINED_NETLISTS_COUNT value
* PANEL_NETLIST_INDEX values are used as index in m_PanelNetType[]
*/
enum PANEL_NETLIST_INDEX
{
PANELPCBNEW = 0, /* Handle Netlist format Pcbnew */
PANELORCADPCB2, /* Handle Netlist format OracdPcb2 */
PANELALLEGRO, /* Handle Netlist format Allegro */
PANELCADSTAR, /* Handle Netlist format CadStar */
PANELSPICE, /* Handle Netlist format Spice */
PANELSPICEMODEL, /* Handle Netlist format Spice Model (subcircuit) */
PANELCUSTOMBASE /* First auxiliary panel (custom netlists).
2023-07-08 07:51:23 +00:00
* others use PANELCUSTOMBASE+1, PANELCUSTOMBASE+2.. */
2013-06-27 20:34:30 +00:00
};
2023-07-08 07:51:23 +00:00
// The count of panels for internally defined netlist formats
// (the max count of panel is DEFINED_NETLISTS_COUNT+CUSTOMPANEL_COUNTMAX)
#define DEFINED_NETLISTS_COUNT 6
2013-06-27 20:34:30 +00:00
/* wxPanels for creating the NoteBook pages for each netlist format: */
class EXPORT_NETLIST_PAGE : public wxPanel
2013-06-27 20:34:30 +00:00
{
2013-06-27 20:34:30 +00:00
public:
/**
* Create a setup page for one netlist format.
*
* Used in Netlist format dialog box creation.
*
* @param parent is the wxNotebook parent.
* @param title is the title of the notebook page.
* @param id_NetType is the netlist ID type.
*/
EXPORT_NETLIST_PAGE( wxNotebook* aParent, const wxString& aTitle,
NETLIST_TYPE_ID aIdNetType, bool aCustom );
~EXPORT_NETLIST_PAGE() { };
/**
* @return the name of the netlist format for this page.
*/
const wxString GetPageNetFmtName() { return m_pageNetFmtName; }
2013-06-27 20:34:30 +00:00
NETLIST_TYPE_ID m_IdNetType;
// opt to reformat passive component values (e.g. 1M -> 1Meg):
wxCheckBox* m_CurSheetAsRoot;
wxCheckBox* m_SaveAllVoltages;
wxCheckBox* m_SaveAllCurrents;
wxCheckBox* m_SaveAllDissipations;
wxCheckBox* m_RunExternalSpiceCommand;
2013-06-27 20:34:30 +00:00
wxTextCtrl* m_CommandStringCtrl;
wxTextCtrl* m_TitleStringCtrl;
wxBoxSizer* m_LeftBoxSizer;
wxBoxSizer* m_RightBoxSizer;
wxBoxSizer* m_RightOptionsBoxSizer;
wxBoxSizer* m_LowBoxSizer;
bool IsCustom() const { return m_custom; }
2013-06-27 20:34:30 +00:00
private:
wxString m_pageNetFmtName;
bool m_custom;
2013-06-27 20:34:30 +00:00
};
/* Dialog frame for creating netlists */
class DIALOG_EXPORT_NETLIST : public DIALOG_EXPORT_NETLIST_BASE
2013-06-27 20:34:30 +00:00
{
public:
DIALOG_EXPORT_NETLIST( SCH_EDIT_FRAME* parent );
~DIALOG_EXPORT_NETLIST() { };
2013-06-27 20:34:30 +00:00
private:
void InstallCustomPages();
EXPORT_NETLIST_PAGE* AddOneCustomPage( const wxString& aTitle, const wxString& aCommandString,
2013-06-27 20:34:30 +00:00
NETLIST_TYPE_ID aNetTypeId );
void InstallPageSpice();
void InstallPageSpiceModel();
2022-09-15 08:50:14 +00:00
bool TransferDataFromWindow() override;
bool NetlistUpdateOpt();
void updateGeneratorButtons();
// Called when changing the notebook page (and therefore the current netlist format)
void OnNetlistTypeSelection( wxNotebookEvent& event ) override;
2013-06-27 20:34:30 +00:00
/**
* Add a new panel for a new netlist plugin.
2013-06-27 20:34:30 +00:00
*/
void OnAddGenerator( wxCommandEvent& event ) override;
2013-06-27 20:34:30 +00:00
/**
* Remove a panel relative to a netlist plugin.
2013-06-27 20:34:30 +00:00
*/
void OnDelGenerator( wxCommandEvent& event ) override;
2013-06-27 20:34:30 +00:00
/**
* Write the current netlist options setup in the configuration.
2013-06-27 20:34:30 +00:00
*/
void WriteCurrentNetlistSetup();
/**
* Return the filename extension and the wildcard string for this page or a void name
* if there is no default name.
*
* @param aType is the netlist type ( NET_TYPE_PCBNEW ... ).
* @param aExt [in] is a holder for the netlist file extension.
* @param aWildCard [in] is a holder for netlist file dialog wildcard.
* @return true for known netlist type, false for custom formats.
2013-06-27 20:34:30 +00:00
*/
bool FilenamePrms( NETLIST_TYPE_ID aType, wxString* aExt, wxString* aWildCard );
2013-06-27 20:34:30 +00:00
public:
SCH_EDIT_FRAME* m_Parent;
2023-07-08 07:51:23 +00:00
EXPORT_NETLIST_PAGE* m_PanelNetType[DEFINED_NETLISTS_COUNT + CUSTOMPANEL_COUNTMAX];
2013-06-27 20:34:30 +00:00
};
class NETLIST_DIALOG_ADD_GENERATOR : public NETLIST_DIALOG_ADD_GENERATOR_BASE
2013-06-27 20:34:30 +00:00
{
public:
NETLIST_DIALOG_ADD_GENERATOR( DIALOG_EXPORT_NETLIST* parent );
2013-06-27 20:34:30 +00:00
const wxString GetGeneratorTitle() { return m_textCtrlName->GetValue(); }
const wxString GetGeneratorTCommandLine() { return m_textCtrlCommand->GetValue(); }
2013-06-27 20:34:30 +00:00
bool TransferDataFromWindow() override;
2013-06-27 20:34:30 +00:00
private:
2013-06-27 20:34:30 +00:00
/*
* Browse plugin files, and set m_CommandStringCtrl field
*/
void OnBrowseGenerators( wxCommandEvent& event ) override;
DIALOG_EXPORT_NETLIST* m_Parent;
2013-06-27 20:34:30 +00:00
};
/* Event id for notebook page buttons: */
enum id_netlist {
ID_CREATE_NETLIST = ID_END_EESCHEMA_ID_LIST + 1,
ID_CUR_SHEET_AS_ROOT,
ID_SAVE_ALL_VOLTAGES,
ID_SAVE_ALL_CURRENTS,
ID_SAVE_ALL_DISSIPATIONS,
ID_RUN_SIMULATOR
};
EXPORT_NETLIST_PAGE::EXPORT_NETLIST_PAGE( wxNotebook* aParent, const wxString& aTitle,
NETLIST_TYPE_ID aIdNetType, bool aCustom ) :
wxPanel( aParent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL )
{
m_IdNetType = aIdNetType;
m_pageNetFmtName = aTitle;
2021-07-16 20:13:26 +00:00
m_CommandStringCtrl = nullptr;
2022-09-15 08:50:14 +00:00
m_CurSheetAsRoot = nullptr;
2021-07-16 20:13:26 +00:00
m_TitleStringCtrl = nullptr;
m_SaveAllVoltages = nullptr;
m_SaveAllCurrents = nullptr;
m_SaveAllDissipations = nullptr;
m_RunExternalSpiceCommand = nullptr;
m_custom = aCustom;
aParent->AddPage( this, aTitle, false );
wxBoxSizer* MainBoxSizer = new wxBoxSizer( wxVERTICAL );
SetSizer( MainBoxSizer );
wxBoxSizer* UpperBoxSizer = new wxBoxSizer( wxHORIZONTAL );
m_LowBoxSizer = new wxBoxSizer( wxVERTICAL );
MainBoxSizer->Add( UpperBoxSizer, 0, wxGROW | wxALL, 5 );
MainBoxSizer->Add( m_LowBoxSizer, 0, wxGROW | wxALL, 5 );
m_LeftBoxSizer = new wxBoxSizer( wxVERTICAL );
m_RightBoxSizer = new wxBoxSizer( wxVERTICAL );
m_RightOptionsBoxSizer = new wxBoxSizer( wxVERTICAL );
UpperBoxSizer->Add( m_LeftBoxSizer, 0, wxGROW | wxALL, 5 );
UpperBoxSizer->Add( m_RightBoxSizer, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
UpperBoxSizer->Add( m_RightOptionsBoxSizer, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
}
2013-06-27 20:34:30 +00:00
DIALOG_EXPORT_NETLIST::DIALOG_EXPORT_NETLIST( SCH_EDIT_FRAME* parent ) :
DIALOG_EXPORT_NETLIST_BASE( parent )
{
m_Parent = parent;
SCHEMATIC_SETTINGS& settings = m_Parent->Schematic().Settings();
for( EXPORT_NETLIST_PAGE*& page : m_PanelNetType )
2021-07-16 20:13:26 +00:00
page = nullptr;
// Add notebook pages:
m_PanelNetType[PANELPCBNEW] =
new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "KiCad" ), NET_TYPE_PCBNEW, false );
m_PanelNetType[PANELORCADPCB2] =
new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "OrcadPCB2" ), NET_TYPE_ORCADPCB2, false );
m_PanelNetType[PANELALLEGRO] =
new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "Allegro" ), NET_TYPE_ALLEGRO, false );
m_PanelNetType[PANELCADSTAR] =
new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "CadStar" ), NET_TYPE_CADSTAR, false );
InstallPageSpice();
InstallPageSpiceModel();
InstallCustomPages();
SetupStandardButtons( { { wxID_OK, _( "Export Netlist" ) },
{ wxID_CANCEL, _( "Close" ) } } );
2010-08-11 15:32:44 +00:00
for( int ii = 0; (ii < 4 + CUSTOMPANEL_COUNTMAX) && m_PanelNetType[ii]; ++ii )
{
if( m_PanelNetType[ii]->GetPageNetFmtName() == settings.m_NetFormatName )
{
m_NoteBook->ChangeSelection( ii );
break;
}
}
2016-07-16 10:54:55 +00:00
// Now all widgets have the size fixed, call FinishDialogSettings
2020-11-16 11:16:44 +00:00
finishDialogSettings();
updateGeneratorButtons();
}
void DIALOG_EXPORT_NETLIST::InstallPageSpice()
{
EXPORT_NETLIST_PAGE* page = m_PanelNetType[PANELSPICE] =
new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "Spice" ), NET_TYPE_SPICE, false );
SCHEMATIC_SETTINGS& settings = m_Parent->Schematic().Settings();
page->m_CurSheetAsRoot = new wxCheckBox( page, ID_CUR_SHEET_AS_ROOT,
_( "Use current sheet as root" ) );
page->m_CurSheetAsRoot->SetToolTip( _( "Export netlist only for the current sheet" ) );
page->m_CurSheetAsRoot->SetValue( settings.m_SpiceCurSheetAsRoot );
page->m_LeftBoxSizer->Add( page->m_CurSheetAsRoot, 0, wxGROW | wxBOTTOM | wxRIGHT, 5 );
page->m_SaveAllVoltages = new wxCheckBox( page, ID_SAVE_ALL_VOLTAGES,
_( "Save all voltages" ) );
page->m_SaveAllVoltages->SetToolTip( _( "Write a directive to save all voltages (.save all)" ) );
page->m_SaveAllVoltages->SetValue( settings.m_SpiceSaveAllVoltages );
page->m_LeftBoxSizer->Add( page->m_SaveAllVoltages, 0, wxBOTTOM | wxRIGHT, 5 );
page->m_SaveAllCurrents = new wxCheckBox( page, ID_SAVE_ALL_CURRENTS,
_( "Save all currents" ) );
page->m_SaveAllCurrents->SetToolTip( _( "Write a directive to save all currents (.probe alli)" ) );
page->m_SaveAllCurrents->SetValue( settings.m_SpiceSaveAllCurrents );
page->m_LeftBoxSizer->Add( page->m_SaveAllCurrents, 0, wxBOTTOM | wxRIGHT, 5 );
page->m_SaveAllDissipations = new wxCheckBox( page, ID_SAVE_ALL_DISSIPATIONS,
_( "Save all power dissipations" ) );
page->m_SaveAllDissipations->SetToolTip( _( "Write directives to save power dissipation of all items (.probe p(<item>))" ) );
page->m_SaveAllDissipations->SetValue( settings.m_SpiceSaveAllDissipations );
page->m_LeftBoxSizer->Add( page->m_SaveAllDissipations, 0, wxBOTTOM | wxRIGHT, 5 );
page->m_RunExternalSpiceCommand = new wxCheckBox( page, ID_RUN_SIMULATOR,
_( "Run external simulator command:" ) );
wxString simulatorCommand = settings.m_SpiceCommandString;
page->m_RunExternalSpiceCommand->SetToolTip( _( "Enter the command line to run SPICE\n"
"Usually '<path to SPICE binary> \"%I\"'\n"
"%I will be replaced by the netlist filepath" ) );
page->m_LowBoxSizer->Add( page->m_RunExternalSpiceCommand, 0,
wxGROW | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
page->m_CommandStringCtrl = new wxTextCtrl( page, -1, simulatorCommand,
wxDefaultPosition, wxDefaultSize );
page->m_CommandStringCtrl->SetInsertionPoint( 1 );
page->m_LowBoxSizer->Add( page->m_CommandStringCtrl, 0,
wxGROW | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
}
void DIALOG_EXPORT_NETLIST::InstallPageSpiceModel()
{
EXPORT_NETLIST_PAGE* page = m_PanelNetType[PANELSPICEMODEL] =
new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "Spice Model" ), NET_TYPE_SPICE_MODEL, false );
SCHEMATIC_SETTINGS& settings = m_Parent->Schematic().Settings();
page->m_CurSheetAsRoot = new wxCheckBox( page, ID_CUR_SHEET_AS_ROOT,
_( "Use current sheet as root" ) );
page->m_CurSheetAsRoot->SetToolTip( _( "Export netlist only for the current sheet" ) );
page->m_CurSheetAsRoot->SetValue( settings.m_SpiceModelCurSheetAsRoot );
page->m_LeftBoxSizer->Add( page->m_CurSheetAsRoot, 0, wxGROW | wxBOTTOM | wxRIGHT, 5 );
}
void DIALOG_EXPORT_NETLIST::InstallCustomPages()
{
EXPORT_NETLIST_PAGE* currPage;
EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
2020-03-21 16:31:48 +00:00
wxASSERT( cfg );
2020-03-21 16:31:48 +00:00
if( cfg )
{
for( size_t i = 0; i < CUSTOMPANEL_COUNTMAX && i < cfg->m_NetlistPanel.plugins.size(); i++ )
2020-03-21 16:31:48 +00:00
{
// pairs of (title, command) are stored
wxString title = cfg->m_NetlistPanel.plugins[i].name;
if( i >= cfg->m_NetlistPanel.plugins.size() )
2020-03-21 16:31:48 +00:00
break; // No more panel to install
wxString command = cfg->m_NetlistPanel.plugins[i].command;
2020-03-21 16:31:48 +00:00
currPage = AddOneCustomPage( title, command,
static_cast<NETLIST_TYPE_ID>( NET_TYPE_CUSTOM1 + i ) );
2020-03-21 16:31:48 +00:00
m_PanelNetType[PANELCUSTOMBASE + i] = currPage;
}
}
}
2013-06-27 20:34:30 +00:00
EXPORT_NETLIST_PAGE* DIALOG_EXPORT_NETLIST::AddOneCustomPage( const wxString& aTitle,
const wxString& aCommandString,
NETLIST_TYPE_ID aNetTypeId )
{
EXPORT_NETLIST_PAGE* currPage = new EXPORT_NETLIST_PAGE( m_NoteBook, aTitle, aNetTypeId, true );
currPage->m_LowBoxSizer->Add( new wxStaticText( currPage, -1, _( "Title:" ) ), 0,
wxGROW | wxLEFT | wxRIGHT | wxTOP, 5 );
currPage->m_TitleStringCtrl = new wxTextCtrl( currPage, -1, aTitle,
wxDefaultPosition, wxDefaultSize );
currPage->m_TitleStringCtrl->SetInsertionPoint( 1 );
currPage->m_LowBoxSizer->Add( currPage->m_TitleStringCtrl, 0,
wxGROW | wxTOP | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
currPage->m_LowBoxSizer->Add( new wxStaticText( currPage, -1, _( "Netlist command:" ) ), 0,
wxGROW | wxLEFT | wxRIGHT | wxTOP, 5 );
currPage->m_CommandStringCtrl = new wxTextCtrl( currPage, -1, aCommandString,
wxDefaultPosition, wxDefaultSize );
currPage->m_CommandStringCtrl->SetInsertionPoint( 1 );
currPage->m_LowBoxSizer->Add( currPage->m_CommandStringCtrl, 0,
wxGROW | wxTOP | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
return currPage;
}
void DIALOG_EXPORT_NETLIST::OnNetlistTypeSelection( wxNotebookEvent& event )
{
updateGeneratorButtons();
}
2013-06-27 20:34:30 +00:00
bool DIALOG_EXPORT_NETLIST::NetlistUpdateOpt()
{
bool changed = false;
bool saveAllVoltages = m_PanelNetType[ PANELSPICE ]->m_SaveAllVoltages->IsChecked();
bool saveAllCurrents = m_PanelNetType[ PANELSPICE ]->m_SaveAllCurrents->IsChecked();
bool saveAllDissipations = m_PanelNetType[ PANELSPICE ]->m_SaveAllDissipations->IsChecked();
wxString spiceCmdString = m_PanelNetType[ PANELSPICE ]->m_CommandStringCtrl->GetValue();
bool curSheetAsRoot = m_PanelNetType[ PANELSPICE ]->m_CurSheetAsRoot->GetValue();
bool spiceModelCurSheetAsRoot = m_PanelNetType[ PANELSPICEMODEL ]->m_CurSheetAsRoot->GetValue();
SCHEMATIC_SETTINGS& settings = m_Parent->Schematic().Settings();
wxString netFormatName = m_PanelNetType[m_NoteBook->GetSelection()]->GetPageNetFmtName();
changed |= ( settings.m_SpiceSaveAllVoltages != saveAllVoltages );
changed |= ( settings.m_SpiceSaveAllCurrents != saveAllCurrents );
changed |= ( settings.m_SpiceSaveAllDissipations != saveAllDissipations );
changed |= ( settings.m_SpiceCommandString != spiceCmdString );
changed |= ( settings.m_SpiceCurSheetAsRoot != curSheetAsRoot );
changed |= ( settings.m_SpiceModelCurSheetAsRoot != spiceModelCurSheetAsRoot );
changed |= ( settings.m_NetFormatName != netFormatName );
settings.m_SpiceSaveAllVoltages = saveAllVoltages;
settings.m_SpiceSaveAllCurrents = saveAllCurrents;
settings.m_SpiceSaveAllDissipations = saveAllDissipations;
settings.m_SpiceCommandString = spiceCmdString;
settings.m_SpiceCurSheetAsRoot = curSheetAsRoot;
settings.m_SpiceModelCurSheetAsRoot = spiceModelCurSheetAsRoot;
settings.m_NetFormatName = netFormatName;
return changed;
}
bool DIALOG_EXPORT_NETLIST::TransferDataFromWindow()
{
wxFileName fn;
wxString fileWildcard;
wxString fileExt;
wxString title = _( "Save Netlist File" );
if( NetlistUpdateOpt() )
m_Parent->OnModify();
EXPORT_NETLIST_PAGE* currPage;
currPage = (EXPORT_NETLIST_PAGE*) m_NoteBook->GetCurrentPage();
bool runExternalSpiceCommand = false;
unsigned netlist_opt = 0;
2013-06-27 20:34:30 +00:00
// Calculate the netlist filename
fn = m_Parent->Schematic().GetFileName();
* KIWAY Milestone A): Make major modules into DLL/DSOs. ! The initial testing of this commit should be done using a Debug build so that all the wxASSERT()s are enabled. Also, be sure and keep enabled the USE_KIWAY_DLLs option. The tree won't likely build without it. Turning it off is senseless anyways. If you want stable code, go back to a prior version, the one tagged with "stable". * Relocate all functionality out of the wxApp derivative into more finely targeted purposes: a) DLL/DSO specific b) PROJECT specific c) EXE or process specific d) configuration file specific data e) configuration file manipulations functions. All of this functionality was blended into an extremely large wxApp derivative and that was incompatible with the desire to support multiple concurrently loaded DLL/DSO's ("KIFACE")s and multiple concurrently open projects. An amazing amount of organization come from simply sorting each bit of functionality into the proper box. * Switch to wxConfigBase from wxConfig everywhere except instantiation. * Add classes KIWAY, KIFACE, KIFACE_I, SEARCH_STACK, PGM_BASE, PGM_KICAD, PGM_SINGLE_TOP, * Remove "Return" prefix on many function names. * Remove obvious comments from CMakeLists.txt files, and from else() and endif()s. * Fix building boost for use in a DSO on linux. * Remove some of the assumptions in the CMakeLists.txt files that windows had to be the host platform when building windows binaries. * Reduce the number of wxStrings being constructed at program load time via static construction. * Pass wxConfigBase* to all SaveSettings() and LoadSettings() functions so that these functions are useful even when the wxConfigBase comes from another source, as is the case in the KICAD_MANAGER_FRAME. * Move the setting of the KIPRJMOD environment variable into class PROJECT, so that it can be moved into a project variable soon, and out of FP_LIB_TABLE. * Add the KIWAY_PLAYER which is associated with a particular PROJECT, and all its child wxFrames and wxDialogs now have a Kiway() member function which returns a KIWAY& that that window tree branch is in support of. This is like wxWindows DNA in that child windows get this member with proper value at time of construction. * Anticipate some of the needs for milestones B) and C) and make code adjustments now in an effort to reduce work in those milestones. * No testing has been done for python scripting, since milestone C) has that being largely reworked and re-thought-out.
2014-03-20 00:42:08 +00:00
FilenamePrms( currPage->m_IdNetType, &fileExt, &fileWildcard );
// Set some parameters
switch( currPage->m_IdNetType )
{
case NET_TYPE_SPICE:
// Set spice netlist options:
netlist_opt |= NETLIST_EXPORTER_SPICE::OPTION_SIM_COMMAND;
if( currPage->m_SaveAllVoltages->GetValue() )
netlist_opt |= NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_VOLTAGES;
if( currPage->m_SaveAllCurrents->GetValue() )
netlist_opt |= NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_CURRENTS;
if( currPage->m_SaveAllDissipations->GetValue() )
netlist_opt |= NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_DISSIPATIONS;
if( currPage->m_CurSheetAsRoot->GetValue() )
netlist_opt |= NETLIST_EXPORTER_SPICE::OPTION_CUR_SHEET_AS_ROOT;
runExternalSpiceCommand = currPage->m_RunExternalSpiceCommand->GetValue();
break;
case NET_TYPE_SPICE_MODEL:
if( currPage->m_CurSheetAsRoot->GetValue() )
netlist_opt |= NETLIST_EXPORTER_SPICE::OPTION_CUR_SHEET_AS_ROOT;
break;
case NET_TYPE_CADSTAR:
break;
case NET_TYPE_PCBNEW:
break;
case NET_TYPE_ORCADPCB2:
break;
case NET_TYPE_ALLEGRO:
2023-07-08 07:51:23 +00:00
break;
default: // custom, NET_TYPE_CUSTOM1 and greater
{
title.Printf( _( "%s Export" ), currPage->m_TitleStringCtrl->GetValue() );
break;
}
}
wxString fullpath;
if( runExternalSpiceCommand )
{
fn.SetExt( FILEEXT::SpiceFileExtension );
fullpath = fn.GetFullPath();
}
else
{
fn.SetExt( fileExt );
if( fn.GetPath().IsEmpty() )
fn.SetPath( wxPathOnly( Prj().GetProjectFullName() ) );
wxString fullname = fn.GetFullName();
wxString path = fn.GetPath();
// full name does not and should not include the path, per wx docs.
wxFileDialog dlg( this, title, path, fullname, fileWildcard, wxFD_SAVE );
if( dlg.ShowModal() == wxID_CANCEL )
return false;
fullpath = dlg.GetPath(); // directory + filename
}
m_Parent->ClearMsgPanel();
REPORTER& reporter = m_MessagesBox->Reporter();
if( currPage->m_CommandStringCtrl )
m_Parent->SetNetListerCommand( currPage->m_CommandStringCtrl->GetValue() );
else
m_Parent->SetNetListerCommand( wxEmptyString );
if( !m_Parent->ReadyToNetlist( _( "Exporting netlist requires a fully annotated schematic." ) ) )
return false;
m_Parent->WriteNetListFile( currPage->m_IdNetType, fullpath, netlist_opt, &reporter );
if( runExternalSpiceCommand )
2022-11-18 15:27:53 +00:00
{
// Build the command line
wxString commandLine = m_Parent->Schematic().Settings().m_SpiceCommandString;
commandLine.Replace( wxS( "%I" ), fullpath, true );
commandLine.Trim( true ).Trim( false );
if( !commandLine.IsEmpty() )
{
wxProcess* process = new wxProcess( GetEventHandler(), wxID_ANY );
process->Redirect();
wxExecute( commandLine, wxEXEC_ASYNC, process );
reporter.ReportHead( commandLine, RPT_SEVERITY_ACTION );
process->Activate();
2023-11-27 23:03:06 +00:00
std::this_thread::sleep_for( std::chrono::seconds( 1 ) ); // give the process time to start and output any data or errors
if( process->IsInputAvailable() )
{
wxInputStream* in = process->GetInputStream();
wxTextInputStream textstream( *in );
while( in->CanRead() )
{
wxString line = textstream.ReadLine();
if( !line.IsEmpty() )
reporter.Report( line, RPT_SEVERITY_INFO );
}
}
if( process->IsErrorAvailable() )
{
wxInputStream* err = process->GetErrorStream();
wxTextInputStream textstream( *err );
while( err->CanRead() )
{
wxString line = textstream.ReadLine();
if( !line.IsEmpty() )
{
if( line.EndsWith( wxS( "failed with error 2!" ) ) ) // ENOENT
{
reporter.Report( _( "external simulator not found" ), RPT_SEVERITY_ERROR );
reporter.Report( _( "Note: command line is usually: "
"<tt>&lt;path to SPICE binary&gt; \"%I\"</tt>" ),
RPT_SEVERITY_INFO );
}
else if( line.EndsWith( wxS( "failed with error 8!" ) ) ) // ENOEXEC
{
reporter.Report( _( "external simulator has the wrong format or "
"architecture" ), RPT_SEVERITY_ERROR );
}
else if( line.EndsWith( "failed with error 13!" ) ) // EACCES
{
reporter.Report( _( "permission denied" ), RPT_SEVERITY_ERROR );
}
else
{
reporter.Report( line, RPT_SEVERITY_ERROR );
}
}
}
}
process->CloseOutput();
process->Detach();
// Do not delete process, it will delete itself when it terminates
}
2022-11-18 15:27:53 +00:00
}
WriteCurrentNetlistSetup();
return !runExternalSpiceCommand;
}
2013-06-27 20:34:30 +00:00
bool DIALOG_EXPORT_NETLIST::FilenamePrms( NETLIST_TYPE_ID aType, wxString * aExt, wxString * aWildCard )
{
wxString fileExt;
wxString fileWildcard;
bool ret = true;
switch( aType )
{
case NET_TYPE_SPICE:
fileExt = FILEEXT::SpiceFileExtension;
fileWildcard = FILEEXT::SpiceNetlistFileWildcard();
break;
case NET_TYPE_CADSTAR:
fileExt = FILEEXT::CadstarNetlistFileExtension;
fileWildcard = FILEEXT::CadstarNetlistFileWildcard();
break;
case NET_TYPE_ORCADPCB2:
fileExt = FILEEXT::OrCadPcb2NetlistFileExtension;
fileWildcard = FILEEXT::OrCadPcb2NetlistFileWildcard();
break;
case NET_TYPE_PCBNEW:
fileExt = FILEEXT::NetlistFileExtension;
fileWildcard = FILEEXT::NetlistFileWildcard();
break;
case NET_TYPE_ALLEGRO:
fileExt = FILEEXT::AllegroNetlistFileExtension;
fileWildcard = FILEEXT::AllegroNetlistFileWildcard();
break;
default: // custom, NET_TYPE_CUSTOM1 and greater
fileWildcard = FILEEXT::AllFilesWildcard();
ret = false;
}
if( aExt )
*aExt = fileExt;
if( aWildCard )
*aWildCard = fileWildcard;
return ret;
}
2013-06-27 20:34:30 +00:00
void DIALOG_EXPORT_NETLIST::WriteCurrentNetlistSetup()
{
if( NetlistUpdateOpt() )
m_Parent->OnModify();
2020-03-25 13:13:03 +00:00
EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
wxASSERT( cfg );
if( !cfg )
return;
cfg->m_NetlistPanel.plugins.clear();
// Update existing custom pages
for( int ii = 0; ii < CUSTOMPANEL_COUNTMAX; ii++ )
{
EXPORT_NETLIST_PAGE* currPage = m_PanelNetType[ii + PANELCUSTOMBASE];
if( currPage == nullptr )
break;
wxString title = currPage->m_TitleStringCtrl->GetValue();
wxString command = currPage->m_CommandStringCtrl->GetValue();
2020-03-25 13:13:03 +00:00
if( title.IsEmpty() || command.IsEmpty() )
continue;
cfg->m_NetlistPanel.plugins.emplace_back( title, wxEmptyString );
cfg->m_NetlistPanel.plugins.back().command = command;
}
}
void DIALOG_EXPORT_NETLIST::OnDelGenerator( wxCommandEvent& event )
{
EXPORT_NETLIST_PAGE* currPage = (EXPORT_NETLIST_PAGE*) m_NoteBook->GetCurrentPage();
if( !currPage->IsCustom() )
return;
currPage->m_CommandStringCtrl->SetValue( wxEmptyString );
currPage->m_TitleStringCtrl->SetValue( wxEmptyString );
WriteCurrentNetlistSetup();
if( IsQuasiModal() )
EndQuasiModal( NET_PLUGIN_CHANGE );
else
EndDialog( NET_PLUGIN_CHANGE );
}
2013-06-27 20:34:30 +00:00
void DIALOG_EXPORT_NETLIST::OnAddGenerator( wxCommandEvent& event )
{
NETLIST_DIALOG_ADD_GENERATOR dlg( this );
if( dlg.ShowModal() != wxID_OK )
return;
// Creates a new custom plugin page
wxString title = dlg.GetGeneratorTitle();
// Verify it does not exists
int netTypeId = PANELCUSTOMBASE; // the first not used type id
EXPORT_NETLIST_PAGE* currPage;
for( int ii = 0; ii < CUSTOMPANEL_COUNTMAX; ii++ )
{
netTypeId = PANELCUSTOMBASE + ii;
currPage = m_PanelNetType[ii + PANELCUSTOMBASE];
2021-07-16 20:13:26 +00:00
if( currPage == nullptr )
break;
if( currPage->GetPageNetFmtName() == title )
{
wxMessageBox( _("This plugin already exists.") );
return;
}
}
wxString cmd = dlg.GetGeneratorTCommandLine();
currPage = AddOneCustomPage( title,cmd, (NETLIST_TYPE_ID)netTypeId );
m_PanelNetType[netTypeId] = currPage;
WriteCurrentNetlistSetup();
if( IsQuasiModal() )
EndQuasiModal( NET_PLUGIN_CHANGE );
else
EndDialog( NET_PLUGIN_CHANGE );
}
NETLIST_DIALOG_ADD_GENERATOR::NETLIST_DIALOG_ADD_GENERATOR( DIALOG_EXPORT_NETLIST* parent ) :
NETLIST_DIALOG_ADD_GENERATOR_BASE( parent )
{
m_Parent = parent;
SetupStandardButtons();
GetSizer()->SetSizeHints( this );
}
2013-06-27 20:34:30 +00:00
bool NETLIST_DIALOG_ADD_GENERATOR::TransferDataFromWindow()
{
if( !wxDialog::TransferDataFromWindow() )
return false;
if( m_textCtrlCommand->GetValue() == wxEmptyString )
{
wxMessageBox( _( "You must provide a netlist generator command string" ) );
return false;
}
if( m_textCtrlName->GetValue() == wxEmptyString )
{
wxMessageBox( _( "You must provide a netlist generator title" ) );
return false;
}
return true;
}
2013-06-27 20:34:30 +00:00
void NETLIST_DIALOG_ADD_GENERATOR::OnBrowseGenerators( wxCommandEvent& event )
{
wxString FullFileName, Path;
#ifndef __WXMAC__
* KIWAY Milestone A): Make major modules into DLL/DSOs. ! The initial testing of this commit should be done using a Debug build so that all the wxASSERT()s are enabled. Also, be sure and keep enabled the USE_KIWAY_DLLs option. The tree won't likely build without it. Turning it off is senseless anyways. If you want stable code, go back to a prior version, the one tagged with "stable". * Relocate all functionality out of the wxApp derivative into more finely targeted purposes: a) DLL/DSO specific b) PROJECT specific c) EXE or process specific d) configuration file specific data e) configuration file manipulations functions. All of this functionality was blended into an extremely large wxApp derivative and that was incompatible with the desire to support multiple concurrently loaded DLL/DSO's ("KIFACE")s and multiple concurrently open projects. An amazing amount of organization come from simply sorting each bit of functionality into the proper box. * Switch to wxConfigBase from wxConfig everywhere except instantiation. * Add classes KIWAY, KIFACE, KIFACE_I, SEARCH_STACK, PGM_BASE, PGM_KICAD, PGM_SINGLE_TOP, * Remove "Return" prefix on many function names. * Remove obvious comments from CMakeLists.txt files, and from else() and endif()s. * Fix building boost for use in a DSO on linux. * Remove some of the assumptions in the CMakeLists.txt files that windows had to be the host platform when building windows binaries. * Reduce the number of wxStrings being constructed at program load time via static construction. * Pass wxConfigBase* to all SaveSettings() and LoadSettings() functions so that these functions are useful even when the wxConfigBase comes from another source, as is the case in the KICAD_MANAGER_FRAME. * Move the setting of the KIPRJMOD environment variable into class PROJECT, so that it can be moved into a project variable soon, and out of FP_LIB_TABLE. * Add the KIWAY_PLAYER which is associated with a particular PROJECT, and all its child wxFrames and wxDialogs now have a Kiway() member function which returns a KIWAY& that that window tree branch is in support of. This is like wxWindows DNA in that child windows get this member with proper value at time of construction. * Anticipate some of the needs for milestones B) and C) and make code adjustments now in an effort to reduce work in those milestones. * No testing has been done for python scripting, since milestone C) has that being largely reworked and re-thought-out.
2014-03-20 00:42:08 +00:00
Path = Pgm().GetExecutablePath();
#else
Path = PATHS::GetOSXKicadDataDir() + wxT( "/plugins" );
#endif
FullFileName = wxFileSelector( _( "Generator File" ), Path, FullFileName,
wxEmptyString, wxFileSelectorDefaultWildcardStr,
wxFD_OPEN, this );
if( FullFileName.IsEmpty() )
return;
// Creates a default command line, suitable for external tool xslproc or python, based on
// the plugin extension ("xsl" or "exe" or "py")
wxString cmdLine;
wxFileName fn( FullFileName );
wxString ext = fn.GetExt();
if( ext == wxT( "xsl" ) )
cmdLine.Printf( wxT( "xsltproc -o \"%%O\" \"%s\" \"%%I\"" ), FullFileName );
else if( ext == wxT( "exe" ) || ext.IsEmpty() )
cmdLine.Printf( wxT( "\"%s\" > \"%%O\" < \"%%I\"" ), FullFileName );
else if( ext == wxT( "py" ) || ext.IsEmpty() )
cmdLine.Printf( wxT( "python \"%s\" \"%%I\" \"%%O\"" ), FullFileName );
else
cmdLine.Printf( wxT( "\"%s\"" ), FullFileName );
m_textCtrlCommand->SetValue( cmdLine );
// We need a title for this panel
// Propose a default value if empty ( i.e. the short filename of the script)
if( m_textCtrlName->GetValue().IsEmpty() )
m_textCtrlName->SetValue( fn.GetName() );
}
2013-06-27 20:34:30 +00:00
void DIALOG_EXPORT_NETLIST::updateGeneratorButtons()
{
EXPORT_NETLIST_PAGE* currPage = (EXPORT_NETLIST_PAGE*) m_NoteBook->GetCurrentPage();
if( currPage == nullptr )
return;
m_buttonDelGenerator->Enable( currPage->IsCustom() );
}
2013-06-27 20:34:30 +00:00
int InvokeDialogNetList( SCH_EDIT_FRAME* aCaller )
{
DIALOG_EXPORT_NETLIST dlg( aCaller );
2013-06-27 20:34:30 +00:00
int ret = dlg.ShowModal();
aCaller->SaveProjectLocalSettings();
return ret;
2013-06-27 20:34:30 +00:00
}