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.

231 lines
6.9 KiB

  1. /*
  2. * This program source code file is part of KICAD, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2020 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 <panel_text_variables.h>
  24. #include <bitmaps.h>
  25. #include <confirm.h>
  26. #include <validators.h>
  27. #include <project.h>
  28. #include <grid_tricks.h>
  29. #include <widgets/wx_grid.h>
  30. #include <algorithm>
  31. enum TEXT_VAR_GRID_COLUMNS
  32. {
  33. TV_NAME_COL = 0,
  34. TV_VALUE_COL
  35. };
  36. PANEL_TEXT_VARIABLES::PANEL_TEXT_VARIABLES( wxWindow* aParent, PROJECT* aProject ) :
  37. PANEL_TEXT_VARIABLES_BASE( aParent ),
  38. m_project( aProject ),
  39. m_errorRow( -1 ), m_errorCol( -1 ),
  40. m_gridWidthsDirty( true )
  41. {
  42. m_btnAddTextVar->SetBitmap( KiBitmap( small_plus_xpm ) );
  43. m_btnDeleteTextVar->SetBitmap( KiBitmap( trash_xpm ) );
  44. m_TextVars->DeleteRows( 0, m_TextVars->GetNumberRows() );
  45. // prohibit these characters in the alias names: []{}()%~<>"='`;:.,&?/\|$
  46. m_nameValidator.SetStyle( wxFILTER_EXCLUDE_CHAR_LIST );
  47. m_nameValidator.SetCharExcludes( wxT( "{}[]()%~<>\"='`;:.,&?/\\|$" ) );
  48. m_TextVars->PushEventHandler( new GRID_TRICKS( m_TextVars ) );
  49. m_TextVars->SetSelectionMode( wxGrid::wxGridSelectionModes::wxGridSelectRows );
  50. // wxFormBuilder doesn't include this event...
  51. m_TextVars->Connect( wxEVT_GRID_CELL_CHANGING, wxGridEventHandler( PANEL_TEXT_VARIABLES::OnGridCellChanging ), NULL, this );
  52. }
  53. PANEL_TEXT_VARIABLES::~PANEL_TEXT_VARIABLES()
  54. {
  55. // Delete the GRID_TRICKS.
  56. m_TextVars->PopEventHandler( true );
  57. m_TextVars->Disconnect( wxEVT_GRID_CELL_CHANGING, wxGridEventHandler( PANEL_TEXT_VARIABLES::OnGridCellChanging ), NULL, this );
  58. }
  59. bool PANEL_TEXT_VARIABLES::TransferDataToWindow()
  60. {
  61. std::map<wxString, wxString>& variables = m_project->GetTextVars();
  62. for( const auto& var : variables )
  63. AppendTextVar( var.first, var.second );
  64. return true;
  65. }
  66. void PANEL_TEXT_VARIABLES::AppendTextVar( const wxString& aName, const wxString& aValue )
  67. {
  68. int i = m_TextVars->GetNumberRows();
  69. m_TextVars->AppendRows( 1 );
  70. m_TextVars->SetCellValue( i, TV_NAME_COL, aName );
  71. wxGridCellAttr* nameCellAttr = m_TextVars->GetOrCreateCellAttr( i, TV_NAME_COL );
  72. wxGridCellTextEditor* nameTextEditor = new GRID_CELL_TEXT_EDITOR();
  73. nameTextEditor->SetValidator( m_nameValidator );
  74. nameCellAttr->SetEditor( nameTextEditor );
  75. nameCellAttr->DecRef();
  76. m_TextVars->SetCellValue( i, TV_VALUE_COL, aValue );
  77. }
  78. bool PANEL_TEXT_VARIABLES::TransferDataFromWindow()
  79. {
  80. if( !m_TextVars->CommitPendingChanges() )
  81. return false;
  82. for( int row = 0; row < m_TextVars->GetNumberRows(); ++row )
  83. {
  84. if( m_TextVars->GetCellValue( row, TV_NAME_COL ).IsEmpty() )
  85. {
  86. m_errorRow = row;
  87. m_errorCol = TV_NAME_COL;
  88. m_errorMsg = _( "Variable name cannot be empty." );
  89. return false;
  90. }
  91. }
  92. std::map<wxString, wxString>& variables = m_project->GetTextVars();
  93. variables.clear();
  94. for( int row = 0; row < m_TextVars->GetNumberRows(); ++row )
  95. {
  96. wxString name = m_TextVars->GetCellValue( row, TV_NAME_COL );
  97. wxString value = m_TextVars->GetCellValue( row, TV_VALUE_COL );
  98. variables[ name ] = value;
  99. }
  100. return true;
  101. }
  102. void PANEL_TEXT_VARIABLES::OnGridCellChanging( wxGridEvent& event )
  103. {
  104. int row = event.GetRow();
  105. int col = event.GetCol();
  106. wxString text = event.GetString();
  107. if( text.IsEmpty() && col == TV_NAME_COL )
  108. {
  109. m_errorMsg = _( "Variable name cannot be empty." );
  110. m_errorRow = row;
  111. m_errorCol = col;
  112. event.Veto();
  113. }
  114. }
  115. void PANEL_TEXT_VARIABLES::OnAddTextVar( wxCommandEvent& event )
  116. {
  117. if( !m_TextVars->CommitPendingChanges() )
  118. return;
  119. AppendTextVar( wxEmptyString, wxEmptyString );
  120. m_TextVars->MakeCellVisible( m_TextVars->GetNumberRows() - 1, TV_NAME_COL );
  121. m_TextVars->SetGridCursor( m_TextVars->GetNumberRows() - 1, TV_NAME_COL );
  122. m_TextVars->EnableCellEditControl( true );
  123. m_TextVars->ShowCellEditControl();
  124. }
  125. void PANEL_TEXT_VARIABLES::OnRemoveTextVar( wxCommandEvent& event )
  126. {
  127. int curRow = m_TextVars->GetGridCursorRow();
  128. if( curRow < 0 || m_TextVars->GetNumberRows() <= curRow )
  129. return;
  130. m_TextVars->CommitPendingChanges( true /* silent mode; we don't care if it's valid */ );
  131. m_TextVars->DeleteRows( curRow, 1 );
  132. m_TextVars->MakeCellVisible( std::max( 0, curRow-1 ), m_TextVars->GetGridCursorCol() );
  133. m_TextVars->SetGridCursor( std::max( 0, curRow-1 ), m_TextVars->GetGridCursorCol() );
  134. }
  135. void PANEL_TEXT_VARIABLES::OnGridCellChange( wxGridEvent& aEvent )
  136. {
  137. m_gridWidthsDirty = true;
  138. aEvent.Skip();
  139. }
  140. void PANEL_TEXT_VARIABLES::OnUpdateUI( wxUpdateUIEvent& event )
  141. {
  142. if( m_gridWidthsDirty && ( !m_TextVars->IsCellEditControlShown() ) )
  143. {
  144. int width = m_TextVars->GetClientRect().GetWidth();
  145. m_TextVars->AutoSizeColumn( TV_NAME_COL );
  146. m_TextVars->SetColSize( TV_NAME_COL, std::max( m_TextVars->GetColSize( TV_NAME_COL ), 120 ) );
  147. m_TextVars->SetColSize( TV_VALUE_COL, width - m_TextVars->GetColSize( TV_NAME_COL ) );
  148. m_gridWidthsDirty = false;
  149. }
  150. // Handle a grid error. This is delayed to OnUpdateUI so that we can change focus
  151. // even when the original validation was triggered from a killFocus event (and for
  152. // dialog with notebooks, so that the corresponding notebook page can be shown in
  153. // the background when triggered from an OK).
  154. if( !m_errorMsg.IsEmpty() )
  155. {
  156. // We will re-enter this routine when the error dialog is displayed, so make
  157. // sure we don't keep putting up more dialogs.
  158. wxString errorMsg = m_errorMsg;
  159. m_errorMsg = wxEmptyString;
  160. DisplayErrorMessage( this, errorMsg );
  161. m_TextVars->SetFocus();
  162. m_TextVars->MakeCellVisible( m_errorRow, m_errorCol );
  163. m_TextVars->SetGridCursor( m_errorRow, m_errorCol );
  164. m_TextVars->EnableCellEditControl( true );
  165. m_TextVars->ShowCellEditControl();
  166. }
  167. }
  168. void PANEL_TEXT_VARIABLES::OnGridSize( wxSizeEvent& event )
  169. {
  170. m_gridWidthsDirty = true;
  171. event.Skip();
  172. }