Refactor Import Netlist to use the same codepath as Update PCB
This commit is contained in:
parent
3a8ffd66ca
commit
105825c058
|
@ -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<MODULE*>* aNewFootprints, REPORTER& aReporter )
|
||||
{
|
||||
unsigned i;
|
||||
wxPoint bestPosition;
|
||||
wxString msg;
|
||||
std::vector<MODULE*> newFootprints;
|
||||
std::map< ZONE_CONTAINER*, std::vector<D_PAD*> > 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 <no net>) 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<D_PAD*> padlist = GetPads();
|
||||
auto connAlgo = m_connectivity->GetConnectivityAlgo();
|
||||
|
||||
// If needed, remove the single pad nets:
|
||||
if( aDeleteSinglePadNets && !aNetlist.IsDryRun() )
|
||||
{
|
||||
std::vector<unsigned int> 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<D_PAD*>( 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 )
|
||||
{
|
||||
|
|
|
@ -243,9 +243,6 @@ public:
|
|||
private:
|
||||
DLIST<BOARD_ITEM> m_Drawings; // linked list of lines & texts
|
||||
|
||||
// TODO: remove this when BOARD::updateComponentPadConnections is removed
|
||||
std::map< wxString, wxString > m_oldToNewNets;
|
||||
|
||||
public:
|
||||
|
||||
DLIST<MODULE> 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<MODULE*>* 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.
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include <class_module.h>
|
||||
#include <connectivity/connectivity_data.h>
|
||||
#include <wildcards_and_files_ext.h>
|
||||
#include <board_netlist_updater.h>
|
||||
|
||||
#include <dialog_netlist.h>
|
||||
#include <wx_html_report_panel.h>
|
||||
|
@ -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 );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -52,6 +52,8 @@ private:
|
|||
|
||||
void loadNetlist( bool aDryRun );
|
||||
|
||||
|
||||
|
||||
// Virtual event handlers:
|
||||
void OnOpenNetlistClick( wxCommandEvent& event ) override;
|
||||
void OnUpdatePCB( wxCommandEvent& event ) override;
|
||||
|
|
|
@ -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<MODULE*> 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_TOOL>();
|
||||
SELECTION& selection = selTool->GetSelection();
|
||||
selection.SetReferencePoint( newFootprints[0]->GetPosition() );
|
||||
}
|
||||
}
|
||||
|
||||
m_frame->GetCanvas()->Refresh();
|
||||
m_frame->OnNetlistChanged( updater, &m_runDragCommand );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -49,97 +49,83 @@ using namespace std::placeholders;
|
|||
#include <ratsnest_data.h>
|
||||
#include <pcbnew.h>
|
||||
#include <io_mgr.h>
|
||||
#include <board_netlist_updater.h>
|
||||
|
||||
#include <tool/tool_manager.h>
|
||||
#include <tools/pcb_actions.h>
|
||||
#include <tools/selection_tool.h>
|
||||
#include <view/view.h>
|
||||
|
||||
|
||||
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<MODULE*> 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<NETLIST_READER> 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<MODULE*> 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_TOOL>();
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue