Layers setup management: Warn user if some removed layers are in use in footprints loaded on the board.

Fix also memory leak and missing connectivity rebuild.
This commit is contained in:
jean-pierre charras 2018-03-27 10:18:20 +02:00
parent 602d9e1972
commit 78161b5922
3 changed files with 110 additions and 19 deletions

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2007-2008 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com> * Copyright (C) 2007-2008 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2004-2017 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2004-2018 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -499,7 +499,12 @@ SEARCH_RESULT PCB_LAYER_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData )
{ {
BOARD_ITEM* item = (BOARD_ITEM*) testItem; BOARD_ITEM* item = (BOARD_ITEM*) testItem;
if( item->GetLayer() == m_layer_id ) if( item->Type() == PCB_PAD_T ) // multilayer
{
if( static_cast<D_PAD*>( item )->IsOnLayer( m_layer_id ) )
Append( testItem );
}
else if( item->GetLayer() == m_layer_id )
Append( testItem ); Append( testItem );
return SEARCH_CONTINUE; return SEARCH_CONTINUE;

View File

@ -29,6 +29,9 @@
#include <confirm.h> #include <confirm.h>
#include <pcbnew.h> #include <pcbnew.h>
#include <pcb_edit_frame.h>
#include <view/view.h>
#include <invoke_pcb_dialog.h> #include <invoke_pcb_dialog.h>
#include <class_board.h> #include <class_board.h>
@ -43,11 +46,6 @@
// if not displays always 1=the full set (32 copper layers) // if not displays always 1=the full set (32 copper layers)
#define HIDE_INACTIVE_LAYERS #define HIDE_INACTIVE_LAYERS
// if defined, use the layer manager copper layers order (from FRONT to BACK)
// to display inner layers.
// if not, use the default order (from BACK to FRONT)
#define USE_LAYER_MANAGER_COPPER_LAYERS_ORDER
/** /**
* Holds the 3 UI control pointers for a single board layer. * Holds the 3 UI control pointers for a single board layer.
@ -138,7 +136,7 @@ static LSEQ dlg_layers()
class DIALOG_LAYERS_SETUP : public DIALOG_LAYERS_SETUP_BASE class DIALOG_LAYERS_SETUP : public DIALOG_LAYERS_SETUP_BASE
{ {
public: public:
DIALOG_LAYERS_SETUP( wxTopLevelWindow* aCaller, BOARD* aBoard ); DIALOG_LAYERS_SETUP( PCB_EDIT_FRAME* aCaller, BOARD* aBoard );
private: private:
int m_copperLayerCount; int m_copperLayerCount;
@ -152,6 +150,8 @@ private:
void setLayerCheckBox( LAYER_NUM layer, bool isChecked ); void setLayerCheckBox( LAYER_NUM layer, bool isChecked );
void setCopperLayerCheckBoxes( int copperCount ); void setCopperLayerCheckBoxes( int copperCount );
// Force mandatory non copper layers enabled
void enableMandatoryLayerCheckBoxes();
void showCopperChoice( int copperCount ); void showCopperChoice( int copperCount );
void showBoardLayerNames(); void showBoardLayerNames();
@ -179,6 +179,11 @@ private:
*/ */
LSEQ getRemovedLayersWithItems(); LSEQ getRemovedLayersWithItems();
/**
* Return a list of layers in use in footprints, and therefore not removable.
*/
LSEQ getNonRemovableLayers();
/** /**
* Map \a aLayerNumber to the wx IDs for that layer which are * Map \a aLayerNumber to the wx IDs for that layer which are
* the layer name control ID, checkbox control ID, and choice control ID * the layer name control ID, checkbox control ID, and choice control ID
@ -323,7 +328,7 @@ CTLs DIALOG_LAYERS_SETUP::getCTLs( LAYER_NUM aLayerNumber )
} }
DIALOG_LAYERS_SETUP::DIALOG_LAYERS_SETUP( wxTopLevelWindow* aParent, BOARD* aBoard ) : DIALOG_LAYERS_SETUP::DIALOG_LAYERS_SETUP( PCB_EDIT_FRAME* aParent, BOARD* aBoard ) :
DIALOG_LAYERS_SETUP_BASE( aParent ) DIALOG_LAYERS_SETUP_BASE( aParent )
{ {
m_pcb = aBoard; m_pcb = aBoard;
@ -382,6 +387,7 @@ bool DIALOG_LAYERS_SETUP::TransferDataToWindow()
showSelectedLayerCheckBoxes( m_enabledLayers ); showSelectedLayerCheckBoxes( m_enabledLayers );
showPresets( m_enabledLayers ); showPresets( m_enabledLayers );
showLayerTypes(); showLayerTypes();
enableMandatoryLayerCheckBoxes();
// All widgets are now initialized. Fix the min sizes: // All widgets are now initialized. Fix the min sizes:
GetSizer()->SetSizeHints( this ); GetSizer()->SetSizeHints( this );
@ -390,10 +396,23 @@ bool DIALOG_LAYERS_SETUP::TransferDataToWindow()
} }
void DIALOG_LAYERS_SETUP::enableMandatoryLayerCheckBoxes()
{
// Currently, do nothing
#if 0
setLayerCheckBox( F_CrtYd, true );
setLayerCheckBox( B_CrtYd, true );
setLayerCheckBox( Edge_Cuts, true );
setLayerCheckBox( Margin, true );
#endif
}
void DIALOG_LAYERS_SETUP::OnSize( wxSizeEvent& event ) void DIALOG_LAYERS_SETUP::OnSize( wxSizeEvent& event )
{ {
moveTitles(); moveTitles();
event.Skip(); event.Skip();
Refresh();
} }
@ -634,14 +653,31 @@ bool DIALOG_LAYERS_SETUP::TransferDataFromWindow()
// Check for removed layers with items which will get deleted from the board. // Check for removed layers with items which will get deleted from the board.
LSEQ removedLayers = getRemovedLayersWithItems(); LSEQ removedLayers = getRemovedLayersWithItems();
if( !removedLayers.empty() // Check for non copper layers in use in footprints, and therefore not removable.
&& !IsOK( this, _( "Items have been found on removed layers. This operation will delete " LSEQ notremovableLayers = getNonRemovableLayers();
"all items from removed layers and cannot be undone. Do you wish to "
"continue?" ) ) ) if( !notremovableLayers.empty() )
{
for( unsigned int ii = 0; ii < notremovableLayers.size(); ii++ )
msg << m_pcb->GetLayerName( notremovableLayers[ii] ) << "\n";
if( !IsOK( this, wxString::Format( _( "Footprints have some items on removed layers:\n"
"%s\n"
"These items will be no longer accessible\n"
"Do you wish to continue?" ), msg ) ) )
return false;
}
if( !removedLayers.empty() &&
!IsOK( this, _( "Items have been found on removed layers. This operation will delete "
"all items from removed layers and cannot be undone. Do you wish to "
"continue?" ) ) )
return false; return false;
// Delete all objects on layers that have been removed. Leaving them in copper layers // Delete all objects on layers that have been removed. Leaving them in copper layers
// can (will?) result in DRC errors and it pollutes the board file with cruft. // can (will?) result in DRC errors and it pollutes the board file with cruft.
bool hasRemovedBoardItems = false;
if( !removedLayers.empty() ) if( !removedLayers.empty() )
{ {
PCB_LAYER_COLLECTOR collector; PCB_LAYER_COLLECTOR collector;
@ -654,8 +690,14 @@ bool DIALOG_LAYERS_SETUP::TransferDataFromWindow()
// Bye-bye items on on removed layer. // Bye-bye items on on removed layer.
if( collector.GetCount() != 0 ) if( collector.GetCount() != 0 )
{ {
hasRemovedBoardItems = true;
for( int i = 0; i < collector.GetCount(); i++ ) for( int i = 0; i < collector.GetCount(); i++ )
m_pcb->Remove( collector[i] ); {
BOARD_ITEM* item = collector[i];
m_pcb->Remove( item );
delete item;
}
} }
} }
} }
@ -686,6 +728,16 @@ bool DIALOG_LAYERS_SETUP::TransferDataFromWindow()
m_pcb->GetDesignSettings().SetBoardThickness( thickness ); m_pcb->GetDesignSettings().SetBoardThickness( thickness );
// If some board items are deleted: rebuild the connectivity,
// because it is likely some tracks and vias where removed
if( hasRemovedBoardItems )
{
PCB_EDIT_FRAME* editFrame = static_cast<PCB_EDIT_FRAME*>( GetParent() );
// Rebuild list of nets (full ratsnest rebuild)
editFrame->Compile_Ratsnest( NULL, true );
m_pcb->BuildConnectivity();
}
return true; return true;
} }
@ -800,7 +852,7 @@ LSEQ DIALOG_LAYERS_SETUP::getRemovedLayersWithItems()
LSET newLayers = getUILayerMask(); LSET newLayers = getUILayerMask();
LSET curLayers = m_pcb->GetEnabledLayers(); LSET curLayers = m_pcb->GetEnabledLayers();
if( newLayers == curLayers ) if( newLayers == curLayers ) // return a empty list if no change
return removedLayers; return removedLayers;
PCB_LAYER_COLLECTOR collector; PCB_LAYER_COLLECTOR collector;
@ -823,7 +875,40 @@ LSEQ DIALOG_LAYERS_SETUP::getRemovedLayersWithItems()
} }
bool InvokeLayerSetup( wxTopLevelWindow* aCaller, BOARD* aBoard ) LSEQ DIALOG_LAYERS_SETUP::getNonRemovableLayers()
{
//Build the list of non copper layers in use in footprints.
LSEQ inUseLayers;
LSET newLayers = getUILayerMask();
LSET curLayers = m_pcb->GetEnabledLayers();
if( newLayers == curLayers ) // return a empty list if no change
return inUseLayers;
PCB_LAYER_COLLECTOR collector;
LSEQ newLayerSeq = newLayers.Seq();
std::vector< PCB_LAYER_ID >::iterator it;
for( auto layer_id : curLayers.Seq() )
{
if( IsCopperLayer( layer_id ) ) // Copper layers are not taken in account here
continue;
if( std::find( newLayerSeq.begin(), newLayerSeq.end(), layer_id ) == newLayerSeq.end() )
{
collector.SetLayerId( layer_id );
collector.Collect( m_pcb, GENERAL_COLLECTOR::ModuleItems );
if( collector.GetCount() != 0 )
inUseLayers.push_back( layer_id );
}
}
return inUseLayers;
}
bool InvokeLayerSetup( PCB_EDIT_FRAME* aCaller, BOARD* aBoard )
{ {
DIALOG_LAYERS_SETUP dlg( aCaller, aBoard ); DIALOG_LAYERS_SETUP dlg( aCaller, aBoard );

View File

@ -5,7 +5,7 @@
/* This program source code file is part of KiCad, a free EDA CAD application. /* This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com> * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2013-2016 KiCad Developers, see change_log.txt for contributors. * Copyright (C) 2013-2018 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -54,6 +54,7 @@ class MODULE;
// Often this is not used in the prototypes, since wxFrame is good enough and would // Often this is not used in the prototypes, since wxFrame is good enough and would
// represent maximum information hiding. // represent maximum information hiding.
class PCB_BASE_FRAME; class PCB_BASE_FRAME;
class PCB_EDIT_FRAME;
class FOOTPRINT_EDIT_FRAME; class FOOTPRINT_EDIT_FRAME;
class FP_LIB_TABLE; class FP_LIB_TABLE;
class BOARD; class BOARD;
@ -137,11 +138,11 @@ bool InvokeDXFDialogModuleImport( PCB_BASE_FRAME* aCaller, MODULE* aModule );
/** /**
* Function InvokeLayerSetup * Function InvokeLayerSetup
* shows the layer setup dialog * shows the layer setup dialog
* @param aCaller is the wxTopLevelWindow which is invoking the dialog. * @param aCaller is the PCB_EDIT_FRAME which is invoking the dialog.
* @param aBoard is the currently edited board. * @param aBoard is the currently edited board.
* @return bool - true if user pressed OK (did not abort), else false. * @return bool - true if user pressed OK (did not abort), else false.
*/ */
bool InvokeLayerSetup( wxTopLevelWindow* aCaller, BOARD* aBoard ); bool InvokeLayerSetup( PCB_EDIT_FRAME* aCaller, BOARD* aBoard );
/** /**
* Function InvokeSVGPrint * Function InvokeSVGPrint