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.

284 lines
7.7 KiB

12 years ago
12 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
  5. * Copyright (C) 2012 KiCad Developers, see change_log.txt for contributors.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. #include <fctsys.h>
  25. #include <grid_tricks.h>
  26. #include <wx/tokenzr.h>
  27. #include <wx/arrstr.h>
  28. #include <wx/clipbrd.h>
  29. // It works for table data on clipboard for an Excell spreadsheet,
  30. // why not us too for now.
  31. #define COL_SEP wxT( '\t' )
  32. #define ROW_SEP wxT( '\n' )
  33. enum
  34. {
  35. MYID_FIRST = -1,
  36. MYID_CUT,
  37. MYID_COPY,
  38. MYID_PASTE,
  39. MYID_SELECT,
  40. MYID_LAST,
  41. };
  42. GRID_TRICKS::GRID_TRICKS( wxGrid* aGrid ):
  43. m_grid( aGrid )
  44. {
  45. aGrid->Connect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( GRID_TRICKS::onGridCellRightClick ), NULL, this );
  46. aGrid->Connect( MYID_FIRST, MYID_LAST, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GRID_TRICKS::onPopupSelection ), NULL, this );
  47. aGrid->Connect( wxEVT_KEY_DOWN, wxKeyEventHandler( GRID_TRICKS::onKeyDown ), NULL, this );
  48. aGrid->Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( GRID_TRICKS::onRightDown ), NULL, this );
  49. }
  50. void GRID_TRICKS::getSelectedArea()
  51. {
  52. wxGridCellCoordsArray topLeft = m_grid->GetSelectionBlockTopLeft();
  53. wxGridCellCoordsArray botRight = m_grid->GetSelectionBlockBottomRight();
  54. wxArrayInt cols = m_grid->GetSelectedCols();
  55. wxArrayInt rows = m_grid->GetSelectedRows();
  56. DBG(printf("topLeft.Count():%zd botRight:Count():%zd\n", topLeft.Count(), botRight.Count() );)
  57. if( topLeft.Count() && botRight.Count() )
  58. {
  59. m_sel_row_start = topLeft[0].GetRow();
  60. m_sel_col_start = topLeft[0].GetCol();
  61. m_sel_row_count = botRight[0].GetRow() - m_sel_row_start + 1;
  62. m_sel_col_count = botRight[0].GetCol() - m_sel_col_start + 1;
  63. }
  64. else if( cols.Count() )
  65. {
  66. m_sel_col_start = cols[0];
  67. m_sel_col_count = cols.Count();
  68. m_sel_row_start = 0;
  69. m_sel_row_count = m_grid->GetNumberRows();
  70. }
  71. else if( rows.Count() )
  72. {
  73. m_sel_col_start = 0;
  74. m_sel_col_count = m_grid->GetNumberCols();
  75. m_sel_row_start = rows[0];
  76. m_sel_row_count = rows.Count();
  77. }
  78. else
  79. {
  80. m_sel_row_start = -1;
  81. m_sel_col_start = -1;
  82. m_sel_row_count = 0;
  83. m_sel_col_count = 0;
  84. }
  85. //DBG(printf("m_sel_row_start:%d m_sel_col_start:%d m_sel_row_count:%d m_sel_col_count:%d\n", m_sel_row_start, m_sel_col_start, m_sel_row_count, m_sel_col_count );)
  86. }
  87. void GRID_TRICKS::showPopupMenu()
  88. {
  89. wxMenu menu;
  90. menu.Append( MYID_CUT, _( "Cut\tCTRL+X" ), _( "Clear selected cells pasting original contents to clipboard" ) );
  91. menu.Append( MYID_COPY, _( "Copy\tCTRL+C" ), _( "Copy selected cells to clipboard" ) );
  92. menu.Append( MYID_PASTE, _( "Paste\tCTRL+V" ), _( "Paste clipboard cells to matrix at current cell" ) );
  93. menu.Append( MYID_SELECT, _( "Select All\tCTRL+A" ), _( "Select all cells" ) );
  94. getSelectedArea();
  95. // if nothing is selected, disable cut and copy.
  96. if( !m_sel_row_count && !m_sel_col_count )
  97. {
  98. menu.Enable( MYID_CUT, false );
  99. menu.Enable( MYID_COPY, false );
  100. }
  101. bool have_cb_text = false;
  102. if( wxTheClipboard->Open() )
  103. {
  104. if( wxTheClipboard->IsSupported( wxDF_TEXT ) )
  105. have_cb_text = true;
  106. wxTheClipboard->Close();
  107. }
  108. if( !have_cb_text )
  109. {
  110. // if nothing on clipboard, disable paste.
  111. menu.Enable( MYID_PASTE, false );
  112. }
  113. m_grid->PopupMenu( &menu );
  114. }
  115. void GRID_TRICKS::onPopupSelection( wxCommandEvent& event )
  116. {
  117. int menu_id = event.GetId();
  118. // assume getSelectedArea() was called by rightClickPopupMenu() and there's
  119. // no way to have gotten here without that having been called.
  120. switch( menu_id )
  121. {
  122. case MYID_CUT:
  123. case MYID_COPY:
  124. cutcopy( menu_id == MYID_CUT );
  125. break;
  126. case MYID_PASTE:
  127. paste_clipboard();
  128. break;
  129. case MYID_SELECT:
  130. m_grid->SelectAll();
  131. break;
  132. default:
  133. ;
  134. }
  135. }
  136. void GRID_TRICKS::onKeyDown( wxKeyEvent& ev )
  137. {
  138. if( isCtl( 'A', ev ) )
  139. {
  140. m_grid->SelectAll();
  141. }
  142. else if( isCtl( 'C', ev ) )
  143. {
  144. getSelectedArea();
  145. cutcopy( false );
  146. }
  147. else if( isCtl( 'V', ev ) )
  148. {
  149. getSelectedArea();
  150. paste_clipboard();
  151. }
  152. else if( isCtl( 'X', ev ) )
  153. {
  154. getSelectedArea();
  155. cutcopy( true );
  156. }
  157. else
  158. {
  159. ev.Skip( true );
  160. }
  161. }
  162. void GRID_TRICKS::paste_clipboard()
  163. {
  164. if( wxTheClipboard->Open() )
  165. {
  166. if( wxTheClipboard->IsSupported( wxDF_TEXT ) )
  167. {
  168. wxTextDataObject data;
  169. wxTheClipboard->GetData( data );
  170. wxString cb_text = data.GetText();
  171. paste_text( cb_text );
  172. }
  173. wxTheClipboard->Close();
  174. m_grid->ForceRefresh();
  175. }
  176. }
  177. void GRID_TRICKS::paste_text( const wxString& cb_text )
  178. {
  179. wxGridTableBase* tbl = m_grid->GetTable();
  180. const int cur_row = std::max( getCursorRow(), 0 ); // no -1
  181. const int cur_col = std::max( getCursorCol(), 0 );
  182. wxStringTokenizer rows( cb_text, ROW_SEP, wxTOKEN_RET_EMPTY );
  183. // if clipboard rows would extend past end of current table size...
  184. if( int( rows.CountTokens() ) > tbl->GetNumberRows() - cur_row )
  185. {
  186. int newRowsNeeded = rows.CountTokens() - ( tbl->GetNumberRows() - cur_row );
  187. tbl->AppendRows( newRowsNeeded );
  188. }
  189. for( int row = cur_row; rows.HasMoreTokens(); ++row )
  190. {
  191. wxString rowTxt = rows.GetNextToken();
  192. wxStringTokenizer cols( rowTxt, COL_SEP, wxTOKEN_RET_EMPTY );
  193. for( int col = cur_col; cols.HasMoreTokens(); ++col )
  194. {
  195. wxString cellTxt = cols.GetNextToken();
  196. tbl->SetValue( row, col, cellTxt );
  197. }
  198. }
  199. m_grid->AutoSizeColumns( false );
  200. }
  201. void GRID_TRICKS::cutcopy( bool doCut )
  202. {
  203. if( wxTheClipboard->Open() )
  204. {
  205. wxGridTableBase* tbl = m_grid->GetTable();
  206. wxString txt;
  207. // fill txt with a format that is compatible with most spreadsheets
  208. for( int row = m_sel_row_start; row < m_sel_row_start + m_sel_row_count; ++row )
  209. {
  210. for( int col = m_sel_col_start; col < m_sel_col_start + m_sel_col_count; ++col )
  211. {
  212. txt += tbl->GetValue( row, col );
  213. if( col < m_sel_col_start + m_sel_col_count - 1 ) // that was not last column
  214. txt += COL_SEP;
  215. if( doCut )
  216. tbl->SetValue( row, col, wxEmptyString );
  217. }
  218. txt += ROW_SEP;
  219. }
  220. wxTheClipboard->SetData( new wxTextDataObject( txt ) );
  221. wxTheClipboard->Close();
  222. if( doCut )
  223. {
  224. m_grid->AutoSizeColumns( false );
  225. m_grid->ForceRefresh();
  226. }
  227. }
  228. }