Pcbnew #4904 : Import settings from another board deleted internal layers

When importing settings from a board with more copper layers and applying it
to a board with less copper layers, if the user has ticked the checkbox
"Layer settings", then KiCad will delete the inner copper layers.  Only
when the user clicks OK does it then warn that it found deleted items on inner
layers.  The message is too generic and comes after the layers have already
been deleted.

This Merge Request tries to address this by warning them early.  The changes are:

1 - Added code to check if user is trying to import settings from a
board with less copper layers than the current loaded board.  This
results in KiCad deleting inner copper layers.  Now it presents a
warning dialog that explains the current settings will result in deleted
inner layers, and lets the user stop the import process before making any changes.

2 - Made "Import Settings" dialog disable "Import Settings" button
until at least one import option checkbox is checked.

3 - Made "Select All" button on "Import Settings" dialog toggle
between "Select All" and "Deselect All" on each click.

Items 2&3 were added to improve the overall import settings usability
experience.

Fixes issue https://gitlab.com/kicad/code/kicad/-/issues/4904
This commit is contained in:
PJM 2020-08-07 10:08:45 -07:00 committed by Ian McInerney
parent f615b026d9
commit 829316fad4
8 changed files with 264 additions and 87 deletions

View File

@ -151,6 +151,10 @@ void DIALOG_BOARD_SETUP::OnAuxiliaryAction( wxCommandEvent& event )
return;
}
// Flag so user can stop work if it will result in deleted inner copper layers
// and still clean up this function properly.
bool okToProceed = true;
PROJECT* otherPrj = m_frame->GetSettingsManager()->GetProject( projectFn.GetFullPath() );
PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::KICAD_SEXP ) );
@ -160,6 +164,14 @@ void DIALOG_BOARD_SETUP::OnAuxiliaryAction( wxCommandEvent& event )
try
{
otherBoard = pi->Load( boardFn.GetFullPath(), nullptr, nullptr );
if( importDlg.m_LayersOpt->GetValue() )
{
BOARD* loadedBoard = m_frame->GetBoard();
// Check if "Import Settings" board has more layers than the current board.
okToProceed = m_layers->compareCopperLayerCount( loadedBoard, otherBoard );
}
}
catch( const IO_ERROR& ioe )
{
@ -175,37 +187,48 @@ void DIALOG_BOARD_SETUP::OnAuxiliaryAction( wxCommandEvent& event )
return;
}
otherBoard->SetProject( otherPrj );
if( importDlg.m_LayersOpt->GetValue() )
m_layers->ImportSettingsFrom( otherBoard );
if( importDlg.m_TextAndGraphicsOpt->GetValue() )
m_textAndGraphics->ImportSettingsFrom( otherBoard );
if( importDlg.m_ConstraintsOpt->GetValue() )
m_constraints->ImportSettingsFrom( otherBoard );
if( importDlg.m_NetclassesOpt->GetValue() )
m_netclasses->ImportSettingsFrom( &otherBoard->GetDesignSettings().GetNetClasses() );
if( importDlg.m_TracksAndViasOpt->GetValue() )
m_tracksAndVias->ImportSettingsFrom( otherBoard );
if( importDlg.m_MaskAndPasteOpt->GetValue() )
m_maskAndPaste->ImportSettingsFrom( otherBoard );
if( okToProceed )
{
otherBoard->SetProject( otherPrj );
// If layers options are imported, import also the stackup
// layers options and stackup are linked, so they cannot be imported
// separately, and stackup can be imported only after layers options
//
// Note also currently only the list of enabled layers can be imported, because
// we import settings from a .pro project file, not the settings inside
// a board, and info only living in the board is not imported.
// TODO: Add import of physical settings now that we are actually loading the board here
if( importDlg.m_LayersOpt->GetValue() )
m_physicalStackup->ImportSettingsFrom( otherBoard );
if( importDlg.m_LayersOpt->GetValue() )
m_layers->ImportSettingsFrom( otherBoard );
if( importDlg.m_SeveritiesOpt->GetValue() )
m_severities->ImportSettingsFrom( otherBoard->GetDesignSettings().m_DRCSeverities );
if( importDlg.m_TextAndGraphicsOpt->GetValue() )
m_textAndGraphics->ImportSettingsFrom( otherBoard );
otherBoard->ClearProject();
if( importDlg.m_ConstraintsOpt->GetValue() )
m_constraints->ImportSettingsFrom( otherBoard );
if( importDlg.m_NetclassesOpt->GetValue() )
m_netclasses->ImportSettingsFrom( &otherBoard->GetDesignSettings().GetNetClasses() );
if( importDlg.m_TracksAndViasOpt->GetValue() )
m_tracksAndVias->ImportSettingsFrom( otherBoard );
if( importDlg.m_MaskAndPasteOpt->GetValue() )
m_maskAndPaste->ImportSettingsFrom( otherBoard );
// If layers options are imported, import also the stackup
// layers options and stackup are linked, so they cannot be imported
// separately, and stackup can be imported only after layers options
//
// Note also currently only the list of enabled layers can be imported, because
// we import settings from a .pro project file, not the settings inside
// a board, and info only living in the board is not imported.
// TODO: Add import of physical settings now that we are actually loading the board here
if( importDlg.m_LayersOpt->GetValue() )
m_physicalStackup->ImportSettingsFrom( otherBoard );
if( importDlg.m_SeveritiesOpt->GetValue() )
m_severities->ImportSettingsFrom( otherBoard->GetDesignSettings().m_DRCSeverities );
otherBoard->ClearProject();
}
// Clean up and free memory before leaving
m_frame->GetSettingsManager()->UnloadProject( otherPrj, false );
delete otherBoard;

View File

@ -37,12 +37,67 @@ DIALOG_IMPORT_SETTINGS::DIALOG_IMPORT_SETTINGS( wxWindow* aParent, PCB_EDIT_FRAM
DIALOG_IMPORT_SETTINGS_BASE( aParent ),
m_frame( aFrame )
{
wxSize sizeNeeded;
m_browseButton->SetBitmap( KiBitmap( folder_xpm ) );
// Button created in wxFormBuilder is an "OK" button. Change label here
m_sdbSizer1OK->SetLabel( _( "Import Settings" ) );
// Disable "Import Settings" button until user selects at least one import option
m_sdbSizer1OK->Enable( false );
// Make sure "Select All" button is big enough to hold "Deselect All"
m_selectAllButton->SetLabel( _( "Deselect All" ) ); // Change the text temporarily
sizeNeeded = m_selectAllButton->GetBestSize(); // Get control to tell us the width required
m_selectAllButton->SetLabel( _( "Select All" ) ); // Restore "Select All" as default text
sizeNeeded.y = m_selectAllButton->GetSize().y; // Keep the height unchanged
m_selectAllButton->SetMinSize( sizeNeeded ); // Set control to the required size
m_buttonsSizer->Layout();
m_sdbSizer1OK->SetDefault();
m_showSelectAllOnBtn = true; // Store state to toggle message/usage of "Select All" button
}
void DIALOG_IMPORT_SETTINGS::OnCheckboxClicked( wxCommandEvent& event )
{
bool importButtonEnabled = UpdateImportSettingsButton();
// If clicking this checkbox clears the last of the import selection checkboxes,
// then make sure the "Select All" button is actually going to select all.
if( !importButtonEnabled )
{
m_showSelectAllOnBtn = true;
UpdateSelectAllButton();
}
}
bool DIALOG_IMPORT_SETTINGS::UpdateImportSettingsButton()
{
// Enable "Import Settings" button if at least one import option is selected
bool buttonEnableState = ( m_LayersOpt->IsChecked() || m_MaskAndPasteOpt->IsChecked()
|| m_ConstraintsOpt->IsChecked() || m_NetclassesOpt->IsChecked()
|| m_SeveritiesOpt->IsChecked() || m_TextAndGraphicsOpt->IsChecked()
|| m_TracksAndViasOpt->IsChecked() );
m_sdbSizer1OK->Enable( buttonEnableState );
return buttonEnableState;
}
void DIALOG_IMPORT_SETTINGS::UpdateSelectAllButton()
{
// Update message on button
if( m_showSelectAllOnBtn )
m_selectAllButton->SetLabel( _( "Select All" ) );
else
m_selectAllButton->SetLabel( _( "Deselect All" ) );
}
@ -82,11 +137,19 @@ bool DIALOG_IMPORT_SETTINGS::TransferDataFromWindow()
void DIALOG_IMPORT_SETTINGS::OnSelectAll( wxCommandEvent& event )
{
m_LayersOpt->SetValue( true );
m_TextAndGraphicsOpt->SetValue( true );
m_ConstraintsOpt->SetValue( true );
m_NetclassesOpt->SetValue( true );
m_TracksAndViasOpt->SetValue( true );
m_MaskAndPasteOpt->SetValue( true );
m_SeveritiesOpt->SetValue( true );
// Select or deselect all options based on internal flag
m_LayersOpt->SetValue( m_showSelectAllOnBtn );
m_TextAndGraphicsOpt->SetValue( m_showSelectAllOnBtn );
m_ConstraintsOpt->SetValue( m_showSelectAllOnBtn );
m_NetclassesOpt->SetValue( m_showSelectAllOnBtn );
m_TracksAndViasOpt->SetValue( m_showSelectAllOnBtn );
m_MaskAndPasteOpt->SetValue( m_showSelectAllOnBtn );
m_SeveritiesOpt->SetValue( m_showSelectAllOnBtn );
// Ensure "Import Settings" button state is enabled as appropriate
UpdateImportSettingsButton();
// Toggle whether button selects or deselects all.
m_showSelectAllOnBtn = !m_showSelectAllOnBtn;
UpdateSelectAllButton();
}

View File

@ -34,18 +34,42 @@ class PCB_EDIT_FRAME;
class DIALOG_IMPORT_SETTINGS : public DIALOG_IMPORT_SETTINGS_BASE
{
protected:
PCB_EDIT_FRAME* m_frame;
static wxString m_filePath;
PCB_EDIT_FRAME* m_frame;
static wxString m_filePath;
private:
/**
* Stores state used to toggle button between "Select All" and "Deselect All"
*/
bool m_showSelectAllOnBtn;
public:
DIALOG_IMPORT_SETTINGS( wxWindow* aParent, PCB_EDIT_FRAME* aFrame );
void OnBrowseClicked( wxCommandEvent& event ) override;
void OnSelectAll( wxCommandEvent& event ) override;
void OnCheckboxClicked( wxCommandEvent& event ) override;
bool TransferDataToWindow() override;
bool TransferDataFromWindow() override;
/**
* Enables/Disables "Import Settings" button
*
* This dialog defaults to all import selections cleared, and the "Import
* Settings" button disabled. The user must check at least one of the import
* selection checkboxes for the "Import Settings" button to be enabled.
*
* @return bool - "Import Settings" button enable state
*/
bool UpdateImportSettingsButton();
/**
* Update "Select All" button label as appropriate
*/
void UpdateSelectAllButton();
wxString GetFilePath() { return m_filePath; }
};

View File

@ -95,6 +95,13 @@ DIALOG_IMPORT_SETTINGS_BASE::DIALOG_IMPORT_SETTINGS_BASE( wxWindow* parent, wxWi
// Connect Events
m_browseButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnBrowseClicked ), NULL, this );
m_LayersOpt->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnCheckboxClicked ), NULL, this );
m_TextAndGraphicsOpt->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnCheckboxClicked ), NULL, this );
m_ConstraintsOpt->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnCheckboxClicked ), NULL, this );
m_TracksAndViasOpt->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnCheckboxClicked ), NULL, this );
m_MaskAndPasteOpt->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnCheckboxClicked ), NULL, this );
m_SeveritiesOpt->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnCheckboxClicked ), NULL, this );
m_NetclassesOpt->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnCheckboxClicked ), NULL, this );
m_selectAllButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnSelectAll ), NULL, this );
}
@ -102,6 +109,13 @@ DIALOG_IMPORT_SETTINGS_BASE::~DIALOG_IMPORT_SETTINGS_BASE()
{
// Disconnect Events
m_browseButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnBrowseClicked ), NULL, this );
m_LayersOpt->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnCheckboxClicked ), NULL, this );
m_TextAndGraphicsOpt->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnCheckboxClicked ), NULL, this );
m_ConstraintsOpt->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnCheckboxClicked ), NULL, this );
m_TracksAndViasOpt->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnCheckboxClicked ), NULL, this );
m_MaskAndPasteOpt->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnCheckboxClicked ), NULL, this );
m_SeveritiesOpt->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnCheckboxClicked ), NULL, this );
m_NetclassesOpt->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnCheckboxClicked ), NULL, this );
m_selectAllButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnSelectAll ), NULL, this );
}

View File

@ -27,7 +27,7 @@
<property name="ui_table">UI</property>
<property name="use_enum">1</property>
<property name="use_microsoft_bom">0</property>
<object class="Dialog" expanded="1">
<object class="Dialog" expanded="0">
<property name="aui_managed">0</property>
<property name="aui_manager_style">wxAUI_MGR_DEFAULT</property>
<property name="bg"></property>
@ -53,16 +53,16 @@
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<object class="wxBoxSizer" expanded="1">
<object class="wxBoxSizer" expanded="0">
<property name="minimum_size"></property>
<property name="name">m_MainSizer</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">protected</property>
<object class="sizeritem" expanded="1">
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND|wxTOP|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="1">
<object class="wxBoxSizer" expanded="0">
<property name="minimum_size"></property>
<property name="name">bupperSizer</property>
<property name="orient">wxHORIZONTAL</property>
@ -192,11 +192,11 @@
<property name="window_style"></property>
</object>
</object>
<object class="sizeritem" expanded="1">
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxRIGHT</property>
<property name="proportion">0</property>
<object class="wxBitmapButton" expanded="1">
<object class="wxBitmapButton" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -267,20 +267,20 @@
</object>
</object>
</object>
<object class="sizeritem" expanded="1">
<object class="sizeritem" expanded="0">
<property name="border">10</property>
<property name="flag">wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="1">
<object class="wxBoxSizer" expanded="0">
<property name="minimum_size"></property>
<property name="name">bmiddleSizer</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxTOP|wxBOTTOM|wxRIGHT</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="1">
<object class="wxStaticText" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -337,11 +337,11 @@
<property name="wrap">-1</property>
</object>
</object>
<object class="sizeritem" expanded="1">
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxBOTTOM|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="1">
<object class="wxCheckBox" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -399,13 +399,14 @@
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnCheckBox">OnCheckboxClicked</event>
</object>
</object>
<object class="sizeritem" expanded="1">
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxBOTTOM|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="1">
<object class="wxCheckBox" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -463,13 +464,14 @@
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnCheckBox">OnCheckboxClicked</event>
</object>
</object>
<object class="sizeritem" expanded="1">
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxBOTTOM|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="1">
<object class="wxCheckBox" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -527,13 +529,14 @@
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnCheckBox">OnCheckboxClicked</event>
</object>
</object>
<object class="sizeritem" expanded="1">
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxBOTTOM|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="1">
<object class="wxCheckBox" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -591,13 +594,14 @@
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnCheckBox">OnCheckboxClicked</event>
</object>
</object>
<object class="sizeritem" expanded="1">
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxBOTTOM|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="1">
<object class="wxCheckBox" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -655,13 +659,14 @@
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnCheckBox">OnCheckboxClicked</event>
</object>
</object>
<object class="sizeritem" expanded="1">
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="1">
<object class="wxCheckBox" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -719,13 +724,14 @@
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnCheckBox">OnCheckboxClicked</event>
</object>
</object>
<object class="sizeritem" expanded="1">
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="1">
<object class="wxCheckBox" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -783,24 +789,25 @@
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnCheckBox">OnCheckboxClicked</event>
</object>
</object>
</object>
</object>
<object class="sizeritem" expanded="1">
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="1">
<object class="wxBoxSizer" expanded="0">
<property name="minimum_size"></property>
<property name="name">m_buttonsSizer</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">protected</property>
<object class="sizeritem" expanded="1">
<object class="sizeritem" expanded="0">
<property name="border">10</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxButton" expanded="1">
<object class="wxButton" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -869,11 +876,11 @@
<event name="OnButtonClick">OnSelectAll</event>
</object>
</object>
<object class="sizeritem" expanded="1">
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxStdDialogButtonSizer" expanded="1">
<object class="wxStdDialogButtonSizer" expanded="0">
<property name="Apply">0</property>
<property name="Cancel">1</property>
<property name="ContextHelp">0</property>

View File

@ -48,6 +48,7 @@ class DIALOG_IMPORT_SETTINGS_BASE : public DIALOG_SHIM
// Virtual event handlers, overide them in your derived class
virtual void OnBrowseClicked( wxCommandEvent& event ) { event.Skip(); }
virtual void OnCheckboxClicked( wxCommandEvent& event ) { event.Skip(); }
virtual void OnSelectAll( wxCommandEvent& event ) { event.Skip(); }

View File

@ -43,7 +43,7 @@
static LSEQ dlg_layers()
{
// layers that are put out into the dialog UI, coordinate with wxformbuilder and
// Layers that are put out into the dialog UI, coordinate with wxformbuilder and
// getCTLs( LAYER_NUM aLayerNumber )
static const PCB_LAYER_ID layers[] = {
F_CrtYd,
@ -260,7 +260,7 @@ void PANEL_SETUP_LAYERS::showCopperChoice( int copperCount )
for( int lyrCnt = 2; lyrCnt <= MAX_CU_LAYERS; lyrCnt += 2 )
{
// note this will change a one layer board to 2:
// Note: This will change a 1 layer board to 2
if( copperCount <= lyrCnt )
{
int idx = lyrCnt/2 - 1;
@ -296,7 +296,7 @@ void PANEL_SETUP_LAYERS::showBoardLayerNames()
void PANEL_SETUP_LAYERS::showSelectedLayerCheckBoxes( LSET enabledLayers )
{
// the check boxes
// The check boxes
for( LSEQ seq = dlg_layers(); seq; ++seq )
{
PCB_LAYER_ID layer = *seq;
@ -307,7 +307,7 @@ void PANEL_SETUP_LAYERS::showSelectedLayerCheckBoxes( LSET enabledLayers )
void PANEL_SETUP_LAYERS::showPresets( LSET enabledLayers )
{
int presetsNdx = 0; // the "Custom" setting, matches nothing
int presetsNdx = 0; // The "Custom" setting, matches nothing
for( unsigned i=1; i<arrayDim( presets ); ++i )
{
@ -420,7 +420,7 @@ void PANEL_SETUP_LAYERS::DenyChangeCheckBox( wxCommandEvent& event )
if( source == copper )
{
wxString controlLabel = m_staticTextCopperLayers->GetLabel();
// knock the ':' off the end
// Knock the ':' off the end
controlLabel = controlLabel.substr( 0, controlLabel.size() - 1 );
msg.Printf( _( "Use the \"%s\" control to change the number of copper layers." ),
@ -488,7 +488,7 @@ bool PANEL_SETUP_LAYERS::TransferDataFromWindow()
// Check for removed layers with items which will get deleted from the board.
LSEQ removedLayers = getRemovedLayersWithItems();
// Check for non copper layers in use in footprints, and therefore not removable.
// Check for non-copper layers in use in footprints, and therefore not removable.
LSEQ notremovableLayers = getNonRemovableLayers();
if( !notremovableLayers.empty() )
@ -522,7 +522,7 @@ bool PANEL_SETUP_LAYERS::TransferDataFromWindow()
collector.SetLayerId( layer_id );
collector.Collect( m_pcb, GENERAL_COLLECTOR::BoardLevelItems );
// Bye-bye items on on removed layer.
// Bye-bye items on removed layer.
if( collector.GetCount() != 0 )
{
hasRemovedBoardItems = true;
@ -562,8 +562,8 @@ bool PANEL_SETUP_LAYERS::TransferDataFromWindow()
}
}
// If some board items are deleted: rebuild the connectivity,
// because it is likely some tracks and vias where removed
// If some board items are deleted: Rebuild the connectivity,
// because it is likely some tracks and vias were removed
if( hasRemovedBoardItems )
{
// Rebuild list of nets (full ratsnest rebuild)
@ -577,8 +577,8 @@ bool PANEL_SETUP_LAYERS::TransferDataFromWindow()
int PANEL_SETUP_LAYERS::getLayerTypeIndex( LAYER_NUM aLayer )
{
wxChoice* ctl = getChoice( aLayer );
int ret = ctl->GetCurrentSelection(); // indices must have same sequence as LAYER_T
wxChoice* ctl = getChoice( aLayer );
int ret = ctl->GetCurrentSelection(); // Indices must have same sequence as LAYER_T
return ret;
}
@ -616,6 +616,7 @@ bool PANEL_SETUP_LAYERS::testLayerNames()
PCB_LAYER_ID layer = *seq;
// we _can_ rely on m_enabledLayers being current here:
if( !m_enabledLayers[layer] )
continue;
@ -623,13 +624,13 @@ bool PANEL_SETUP_LAYERS::testLayerNames()
ctl = (wxTextCtrl*) getName( layer );
// check name for legality.
// 1) cannot be blank.
// 2) cannot have blanks.
// 3) cannot have " chars
// 4) cannot be 'signal'
// 5) must be unique.
// 6) cannot have illegal chars in filenames ( some filenames are built from layer names )
// Check name for legality:
// 1) Cannot be blank.
// 2) Cannot have blanks.
// 3) Cannot have " chars
// 4) Cannot be 'signal'
// 5) Must be unique.
// 6) Cannot have illegal chars in filenames ( some filenames are built from layer names )
// like : % $ \ " / :
wxString badchars = wxFileName::GetForbiddenChars( wxPATH_DOS );
badchars.Append( '%' );
@ -676,7 +677,7 @@ LSEQ PANEL_SETUP_LAYERS::getRemovedLayersWithItems()
LSET newLayers = GetUILayerMask();
LSET curLayers = m_pcb->GetEnabledLayers();
if( newLayers == curLayers ) // return a empty list if no change
if( newLayers == curLayers ) // Return an empty list if no change
return removedLayers;
PCB_LAYER_COLLECTOR collector;
@ -700,12 +701,12 @@ LSEQ PANEL_SETUP_LAYERS::getRemovedLayersWithItems()
LSEQ PANEL_SETUP_LAYERS::getNonRemovableLayers()
{
//Build the list of non copper layers in use in footprints.
// 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
if( newLayers == curLayers ) // Return an empty list if no change
return inUseLayers;
PCB_LAYER_COLLECTOR collector;
@ -713,7 +714,7 @@ LSEQ PANEL_SETUP_LAYERS::getNonRemovableLayers()
for( auto layer_id : curLayers.Seq() )
{
if( IsCopperLayer( layer_id ) ) // Copper layers are not taken in account here
if( IsCopperLayer( layer_id ) ) // Copper layers are not taken into account here
continue;
if( std::find( newLayerSeq.begin(), newLayerSeq.end(), layer_id ) == newLayerSeq.end() )
@ -739,3 +740,33 @@ void PANEL_SETUP_LAYERS::ImportSettingsFrom( BOARD* aBoard )
m_pcb = savedBoard;
}
bool PANEL_SETUP_LAYERS::compareCopperLayerCount( BOARD* aWorkingBoard, BOARD* aImportedBoard )
{
/* This function warns users if they are going to delete inner copper layers because
they're importing settings from a board with less copper layers than the board
already loaded. We want to return "true" as default on the assumption no layer will
actually be deleted. */
bool okToDeleteCopperLayers = true;
// Get the number of copper layers in the loaded board and the "import settings" board
int currNumLayers = aWorkingBoard->GetCopperLayerCount();
int newNumLayers = aImportedBoard->GetCopperLayerCount();
if( newNumLayers < currNumLayers )
{
wxMessageDialog dlg( this,
wxString::Format(
wxT( "Imported settings have fewer copper layers than current board (%i instead of %i)."
"\n\nContinue and delete extra inner copper layers from current board?" ),
newNumLayers, currNumLayers ),
_( "Inner Layers To Be Deleted" ),
wxICON_WARNING | wxSTAY_ON_TOP | wxYES | wxNO | wxNO_DEFAULT );
if( wxID_NO == dlg.ShowModal() )
okToDeleteCopperLayers = false;
}
return okToDeleteCopperLayers;
}

View File

@ -59,8 +59,22 @@ public:
void ImportSettingsFrom( BOARD* aBoard );
/**
* Check and warn if inner copper layers will be deleted
*
* This function warns users if they are going to delete inner copper layers because
* they're importing settings from a board with less copper layers than the board
* already loaded.
* @param aWorkingBoard = Currently loaded PCB
* @param aImportedBoard = PCB imported to get settings from
*
* @return bool - Approval to delete inner copper if needed
*/
bool compareCopperLayerCount( BOARD* aWorkingBoard, BOARD* aImportedBoard );
///> @return the selected layer mask within the UI checkboxes
LSET GetUILayerMask();
///> @return the layer name within the UI wxTextCtrl
wxString GetLayerName( LAYER_NUM layer );