One-click PCB update improvements

- Fix repetitive undo/redo segfaults & assertions.
- Add Update menu entry on PCB side.
- Fix Python build error
- Add spread footprints after updating
This commit is contained in:
Tomasz Wlostowski 2016-01-29 15:43:40 +01:00 committed by Maciej Suminski
parent 689072c0e1
commit ee3418e90b
20 changed files with 160 additions and 63 deletions

View File

@ -197,6 +197,14 @@ void SCH_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
ExecuteRemoteCommand( payload.c_str() );
break;
case MAIL_SCH_PCB_UPDATE_REQUEST:
{
wxCommandEvent dummy;
OnUpdatePCB( dummy );
break;
}
case MAIL_BACKANNOTATE_FOOTPRINTS:
try
{

View File

@ -297,9 +297,9 @@ static EDA_HOTKEY* schematic_Hotkey_List[] =
&HkAddBusEntry,
&HkAddGraphicPolyLine,
&HkAddGraphicText,
&HkLeaveSheet,
&HkUpdatePcbFromSch,
&HkAutoplaceFields,
&HkLeaveSheet,
&HkDeleteNode,
NULL
};

View File

@ -78,9 +78,9 @@ enum hotkey_id_commnand {
HK_LEFT_CLICK,
HK_LEFT_DCLICK,
HK_LEAVE_SHEET,
HK_UPDATE_PCB_FROM_SCH,
HK_DELETE_NODE,
HK_AUTOPLACE_FIELDS,
HK_DELETE_NODE
HK_UPDATE_PCB_FROM_SCH
};
// List of hotkey descriptors for Eeschema

View File

@ -429,15 +429,17 @@ void SCH_EDIT_FRAME::ReCreateMenuBar()
text = AddHotkeyName( _( "Update PCB from Schematics" ), g_Schematic_Hokeys_Descr, HK_UPDATE_PCB_FROM_SCH );
wxMenuItem* updItem = AddMenuItem( toolsMenu,
AddMenuItem( toolsMenu,
ID_UPDATE_PCB_FROM_SCH,
text, _( "Updates the PCB design with the current schematic (forward annotation)." ),
KiBitmap( libedit_xpm ) );
KiBitmap( pcbnew_xpm ) );
KIWAY_PLAYER* pcbFrame = Kiway().Player( FRAME_PCB, false ); // test open already.
//if( Kiface().IsSingle() || !pcbFrame ) FIXME: refresh
//updItem->Enable( false );
// Run Pcbnew
AddMenuItem( toolsMenu,
ID_RUN_PCB,
_( "&Open PCB Editor" ),
_( "Run Pcbnew" ),
KiBitmap( pcbnew_xpm ) );
toolsMenu->AppendSeparator();
@ -488,17 +490,10 @@ void SCH_EDIT_FRAME::ReCreateMenuBar()
// Run CvPcb
AddMenuItem( toolsMenu,
ID_RUN_CVPCB,
_( "A&ssign Component Footprint" ),
_( "A&ssign Component Footprints" ),
_( "Run CvPcb" ),
KiBitmap( cvpcb_xpm ) );
// Run Pcbnew
AddMenuItem( toolsMenu,
ID_RUN_PCB,
_( "&Layout Printed Circuit Board" ),
_( "Run Pcbnew" ),
KiBitmap( pcbnew_xpm ) );
// Help Menu:
wxMenu* helpMenu = new wxMenu;

View File

@ -39,7 +39,9 @@ enum MAIL_T
MAIL_CROSS_PROBE, ///< PCB<->SCH, CVPCB->SCH cross-probing.
MAIL_BACKANNOTATE_FOOTPRINTS, ///< CVPCB->SCH footprint stuffing at cvpcb termination
MAIL_EESCHEMA_NETLIST, ///< EESCHEMA->CVPCB netlist immediately after launching CVPCB
MAIL_SCH_PCB_UPDATE ///< Sch->PCB forward update
MAIL_SCH_PCB_UPDATE, ///< Sch->PCB forward update
MAIL_SCH_PCB_UPDATE_REQUEST ///< Sch->PCB forward update, requests SCH to re-generate netlist and send it to PCB via another mail (kind of bootstrap)
};
#endif // MAIL_TYPE_H_

View File

@ -91,8 +91,6 @@ class PCB_EDIT_FRAME : public PCB_BASE_EDIT_FRAME
protected:
bool m_undoDisabled;
PCB_LAYER_WIDGET* m_Layers;
DRC* m_drc; ///< the DRC controller, see drc.cpp
@ -228,11 +226,6 @@ public:
void LoadFootprints( NETLIST& aNetlist, REPORTER* aReporter )
throw( IO_ERROR, PARSE_ERROR );
void DisableUndo( bool aDisable = true )
{
m_undoDisabled = aDisable;
}
void OnQuit( wxCommandEvent& event );
/**
@ -288,6 +281,7 @@ public:
void OnUpdateMuWaveToolbar( wxUpdateUIEvent& aEvent );
void OnLayerColorChange( wxCommandEvent& aEvent );
void OnConfigurePaths( wxCommandEvent& aEvent );
void OnUpdatePCBFromSch( wxCommandEvent& event );
/**
* called when the alt key is pressed during a mouse wheel action

View File

@ -62,9 +62,19 @@ BOARD_NETLIST_UPDATER::~BOARD_NETLIST_UPDATER ()
delete m_undoList;
}
void BOARD_NETLIST_UPDATER::pushUndo( BOARD_ITEM* aItem, UNDO_REDO_T aCommandType )
void BOARD_NETLIST_UPDATER::pushUndo( BOARD_ITEM* aItem, UNDO_REDO_T aCommandType, BOARD_ITEM* aCopy )
{
m_undoList->PushItem( ITEM_PICKER( aItem, aCommandType ) );
ITEM_PICKER picker( aItem, aCommandType );
if( aCommandType == UR_CHANGED )
{
if( m_undoList->FindItem ( aItem ) >= 0 ) // add only once
return;
picker.SetLink( aCopy ? aCopy : aItem->Clone() );
}
m_undoList->PushItem( picker );
}
wxPoint BOARD_NETLIST_UPDATER::estimateComponentInsertionPosition()
@ -124,6 +134,7 @@ MODULE* BOARD_NETLIST_UPDATER::addNewComponent( COMPONENT* aComponent )
footprint->SetTimeStamp( GetNewTimeStamp() );
m_board->Add( footprint, ADD_APPEND );
m_addedComponents.push_back( footprint );
pushUndo( footprint, UR_NEW );
@ -192,7 +203,7 @@ MODULE* BOARD_NETLIST_UPDATER::replaceComponent( NETLIST& aNetlist, MODULE *aPcb
else
newFootprint->SetPath( aPcbComponent->GetPath() );
aPcbComponent->CopyNetlistSettings( newFootprint );
aPcbComponent->CopyNetlistSettings( newFootprint, false );
m_board->Remove( aPcbComponent );
m_board->Add( newFootprint, ADD_APPEND );
@ -231,7 +242,8 @@ bool BOARD_NETLIST_UPDATER::updateComponentParameters( MODULE *aPcbComponent, CO
if( !aPcbComponent )
return false;
pushUndo ( aPcbComponent, UR_CHANGED );
bool changed = false;
MODULE* copy = (MODULE*) aPcbComponent->Clone();
// Test for reference designator field change.
if( aPcbComponent->GetReference() != aNewComponent->GetReference() )
@ -250,8 +262,11 @@ bool BOARD_NETLIST_UPDATER::updateComponentParameters( MODULE *aPcbComponent, CO
m_reporter->Report( msg, REPORTER::RPT_INFO );
if ( !m_isDryRun )
{
changed = true;
aPcbComponent->SetReference( aNewComponent->GetReference() );
}
}
// Test for value field change.
if( aPcbComponent->GetValue() != aNewComponent->GetValue() )
@ -271,8 +286,11 @@ bool BOARD_NETLIST_UPDATER::updateComponentParameters( MODULE *aPcbComponent, CO
m_reporter->Report( msg, REPORTER::RPT_ACTION );
if ( !m_isDryRun )
{
changed = true;
aPcbComponent->SetValue( aNewComponent->GetValue() );
}
}
// Test for time stamp change.
if( aPcbComponent->GetPath() != aNewComponent->GetTimeStamp() )
@ -284,8 +302,16 @@ bool BOARD_NETLIST_UPDATER::updateComponentParameters( MODULE *aPcbComponent, CO
m_reporter->Report( msg, REPORTER::RPT_INFO );
if ( !m_isDryRun )
{
changed = true;
aPcbComponent->SetPath( aNewComponent->GetTimeStamp() );
}
}
if( changed )
pushUndo( aPcbComponent, UR_CHANGED, copy );
else
delete copy;
return true;
}
@ -294,6 +320,9 @@ bool BOARD_NETLIST_UPDATER::updateComponentPadConnections( MODULE *aPcbComponent
{
wxString msg;
bool changed = false;
MODULE* copy = (MODULE*) aPcbComponent->Clone();
// At this point, the component footprint is updated. Now update the nets.
for( D_PAD *pad = aPcbComponent->Pads(); pad; pad = pad->Next() )
{
@ -316,11 +345,9 @@ bool BOARD_NETLIST_UPDATER::updateComponentPadConnections( MODULE *aPcbComponent
}
if( !m_isDryRun )
{
pushUndo( pad, UR_CHANGED );
changed = true;
pad->SetNetCode( NETINFO_LIST::UNCONNECTED );
}
}
@ -335,6 +362,7 @@ bool BOARD_NETLIST_UPDATER::updateComponentPadConnections( MODULE *aPcbComponent
// It is a new net, we have to add it
if( !m_isDryRun )
{
changed = true;
netinfo = new NETINFO_ITEM( m_board, net.GetNetName() );
m_board->AppendNet( netinfo );
pushUndo( netinfo, UR_NEW );
@ -375,13 +403,18 @@ bool BOARD_NETLIST_UPDATER::updateComponentPadConnections( MODULE *aPcbComponent
if ( !m_isDryRun )
{
pushUndo( pad, UR_CHANGED );
changed = true;
pad->SetNetCode( netinfo->GetNet() );
}
}
}
}
if( changed )
pushUndo( aPcbComponent, UR_CHANGED, copy );
else
delete copy;
return true;
}
@ -417,7 +450,7 @@ bool BOARD_NETLIST_UPDATER::deleteUnusedComponents( NETLIST& aNetlist )
if( !m_isDryRun )
{
pushUndo( module, UR_DELETED );
module->DeleteStructure();
m_board->Remove( module );
}
}
}
@ -488,7 +521,7 @@ bool BOARD_NETLIST_UPDATER::deleteSinglePadNets()
GetChars( previouspad->GetPadName() ) );
m_reporter->Report( msg, REPORTER::RPT_ACTION );
pushUndo( previouspad, UR_CHANGED );
//pushUndo( previouspad, UR_CHANGED );
previouspad->SetNetCode( NETINFO_LIST::UNCONNECTED );
}
}
@ -507,7 +540,7 @@ bool BOARD_NETLIST_UPDATER::deleteSinglePadNets()
// Examine last pad
if( pad && count == 1 )
{
pushUndo( pad, UR_CHANGED );
//pushUndo( pad, UR_CHANGED );
pad->SetNetCode( NETINFO_LIST::UNCONNECTED );
}
return true;
@ -640,12 +673,14 @@ bool BOARD_NETLIST_UPDATER::UpdateNetlist( NETLIST& aNetlist )
{
m_frame->SaveCopyInUndoList( *m_undoList, UR_UNSPECIFIED, wxPoint(0, 0) );
m_frame->OnModify();
}
// Update the ratsnest
m_frame->Compile_Ratsnest( NULL, true );
m_board->GetRatsnest()->ProcessBoard();
testConnectivity( aNetlist );
}
// Update the ratsnest
m_reporter->Report( _(""), REPORTER::RPT_ACTION );
m_reporter->Report( _(""), REPORTER::RPT_ACTION );

View File

@ -127,9 +127,14 @@ public:
m_lookupByTimestamp = aEnabled;
}
std::vector<MODULE*> GetAddedComponents() const
{
return m_addedComponents;
}
private:
void pushUndo( BOARD_ITEM* aItem, UNDO_REDO_T aCommandType );
void pushUndo( BOARD_ITEM* aItem, UNDO_REDO_T aCommandType, BOARD_ITEM* aCopy = NULL );
wxPoint estimateComponentInsertionPosition();
MODULE* addNewComponent( COMPONENT* aComponent );
@ -145,6 +150,8 @@ private:
BOARD *m_board;
REPORTER *m_reporter;
std::vector<MODULE*> m_addedComponents;
bool m_deleteSinglePadNets;
bool m_deleteUnusedComponents;
bool m_isDryRun;
@ -156,5 +163,3 @@ private:
};
#endif

View File

@ -116,6 +116,7 @@
* @param aItem = item to find
* = NULL to build the list of existing items
*/
static bool TestForExistingItem( BOARD* aPcb, BOARD_ITEM* aItem )
{
static std::vector<BOARD_ITEM*> itemsList;
@ -391,8 +392,8 @@ void PCB_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList,
for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ )
{
ITEM_PICKER picker = aItemsList.GetItemWrapper(ii);
BOARD_ITEM* item = (BOARD_ITEM*) aItemsList.GetPickedItem( ii );
UNDO_REDO_T status = aItemsList.GetPickedItemStatus( ii );
// For texts belonging to modules, we need to save state of the parent module
if( item->Type() == PCB_MODULE_TEXT_T || item->Type() == PCB_PAD_T )
@ -405,7 +406,7 @@ void PCB_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList,
bool found = false;
for( int j = 0; j < commandToUndo->GetCount(); j++ )
for( unsigned j = 0; j < commandToUndo->GetCount(); j++ )
{
if( commandToUndo->GetPickedItem( j ) == item && commandToUndo->GetPickedItemStatus( j ) == UR_CHANGED )
{
@ -420,15 +421,13 @@ void PCB_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList,
continue;
} else {
commandToUndo->PushItem( ITEM_PICKER( item, status ) );
commandToUndo->PushItem( picker );
}
}
for( unsigned ii = 0; ii < commandToUndo->GetCount(); ii++ )
{
BOARD_ITEM* item = (BOARD_ITEM*) commandToUndo->GetPickedItem( ii );
UNDO_REDO_T status = commandToUndo->GetPickedItemStatus( ii );
UNDO_REDO_T command = commandToUndo->GetPickedItemStatus( ii );
if( command == UR_UNSPECIFIED )
@ -448,7 +447,10 @@ void PCB_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList,
* If this link is not null, the copy is already done
*/
if( commandToUndo->GetPickedItemLink( ii ) == NULL )
commandToUndo->SetPickedItemLink( item->Clone(), ii );
{
EDA_ITEM* cloned = item->Clone();
commandToUndo->SetPickedItemLink( cloned, ii );
}
break;
case UR_MOVED:
@ -492,6 +494,8 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed
BOARD_ITEM* item;
bool not_found = false;
bool reBuild_ratsnest = false;
bool deep_reBuild_ratsnest = false;
KIGFX::VIEW* view = GetGalCanvas()->GetView();
RN_DATA* ratsnest = GetBoard()->GetRatsnest();
@ -545,6 +549,11 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed
reBuild_ratsnest = true;
break;
case PCB_NETINFO_T:
reBuild_ratsnest = true;
deep_reBuild_ratsnest = true;
break;
default:
break;
}
@ -591,8 +600,8 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed
MODULE* module = static_cast<MODULE*>( item );
module->RunOnChildren( boost::bind( &KIGFX::VIEW::Remove, view, _1 ) );
}
view->Remove( item );
view->Remove( item );
item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
break;
@ -652,12 +661,18 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed
wxMessageBox( wxT( "Incomplete undo/redo operation: some items not found" ) );
// Rebuild pointers and ratsnest that can be changed.
if( reBuild_ratsnest && aRebuildRatsnet )
if( reBuild_ratsnest )
{
if( IsGalCanvasActive() )
ratsnest->Recalculate();
else
Compile_Ratsnest( NULL, true );
if( IsGalCanvasActive() )
{
if( deep_reBuild_ratsnest )
ratsnest->ProcessBoard();
else
ratsnest->Recalculate();
}
}
}

View File

@ -764,9 +764,11 @@ BOARD_ITEM* BOARD::Remove( BOARD_ITEM* aBoardItem )
switch( aBoardItem->Type() )
{
case PCB_NETINFO_T:
m_NetInfo.RemoveNet ( (NETINFO_ITEM*) aBoardItem );
{
NETINFO_ITEM* item = (NETINFO_ITEM*) aBoardItem;
m_NetInfo.RemoveNet( item );
break;
}
case PCB_MARKER_T:
// find the item in the vector, then remove it

View File

@ -115,6 +115,7 @@ MODULE::MODULE( const MODULE& aModule ) :
for( D_PAD* pad = aModule.m_Pads; pad; pad = pad->Next() )
{
D_PAD* newpad = new D_PAD( *pad );
assert( newpad->GetNet() == pad->GetNet() );
newpad->SetParent( this );
m_Pads.PushBack( newpad );
}

View File

@ -297,7 +297,6 @@ public:
*/
void AppendNet( NETINFO_ITEM* aNewElement );
/**
* Function RemoveNet
* Removes a new from the net list.

View File

@ -88,6 +88,8 @@ void NETINFO_LIST::RemoveNet( NETINFO_ITEM* aNet )
break;
}
}
m_newNetCode = std::min( m_newNetCode, aNet->m_NetCode - 1 );
}

View File

@ -84,8 +84,9 @@ void DIALOG_UPDATE_PCB::PerformUpdate( bool aDryRun )
if( aDryRun )
return;
m_frame->OnModify();
std::vector<MODULE*> newFootprints = updater.GetAddedComponents();
m_frame->OnModify();
m_frame->SetCurItem( NULL );
// Reload modules

View File

@ -605,6 +605,14 @@ void PCB_EDIT_FRAME::ReCreateMenuBar()
//----- Tools menu ----------------------------------------------------------
wxMenu* toolsMenu = new wxMenu;
AddMenuItem( toolsMenu,
ID_UPDATE_PCB_FROM_SCH,
_( "Update PCB from Schematics" ),
_( "Updates the PCB design with the current schematic (forward annotation)." ),
KiBitmap( libedit_xpm ) );
toolsMenu->AppendSeparator( );
AddMenuItem( toolsMenu, ID_GET_NETLIST,
_( "&Netlist" ),
_( "Read the netlist and update board connectivity" ),

View File

@ -116,7 +116,6 @@ void PCB_EDIT_FRAME::ReadPcbNetlist( const wxString& aNetlistFileName,
netlist.SortByReference();
board->ReplaceNetlist( netlist, aDeleteSinglePadNets, &newFootprints, aReporter );
// If it was a dry run, nothing has changed so we're done.
if( netlist.IsDryRun() )
return;
@ -329,4 +328,3 @@ void PCB_EDIT_FRAME::LoadFootprints( NETLIST& aNetlist, REPORTER* aReporter )
component->SetModule( module );
}
}

View File

@ -70,6 +70,8 @@
#include <tool/tool_dispatcher.h>
#include <tools/common_actions.h>
#include <wildcards_and_files_ext.h>
#if defined(KICAD_SCRIPTING) || defined(KICAD_SCRIPTING_WXPYTHON)
#include <python_scripting.h>
#endif
@ -232,6 +234,8 @@ BEGIN_EVENT_TABLE( PCB_EDIT_FRAME, PCB_BASE_FRAME )
EVT_TOOL( ID_TB_OPTIONS_SHOW_EXTRA_VERTICAL_TOOLBAR_MICROWAVE,
PCB_EDIT_FRAME::OnSelectOptionToolbar )
EVT_TOOL( ID_UPDATE_PCB_FROM_SCH, PCB_EDIT_FRAME::OnUpdatePCBFromSch )
EVT_TOOL_RANGE( ID_TB_OPTIONS_SHOW_ZONES, ID_TB_OPTIONS_SHOW_ZONES_OUTLINES_ONLY,
PCB_EDIT_FRAME::OnSelectOptionToolbar )
@ -309,7 +313,6 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
PCB_BASE_EDIT_FRAME( aKiway, aParent, FRAME_PCB, wxT( "Pcbnew" ), wxDefaultPosition,
wxDefaultSize, KICAD_DEFAULT_DRAWFRAME_STYLE, PCB_EDIT_FRAME_NAME )
{
m_undoDisabled = false;
m_showBorderAndTitleBlock = true; // true to display sheet references
m_showAxis = false; // true to display X and Y axis
m_showOriginAxis = true;
@ -1081,3 +1084,30 @@ void PCB_EDIT_FRAME::OnConfigurePaths( wxCommandEvent& aEvent )
{
Pgm().ConfigurePaths( this );
}
void PCB_EDIT_FRAME::OnUpdatePCBFromSch( wxCommandEvent& event )
{
if( Kiface().IsSingle() )
{
DisplayError( this, _( "Cannot update the PCB, because the Kicad 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_SCH, true );
wxFileName schfn = Prj().AbsolutePath( Prj().GetProjectName() );
schfn.SetExt( SchematicFileExtension );
if( !frame->IsVisible() )
{
frame->OpenProjectFiles( std::vector<wxString>( 1, schfn.GetFullPath() ) );
frame->Show( false );
}
Kiway().ExpressMail( FRAME_SCH, MAIL_SCH_PCB_UPDATE_REQUEST, "", this );
}
}

View File

@ -393,6 +393,7 @@ enum pcbnew_ids
ID_FOOTPRINT_WIZARD_SELECT_WIZARD,
ID_FOOTPRINT_WIZARD_EXPORT_TO_BOARD,
ID_UPDATE_PCB_FROM_SCH,
ID_PCBNEW_END_LIST
};

View File

@ -39,6 +39,7 @@
// ignore a couple of items that generate warnings from swig built code
%ignore NETINFO_ITEM;
%ignore BOARD_ITEM::ZeroOffset;
%ignore D_PAD::m_PadSketchModePenSize;

View File

@ -357,7 +357,7 @@ int DRAWING_TOOL::DrawDimension( const TOOL_EVENT& aEvent )
m_view->Add( dimension );
m_board->Add( dimension );
dimension->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
//dimension->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
m_frame->OnModify();
m_frame->SaveCopyInUndoList( dimension, UR_NEW );