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.

291 lines
11 KiB

3 years ago
3 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2020-2023 KiCad Developers, see AUTHORS.txt for contributors.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, you may find one here:
  18. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  19. * or you may search the http://www.gnu.org website for the version 2 license,
  20. * or you may write to the Free Software Foundation, Inc.,
  21. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  22. */
  23. #include <widgets/paged_dialog.h>
  24. #include <widgets/ui_common.h>
  25. #include <rc_item.h>
  26. #include <dialogs/panel_setup_severities.h>
  27. #include <wx/radiobut.h>
  28. #include <wx/scrolwin.h>
  29. #include <wx/stattext.h>
  30. #include "confirm.h"
  31. PANEL_SETUP_SEVERITIES::PANEL_SETUP_SEVERITIES( wxWindow* aParentWindow,
  32. std::vector<std::reference_wrapper<RC_ITEM>> aItems,
  33. std::map<int, SEVERITY>& aSeverities,
  34. RC_ITEM* aPinMapSpecialCase ) :
  35. wxPanel( aParentWindow ),
  36. m_severities( aSeverities ),
  37. m_items( std::move( aItems ) ),
  38. m_pinMapSpecialCase( aPinMapSpecialCase )
  39. {
  40. wxString severities[] = { _( "Error" ), _( "Warning" ), _( "Ignore" ) };
  41. int severityCount = sizeof( severities ) / sizeof( wxString );
  42. int baseID = 1000;
  43. wxBoxSizer* panelSizer = new wxBoxSizer( wxVERTICAL );
  44. wxScrolledWindow* scrollWin = new wxScrolledWindow( this, wxID_ANY,
  45. wxDefaultPosition, wxDefaultSize,
  46. wxTAB_TRAVERSAL | wxVSCROLL );
  47. bool firstLine = true;
  48. scrollWin->SetScrollRate( 0, 5 );
  49. wxBoxSizer* scrollWinSizer = new wxBoxSizer( wxVERTICAL );
  50. scrollWin->SetSizer( scrollWinSizer );
  51. wxFlexGridSizer* gridSizer = new wxFlexGridSizer( 0, 2, 0, 5 );
  52. gridSizer->SetFlexibleDirection( wxBOTH );
  53. gridSizer->SetVGap( 5 );
  54. for( const RC_ITEM& item : m_items )
  55. {
  56. int errorCode = item.GetErrorCode();
  57. wxString msg = item.GetErrorText();
  58. if( m_pinMapSpecialCase && errorCode == m_pinMapSpecialCase->GetErrorCode() )
  59. continue;
  60. if( errorCode == 0 )
  61. {
  62. wxStaticText* heading = new wxStaticText( scrollWin, wxID_ANY, msg );
  63. wxFont headingFont = heading->GetFont();
  64. heading->SetFont( headingFont.Bold() );
  65. if( !firstLine )
  66. {
  67. gridSizer->AddSpacer( 5 ); // col 1
  68. gridSizer->AddSpacer( 5 ); // col 2
  69. }
  70. gridSizer->Add( heading, 0, wxALIGN_BOTTOM | wxALL | wxEXPAND, 4 );
  71. gridSizer->AddSpacer( 0 ); // col 2
  72. }
  73. else if( !msg.IsEmpty() ) // items with no message are for internal use only
  74. {
  75. wxStaticText* errorLabel = new wxStaticText( scrollWin, wxID_ANY, msg + wxT( ":" ) );
  76. gridSizer->Add( errorLabel, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 15 );
  77. // OSX can't handle more than 100 radio buttons in a single window (yes, seriously),
  78. // so we have to create a window for each set
  79. wxPanel* radioPanel = new wxPanel( scrollWin );
  80. wxBoxSizer* radioSizer = new wxBoxSizer( wxHORIZONTAL );
  81. for( int i = 0; i < severityCount; ++i )
  82. {
  83. m_buttonMap[ errorCode ][i] = new wxRadioButton( radioPanel,
  84. baseID + errorCode * 10 + i,
  85. severities[i],
  86. wxDefaultPosition, wxDefaultSize,
  87. i == 0 ? wxRB_GROUP : 0 );
  88. radioSizer->Add( m_buttonMap[ errorCode ][i], 0,
  89. wxRIGHT | wxALIGN_CENTER_VERTICAL, 30 );
  90. }
  91. radioPanel->SetSizer( radioSizer );
  92. radioPanel->Layout();
  93. gridSizer->Add( radioPanel, 0, wxALIGN_CENTER_VERTICAL );
  94. }
  95. firstLine = false;
  96. }
  97. if( m_pinMapSpecialCase )
  98. {
  99. wxString pinMapSeverities[] = { _( "From Pin Conflicts Map" ), wxT( "" ), _( "Ignore" ) };
  100. int errorCode = m_pinMapSpecialCase->GetErrorCode();
  101. wxString msg = m_pinMapSpecialCase->GetErrorText();
  102. wxStaticText* errorLabel = new wxStaticText( scrollWin, wxID_ANY, msg + wxT( ":" ) );
  103. gridSizer->Add( errorLabel, 0, wxALIGN_CENTER_VERTICAL | wxALL | wxEXPAND, 15 );
  104. wxPanel* radioPanel = new wxPanel( scrollWin );
  105. wxBoxSizer* radioSizer = new wxBoxSizer( wxHORIZONTAL );
  106. for( size_t i = 0; i < 3; ++i )
  107. {
  108. if( pinMapSeverities[i] == wxT( "" ) )
  109. {
  110. wxStaticText* spacer = new wxStaticText( radioPanel, wxID_ANY, wxT( "" ) );
  111. radioSizer->Add( spacer, 0, wxRIGHT | wxEXPAND, 17 );
  112. }
  113. else
  114. {
  115. m_buttonMap[ errorCode ][i] = new wxRadioButton( radioPanel,
  116. baseID + errorCode * 10 + i,
  117. pinMapSeverities[i],
  118. wxDefaultPosition, wxDefaultSize,
  119. i == 0 ? wxRB_GROUP : 0 );
  120. radioSizer->Add( m_buttonMap[ errorCode ][i], 0, wxEXPAND );
  121. }
  122. }
  123. radioPanel->SetSizer( radioSizer );
  124. radioPanel->Layout();
  125. gridSizer->Add( radioPanel, 0, wxALIGN_CENTER_VERTICAL );
  126. }
  127. scrollWinSizer->Add( gridSizer, 1, wxEXPAND | wxALL, 5 );
  128. panelSizer->Add( scrollWin, 1, wxEXPAND, 0 );
  129. Bind( wxEVT_IDLE,
  130. [this]( wxIdleEvent& aEvent )
  131. {
  132. if( m_lastLoaded != m_severities )
  133. {
  134. wxWindow* dialog = wxGetTopLevelParent( this );
  135. wxWindow* topLevelFocus = wxGetTopLevelParent( wxWindow::FindFocus() );
  136. if( topLevelFocus == dialog )
  137. checkReload();
  138. }
  139. } );
  140. SetSizer( panelSizer );
  141. Layout();
  142. panelSizer->Fit( this );
  143. }
  144. void PANEL_SETUP_SEVERITIES::checkReload()
  145. {
  146. // MUST update lastLoaded before calling IsOK (or we'll end up re-entering through the idle
  147. // event until we crash the stack).
  148. m_lastLoaded = m_severities;
  149. if( IsOK( m_parent, _( "The violation severities have been changed outside the Setup dialog.\n"
  150. "Do you wish to reload them?" ) ) )
  151. {
  152. TransferDataToWindow();
  153. }
  154. }
  155. void PANEL_SETUP_SEVERITIES::ImportSettingsFrom( std::map<int, SEVERITY>& aSettings )
  156. {
  157. for( const RC_ITEM& item : m_items )
  158. {
  159. int errorCode = item.GetErrorCode();
  160. wxRadioButton* button = nullptr;
  161. switch( aSettings[ errorCode ] )
  162. {
  163. case RPT_SEVERITY_ERROR: button = m_buttonMap[ errorCode ][0]; break;
  164. case RPT_SEVERITY_WARNING: button = m_buttonMap[ errorCode ][1]; break;
  165. case RPT_SEVERITY_IGNORE: button = m_buttonMap[ errorCode ][2]; break;
  166. default: break;
  167. }
  168. if( button ) // this entry must actually exist
  169. button->SetValue( true );
  170. }
  171. if( m_pinMapSpecialCase )
  172. {
  173. int pinMapCode = m_pinMapSpecialCase->GetErrorCode();
  174. int newSeverity = aSettings[ pinMapCode ];
  175. m_buttonMap[ pinMapCode ][0]->SetValue( newSeverity != RPT_SEVERITY_IGNORE );
  176. m_buttonMap[ pinMapCode ][2]->SetValue( newSeverity == RPT_SEVERITY_IGNORE );
  177. }
  178. }
  179. bool PANEL_SETUP_SEVERITIES::TransferDataToWindow()
  180. {
  181. m_lastLoaded = m_severities;
  182. for( const RC_ITEM& item : m_items )
  183. {
  184. int errorCode = item.GetErrorCode();
  185. if( !m_buttonMap[ errorCode ][0] ) // this entry does not actually exist
  186. continue;
  187. if( m_pinMapSpecialCase && errorCode == m_pinMapSpecialCase->GetErrorCode() )
  188. continue;
  189. switch( m_severities[ errorCode ] )
  190. {
  191. case RPT_SEVERITY_ERROR: m_buttonMap[ errorCode ][0]->SetValue( true ); break;
  192. case RPT_SEVERITY_WARNING: m_buttonMap[ errorCode ][1]->SetValue( true ); break;
  193. case RPT_SEVERITY_IGNORE: m_buttonMap[ errorCode ][2]->SetValue( true ); break;
  194. default: break;
  195. }
  196. }
  197. if( m_pinMapSpecialCase )
  198. {
  199. int pinMapCode = m_pinMapSpecialCase->GetErrorCode();
  200. int severity = m_severities[pinMapCode];
  201. m_buttonMap[ pinMapCode ][0]->SetValue( severity != RPT_SEVERITY_IGNORE );
  202. m_buttonMap[ pinMapCode ][2]->SetValue( severity == RPT_SEVERITY_IGNORE );
  203. }
  204. return true;
  205. }
  206. bool PANEL_SETUP_SEVERITIES::TransferDataFromWindow()
  207. {
  208. for( const RC_ITEM& item : m_items )
  209. {
  210. int errorCode = item.GetErrorCode();
  211. if( m_pinMapSpecialCase && m_pinMapSpecialCase->GetErrorCode() == errorCode )
  212. continue;
  213. if( !m_buttonMap[ errorCode ][0] ) // this entry does not actually exist
  214. continue;
  215. SEVERITY severity = RPT_SEVERITY_UNDEFINED;
  216. if( m_buttonMap[ errorCode ][0]->GetValue() )
  217. severity = RPT_SEVERITY_ERROR;
  218. else if( m_buttonMap[ errorCode ][1]->GetValue() )
  219. severity = RPT_SEVERITY_WARNING;
  220. else if( m_buttonMap[ errorCode ][2]->GetValue() )
  221. severity = RPT_SEVERITY_IGNORE;
  222. m_severities[ errorCode ] = severity;
  223. }
  224. if( m_pinMapSpecialCase )
  225. {
  226. int pinMapCode = m_pinMapSpecialCase->GetErrorCode();
  227. SEVERITY severity = RPT_SEVERITY_UNDEFINED;
  228. if( m_buttonMap[ pinMapCode ][0]->GetValue() )
  229. severity = RPT_SEVERITY_ERROR;
  230. else if( m_buttonMap[ pinMapCode ][2]->GetValue() )
  231. severity = RPT_SEVERITY_IGNORE;
  232. m_severities[ pinMapCode ] = severity;
  233. }
  234. return true;
  235. }