You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

277 lines
10 KiB

4 years ago
4 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2017-2021 KiCad Developers, see AUTHORS.txt for contributors.
  5. *
  6. * This program is free software: you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License as published by the
  8. * Free Software Foundation, either version 3 of the License, or (at your
  9. * option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <pcb_edit_frame.h>
  20. #include <panel_setup_layers.h>
  21. #include <panel_setup_text_and_graphics.h>
  22. #include <panel_setup_constraints.h>
  23. #include <dialogs/panel_setup_netclasses.h>
  24. #include <panel_setup_tracks_and_vias.h>
  25. #include <panel_setup_mask_and_paste.h>
  26. #include <../board_stackup_manager/panel_board_stackup.h>
  27. #include <../board_stackup_manager/panel_board_finish.h>
  28. #include <confirm.h>
  29. #include <board_design_settings.h>
  30. #include <kiface_base.h>
  31. #include <drc/drc_item.h>
  32. #include <dialog_import_settings.h>
  33. #include <io_mgr.h>
  34. #include <dialogs/panel_setup_severities.h>
  35. #include <panel_text_variables.h>
  36. #include <project.h>
  37. #include <project/project_file.h>
  38. #include <settings/settings_manager.h>
  39. #include <widgets/resettable_panel.h>
  40. #include <widgets/wx_progress_reporters.h>
  41. #include <wildcards_and_files_ext.h>
  42. #include "dialog_board_setup.h"
  43. #include "panel_setup_rules.h"
  44. #include <wx/treebook.h>
  45. using std::placeholders::_1;
  46. DIALOG_BOARD_SETUP::DIALOG_BOARD_SETUP( PCB_EDIT_FRAME* aFrame ) :
  47. PAGED_DIALOG( aFrame, _( "Board Setup" ), false,
  48. _( "Import Settings from Another Board..." ) ),
  49. m_frame( aFrame )
  50. {
  51. BOARD* board = aFrame->GetBoard();
  52. BOARD_DESIGN_SETTINGS& bds = board->GetDesignSettings();
  53. m_layers = new PANEL_SETUP_LAYERS( this, aFrame );
  54. m_textAndGraphics = new PANEL_SETUP_TEXT_AND_GRAPHICS( this, aFrame );
  55. m_constraints = new PANEL_SETUP_CONSTRAINTS( this, aFrame );
  56. m_rules = new PANEL_SETUP_RULES( this, aFrame );
  57. m_tracksAndVias = new PANEL_SETUP_TRACKS_AND_VIAS( this, aFrame, m_constraints );
  58. m_maskAndPaste = new PANEL_SETUP_MASK_AND_PASTE( this, aFrame );
  59. m_physicalStackup = new PANEL_SETUP_BOARD_STACKUP( this, aFrame, m_layers );
  60. m_boardFinish = new PANEL_SETUP_BOARD_FINISH( this, board );
  61. m_severities = new PANEL_SETUP_SEVERITIES( this, DRC_ITEM::GetItemsWithSeverities(),
  62. bds.m_DRCSeverities );
  63. m_netclasses = new PANEL_SETUP_NETCLASSES( this, &bds.GetNetClasses(),
  64. board->GetNetClassAssignmentCandidates(), false );
  65. m_textVars = new PANEL_TEXT_VARIABLES( m_treebook, &Prj() );
  66. /*
  67. * WARNING: If you change page names you MUST update calls to ShowBoardSetupDialog().
  68. */
  69. m_treebook->AddPage( new wxPanel( this ), _( "Board Stackup" ) );
  70. /*
  71. * WARNING: Code currently relies on the layers setup coming before the physical stackup panel,
  72. * and thus transferring data to the board first. See comment in
  73. * PANEL_SETUP_BOARD_STACKUP::TransferDataFromWindow and rework this logic if it is determined
  74. * that the order of these pages should be changed.
  75. */
  76. m_treebook->AddSubPage( m_layers, _( "Board Editor Layers" ) );
  77. m_layerSetupPage = 1;
  78. m_treebook->AddSubPage( m_physicalStackup, _( "Physical Stackup" ) );
  79. // Change this value if m_physicalStackup is not the page 2 of m_treebook
  80. m_physicalStackupPage = 2; // The page number (from 0) to select the m_physicalStackup panel
  81. m_treebook->AddSubPage( m_boardFinish, _( "Board Finish" ) );
  82. m_treebook->AddSubPage( m_maskAndPaste, _( "Solder Mask/Paste" ) );
  83. m_treebook->AddPage( new wxPanel( this ), _( "Text & Graphics" ) );
  84. m_treebook->AddSubPage( m_textAndGraphics, _( "Defaults" ) );
  85. m_treebook->AddSubPage( m_textVars, _( "Text Variables" ) );
  86. m_treebook->AddPage( new wxPanel( this ), _( "Design Rules" ) );
  87. m_treebook->AddSubPage( m_constraints, _( "Constraints" ) );
  88. m_treebook->AddSubPage( m_tracksAndVias, _( "Pre-defined Sizes" ) );
  89. m_treebook->AddSubPage( m_netclasses, _( "Net Classes" ) );
  90. m_treebook->AddSubPage( m_rules, _( "Custom Rules" ) );
  91. m_treebook->AddSubPage( m_severities, _( "Violation Severity" ) );
  92. for( size_t i = 0; i < m_treebook->GetPageCount(); ++i )
  93. m_macHack.push_back( true );
  94. m_treebook->SetMinSize( wxSize( -1, 480 ) );
  95. // Connect Events
  96. m_treebook->Connect( wxEVT_TREEBOOK_PAGE_CHANGED,
  97. wxBookCtrlEventHandler( DIALOG_BOARD_SETUP::OnPageChange ), nullptr,
  98. this );
  99. finishDialogSettings();
  100. if( Prj().IsReadOnly() )
  101. {
  102. m_infoBar->ShowMessage( _( "Project is missing or read-only. Some settings will not "
  103. "be editable." ), wxICON_WARNING );
  104. }
  105. }
  106. DIALOG_BOARD_SETUP::~DIALOG_BOARD_SETUP()
  107. {
  108. m_treebook->Disconnect( wxEVT_TREEBOOK_PAGE_CHANGED,
  109. wxBookCtrlEventHandler( DIALOG_BOARD_SETUP::OnPageChange ), nullptr,
  110. this );
  111. }
  112. void DIALOG_BOARD_SETUP::OnPageChange( wxBookCtrlEvent& event )
  113. {
  114. int page = event.GetSelection();
  115. if( page == m_physicalStackupPage )
  116. m_physicalStackup->OnLayersOptionsChanged( m_layers->GetUILayerMask() );
  117. else if( page == m_layerSetupPage )
  118. m_layers->SyncCopperLayers( m_physicalStackup->GetCopperLayerCount() );
  119. else if( Prj().IsReadOnly() )
  120. KIUI::Disable( m_treebook->GetPage( page ) );
  121. #ifdef __WXMAC__
  122. // Work around an OSX bug where the wxGrid children don't get placed correctly until
  123. // the first resize event
  124. if( m_macHack[ page ] )
  125. {
  126. wxSize pageSize = m_treebook->GetPage( page )->GetSize();
  127. pageSize.x -= 1;
  128. pageSize.y += 2;
  129. m_treebook->GetPage( page )->SetSize( pageSize );
  130. m_macHack[ page ] = false;
  131. }
  132. #endif
  133. }
  134. void DIALOG_BOARD_SETUP::OnAuxiliaryAction( wxCommandEvent& event )
  135. {
  136. DIALOG_IMPORT_SETTINGS importDlg( this, m_frame );
  137. if( importDlg.ShowModal() == wxID_CANCEL )
  138. return;
  139. wxFileName boardFn( importDlg.GetFilePath() );
  140. wxFileName projectFn( boardFn );
  141. projectFn.SetExt( ProjectFileExtension );
  142. if( !m_frame->GetSettingsManager()->LoadProject( projectFn.GetFullPath(), false ) )
  143. {
  144. wxString msg = wxString::Format( _( "Error importing settings from board:\n"
  145. "Associated project file %s could not be loaded" ),
  146. projectFn.GetFullPath() );
  147. DisplayErrorMessage( this, msg );
  148. return;
  149. }
  150. // Flag so user can stop work if it will result in deleted inner copper layers
  151. // and still clean up this function properly.
  152. bool okToProceed = true;
  153. PROJECT* otherPrj = m_frame->GetSettingsManager()->GetProject( projectFn.GetFullPath() );
  154. PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::KICAD_SEXP ) );
  155. BOARD* otherBoard = nullptr;
  156. try
  157. {
  158. WX_PROGRESS_REPORTER progressReporter( this, _( "Loading PCB" ), 1 );
  159. otherBoard = pi->Load( boardFn.GetFullPath(), nullptr, nullptr, nullptr,
  160. &progressReporter );
  161. if( importDlg.m_LayersOpt->GetValue() )
  162. {
  163. BOARD* loadedBoard = m_frame->GetBoard();
  164. // Check if "Import Settings" board has more layers than the current board.
  165. okToProceed = m_layers->CheckCopperLayerCount( loadedBoard, otherBoard );
  166. }
  167. }
  168. catch( const IO_ERROR& ioe )
  169. {
  170. // You wouldn't think boardFn.GetFullPath() would throw, but we get a stack buffer
  171. // underflow from ASAN. While it's probably an ASAN error, a second try/catch doesn't
  172. // cost us much.
  173. try
  174. {
  175. if( ioe.Problem() != wxT( "CANCEL" ) )
  176. {
  177. wxString msg = wxString::Format( _( "Error loading board file:\n%s" ),
  178. boardFn.GetFullPath() );
  179. DisplayErrorMessage( this, msg, ioe.What() );
  180. }
  181. if( otherPrj != &m_frame->Prj() )
  182. m_frame->GetSettingsManager()->UnloadProject( otherPrj, false );
  183. }
  184. catch(...)
  185. {
  186. // That was already our best-efforts
  187. }
  188. return;
  189. }
  190. if( okToProceed )
  191. {
  192. otherBoard->SetProject( otherPrj );
  193. // If layers options are imported, import also the stackup
  194. // layers options and stackup are linked, so they cannot be imported
  195. // separately, and stackup can be imported only after layers options
  196. if( importDlg.m_LayersOpt->GetValue() )
  197. {
  198. m_layers->ImportSettingsFrom( otherBoard );
  199. m_physicalStackup->ImportSettingsFrom( otherBoard );
  200. }
  201. if( importDlg.m_TextAndGraphicsOpt->GetValue() )
  202. m_textAndGraphics->ImportSettingsFrom( otherBoard );
  203. if( importDlg.m_ConstraintsOpt->GetValue() )
  204. m_constraints->ImportSettingsFrom( otherBoard );
  205. if( importDlg.m_NetclassesOpt->GetValue() )
  206. m_netclasses->ImportSettingsFrom( &otherBoard->GetDesignSettings().GetNetClasses() );
  207. if( importDlg.m_TracksAndViasOpt->GetValue() )
  208. m_tracksAndVias->ImportSettingsFrom( otherBoard );
  209. if( importDlg.m_MaskAndPasteOpt->GetValue() )
  210. m_maskAndPaste->ImportSettingsFrom( otherBoard );
  211. if( importDlg.m_SeveritiesOpt->GetValue() )
  212. m_severities->ImportSettingsFrom( otherBoard->GetDesignSettings().m_DRCSeverities );
  213. if( otherPrj != &m_frame->Prj() )
  214. otherBoard->ClearProject();
  215. }
  216. // Clean up and free memory before leaving
  217. if( otherPrj != &m_frame->Prj() )
  218. m_frame->GetSettingsManager()->UnloadProject( otherPrj, false );
  219. delete otherBoard;
  220. }