From 105825c0583d26f2d8ff227e64bdeca568d28c94 Mon Sep 17 00:00:00 2001 From: Jon Evans Date: Wed, 17 Apr 2019 22:10:56 -0400 Subject: [PATCH] Refactor Import Netlist to use the same codepath as Update PCB --- pcbnew/class_board.cpp | 465 --------------------------- pcbnew/class_board.h | 40 --- pcbnew/dialogs/dialog_netlist.cpp | 54 ++-- pcbnew/dialogs/dialog_netlist.h | 2 + pcbnew/dialogs/dialog_update_pcb.cpp | 53 +-- pcbnew/netlist.cpp | 123 +++---- pcbnew/pcb_edit_frame.h | 44 +-- 7 files changed, 91 insertions(+), 690 deletions(-) diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp index f29258e360..5f210a6b62 100644 --- a/pcbnew/class_board.cpp +++ b/pcbnew/class_board.cpp @@ -2428,471 +2428,6 @@ bool BOARD::NormalizeAreaPolygon( PICKED_ITEMS_LIST * aNewZonesList, ZONE_CONTAI } -void BOARD::updateComponentPadConnections( NETLIST& aNetlist, MODULE* footprint, - COMPONENT* component, REPORTER& aReporter ) -{ - wxString msg; - - for( auto pad : footprint->Pads() ) - { - COMPONENT_NET net = component->GetNet( pad->GetName() ); - - if( !net.IsValid() ) // Footprint pad had no net. - { - if( !pad->GetNetname().IsEmpty() ) - { - msg.Printf( _( "Clearing component %s pin %s net." ), - footprint->GetReference(), - pad->GetName() ); - aReporter.Report( msg, REPORTER::RPT_ACTION ); - } - - if( !aNetlist.IsDryRun() ) - { - m_connectivity->Remove( pad ); - pad->SetNetCode( NETINFO_LIST::UNCONNECTED ); - } - } - else // Footprint pad has a net. - { - const wxString& netName = net.GetNetName(); - NETINFO_ITEM* netinfo = FindNet( netName ); - - if( netinfo && !aNetlist.IsDryRun() ) - netinfo->SetIsCurrent( true ); - - if( pad->GetNetname() != netName ) - { - m_oldToNewNets[ pad->GetNetname() ] = netName; - - msg.Printf( _( "Changing footprint %s pad %s net from %s to %s." ), - footprint->GetReference(), - pad->GetName(), - UnescapeString( pad->GetNetname() ), - UnescapeString( netName ) ); - aReporter.Report( msg, REPORTER::RPT_ACTION ); - - if( !aNetlist.IsDryRun() ) - { - if( netinfo == NULL ) - { - // It is a new net, we have to add it - netinfo = new NETINFO_ITEM( this, net.GetNetName() ); - Add( netinfo ); - } - - m_connectivity->Remove( pad ); - pad->SetNetCode( netinfo->GetNet() ); - m_connectivity->Add( pad ); - } - } - } - } -} - - -void BOARD::ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets, - std::vector* aNewFootprints, REPORTER& aReporter ) -{ - unsigned i; - wxPoint bestPosition; - wxString msg; - std::vector newFootprints; - std::map< ZONE_CONTAINER*, std::vector > zoneConnectionsCache; - MODULE* lastPreexistingFootprint = m_Modules.GetLast(); - - m_oldToNewNets.clear(); - - for( int ii = 0; ii < GetAreaCount(); ii++ ) - { - ZONE_CONTAINER* zone = GetArea( ii ); - - if( !zone->IsOnCopperLayer() || zone->GetIsKeepout() ) - continue; - - zoneConnectionsCache[ zone ] = m_connectivity->GetConnectedPads( zone ); - } - - if( !IsEmpty() ) - { - // Position new components below any existing board features. - EDA_RECT bbbox = GetBoardEdgesBoundingBox(); - - if( bbbox.GetWidth() || bbbox.GetHeight() ) - { - bestPosition.x = bbbox.Centre().x; - bestPosition.y = bbbox.GetBottom() + Millimeter2iu( 10 ); - } - } - else - { - // Position new components in the center of the page when the board is empty. - wxSize pageSize = m_paper.GetSizeIU(); - - bestPosition.x = pageSize.GetWidth() / 2; - bestPosition.y = pageSize.GetHeight() / 2; - } - - m_Status_Pcb = 0; - - // Mark all nets (except ) as stale; we'll update those to current that - // we find in the netlist - for( NETINFO_ITEM* net : m_NetInfo ) - net->SetIsCurrent( net->GetNet() == 0 ); - - for( i = 0; i < aNetlist.GetCount(); i++ ) - { - COMPONENT* component = aNetlist.GetComponent( i ); - int matchCount = 0; - MODULE* tmp; - - msg.Printf( _( "Checking netlist symbol footprint \"%s:%s:%s\"." ), - component->GetReference(), - component->GetTimeStamp(), - GetChars( component->GetFPID().Format() ) ); - aReporter.Report( msg, REPORTER::RPT_INFO ); - - for( MODULE* footprint = m_Modules; footprint; footprint = footprint->Next() ) - { - bool match; - - if( aNetlist.IsFindByTimeStamp() ) - match = footprint->GetPath() == component->GetTimeStamp(); - else - match = footprint->GetReference().CmpNoCase( component->GetReference() ) == 0; - - if( match ) - { - // Test for footprint change. - if( !component->GetFPID().empty() && footprint->GetFPID() != component->GetFPID() ) - { - if( aNetlist.GetReplaceFootprints() ) - { - if( component->GetModule() != NULL ) - { - msg.Printf( _( "Changing symbol %s footprint from %s to %s." ), - footprint->GetReference(), - GetChars( footprint->GetFPID().Format() ), - GetChars( component->GetFPID().Format() ) ); - aReporter.Report( msg, REPORTER::RPT_ACTION ); - } - else - { - msg.Printf( _( "Cannot change symbol %s footprint due to missing footprint %s." ), - footprint->GetReference(), - GetChars( component->GetFPID().Format() ) ); - aReporter.Report( msg, REPORTER::RPT_ERROR ); - } - - if( !aNetlist.IsDryRun() && (component->GetModule() != NULL) ) - { - wxASSERT( footprint != NULL ); - MODULE* newFootprint = new MODULE( *component->GetModule() ); - - if( aNetlist.IsFindByTimeStamp() ) - newFootprint->SetReference( footprint->GetReference() ); - else - newFootprint->SetPath( footprint->GetPath() ); - - // Copy placement and pad net names. - // optionally, copy or not local settings (like local clearances) - // if the second parameter is "true", previous values will be used. - // if "false", the default library values of the new footprint - // will be used - footprint->CopyNetlistSettings( newFootprint, false ); - - // Compare the footprint name only, in case the nickname is empty or in case - // user moved the footprint to a new library. Chances are if footprint name is - // same then the footprint is very nearly the same and the two texts should - // be kept at same size, position, and rotation. - if( newFootprint->GetFPID().GetLibItemName() == footprint->GetFPID().GetLibItemName() ) - { - newFootprint->Reference().SetEffects( footprint->Reference() ); - newFootprint->Value().SetEffects( footprint->Value() ); - } - - m_connectivity->Remove( footprint ); - Remove( footprint ); - - Add( newFootprint, ADD_APPEND ); - m_connectivity->Add( footprint ); - - footprint = newFootprint; - } - } - } - - // Test for reference designator field change. - if( footprint->GetReference() != component->GetReference() ) - { - msg.Printf( _( "Changing footprint %s reference to %s." ), - footprint->GetReference(), - component->GetReference() ); - aReporter.Report( msg, REPORTER::RPT_ACTION ); - - if( !aNetlist.IsDryRun() ) - footprint->SetReference( component->GetReference() ); - } - - // Test for value field change. - if( footprint->GetValue() != component->GetValue() ) - { - msg.Printf( _( "Changing footprint %s value from %s to %s." ), - footprint->GetReference(), - footprint->GetValue(), - component->GetValue() ); - aReporter.Report( msg, REPORTER::RPT_ACTION ); - - if( !aNetlist.IsDryRun() ) - footprint->SetValue( component->GetValue() ); - } - - // Test for time stamp change. - if( footprint->GetPath() != component->GetTimeStamp() ) - { - msg.Printf( _( "Changing component path \"%s:%s\" to \"%s\"." ), - footprint->GetReference(), - footprint->GetPath(), - component->GetTimeStamp() ); - aReporter.Report( msg, REPORTER::RPT_INFO ); - - if( !aNetlist.IsDryRun() ) - footprint->SetPath( component->GetTimeStamp() ); - } - - updateComponentPadConnections( aNetlist, footprint, component, aReporter ); - - matchCount++; - } - - if( footprint == lastPreexistingFootprint ) - { - // No sense going through the newly-created footprints: end loop - break; - } - } - - if( matchCount == 0 ) - { - if( component->GetModule() != NULL ) - { - msg.Printf( _( "Adding new symbol %s footprint %s." ), - component->GetReference(), - GetChars( component->GetFPID().Format() ) ); - aReporter.Report( msg, REPORTER::RPT_ACTION ); - } - else - { - msg.Printf( _( "Cannot add new symbol %s due to missing footprint %s." ), - component->GetReference(), - GetChars( component->GetFPID().Format() ) ); - aReporter.Report( msg, REPORTER::RPT_ERROR ); - } - - if( !aNetlist.IsDryRun() && (component->GetModule() != NULL) ) - { - // Owned by NETLIST, can only copy it. - tmp = new MODULE( *component->GetModule() ); - tmp->SetParent( this ); - tmp->SetPosition( bestPosition ); - tmp->SetTimeStamp( GetNewTimeStamp() ); - newFootprints.push_back( tmp ); - Add( tmp, ADD_APPEND ); - m_connectivity->Add( tmp ); - - updateComponentPadConnections( aNetlist, tmp, component, aReporter ); - } - } - else if( matchCount > 1 ) - { - msg.Printf( _( "Multiple footprints found for \"%s\"." ), component->GetReference() ); - aReporter.Report( msg, REPORTER::RPT_ERROR ); - } - } - - // Remove all components not in the netlist. - if( aNetlist.GetDeleteExtraFootprints() ) - { - MODULE* nextModule; - const COMPONENT* component; - - for( MODULE* module = m_Modules; module != NULL; module = nextModule ) - { - nextModule = module->Next(); - - if( module->IsLocked() ) - continue; - - if( aNetlist.IsFindByTimeStamp() ) - component = aNetlist.GetComponentByTimeStamp( module->GetPath() ); - else - component = aNetlist.GetComponentByReference( module->GetReference() ); - - if( component == NULL ) - { - msg.Printf( _( "Removing unused footprint %s." ), module->GetReference() ); - aReporter.Report( msg, REPORTER::RPT_ACTION ); - - if( !aNetlist.IsDryRun() ) - { - m_connectivity->Remove( module ); - module->DeleteStructure(); - } - } - } - } - - BuildListOfNets(); - std::vector padlist = GetPads(); - auto connAlgo = m_connectivity->GetConnectivityAlgo(); - - // If needed, remove the single pad nets: - if( aDeleteSinglePadNets && !aNetlist.IsDryRun() ) - { - std::vector padCount( (unsigned) connAlgo->NetCount() ); - - for( const auto cnItem : connAlgo->ItemList() ) - { - if( !cnItem->Valid() || cnItem->Parent()->Type() != PCB_PAD_T ) - continue; - - int net = cnItem->Parent()->GetNetCode(); - - if( net > 0 ) - ++padCount[net]; - } - - for( i = 0; i < (unsigned)connAlgo->NetCount(); ++i ) - { - // First condition: only one pad in the net - if( padCount[i] == 1 ) - { - // Second condition, no zones attached to the pad - D_PAD* pad = nullptr; - int zoneCount = 0; - const KICAD_T types[] = { PCB_PAD_T, PCB_ZONE_AREA_T, EOT }; - auto netItems = m_connectivity->GetNetItems( i, types ); - - for( const auto item : netItems ) - { - if( item->Type() == PCB_ZONE_AREA_T ) - { - wxASSERT( !pad || pad->GetNet() == item->GetNet() ); - ++zoneCount; - } - else if( item->Type() == PCB_PAD_T ) - { - wxASSERT( !pad ); - pad = static_cast( item ); - } - } - - wxASSERT( pad ); // pad = 0 means the pad list is not up to date - - if( pad && zoneCount == 0 ) - { - msg.Printf( _( "Remove single pad net %s." ), - UnescapeString( pad->GetNetname() ) ); - aReporter.Report( msg, REPORTER::RPT_ACTION ); - - m_connectivity->Remove( pad ); - pad->SetNetCode( NETINFO_LIST::UNCONNECTED ); - } - } - } - } - - // Verify that board contains all pads in netlist: if it doesn't then footprints are - // wrong or missing. - // Note that we use references to find the footprints as they're already updated by this - // point (whether by-reference or by-timestamp). - wxString padname; - for( i = 0; i < aNetlist.GetCount(); i++ ) - { - const COMPONENT* component = aNetlist.GetComponent( i ); - MODULE* footprint = FindModuleByReference( component->GetReference() ); - - if( footprint == NULL ) // It can be missing in partial designs - continue; - - // Explore all pins/pads in component - for( unsigned jj = 0; jj < component->GetNetCount(); jj++ ) - { - const COMPONENT_NET& net = component->GetNet( jj ); - padname = net.GetPinName(); - - if( footprint->FindPadByName( padname ) ) - continue; // OK, pad found - - // not found: bad footprint, report error - msg.Printf( _( "Symbol %s pad %s not found in footprint %s.\n" ), - component->GetReference(), - padname, - GetChars( footprint->GetFPID().Format() ) ); - aReporter.Report( msg, REPORTER::RPT_ERROR ); - } - } - - // Test copper zones to detect "dead" nets (nets without any pad): - for( int ii = 0; ii < GetAreaCount(); ii++ ) - { - ZONE_CONTAINER* zone = GetArea( ii ); - - if( !zone->IsOnCopperLayer() || zone->GetIsKeepout() ) - continue; - - if( m_connectivity->GetPadCount( zone->GetNetCode() ) == 0 ) - { - // Look for a pad in the zone's connected-pad-cache which has been updated to - // a new net and use that. While this won't always be the right net, the dead - // net is guaranteed to be wrong. - NETINFO_ITEM* updatedNet = nullptr; - - for( D_PAD* pad : zoneConnectionsCache[ zone ] ) - { - if( pad->GetNetname() != zone->GetNetname() ) - { - updatedNet = pad->GetNet(); - break; - } - } - - // Take zone name from name change map if it didn't match to a new pad - // (this is useful for zones on internal layers) - if( !updatedNet && m_oldToNewNets.count( zone->GetNetname() ) ) - { - updatedNet = FindNet( m_oldToNewNets[ zone->GetNetname() ] ); - } - - if( updatedNet ) - { - msg.Printf( _( "Updating copper zone from net %s to %s." ), - UnescapeString( zone->GetNetname() ), - UnescapeString( updatedNet->GetNetname() ) ); - aReporter.Report( msg, REPORTER::RPT_ACTION ); - } - else - { - msg.Printf( _( "Copper zone (net %s) has no pads connected." ), - UnescapeString( zone->GetNetname() ) ); - aReporter.Report( msg, REPORTER::RPT_WARNING ); - } - - if( updatedNet && !aNetlist.IsDryRun() ) - { - m_connectivity->Remove( zone ); - zone->SetNet( updatedNet ); - m_connectivity->Add( zone ); - } - } - } - - m_connectivity->RecalculateRatsnest(); - - std::swap( newFootprints, *aNewFootprints ); -} - - BOARD_ITEM* BOARD::Duplicate( const BOARD_ITEM* aItem, bool aAddToBoard ) { diff --git a/pcbnew/class_board.h b/pcbnew/class_board.h index b063755d24..1132081106 100644 --- a/pcbnew/class_board.h +++ b/pcbnew/class_board.h @@ -243,9 +243,6 @@ public: private: DLIST m_Drawings; // linked list of lines & texts - // TODO: remove this when BOARD::updateComponentPadConnections is removed - std::map< wxString, wxString > m_oldToNewNets; - public: DLIST m_Modules; // linked list of MODULEs @@ -869,43 +866,6 @@ public: */ MODULE* FindModule( const wxString& aRefOrTimeStamp, bool aSearchByTimeStamp = false ) const; - /** - * Function ReplaceNetlist - * updates the #BOARD according to \a aNetlist. - * - * The changes are made to the board are as follows they are not disabled in the status - * settings in the #NETLIST: - * - If a new component is found in the #NETLIST and not in the #BOARD, it is added - * to the #BOARD. - * - If a the component in the #NETLIST is already on the #BOARD, then one or more of the - * following actions can occur: - * + If the footprint name in the #NETLIST does not match the footprint name on the - * #BOARD, the footprint on the #BOARD is replaced with the footprint specified in - * the #NETLIST and the proper parameters are copied from the existing footprint. - * + If the reference designator in the #NETLIST does not match the reference designator - * on the #BOARD, the reference designator is updated from the #NETLIST. - * + If the value field in the #NETLIST does not match the value field on the #BOARD, - * the value field is updated from the #NETLIST. - * + If the time stamp in the #NETLIST does not match the time stamp on the #BOARD, - * the time stamp is updated from the #NETLIST. - * - After each footprint is added or update as described above, each footprint pad net - * name is compared and updated to the value defined in the #NETLIST. - * - After all of the footprints have been added, updated, and net names properly set, - * any extra unlock footprints are removed from the #BOARD. - * - * @param aNetlist is the new netlist to revise the contents of the #BOARD with. - * @param aDeleteSinglePadNets if true, remove nets counting only one pad - * and set net code to 0 for these pads - * @param aNewFootprints is a pointer the to a list of new footprints used when updating - * the netlist. - * @param aReporter is a #REPORTER object to report the changes \a aNetlist makes to - * the #BOARD. - */ - void ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets, - std::vector* aNewFootprints, REPORTER& aReporter ); - - void updateComponentPadConnections( NETLIST& aNetlist, MODULE* footprint, - COMPONENT* component, REPORTER& aReporter ); /** * Function SortedNetnamesList * @param aNames An array string to fill with net names. diff --git a/pcbnew/dialogs/dialog_netlist.cpp b/pcbnew/dialogs/dialog_netlist.cpp index 4fcb780040..3c46b8585a 100644 --- a/pcbnew/dialogs/dialog_netlist.cpp +++ b/pcbnew/dialogs/dialog_netlist.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -184,34 +185,11 @@ void DIALOG_NETLIST::OnTestFootprintsClick( wxCommandEvent& event ) } wxString netlistFilename = m_NetlistFilenameCtrl->GetValue(); - NETLIST_READER* netlistReader; NETLIST netlist; wxBusyCursor dummy; // Shows an hourglass while calculating. - try - { - netlistReader = NETLIST_READER::GetNetlistReader( &netlist, netlistFilename, "" ); - - if( netlistReader == NULL ) - { - wxString msg = wxString::Format( _( "Cannot open netlist file \"%s\"." ), - netlistFilename ); - wxMessageBox( msg, _( "Netlist Load Error." ), wxOK | wxICON_ERROR ); - return; - } - - std::unique_ptr< NETLIST_READER > nlr( netlistReader ); - netlistReader->LoadNetlist(); - - m_parent->SetLastNetListRead( netlistFilename ); - } - catch( const IO_ERROR& ioe ) - { - wxString msg = wxString::Format( _( "Error loading netlist file:\n%s" ), - ioe.What().GetData() ); - wxMessageBox( msg, _( "Netlist Load Error" ), wxOK | wxICON_ERROR ); + if( !m_parent->ReadNetlistFromFile( netlistFilename, netlist, NULL_REPORTER::GetInstance() ) ) return; - } HTML_MESSAGE_BOX dlg( this, _( "Check footprints" ) ); DRC_LIST drcItems; @@ -306,17 +284,31 @@ void DIALOG_NETLIST::loadNetlist( bool aDryRun ) reporter.ReportHead( msg, REPORTER::RPT_INFO ); m_MessageWindow->SetLazyUpdate( true ); // Use lazy update to speed the creation of the report // (the window is not updated for each message) + NETLIST netlist; - m_parent->ReadPcbNetlist( netlistFileName, wxEmptyString, reporter, - m_cbUpdateFootprints->GetValue(), - m_cbDeleteShortingTracks->GetValue(), - m_cbDeleteExtraFootprints->GetValue(), - m_matchByTimestamp->GetSelection() == 1, - m_cbDeleteSinglePadNets->GetValue(), - aDryRun, &m_runDragCommand ); + netlist.SetDeleteExtraFootprints( m_cbDeleteExtraFootprints->GetValue() ); + netlist.SetFindByTimeStamp( m_matchByTimestamp->GetSelection() == 1 ); + netlist.SetReplaceFootprints( m_cbUpdateFootprints->GetValue() ); + + if( !m_parent->ReadNetlistFromFile( netlistFileName, netlist, reporter ) ) + return; + + BOARD_NETLIST_UPDATER updater( m_parent, m_parent->GetBoard() ); + updater.SetReporter ( &reporter ); + updater.SetIsDryRun( aDryRun ); + updater.SetLookupByTimestamp( m_matchByTimestamp->GetSelection() == 1 ); + updater.SetDeleteUnusedComponents ( m_cbDeleteExtraFootprints->GetValue() ); + updater.SetReplaceFootprints( m_cbUpdateFootprints->GetValue() ); + updater.SetDeleteSinglePadNets( m_cbDeleteSinglePadNets->GetValue() ); + updater.UpdateNetlist( netlist ); // The creation of the report was made without window update: the full page must be displayed m_MessageWindow->Flush( true ); + + if( aDryRun ) + return; + + m_parent->OnNetlistChanged( updater, &m_runDragCommand ); } diff --git a/pcbnew/dialogs/dialog_netlist.h b/pcbnew/dialogs/dialog_netlist.h index 5a71b3e34f..bc73d19a13 100644 --- a/pcbnew/dialogs/dialog_netlist.h +++ b/pcbnew/dialogs/dialog_netlist.h @@ -52,6 +52,8 @@ private: void loadNetlist( bool aDryRun ); + + // Virtual event handlers: void OnOpenNetlistClick( wxCommandEvent& event ) override; void OnUpdatePCB( wxCommandEvent& event ) override; diff --git a/pcbnew/dialogs/dialog_update_pcb.cpp b/pcbnew/dialogs/dialog_update_pcb.cpp index 8565207408..9d7b06c60b 100644 --- a/pcbnew/dialogs/dialog_update_pcb.cpp +++ b/pcbnew/dialogs/dialog_update_pcb.cpp @@ -103,14 +103,7 @@ void DIALOG_UPDATE_PCB::PerformUpdate( bool aDryRun ) m_messagePanel->Clear(); REPORTER& reporter = m_messagePanel->Reporter(); - TOOL_MANAGER* toolManager = m_frame->GetToolManager(); - BOARD* board = m_frame->GetBoard(); - // keep trace of the initial baord area, if we want to place new footprints - // outside the existinag board - EDA_RECT bbox = board->GetBoundingBox(); - - toolManager->RunAction( PCB_ACTIONS::selectionClear, true ); m_runDragCommand = false; m_netlist->SetDeleteExtraFootprints( m_cbDeleteExtraFootprints->GetValue() ); @@ -131,51 +124,7 @@ void DIALOG_UPDATE_PCB::PerformUpdate( bool aDryRun ) if( aDryRun ) return; - m_frame->SetCurItem( nullptr ); - m_frame->SetMsgPanel( board ); - - // Update rendered tracks and vias net labels - auto view = m_frame->GetGalCanvas()->GetView(); - - // TODO is there a way to extract information about which nets were modified? - for( auto track : board->Tracks() ) - view->Update( track ); - - std::vector newFootprints = updater.GetAddedComponents(); - - // Spread new footprints. - wxPoint areaPosition = m_frame->GetCrossHairPosition(); - - if( !m_frame->IsGalCanvasActive() ) - { - // In legacy mode place area to the left side of the board. - // if the board is empty, the bbox position is (0,0) - areaPosition.x = bbox.GetEnd().x + Millimeter2iu( 10 ); - areaPosition.y = bbox.GetOrigin().y; - } - - m_frame->SpreadFootprints( &newFootprints, false, false, areaPosition, false ); - - if( m_frame->IsGalCanvasActive() ) - { - // Start drag command for new modules - if( !newFootprints.empty() ) - { - for( MODULE* footprint : newFootprints ) - toolManager->RunAction( PCB_ACTIONS::selectItem, true, footprint ); - - m_runDragCommand = true; - - // Now fix a reference point to move the footprints. - // We use the first footprint in list as reference point - // The graphic cursor will be on this fp when moving the footprints. - SELECTION_TOOL* selTool = toolManager->GetTool(); - SELECTION& selection = selTool->GetSelection(); - selection.SetReferencePoint( newFootprints[0]->GetPosition() ); - } - } - - m_frame->GetCanvas()->Refresh(); + m_frame->OnNetlistChanged( updater, &m_runDragCommand ); } diff --git a/pcbnew/netlist.cpp b/pcbnew/netlist.cpp index e2353c0031..191dfdd79a 100644 --- a/pcbnew/netlist.cpp +++ b/pcbnew/netlist.cpp @@ -49,97 +49,83 @@ using namespace std::placeholders; #include #include #include +#include #include #include +#include #include -void PCB_EDIT_FRAME::ReadPcbNetlist( const wxString& aNetlistFileName, - const wxString& aCmpFileName, - REPORTER& aReporter, - bool aChangeFootprints, - bool aDeleteUnconnectedTracks, - bool aDeleteExtraFootprints, - bool aSelectByTimeStamp, - bool aDeleteSinglePadNets, - bool aIsDryRun, - bool* runDragCommand ) +bool PCB_EDIT_FRAME::ReadNetlistFromFile( const wxString &aFilename, + NETLIST& aNetlist, + REPORTER& aReporter ) { - wxString msg; - NETLIST netlist; - KIGFX::VIEW* view = GetGalCanvas()->GetView(); - BOARD* board = GetBoard(); - std::vector newFootprints; - // keep trace of the initial baord area, if we want to place new footprints - // outside the existinag board - EDA_RECT bbox = board->GetBoundingBox(); - - netlist.SetIsDryRun( aIsDryRun ); - netlist.SetFindByTimeStamp( aSelectByTimeStamp ); - netlist.SetDeleteExtraFootprints( aDeleteExtraFootprints ); - netlist.SetReplaceFootprints( aChangeFootprints ); + wxString msg; try { std::unique_ptr netlistReader( NETLIST_READER::GetNetlistReader( - &netlist, aNetlistFileName, aCmpFileName ) ); + &aNetlist, aFilename, wxEmptyString ) ); if( !netlistReader.get() ) { - msg.Printf( _( "Cannot open netlist file \"%s\"." ), GetChars( aNetlistFileName ) ); + msg.Printf( _( "Cannot open netlist file \"%s\"." ), GetChars( aFilename ) ); wxMessageBox( msg, _( "Netlist Load Error." ), wxOK | wxICON_ERROR, this ); - return; + return false; } - SetLastNetListRead( aNetlistFileName ); + SetLastNetListRead( aFilename ); netlistReader->LoadNetlist(); - LoadFootprints( netlist, aReporter ); + LoadFootprints( aNetlist, aReporter ); } catch( const IO_ERROR& ioe ) { msg.Printf( _( "Error loading netlist.\n%s" ), ioe.What().GetData() ); wxMessageBox( msg, _( "Netlist Load Error" ), wxOK | wxICON_ERROR ); - return; + return false; } - // Clear undo and redo lists to avoid inconsistencies between lists - if( !netlist.IsDryRun() ) - GetScreen()->ClearUndoRedoList(); + SetLastNetListRead( aFilename ); - if( !netlist.IsDryRun() ) - { - // Remove old modules - for( MODULE* module = board->m_Modules; module; module = module->Next() ) - view->Remove( module ); - } + return true; +} - // Clear selection, just in case a selected item has to be removed - m_toolManager->RunAction( PCB_ACTIONS::selectionClear, true ); - *runDragCommand = false; - netlist.SortByReference(); - board->ReplaceNetlist( netlist, aDeleteSinglePadNets, &newFootprints, aReporter ); +void PCB_EDIT_FRAME::OnNetlistChanged( BOARD_NETLIST_UPDATER& aUpdater, + bool* aRunDragCommand ) +{ + BOARD* board = GetBoard(); - // If it was a dry run, nothing has changed so we're done. - if( netlist.IsDryRun() ) - return; + SetCurItem( nullptr ); + SetMsgPanel( board ); - wxPoint placementAreaPosition = GetCrossHairPosition(); + TOOL_MANAGER* toolManager = GetToolManager(); + + // Update rendered tracks and vias net labels + auto view = GetGalCanvas()->GetView(); + + // TODO is there a way to extract information about which nets were modified? + for( auto track : board->Tracks() ) + view->Update( track ); + + std::vector newFootprints = aUpdater.GetAddedComponents(); + + // Spread new footprints. + wxPoint areaPosition = GetCrossHairPosition(); + EDA_RECT bbox = board->GetBoundingBox(); if( !IsGalCanvasActive() ) { // In legacy mode place area to the left side of the board. // if the board is empty, the bbox position is (0,0) - placementAreaPosition.x = bbox.GetEnd().x + Millimeter2iu( 10 ); - placementAreaPosition.y = bbox.GetOrigin().y; + areaPosition.x = bbox.GetEnd().x + Millimeter2iu( 10 ); + areaPosition.y = bbox.GetOrigin().y; } - SpreadFootprints( &newFootprints, false, false, placementAreaPosition ); + toolManager->RunAction( PCB_ACTIONS::selectionClear, true ); - // Reload modules - for( MODULE* module = board->m_Modules; module; module = module->Next() ) - view->Add( module ); + SpreadFootprints( &newFootprints, false, false, areaPosition, false ); if( IsGalCanvasActive() ) { @@ -147,31 +133,20 @@ void PCB_EDIT_FRAME::ReadPcbNetlist( const wxString& aNetlistFileName, if( !newFootprints.empty() ) { for( MODULE* footprint : newFootprints ) - m_toolManager->RunAction( PCB_ACTIONS::selectItem, true, footprint ); + toolManager->RunAction( PCB_ACTIONS::selectItem, true, footprint ); - *runDragCommand = true; + *aRunDragCommand = true; + + // Now fix a reference point to move the footprints. + // We use the first footprint in list as reference point + // The graphic cursor will be on this fp when moving the footprints. + SELECTION_TOOL* selTool = toolManager->GetTool(); + SELECTION& selection = selTool->GetSelection(); + selection.SetReferencePoint( newFootprints[0]->GetPosition() ); } } - OnModify(); - - SetCurItem( NULL ); - - if( aDeleteUnconnectedTracks && board->m_Track ) - { - // Remove erroneous tracks. This should probably pushed down to the #BOARD object. - RemoveMisConnectedTracks(); - } - - // Rebuild the board connectivity: - board->GetConnectivity()->Build( board ); - - // TODO is there a way to extract information about which nets were modified? - for( auto track : board->Tracks() ) - view->Update( track ); - - SetMsgPanel( board ); - m_canvas->Refresh(); + GetCanvas()->Refresh(); } diff --git a/pcbnew/pcb_edit_frame.h b/pcbnew/pcb_edit_frame.h index 3c3ba9db46..c8b22871a9 100644 --- a/pcbnew/pcb_edit_frame.h +++ b/pcbnew/pcb_edit_frame.h @@ -61,6 +61,7 @@ class REPORTER; struct PARSE_ERROR; class IO_ERROR; class FP_LIB_TABLE; +class BOARD_NETLIST_UPDATER; namespace PCB { struct IFACE; } // KIFACE_I is in pcbnew.cpp @@ -1564,36 +1565,23 @@ public: void DoUpdatePCBFromNetlist( NETLIST& aNetlist, bool aUseTimestamps ); /** - * Function ReadPcbNetlist - * reads \a aNetlistFileName and updates the footprints (load missing footprints and - * delete on demand extra footprints) on the board. - * Update connectivity info, references, values and "TIME STAMP" + * Reads a netlist from a file into a NETLIST object. * - * @param aNetlistFileName = netlist file name (*.net) - * @param aCmpFileName = cmp/footprint link file name (*.cmp). - * if not found or empty, only the netlist will be used - * @param aReporter a #REPORTER object to write display messages. - * @param aChangeFootprint if true, footprints that have changed in netlist will be changed - * @param aDeleteBadTracks if true, erroneous tracks will be deleted - * @param aDeleteExtraFootprints if true, remove unlocked footprints that are not in netlist - * @param aSelectByTimestamp if true, use timestamp instead of reference to identify - * footprints from components (use after reannotation of the - * schematic) - * @param aDeleteSinglePadNets if true, remove nets counting only one pad - * and set net code to 0 for these pads - * @param aIsDryRun performs a dry run without making any changes if true. - * @param runDragCommand indicates that a selection was created which should be dragged. + * @param aFilename is the netlist to load + * @param aNetlist is the object to populate with data + * @param aReporter is a #REPORTER object to display messages + * @return true if the netlist was read successfully */ - void ReadPcbNetlist( const wxString& aNetlistFileName, - const wxString& aCmpFileName, - REPORTER& aReporter, - bool aChangeFootprint, - bool aDeleteBadTracks, - bool aDeleteExtraFootprints, - bool aSelectByTimestamp, - bool aDeleteSinglePadNets, - bool aIsDryRun, - bool* runDragCommand ); + bool ReadNetlistFromFile( const wxString &aFilename, + NETLIST& aNetlist, + REPORTER& aReporter ); + + /** + * Called after netlist is updated + * @param aUpdater is the updater object that was run + * @param aRunDragCommand is set to true if the drag command was invoked by this call + */ + void OnNetlistChanged( BOARD_NETLIST_UPDATER& aUpdater, bool* aRunDragCommand ); /** * Function RemoveMisConnectedTracks