Support synchronous messaging over KIWAY EXPRESS.

This allows us to make the various netlist and pcb update routines
more atomic and less reliant on carefully sequenced asynchronous
messages.

This is also a prelude to adding support for footprint testing
without a netlist.
This commit is contained in:
Jeff Young 2019-03-27 22:37:26 +00:00
parent 52e3a1d7c4
commit 77f15eeeaf
18 changed files with 189 additions and 197 deletions

View File

@ -149,7 +149,7 @@ KIFACE* KIWAY::KiFACE( FACE_T aFaceId, bool doLoad )
{ {
// Since this will be called from python, cannot assume that code will // Since this will be called from python, cannot assume that code will
// not pass a bad aFaceId. // not pass a bad aFaceId.
if( unsigned( aFaceId ) >= arrayDim( m_kiface ) ) if( (unsigned) aFaceId >= arrayDim( m_kiface ) )
{ {
// @todo : throw an exception here for python's benefit, at least that // @todo : throw an exception here for python's benefit, at least that
// way it gets some explanatory text. // way it gets some explanatory text.
@ -301,7 +301,7 @@ KIWAY_PLAYER* KIWAY::Player( FRAME_T aFrameType, bool doCreate, wxTopLevelWindow
{ {
// Since this will be called from python, cannot assume that code will // Since this will be called from python, cannot assume that code will
// not pass a bad aFrameType. // not pass a bad aFrameType.
if( unsigned( aFrameType ) >= KIWAY_PLAYER_COUNT ) if( (unsigned) aFrameType >= KIWAY_PLAYER_COUNT )
{ {
// @todo : throw an exception here for python's benefit, at least that // @todo : throw an exception here for python's benefit, at least that
// way it gets some explanatory text. // way it gets some explanatory text.
@ -349,7 +349,7 @@ bool KIWAY::PlayerClose( FRAME_T aFrameType, bool doForce )
{ {
// Since this will be called from python, cannot assume that code will // Since this will be called from python, cannot assume that code will
// not pass a bad aFrameType. // not pass a bad aFrameType.
if( unsigned( aFrameType ) >= KIWAY_PLAYER_COUNT ) if( (unsigned) aFrameType >= KIWAY_PLAYER_COUNT )
{ {
// @todo : throw an exception here for python's benefit, at least that // @todo : throw an exception here for python's benefit, at least that
// way it gets some explanatory text. // way it gets some explanatory text.
@ -383,8 +383,7 @@ bool KIWAY::PlayersClose( bool doForce )
} }
void KIWAY::ExpressMail( FRAME_T aDestination, void KIWAY::ExpressMail( FRAME_T aDestination, MAIL_T aCommand, std::string& aPayload, wxWindow* aSource )
MAIL_T aCommand, std::string aPayload, wxWindow* aSource )
{ {
KIWAY_EXPRESS mail( aDestination, aCommand, aPayload, aSource ); KIWAY_EXPRESS mail( aDestination, aCommand, aPayload, aSource );
@ -481,9 +480,9 @@ bool KIWAY::ProcessEvent( wxEvent& aEvent )
void KIWAY::OnKiwayEnd() void KIWAY::OnKiwayEnd()
{ {
for( unsigned i=0; i < arrayDim( m_kiface ); ++i ) for( KIFACE* i : m_kiface )
{ {
if( m_kiface[i] ) if( i )
m_kiface[i]->OnKifaceEnd(); i->OnKifaceEnd();
} }
} }

View File

@ -42,15 +42,15 @@ const wxEventType KIWAY_EXPRESS::wxEVENT_ID = 30000; // commmon accross all l
KIWAY_EXPRESS::KIWAY_EXPRESS( const KIWAY_EXPRESS& anOther ) : KIWAY_EXPRESS::KIWAY_EXPRESS( const KIWAY_EXPRESS& anOther ) :
wxEvent( anOther ) wxEvent( anOther ),
m_destination( anOther.m_destination ),
m_payload( anOther.m_payload )
{ {
m_destination = anOther.m_destination;
m_payload = anOther.m_payload;
} }
KIWAY_EXPRESS::KIWAY_EXPRESS( FRAME_T aDestination, MAIL_T aCommand, KIWAY_EXPRESS::KIWAY_EXPRESS( FRAME_T aDestination, MAIL_T aCommand, std::string& aPayload,
const std::string& aPayload, wxWindow* aSource ) : wxWindow* aSource ) :
wxEvent( aCommand, wxEVENT_ID ), wxEvent( aCommand, wxEVENT_ID ),
m_destination( aDestination ), m_destination( aDestination ),
m_payload( aPayload ) m_payload( aPayload )

View File

@ -976,10 +976,6 @@ void CVPCB_MAINFRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
*/ */
break; break;
case MAIL_STATUS:
SetStatusText( payload, 1 );
break;
default: default:
; // ignore most ; // ignore most
} }

View File

@ -373,14 +373,22 @@ bool CVPCB_MAINFRAME::ReadNetListAndFpFiles( const std::string& aNetlist )
bool CVPCB_MAINFRAME::SaveFootprintAssociation( bool doSaveSchematic ) bool CVPCB_MAINFRAME::SaveFootprintAssociation( bool doSaveSchematic )
{ {
std::string payload;
STRING_FORMATTER sf; STRING_FORMATTER sf;
m_netlist.FormatBackAnnotation( &sf ); m_netlist.FormatBackAnnotation( &sf );
Kiway().ExpressMail( FRAME_SCH, MAIL_BACKANNOTATE_FOOTPRINTS, sf.GetString() ); payload = sf.GetString();
Kiway().ExpressMail( FRAME_SCH, MAIL_BACKANNOTATE_FOOTPRINTS, payload );
if( doSaveSchematic ) if( doSaveSchematic )
Kiway().ExpressMail( FRAME_SCH, MAIL_SCH_SAVE, std::string( "" ) ); {
payload = "";
Kiway().ExpressMail( FRAME_SCH, MAIL_SCH_SAVE, payload );
return true; // we can't tell if it was successful, so just assume the best if( payload == "success" )
SetStatusText( _( "Schematic saved" ), 1 );
}
return true;
} }

View File

@ -43,7 +43,8 @@
#include <sch_component.h> #include <sch_component.h>
#include <sch_sheet.h> #include <sch_sheet.h>
#include <sch_view.h> #include <sch_view.h>
#include <reporter.h>
#include <netlist_exporters/netlist_exporter_kicad.h>
/** /**
* Execute a remote command sent by Pcbnew via a socket connection. * Execute a remote command sent by Pcbnew via a socket connection.
@ -251,7 +252,7 @@ void SCH_EDIT_FRAME::SendCrossProbeNetName( const wxString& aNetName )
void SCH_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail ) void SCH_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
{ {
const std::string& payload = mail.GetPayload(); std::string& payload = mail.GetPayload();
switch( mail.Command() ) switch( mail.Command() )
{ {
@ -259,8 +260,33 @@ void SCH_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
ExecuteRemoteCommand( payload.c_str() ); ExecuteRemoteCommand( payload.c_str() );
break; break;
case MAIL_SCH_PCB_UPDATE_REQUEST: case MAIL_SCH_GET_NETLIST:
doUpdatePcb( payload ); if( payload.find( "quiet-annotate" ) != std::string::npos )
{
SCH_SCREENS schematic;
schematic.UpdateSymbolLinks();
SCH_SHEET_LIST sheets( g_RootSheet );
sheets.AnnotatePowerSymbols();
AnnotateComponents( true, UNSORTED, INCREMENTAL_BY_REF, 0, false, false, true,
NULL_REPORTER::GetInstance() );
}
if( payload.find( "no-annotate" ) == std::string::npos )
{
// Ensure schematic is OK for netlist creation (especially that it is fully annotated):
if( !prepareForNetlist() )
return;
}
{
NETLIST_OBJECT_LIST* net_atoms = BuildNetListBase();
NETLIST_EXPORTER_KICAD exporter( this, net_atoms );
STRING_FORMATTER formatter;
exporter.Format( &formatter, GNL_ALL );
payload = formatter.GetString();
}
break; break;
case MAIL_BACKANNOTATE_FOOTPRINTS: case MAIL_BACKANNOTATE_FOOTPRINTS:
@ -311,7 +337,7 @@ void SCH_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
case MAIL_SCH_SAVE: case MAIL_SCH_SAVE:
if( SaveProject() ) if( SaveProject() )
Kiway().ExpressMail( FRAME_CVPCB, MAIL_STATUS, _( "Schematic saved" ).ToStdString() ); payload = "success";
break; break;
default: default:

View File

@ -1495,7 +1495,8 @@ void LIB_EDIT_FRAME::refreshSchematic()
{ {
// There may be no parent window so use KIWAY message to refresh the schematic editor // There may be no parent window so use KIWAY message to refresh the schematic editor
// in case any symbols have changed. // in case any symbols have changed.
Kiway().ExpressMail( FRAME_SCH, MAIL_SCH_REFRESH, std::string( "" ), this ); std::string dummyPayload;
Kiway().ExpressMail( FRAME_SCH, MAIL_SCH_REFRESH, dummyPayload, this );
} }

View File

@ -193,20 +193,15 @@ bool SCH_EDIT_FRAME::prepareForNetlist()
void SCH_EDIT_FRAME::sendNetlistToCvpcb() void SCH_EDIT_FRAME::sendNetlistToCvpcb()
{ {
NETLIST_OBJECT_LIST* net_atoms = BuildNetListBase(); NETLIST_OBJECT_LIST* net_atoms = BuildNetListBase();
NETLIST_EXPORTER_KICAD exporter( this, net_atoms, g_ConnectionGraph ); NETLIST_EXPORTER_KICAD exporter( this, net_atoms, g_ConnectionGraph );
STRING_FORMATTER formatter;
STRING_FORMATTER formatter;
// @todo : trim GNL_ALL down to minimum for CVPCB // @todo : trim GNL_ALL down to minimum for CVPCB
exporter.Format( &formatter, GNL_ALL ); exporter.Format( &formatter, GNL_ALL );
Kiway().ExpressMail( FRAME_CVPCB, std::string packet = formatter.GetString(); // an abbreviated "kicad" (s-expr) netlist
MAIL_EESCHEMA_NETLIST, Kiway().ExpressMail( FRAME_CVPCB, MAIL_EESCHEMA_NETLIST, packet, this );
formatter.GetString(), // an abbreviated "kicad" (s-expr) netlist
this
);
} }

View File

@ -68,9 +68,7 @@
#include <build_version.h> #include <build_version.h>
#include <wildcards_and_files_ext.h> #include <wildcards_and_files_ext.h>
#include <netlist_exporter_kicad.h>
#include <connection_graph.h> #include <connection_graph.h>
#include <kiway.h>
#include <dialogs/dialog_fields_editor_global.h> #include <dialogs/dialog_fields_editor_global.h>
#include <sch_view.h> #include <sch_view.h>
@ -886,58 +884,8 @@ void SCH_EDIT_FRAME::CloseErc()
void SCH_EDIT_FRAME::OnUpdatePCB( wxCommandEvent& event ) void SCH_EDIT_FRAME::OnUpdatePCB( wxCommandEvent& event )
{ {
doUpdatePcb( "" ); std::string payload;
} Kiway().ExpressMail( FRAME_PCB, MAIL_PCB_UPDATE, payload, this );
void SCH_EDIT_FRAME::doUpdatePcb( const wxString& aUpdateOptions )
{
wxFileName fn = Prj().AbsolutePath( g_RootSheet->GetScreen()->GetFileName() );
fn.SetExt( PcbFileExtension );
if( Kiface().IsSingle() )
{
DisplayError( this, _( "Cannot update the PCB, because the Schematic Editor is"
" opened in stand-alone mode. In order to create/update"
" PCBs from schematics, you need to launch Kicad shell"
" and create a PCB project." ) );
return;
}
else
{
KIWAY_PLAYER* frame = Kiway().Player( FRAME_PCB, true );
// a pcb frame can be already existing, but not yet used.
// this is the case when running the footprint editor, or the footprint viewer first
// if the frame is not visible, the board is not yet loaded
if( !frame->IsVisible() )
{
frame->OpenProjectFiles( std::vector<wxString>( 1, fn.GetFullPath() ) );
frame->Show( true );
}
// On Windows, Raise() does not bring the window on screen, when iconized
if( frame->IsIconized() )
frame->Iconize( false );
frame->Raise();
}
auto net_atoms = CreateNetlist( aUpdateOptions.Contains( "no-annotate" ),
aUpdateOptions.Contains( "quiet-annotate" ) );
NETLIST_EXPORTER_KICAD exporter( this, net_atoms, g_ConnectionGraph );
STRING_FORMATTER formatter;
exporter.Format( &formatter, GNL_ALL );
auto updateOptions = aUpdateOptions.ToStdString();
auto netlistString = formatter.GetString();
auto finalNetlist = updateOptions + "\n" + netlistString;
// Now, send the "kicad" (s-expr) netlist to Pcbnew
Kiway().ExpressMail( FRAME_PCB, MAIL_SCH_PCB_UPDATE, finalNetlist, this );
} }

View File

@ -1559,16 +1559,6 @@ public:
*/ */
void RecalculateConnections(); void RecalculateConnections();
/**
* Updates netlist and sends it to pcbnew.
* @param aUpdateOptions is a string defining update options:
* - "no-annotate" does not perform schematic annotation
* - "quiet-annotate" performs schematic annotation without showing annotation dialog
* aUpdateOptions may also contain other options accepted for netlist reader.
* @see PCB_EDIT_FRAME::KiwayMailIn()
*/
void doUpdatePcb( const wxString& aUpdateOptions = "" );
void SetCurrentSheet( SCH_SHEET_PATH *aSheet ); void SetCurrentSheet( SCH_SHEET_PATH *aSheet );
/** /**

View File

@ -344,7 +344,7 @@ public:
* aCommand in there. * aCommand in there.
*/ */
VTBL_ENTRY void ExpressMail( FRAME_T aDestination, MAIL_T aCommand, VTBL_ENTRY void ExpressMail( FRAME_T aDestination, MAIL_T aCommand,
std::string aPayload, wxWindow* aSource = NULL ); std::string& aPayload, wxWindow* aSource = NULL );
/** /**
* Function Prj * Function Prj
@ -395,7 +395,7 @@ private:
bool set_kiface( FACE_T aFaceType, KIFACE* aKiface ) bool set_kiface( FACE_T aFaceType, KIFACE* aKiface )
{ {
if( unsigned( aFaceType ) < unsigned( KIWAY_FACE_COUNT ) ) if( (unsigned) aFaceType < (unsigned) KIWAY_FACE_COUNT )
{ {
m_kiface[aFaceType] = aKiface; m_kiface[aFaceType] = aKiface;
return true; return true;

View File

@ -59,17 +59,15 @@ public:
* returns the payload, which can be any text but it typicall self * returns the payload, which can be any text but it typicall self
* identifying s-expression. * identifying s-expression.
*/ */
const std::string& GetPayload() { return m_payload; } std::string& GetPayload() { return m_payload; }
void SetPayload( const std::string& aPayload ) { m_payload = aPayload; } void SetPayload( const std::string& aPayload ) { m_payload = aPayload; }
KIWAY_EXPRESS* Clone() const override { return new KIWAY_EXPRESS( *this ); } KIWAY_EXPRESS* Clone() const override { return new KIWAY_EXPRESS( *this ); }
//KIWAY_EXPRESS() {} //KIWAY_EXPRESS() {}
KIWAY_EXPRESS( FRAME_T aDestination, KIWAY_EXPRESS( FRAME_T aDestination, MAIL_T aCommand, std::string& aPayload,
MAIL_T aCommand, wxWindow* aSource = NULL );
const std::string& aPayload,
wxWindow* aSource = NULL );
KIWAY_EXPRESS( const KIWAY_EXPRESS& anOther ); KIWAY_EXPRESS( const KIWAY_EXPRESS& anOther );
@ -82,7 +80,7 @@ public:
private: private:
FRAME_T m_destination; ///< could have been a bitmap indicating multiple recipients FRAME_T m_destination; ///< could have been a bitmap indicating multiple recipients
std::string m_payload; ///< very often s-expression text, but not always std::string& m_payload; ///< very often s-expression text, but not always
// possible new ideas here. // possible new ideas here.
}; };

View File

@ -40,19 +40,13 @@ enum MAIL_T
MAIL_BACKANNOTATE_FOOTPRINTS, ///< CVPCB->SCH footprint stuffing MAIL_BACKANNOTATE_FOOTPRINTS, ///< CVPCB->SCH footprint stuffing
MAIL_SCH_SAVE, ///< CVPCB->SCH save the schematic MAIL_SCH_SAVE, ///< CVPCB->SCH save the schematic
MAIL_EESCHEMA_NETLIST, ///< SCH->CVPCB netlist immediately after launching CVPCB MAIL_EESCHEMA_NETLIST, ///< SCH->CVPCB netlist immediately after launching CVPCB
MAIL_SCH_PCB_UPDATE, ///< SCH->PCB forward update MAIL_PCB_UPDATE, ///< SCH->PCB forward update
MAIL_IMPORT_FILE, ///< Import a different format file MAIL_IMPORT_FILE, ///< Import a different format file
MAIL_SCH_GET_NETLIST, ///< Fetch a netlist
///< Sch->PCB forward update, requests SCH to re-generate netlist and send it to PCB
///< via another mail (kind of bootstrap)
MAIL_SCH_PCB_UPDATE_REQUEST,
MAIL_SCH_REFRESH, ///< The the schematic editor to refresh the display. MAIL_SCH_REFRESH, ///< The the schematic editor to refresh the display.
MAIL_LIB_EDIT, MAIL_LIB_EDIT,
MAIL_FP_EDIT, MAIL_FP_EDIT
///< General-puspose messages
MAIL_STATUS
}; };
#endif // MAIL_TYPE_H_ #endif // MAIL_TYPE_H_

View File

@ -141,9 +141,8 @@ void KICAD_MANAGER_FRAME::OnImportEagleFiles( wxCommandEvent& event )
} }
} }
schframe->Kiway().ExpressMail( FRAME_SCH, MAIL_IMPORT_FILE, std::string packet = wxString::Format( "%d\n%s", SCH_IO_MGR::SCH_EAGLE, sch.GetFullPath() );
wxString::Format( "%d\n%s", SCH_IO_MGR::SCH_EAGLE, schframe->Kiway().ExpressMail( FRAME_SCH, MAIL_IMPORT_FILE, packet, this );
sch.GetFullPath() ).ToStdString(), this );
if( !schframe->IsShown() ) // the frame exists, (created by the dialog field editor) if( !schframe->IsShown() ) // the frame exists, (created by the dialog field editor)
// but no project loaded. // but no project loaded.
@ -184,8 +183,8 @@ void KICAD_MANAGER_FRAME::OnImportEagleFiles( wxCommandEvent& event )
pcbframe->Show( true ); pcbframe->Show( true );
} }
pcbframe->Kiway().ExpressMail( FRAME_PCB, MAIL_IMPORT_FILE, std::string packet = wxString::Format( "%d\n%s", IO_MGR::EAGLE, pcb.GetFullPath() );
wxString::Format( "%d\n%s", IO_MGR::EAGLE, pcb.GetFullPath() ).ToStdString(), this ); pcbframe->Kiway().ExpressMail( FRAME_PCB, MAIL_IMPORT_FILE, packet, this );
// On Windows, Raise() does not bring the window on screen, when iconized // On Windows, Raise() does not bring the window on screen, when iconized
if( pcbframe->IsIconized() ) if( pcbframe->IsIconized() )

View File

@ -256,7 +256,9 @@ void TREEPROJECT_ITEM::Activate( TREE_PROJECT_FRAME* aTreePrjFrame )
{ {
wxCommandEvent dummy; wxCommandEvent dummy;
frame->OnRunPcbFpEditor( dummy ); frame->OnRunPcbFpEditor( dummy );
kiway.ExpressMail( FRAME_PCB_MODULE_EDITOR, MAIL_FP_EDIT, fullFileName.ToStdString() );
std::string packet = fullFileName.ToStdString();
kiway.ExpressMail( FRAME_PCB_MODULE_EDITOR, MAIL_FP_EDIT, packet );
} }
break; break;
@ -264,7 +266,9 @@ void TREEPROJECT_ITEM::Activate( TREE_PROJECT_FRAME* aTreePrjFrame )
{ {
wxCommandEvent dummy; wxCommandEvent dummy;
frame->OnRunSchLibEditor( dummy ); frame->OnRunSchLibEditor( dummy );
kiway.ExpressMail( FRAME_SCH_LIB_EDITOR, MAIL_LIB_EDIT, fullFileName.ToStdString() );
std::string packet = fullFileName.ToStdString();
kiway.ExpressMail( FRAME_SCH_LIB_EDITOR, MAIL_LIB_EDIT, packet );
} }
break; break;

View File

@ -50,8 +50,6 @@
#include <collectors.h> #include <collectors.h>
#include <pcbnew.h> #include <pcbnew.h>
#include <board_netlist_updater.h>
#include <netlist_reader.h>
#include <pcb_netlist.h> #include <pcb_netlist.h>
#include <dialogs/dialog_update_pcb.h> #include <dialogs/dialog_update_pcb.h>
@ -384,56 +382,12 @@ void PCB_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
ExecuteRemoteCommand( payload.c_str() ); ExecuteRemoteCommand( payload.c_str() );
break; break;
case MAIL_SCH_PCB_UPDATE: case MAIL_PCB_UPDATE:
{ {
NETLIST netlist; NETLIST netlist;
size_t split = payload.find( '\n' );
wxCHECK( split != std::string::npos, /*void*/ );
// Extract options and netlist if( FetchNetlistFromSchematic( netlist, ANNOTATION_DIALOG ) )
std::string options = payload.substr( 0, split ); UpdatePCBFromNetlist( netlist );
std::string netlistData = payload.substr( split + 1 );
// Quiet update options
bool by_reference = options.find( "by-reference" ) != std::string::npos;
bool by_timestamp = options.find( "by-timestamp" ) != std::string::npos;
wxASSERT( !( by_reference && by_timestamp ) ); // only one at a time please
try
{
STRING_LINE_READER* lineReader = new STRING_LINE_READER( netlistData, _( "Eeschema netlist" ) );
KICAD_NETLIST_READER netlistReader( lineReader, &netlist );
netlistReader.LoadNetlist();
}
catch( const IO_ERROR& )
{
assert( false ); // should never happen
}
if( by_reference || by_timestamp )
{
netlist.SetDeleteExtraFootprints( false );
netlist.SetFindByTimeStamp( by_timestamp );
netlist.SetReplaceFootprints( true );
BOARD_NETLIST_UPDATER updater( this, GetBoard() );
updater.SetLookupByTimestamp( by_timestamp );
updater.SetDeleteUnusedComponents( false );
updater.SetReplaceFootprints( true );
updater.SetDeleteSinglePadNets( false );
updater.UpdateNetlist( netlist );
}
else
{
DIALOG_UPDATE_PCB updateDialog( this, &netlist );
updateDialog.ShowModal();
auto selectionTool = static_cast<SELECTION_TOOL*>(
m_toolManager->FindTool( "pcbnew.InteractiveSelection" ) );
if( !selectionTool->GetSelection().Empty() )
GetToolManager()->InvokeTool( "pcbnew.InteractiveEdit" );
}
break; break;
} }

View File

@ -46,7 +46,7 @@
#include <kiway_player.h> #include <kiway_player.h>
#include <trace_helpers.h> #include <trace_helpers.h>
#include <lockfile.cpp> #include <lockfile.cpp>
#include <pcb_netlist.h>
#include <pcbnew.h> #include <pcbnew.h>
#include <pcbnew_id.h> #include <pcbnew_id.h>
#include <io_mgr.h> #include <io_mgr.h>
@ -967,10 +967,11 @@ bool PCB_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType )
// - first, assign valid timestamps to footprints (no reannotation) // - first, assign valid timestamps to footprints (no reannotation)
// - second, perform schematic annotation and update footprint references // - second, perform schematic annotation and update footprint references
// based on timestamps // based on timestamps
Kiway().ExpressMail( FRAME_SCH, MAIL_SCH_PCB_UPDATE_REQUEST, NETLIST netlist;
"no-annotate;by-reference", this ); FetchNetlistFromSchematic( netlist, NO_ANNOTATION );
Kiway().ExpressMail( FRAME_SCH, MAIL_SCH_PCB_UPDATE_REQUEST, DoUpdatePCBFromNetlist( netlist, false );
"quiet-annotate;by-timestamp", this ); FetchNetlistFromSchematic( netlist, QUIET_ANNOTATION );
DoUpdatePCBFromNetlist( netlist, true );
std::unordered_map<wxString, wxString> netRemap; std::unordered_map<wxString, wxString> netRemap;

View File

@ -51,6 +51,7 @@
#include <dialog_edit_footprint_for_BoardEditor.h> #include <dialog_edit_footprint_for_BoardEditor.h>
#include <dialog_board_setup.h> #include <dialog_board_setup.h>
#include <dialog_configure_paths.h> #include <dialog_configure_paths.h>
#include <dialog_update_pcb.h>
#include <convert_to_biu.h> #include <convert_to_biu.h>
#include <view/view.h> #include <view/view.h>
#include <view/view_controls.h> #include <view/view_controls.h>
@ -70,9 +71,13 @@
#include <tool/tool_manager.h> #include <tool/tool_manager.h>
#include <tool/tool_dispatcher.h> #include <tool/tool_dispatcher.h>
#include <tools/pcb_actions.h> #include <tools/pcb_actions.h>
#include <tools/selection_tool.h>
#include <gestfich.h> #include <gestfich.h>
#include <executable_names.h> #include <executable_names.h>
#include <eda_dockart.h> #include <eda_dockart.h>
#include <board_netlist_updater.h>
#include <netlist_reader.h>
#include <pcb_netlist.h>
#if defined(KICAD_SCRIPTING) || defined(KICAD_SCRIPTING_WXPYTHON) #if defined(KICAD_SCRIPTING) || defined(KICAD_SCRIPTING_WXPYTHON)
#include <python_scripting.h> #include <python_scripting.h>
@ -1150,6 +1155,15 @@ void PCB_EDIT_FRAME::OnConfigurePaths( wxCommandEvent& aEvent )
void PCB_EDIT_FRAME::OnUpdatePCBFromSch( wxCommandEvent& event ) void PCB_EDIT_FRAME::OnUpdatePCBFromSch( wxCommandEvent& event )
{
NETLIST netlist;
if( FetchNetlistFromSchematic( netlist, ANNOTATION_DIALOG ) )
UpdatePCBFromNetlist( netlist );
}
bool PCB_EDIT_FRAME::FetchNetlistFromSchematic( NETLIST& aNetlist, FETCH_NETLIST_MODE aMode )
{ {
if( Kiface().IsSingle() ) if( Kiface().IsSingle() )
{ {
@ -1157,30 +1171,73 @@ void PCB_EDIT_FRAME::OnUpdatePCBFromSch( wxCommandEvent& event )
"opened in stand-alone mode. In order to create or update " "opened in stand-alone mode. In order to create or update "
"PCBs from schematics, you need to launch the KiCad project manager " "PCBs from schematics, you need to launch the KiCad project manager "
"and create a PCB project." ) ); "and create a PCB project." ) );
return; return false;
} }
else
// Update PCB requires a netlist. Therefore the schematic editor must be running
// If this is not the case, open the schematic editor
KIWAY_PLAYER* frame = Kiway().Player( FRAME_SCH, true );
if( !frame->IsShown() )
{ {
// Update PCB requires a netlist. Therefore the schematic editor must be running wxFileName schfn( Prj().GetProjectPath(), Prj().GetProjectName(), SchematicFileExtension );
// If this is not the case, open the schematic editor
KIWAY_PLAYER* frame = Kiway().Player( FRAME_SCH, true );
if( !frame->IsShown() ) frame->OpenProjectFiles( std::vector<wxString>( 1, schfn.GetFullPath() ) );
{ // Because the schematic editor frame is not on screen, iconize it:
wxFileName schfn( Prj().GetProjectPath(), Prj().GetProjectName(), SchematicFileExtension ); // However, another valid option is to do not iconize the schematic editor frame
// and show it
frame->OpenProjectFiles( std::vector<wxString>( 1, schfn.GetFullPath() ) ); frame->Iconize( true );
// Because the schematic editor frame is not on screen, iconize it: // we show the schematic editor frame, because do not show is seen as
// However, another valid option is to do not iconize the schematic editor frame // a not yet opened schematic by Kicad manager, which is not the case
// and show it frame->Show( true );
frame->Iconize( true );
// we show the schematic editor frame, because do not show is seen as
// a not yet opened schematic by Kicad manager, which is not the case
frame->Show( true );
}
Kiway().ExpressMail( FRAME_SCH, MAIL_SCH_PCB_UPDATE_REQUEST, "", this );
} }
std::string payload;
if( aMode == NO_ANNOTATION )
payload = "no-annotate";
else if( aMode = QUIET_ANNOTATION )
payload = "quiet-annotate";
Kiway().ExpressMail( FRAME_SCH, MAIL_SCH_GET_NETLIST, payload, this );
try
{
auto lineReader = new STRING_LINE_READER( payload, _( "Eeschema netlist" ) );
KICAD_NETLIST_READER netlistReader( lineReader, &aNetlist );
netlistReader.LoadNetlist();
}
catch( const IO_ERROR& )
{
assert( false ); // should never happen
return false;
}
return true;
}
void PCB_EDIT_FRAME::UpdatePCBFromNetlist( NETLIST& aNetlist )
{
DIALOG_UPDATE_PCB updateDialog( this, &aNetlist );
updateDialog.ShowModal();
auto selectionTool = static_cast<SELECTION_TOOL*>(
m_toolManager->FindTool( "pcbnew.InteractiveSelection" ) );
if( !selectionTool->GetSelection().Empty() )
GetToolManager()->InvokeTool( "pcbnew.InteractiveEdit" );
}
void PCB_EDIT_FRAME::DoUpdatePCBFromNetlist( NETLIST& aNetlist, bool aUseTimestamps )
{
BOARD_NETLIST_UPDATER updater( this, GetBoard() );
updater.SetLookupByTimestamp( aUseTimestamps );
updater.SetDeleteUnusedComponents( false );
updater.SetReplaceFootprints( true );
updater.SetDeleteSinglePadNets( false );
updater.UpdateNetlist( aNetlist );
} }

View File

@ -1559,6 +1559,28 @@ public:
// netlist handling: // netlist handling:
void InstallNetlistFrame( wxDC* DC ); void InstallNetlistFrame( wxDC* DC );
/**
* Function FetchNetlistFromSchematic
* @param aNetlist a NETLIST owned by the caller. This function fills it in.
* @return true if a netlist was fetched.
*/
enum FETCH_NETLIST_MODE { NO_ANNOTATION, QUIET_ANNOTATION, ANNOTATION_DIALOG };
bool FetchNetlistFromSchematic( NETLIST& aNetlist, FETCH_NETLIST_MODE aMode );
/**
* Function UpdatePCBFromNetlist
* @param aNetlist
*/
void UpdatePCBFromNetlist( NETLIST& aNetlist );
/**
* Function DoUpdatePCBFromNetlist
* An automated version of UpdatePCBFromNetlist which skips the UI dialog.
* @param aNetlist
* @param aUseTimestamps
*/
void DoUpdatePCBFromNetlist( NETLIST& aNetlist, bool aUseTimestamps );
/** /**
* Function ReadPcbNetlist * Function ReadPcbNetlist
* reads \a aNetlistFileName and updates the footprints (load missing footprints and * reads \a aNetlistFileName and updates the footprints (load missing footprints and