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; 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() ); PROJECT* otherPrj = m_frame->GetSettingsManager()->GetProject( projectFn.GetFullPath() );
PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::KICAD_SEXP ) ); PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::KICAD_SEXP ) );
@ -160,6 +164,14 @@ void DIALOG_BOARD_SETUP::OnAuxiliaryAction( wxCommandEvent& event )
try try
{ {
otherBoard = pi->Load( boardFn.GetFullPath(), nullptr, nullptr ); 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 ) catch( const IO_ERROR& ioe )
{ {
@ -175,18 +187,26 @@ void DIALOG_BOARD_SETUP::OnAuxiliaryAction( wxCommandEvent& event )
return; return;
} }
if( okToProceed )
{
otherBoard->SetProject( otherPrj ); otherBoard->SetProject( otherPrj );
if( importDlg.m_LayersOpt->GetValue() ) if( importDlg.m_LayersOpt->GetValue() )
m_layers->ImportSettingsFrom( otherBoard ); m_layers->ImportSettingsFrom( otherBoard );
if( importDlg.m_TextAndGraphicsOpt->GetValue() ) if( importDlg.m_TextAndGraphicsOpt->GetValue() )
m_textAndGraphics->ImportSettingsFrom( otherBoard ); m_textAndGraphics->ImportSettingsFrom( otherBoard );
if( importDlg.m_ConstraintsOpt->GetValue() ) if( importDlg.m_ConstraintsOpt->GetValue() )
m_constraints->ImportSettingsFrom( otherBoard ); m_constraints->ImportSettingsFrom( otherBoard );
if( importDlg.m_NetclassesOpt->GetValue() ) if( importDlg.m_NetclassesOpt->GetValue() )
m_netclasses->ImportSettingsFrom( &otherBoard->GetDesignSettings().GetNetClasses() ); m_netclasses->ImportSettingsFrom( &otherBoard->GetDesignSettings().GetNetClasses() );
if( importDlg.m_TracksAndViasOpt->GetValue() ) if( importDlg.m_TracksAndViasOpt->GetValue() )
m_tracksAndVias->ImportSettingsFrom( otherBoard ); m_tracksAndVias->ImportSettingsFrom( otherBoard );
if( importDlg.m_MaskAndPasteOpt->GetValue() ) if( importDlg.m_MaskAndPasteOpt->GetValue() )
m_maskAndPaste->ImportSettingsFrom( otherBoard ); m_maskAndPaste->ImportSettingsFrom( otherBoard );
@ -198,6 +218,7 @@ void DIALOG_BOARD_SETUP::OnAuxiliaryAction( wxCommandEvent& event )
// we import settings from a .pro project file, not the settings inside // we import settings from a .pro project file, not the settings inside
// a board, and info only living in the board is not imported. // 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 // TODO: Add import of physical settings now that we are actually loading the board here
if( importDlg.m_LayersOpt->GetValue() ) if( importDlg.m_LayersOpt->GetValue() )
m_physicalStackup->ImportSettingsFrom( otherBoard ); m_physicalStackup->ImportSettingsFrom( otherBoard );
@ -205,7 +226,9 @@ void DIALOG_BOARD_SETUP::OnAuxiliaryAction( wxCommandEvent& event )
m_severities->ImportSettingsFrom( otherBoard->GetDesignSettings().m_DRCSeverities ); m_severities->ImportSettingsFrom( otherBoard->GetDesignSettings().m_DRCSeverities );
otherBoard->ClearProject(); otherBoard->ClearProject();
}
// Clean up and free memory before leaving
m_frame->GetSettingsManager()->UnloadProject( otherPrj, false ); m_frame->GetSettingsManager()->UnloadProject( otherPrj, false );
delete otherBoard; delete otherBoard;

View File

@ -37,12 +37,67 @@ DIALOG_IMPORT_SETTINGS::DIALOG_IMPORT_SETTINGS( wxWindow* aParent, PCB_EDIT_FRAM
DIALOG_IMPORT_SETTINGS_BASE( aParent ), DIALOG_IMPORT_SETTINGS_BASE( aParent ),
m_frame( aFrame ) m_frame( aFrame )
{ {
wxSize sizeNeeded;
m_browseButton->SetBitmap( KiBitmap( folder_xpm ) ); m_browseButton->SetBitmap( KiBitmap( folder_xpm ) );
// Button created in wxFormBuilder is an "OK" button. Change label here
m_sdbSizer1OK->SetLabel( _( "Import Settings" ) ); 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_buttonsSizer->Layout();
m_sdbSizer1OK->SetDefault(); 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 ) void DIALOG_IMPORT_SETTINGS::OnSelectAll( wxCommandEvent& event )
{ {
m_LayersOpt->SetValue( true ); // Select or deselect all options based on internal flag
m_TextAndGraphicsOpt->SetValue( true ); m_LayersOpt->SetValue( m_showSelectAllOnBtn );
m_ConstraintsOpt->SetValue( true ); m_TextAndGraphicsOpt->SetValue( m_showSelectAllOnBtn );
m_NetclassesOpt->SetValue( true ); m_ConstraintsOpt->SetValue( m_showSelectAllOnBtn );
m_TracksAndViasOpt->SetValue( true ); m_NetclassesOpt->SetValue( m_showSelectAllOnBtn );
m_MaskAndPasteOpt->SetValue( true ); m_TracksAndViasOpt->SetValue( m_showSelectAllOnBtn );
m_SeveritiesOpt->SetValue( true ); 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

@ -37,15 +37,39 @@ protected:
PCB_EDIT_FRAME* m_frame; PCB_EDIT_FRAME* m_frame;
static wxString m_filePath; static wxString m_filePath;
private:
/**
* Stores state used to toggle button between "Select All" and "Deselect All"
*/
bool m_showSelectAllOnBtn;
public: public:
DIALOG_IMPORT_SETTINGS( wxWindow* aParent, PCB_EDIT_FRAME* aFrame ); DIALOG_IMPORT_SETTINGS( wxWindow* aParent, PCB_EDIT_FRAME* aFrame );
void OnBrowseClicked( wxCommandEvent& event ) override; void OnBrowseClicked( wxCommandEvent& event ) override;
void OnSelectAll( wxCommandEvent& event ) override; void OnSelectAll( wxCommandEvent& event ) override;
void OnCheckboxClicked( wxCommandEvent& event ) override;
bool TransferDataToWindow() override; bool TransferDataToWindow() override;
bool TransferDataFromWindow() 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; } wxString GetFilePath() { return m_filePath; }
}; };

View File

@ -95,6 +95,13 @@ DIALOG_IMPORT_SETTINGS_BASE::DIALOG_IMPORT_SETTINGS_BASE( wxWindow* parent, wxWi
// Connect Events // Connect Events
m_browseButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnBrowseClicked ), NULL, this ); 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 ); 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 // Disconnect Events
m_browseButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnBrowseClicked ), NULL, this ); 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 ); 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="ui_table">UI</property>
<property name="use_enum">1</property> <property name="use_enum">1</property>
<property name="use_microsoft_bom">0</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_managed">0</property>
<property name="aui_manager_style">wxAUI_MGR_DEFAULT</property> <property name="aui_manager_style">wxAUI_MGR_DEFAULT</property>
<property name="bg"></property> <property name="bg"></property>
@ -53,16 +53,16 @@
<property name="window_extra_style"></property> <property name="window_extra_style"></property>
<property name="window_name"></property> <property name="window_name"></property>
<property name="window_style"></property> <property name="window_style"></property>
<object class="wxBoxSizer" expanded="1"> <object class="wxBoxSizer" expanded="0">
<property name="minimum_size"></property> <property name="minimum_size"></property>
<property name="name">m_MainSizer</property> <property name="name">m_MainSizer</property>
<property name="orient">wxVERTICAL</property> <property name="orient">wxVERTICAL</property>
<property name="permission">protected</property> <property name="permission">protected</property>
<object class="sizeritem" expanded="1"> <object class="sizeritem" expanded="0">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxEXPAND|wxTOP|wxRIGHT|wxLEFT</property> <property name="flag">wxEXPAND|wxTOP|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxBoxSizer" expanded="1"> <object class="wxBoxSizer" expanded="0">
<property name="minimum_size"></property> <property name="minimum_size"></property>
<property name="name">bupperSizer</property> <property name="name">bupperSizer</property>
<property name="orient">wxHORIZONTAL</property> <property name="orient">wxHORIZONTAL</property>
@ -192,11 +192,11 @@
<property name="window_style"></property> <property name="window_style"></property>
</object> </object>
</object> </object>
<object class="sizeritem" expanded="1"> <object class="sizeritem" expanded="0">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxRIGHT</property> <property name="flag">wxALIGN_CENTER_VERTICAL|wxRIGHT</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxBitmapButton" expanded="1"> <object class="wxBitmapButton" expanded="0">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>
<property name="LeftDockable">1</property> <property name="LeftDockable">1</property>
<property name="RightDockable">1</property> <property name="RightDockable">1</property>
@ -267,20 +267,20 @@
</object> </object>
</object> </object>
</object> </object>
<object class="sizeritem" expanded="1"> <object class="sizeritem" expanded="0">
<property name="border">10</property> <property name="border">10</property>
<property name="flag">wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT</property> <property name="flag">wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxBoxSizer" expanded="1"> <object class="wxBoxSizer" expanded="0">
<property name="minimum_size"></property> <property name="minimum_size"></property>
<property name="name">bmiddleSizer</property> <property name="name">bmiddleSizer</property>
<property name="orient">wxVERTICAL</property> <property name="orient">wxVERTICAL</property>
<property name="permission">none</property> <property name="permission">none</property>
<object class="sizeritem" expanded="1"> <object class="sizeritem" expanded="0">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxTOP|wxBOTTOM|wxRIGHT</property> <property name="flag">wxTOP|wxBOTTOM|wxRIGHT</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxStaticText" expanded="1"> <object class="wxStaticText" expanded="0">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>
<property name="LeftDockable">1</property> <property name="LeftDockable">1</property>
<property name="RightDockable">1</property> <property name="RightDockable">1</property>
@ -337,11 +337,11 @@
<property name="wrap">-1</property> <property name="wrap">-1</property>
</object> </object>
</object> </object>
<object class="sizeritem" expanded="1"> <object class="sizeritem" expanded="0">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxBOTTOM|wxRIGHT|wxLEFT</property> <property name="flag">wxBOTTOM|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxCheckBox" expanded="1"> <object class="wxCheckBox" expanded="0">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>
<property name="LeftDockable">1</property> <property name="LeftDockable">1</property>
<property name="RightDockable">1</property> <property name="RightDockable">1</property>
@ -399,13 +399,14 @@
<property name="window_extra_style"></property> <property name="window_extra_style"></property>
<property name="window_name"></property> <property name="window_name"></property>
<property name="window_style"></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="border">5</property>
<property name="flag">wxBOTTOM|wxRIGHT|wxLEFT</property> <property name="flag">wxBOTTOM|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxCheckBox" expanded="1"> <object class="wxCheckBox" expanded="0">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>
<property name="LeftDockable">1</property> <property name="LeftDockable">1</property>
<property name="RightDockable">1</property> <property name="RightDockable">1</property>
@ -463,13 +464,14 @@
<property name="window_extra_style"></property> <property name="window_extra_style"></property>
<property name="window_name"></property> <property name="window_name"></property>
<property name="window_style"></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="border">5</property>
<property name="flag">wxBOTTOM|wxRIGHT|wxLEFT</property> <property name="flag">wxBOTTOM|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxCheckBox" expanded="1"> <object class="wxCheckBox" expanded="0">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>
<property name="LeftDockable">1</property> <property name="LeftDockable">1</property>
<property name="RightDockable">1</property> <property name="RightDockable">1</property>
@ -527,13 +529,14 @@
<property name="window_extra_style"></property> <property name="window_extra_style"></property>
<property name="window_name"></property> <property name="window_name"></property>
<property name="window_style"></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="border">5</property>
<property name="flag">wxBOTTOM|wxRIGHT|wxLEFT</property> <property name="flag">wxBOTTOM|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxCheckBox" expanded="1"> <object class="wxCheckBox" expanded="0">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>
<property name="LeftDockable">1</property> <property name="LeftDockable">1</property>
<property name="RightDockable">1</property> <property name="RightDockable">1</property>
@ -591,13 +594,14 @@
<property name="window_extra_style"></property> <property name="window_extra_style"></property>
<property name="window_name"></property> <property name="window_name"></property>
<property name="window_style"></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="border">5</property>
<property name="flag">wxBOTTOM|wxRIGHT|wxLEFT</property> <property name="flag">wxBOTTOM|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxCheckBox" expanded="1"> <object class="wxCheckBox" expanded="0">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>
<property name="LeftDockable">1</property> <property name="LeftDockable">1</property>
<property name="RightDockable">1</property> <property name="RightDockable">1</property>
@ -655,13 +659,14 @@
<property name="window_extra_style"></property> <property name="window_extra_style"></property>
<property name="window_name"></property> <property name="window_name"></property>
<property name="window_style"></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="border">5</property>
<property name="flag">wxRIGHT|wxLEFT</property> <property name="flag">wxRIGHT|wxLEFT</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxCheckBox" expanded="1"> <object class="wxCheckBox" expanded="0">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>
<property name="LeftDockable">1</property> <property name="LeftDockable">1</property>
<property name="RightDockable">1</property> <property name="RightDockable">1</property>
@ -719,13 +724,14 @@
<property name="window_extra_style"></property> <property name="window_extra_style"></property>
<property name="window_name"></property> <property name="window_name"></property>
<property name="window_style"></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="border">5</property>
<property name="flag">wxALL</property> <property name="flag">wxALL</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxCheckBox" expanded="1"> <object class="wxCheckBox" expanded="0">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>
<property name="LeftDockable">1</property> <property name="LeftDockable">1</property>
<property name="RightDockable">1</property> <property name="RightDockable">1</property>
@ -783,24 +789,25 @@
<property name="window_extra_style"></property> <property name="window_extra_style"></property>
<property name="window_name"></property> <property name="window_name"></property>
<property name="window_style"></property> <property name="window_style"></property>
<event name="OnCheckBox">OnCheckboxClicked</event>
</object> </object>
</object> </object>
</object> </object>
</object> </object>
<object class="sizeritem" expanded="1"> <object class="sizeritem" expanded="0">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxEXPAND</property> <property name="flag">wxEXPAND</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxBoxSizer" expanded="1"> <object class="wxBoxSizer" expanded="0">
<property name="minimum_size"></property> <property name="minimum_size"></property>
<property name="name">m_buttonsSizer</property> <property name="name">m_buttonsSizer</property>
<property name="orient">wxHORIZONTAL</property> <property name="orient">wxHORIZONTAL</property>
<property name="permission">protected</property> <property name="permission">protected</property>
<object class="sizeritem" expanded="1"> <object class="sizeritem" expanded="0">
<property name="border">10</property> <property name="border">10</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT</property> <property name="flag">wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxButton" expanded="1"> <object class="wxButton" expanded="0">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>
<property name="LeftDockable">1</property> <property name="LeftDockable">1</property>
<property name="RightDockable">1</property> <property name="RightDockable">1</property>
@ -869,11 +876,11 @@
<event name="OnButtonClick">OnSelectAll</event> <event name="OnButtonClick">OnSelectAll</event>
</object> </object>
</object> </object>
<object class="sizeritem" expanded="1"> <object class="sizeritem" expanded="0">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property> <property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">1</property> <property name="proportion">1</property>
<object class="wxStdDialogButtonSizer" expanded="1"> <object class="wxStdDialogButtonSizer" expanded="0">
<property name="Apply">0</property> <property name="Apply">0</property>
<property name="Cancel">1</property> <property name="Cancel">1</property>
<property name="ContextHelp">0</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 event handlers, overide them in your derived class
virtual void OnBrowseClicked( wxCommandEvent& event ) { event.Skip(); } virtual void OnBrowseClicked( wxCommandEvent& event ) { event.Skip(); }
virtual void OnCheckboxClicked( wxCommandEvent& event ) { event.Skip(); }
virtual void OnSelectAll( wxCommandEvent& event ) { event.Skip(); } virtual void OnSelectAll( wxCommandEvent& event ) { event.Skip(); }

View File

@ -43,7 +43,7 @@
static LSEQ dlg_layers() 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 ) // getCTLs( LAYER_NUM aLayerNumber )
static const PCB_LAYER_ID layers[] = { static const PCB_LAYER_ID layers[] = {
F_CrtYd, F_CrtYd,
@ -260,7 +260,7 @@ void PANEL_SETUP_LAYERS::showCopperChoice( int copperCount )
for( int lyrCnt = 2; lyrCnt <= MAX_CU_LAYERS; lyrCnt += 2 ) 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 ) if( copperCount <= lyrCnt )
{ {
int idx = lyrCnt/2 - 1; int idx = lyrCnt/2 - 1;
@ -296,7 +296,7 @@ void PANEL_SETUP_LAYERS::showBoardLayerNames()
void PANEL_SETUP_LAYERS::showSelectedLayerCheckBoxes( LSET enabledLayers ) void PANEL_SETUP_LAYERS::showSelectedLayerCheckBoxes( LSET enabledLayers )
{ {
// the check boxes // The check boxes
for( LSEQ seq = dlg_layers(); seq; ++seq ) for( LSEQ seq = dlg_layers(); seq; ++seq )
{ {
PCB_LAYER_ID layer = *seq; PCB_LAYER_ID layer = *seq;
@ -307,7 +307,7 @@ void PANEL_SETUP_LAYERS::showSelectedLayerCheckBoxes( LSET enabledLayers )
void PANEL_SETUP_LAYERS::showPresets( 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 ) for( unsigned i=1; i<arrayDim( presets ); ++i )
{ {
@ -420,7 +420,7 @@ void PANEL_SETUP_LAYERS::DenyChangeCheckBox( wxCommandEvent& event )
if( source == copper ) if( source == copper )
{ {
wxString controlLabel = m_staticTextCopperLayers->GetLabel(); wxString controlLabel = m_staticTextCopperLayers->GetLabel();
// knock the ':' off the end // Knock the ':' off the end
controlLabel = controlLabel.substr( 0, controlLabel.size() - 1 ); controlLabel = controlLabel.substr( 0, controlLabel.size() - 1 );
msg.Printf( _( "Use the \"%s\" control to change the number of copper layers." ), 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. // Check for removed layers with items which will get deleted from the board.
LSEQ removedLayers = getRemovedLayersWithItems(); 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(); LSEQ notremovableLayers = getNonRemovableLayers();
if( !notremovableLayers.empty() ) if( !notremovableLayers.empty() )
@ -522,7 +522,7 @@ bool PANEL_SETUP_LAYERS::TransferDataFromWindow()
collector.SetLayerId( layer_id ); collector.SetLayerId( layer_id );
collector.Collect( m_pcb, GENERAL_COLLECTOR::BoardLevelItems ); collector.Collect( m_pcb, GENERAL_COLLECTOR::BoardLevelItems );
// Bye-bye items on on removed layer. // Bye-bye items on removed layer.
if( collector.GetCount() != 0 ) if( collector.GetCount() != 0 )
{ {
hasRemovedBoardItems = true; hasRemovedBoardItems = true;
@ -562,8 +562,8 @@ bool PANEL_SETUP_LAYERS::TransferDataFromWindow()
} }
} }
// If some board items are deleted: rebuild the connectivity, // If some board items are deleted: Rebuild the connectivity,
// because it is likely some tracks and vias where removed // because it is likely some tracks and vias were removed
if( hasRemovedBoardItems ) if( hasRemovedBoardItems )
{ {
// Rebuild list of nets (full ratsnest rebuild) // Rebuild list of nets (full ratsnest rebuild)
@ -578,7 +578,7 @@ bool PANEL_SETUP_LAYERS::TransferDataFromWindow()
int PANEL_SETUP_LAYERS::getLayerTypeIndex( LAYER_NUM aLayer ) int PANEL_SETUP_LAYERS::getLayerTypeIndex( LAYER_NUM aLayer )
{ {
wxChoice* ctl = getChoice( aLayer ); wxChoice* ctl = getChoice( aLayer );
int ret = ctl->GetCurrentSelection(); // indices must have same sequence as LAYER_T int ret = ctl->GetCurrentSelection(); // Indices must have same sequence as LAYER_T
return ret; return ret;
} }
@ -616,6 +616,7 @@ bool PANEL_SETUP_LAYERS::testLayerNames()
PCB_LAYER_ID layer = *seq; PCB_LAYER_ID layer = *seq;
// we _can_ rely on m_enabledLayers being current here: // we _can_ rely on m_enabledLayers being current here:
if( !m_enabledLayers[layer] ) if( !m_enabledLayers[layer] )
continue; continue;
@ -623,13 +624,13 @@ bool PANEL_SETUP_LAYERS::testLayerNames()
ctl = (wxTextCtrl*) getName( layer ); ctl = (wxTextCtrl*) getName( layer );
// check name for legality. // Check name for legality:
// 1) cannot be blank. // 1) Cannot be blank.
// 2) cannot have blanks. // 2) Cannot have blanks.
// 3) cannot have " chars // 3) Cannot have " chars
// 4) cannot be 'signal' // 4) Cannot be 'signal'
// 5) must be unique. // 5) Must be unique.
// 6) cannot have illegal chars in filenames ( some filenames are built from layer names ) // 6) Cannot have illegal chars in filenames ( some filenames are built from layer names )
// like : % $ \ " / : // like : % $ \ " / :
wxString badchars = wxFileName::GetForbiddenChars( wxPATH_DOS ); wxString badchars = wxFileName::GetForbiddenChars( wxPATH_DOS );
badchars.Append( '%' ); badchars.Append( '%' );
@ -676,7 +677,7 @@ LSEQ PANEL_SETUP_LAYERS::getRemovedLayersWithItems()
LSET newLayers = GetUILayerMask(); LSET newLayers = GetUILayerMask();
LSET curLayers = m_pcb->GetEnabledLayers(); 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; return removedLayers;
PCB_LAYER_COLLECTOR collector; PCB_LAYER_COLLECTOR collector;
@ -700,12 +701,12 @@ LSEQ PANEL_SETUP_LAYERS::getRemovedLayersWithItems()
LSEQ PANEL_SETUP_LAYERS::getNonRemovableLayers() 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; LSEQ inUseLayers;
LSET newLayers = GetUILayerMask(); LSET newLayers = GetUILayerMask();
LSET curLayers = m_pcb->GetEnabledLayers(); 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; return inUseLayers;
PCB_LAYER_COLLECTOR collector; PCB_LAYER_COLLECTOR collector;
@ -713,7 +714,7 @@ LSEQ PANEL_SETUP_LAYERS::getNonRemovableLayers()
for( auto layer_id : curLayers.Seq() ) 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; continue;
if( std::find( newLayerSeq.begin(), newLayerSeq.end(), layer_id ) == newLayerSeq.end() ) 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; 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 ); 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 ///> @return the selected layer mask within the UI checkboxes
LSET GetUILayerMask(); LSET GetUILayerMask();
///> @return the layer name within the UI wxTextCtrl ///> @return the layer name within the UI wxTextCtrl
wxString GetLayerName( LAYER_NUM layer ); wxString GetLayerName( LAYER_NUM layer );