diff --git a/TODO.txt b/TODO.txt index 9e7ac7a7c1..b3cd8fbdfb 100644 --- a/TODO.txt +++ b/TODO.txt @@ -154,6 +154,5 @@ Dick's Final TODO List: *) Apply Fabrizio and Alexander's linux desktop patches after unifying them. *) Get licensing cleaned up. *) Re-arrange the repo architecture. -*) Merge KiCad GAL/TOM/ORSON if nobody else does. *) DLL-ization of pcbnew & eeschema http://www.eevblog.com/forum/open-source-kicad-geda/seriously-irritated-with-the-library-editor!/ diff --git a/pcbnew/dialogs/dialog_fp_lib_table.cpp b/pcbnew/dialogs/dialog_fp_lib_table.cpp index ba34bf9a69..34e95ec216 100644 --- a/pcbnew/dialogs/dialog_fp_lib_table.cpp +++ b/pcbnew/dialogs/dialog_fp_lib_table.cpp @@ -56,7 +56,7 @@ enum COL_ORDER /** * Class FP_TBL_MODEL - * mixes in wxGridTableBase into FP_LIB_TABLE so that the latter can be used + * mixes in FP_LIB_TABLE into wxGridTableBase so the result can be used * as a table within wxGrid. */ class FP_TBL_MODEL : public wxGridTableBase, public FP_LIB_TABLE @@ -282,369 +282,17 @@ protected: */ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE { - typedef FP_LIB_TABLE::ROW ROW; - - /// If the cursor is not on a valid cell, because there are no rows at all, return -1, - /// else return a 0 based column index. - int getCursorCol() const - { - return m_cur_grid->GetGridCursorCol(); - } - - /// If the cursor is not on a valid cell, because there are no rows at all, return -1, - /// else return a 0 based row index. - int getCursorRow() const - { - return m_cur_grid->GetGridCursorRow(); - } - - - /** - * Function verifyTables - * trims important fields, removes blank row entries, and checks for duplicates. - * @return bool - true if tables are OK, else false. - */ - bool verifyTables() - { - for( int t=0; t<2; ++t ) - { - FP_TBL_MODEL& model = t==0 ? m_global_model : m_project_model; - - for( int r = 0; r < model.GetNumberRows(); ) - { - wxString nick = model.GetValue( r, COL_NICKNAME ).Trim( false ).Trim(); - wxString uri = model.GetValue( r, COL_URI ).Trim( false ).Trim(); - - if( !nick || !uri ) - { - // Delete the "empty" row, where empty means missing nick or uri. - // This also updates the UI which could be slow, but there should only be a few - // rows to delete, unless the user fell asleep on the Add Row - // button. - model.DeleteRows( r, 1 ); - } - else if( nick.find(':') != size_t(-1) ) - { - wxString msg = wxString::Format( - _( "Illegal character '%s' found in Nickname: '%s' in row %d" ), - wxT( ":" ), GetChars( nick ), r ); - - // show the tabbed panel holding the grid we have flunked: - if( &model != (FP_TBL_MODEL*) m_cur_grid->GetTable() ) - { - m_auinotebook->SetSelection( &model == &m_global_model ? 0 : 1 ); - } - - // go to the problematic row - m_cur_grid->SetGridCursor( r, 0 ); - m_cur_grid->SelectBlock( r, 0, r, 0 ); - m_cur_grid->MakeCellVisible( r, 0 ); - - wxMessageDialog errdlg( this, msg, _( "No Colon in Nicknames" ) ); - errdlg.ShowModal(); - return false; - } - else - { - // set the trimmed values back into the table so they get saved to disk. - model.SetValue( r, COL_NICKNAME, nick ); - model.SetValue( r, COL_URI, uri ); - ++r; // this row was OK. - } - } - } - - // check for duplicate nickNames, separately in each table. - for( int t=0; t<2; ++t ) - { - FP_TBL_MODEL& model = t==0 ? m_global_model : m_project_model; - - for( int r1 = 0; r1 < model.GetNumberRows() - 1; ++r1 ) - { - wxString nick1 = model.GetValue( r1, COL_NICKNAME ); - - for( int r2=r1+1; r2 < model.GetNumberRows(); ++r2 ) - { - wxString nick2 = model.GetValue( r2, COL_NICKNAME ); - - if( nick1 == nick2 ) - { - wxString msg = wxString::Format( - _( "Duplicate Nickname: '%s' in rows %d and %d" ), - GetChars( nick1 ), r1+1, r2+1 - ); - - // show the tabbed panel holding the grid we have flunked: - if( &model != (FP_TBL_MODEL*) m_cur_grid->GetTable() ) - { - m_auinotebook->SetSelection( &model == &m_global_model ? 0 : 1 ); - } - - // go to the lower of the two rows, it is technically the duplicate: - m_cur_grid->SetGridCursor( r2, 0 ); - m_cur_grid->SelectBlock( r2, 0, r2, 0 ); - m_cur_grid->MakeCellVisible( r2, 0 ); - - wxMessageDialog errdlg( this, msg, _( "Please Delete or Modify One" ) ); - errdlg.ShowModal(); - return false; - } - } - } - } - - return true; - } - - //--------------------------------------- - - void onKeyDown( wxKeyEvent& ev ) - { -#if 0 - // send the key to the current grid - ((wxEvtHandler*)m_cur_grid)->ProcessEvent( ev ); -#else - // or no: - // m_cur_grid has the focus most of the time anyways, so above not needed. - ev.Skip(); -#endif - } - - void pageChangedHandler( wxAuiNotebookEvent& event ) - { - int pageNdx = m_auinotebook->GetSelection(); - m_cur_grid = ( pageNdx == 0 ) ? m_global_grid : m_project_grid; - } - - void appendRowHandler( wxMouseEvent& event ) - { - if( m_cur_grid->AppendRows( 1 ) ) - { - int last_row = m_cur_grid->GetNumberRows() - 1; - - m_cur_grid->MakeCellVisible( last_row, 0 ); - m_cur_grid->SetGridCursor( last_row, 0 ); - } - } - - void deleteRowHandler( wxMouseEvent& event ) - { - int rowCount = m_cur_grid->GetNumberRows(); - int curRow = getCursorRow(); - - m_cur_grid->DeleteRows( curRow ); - - if( curRow && curRow == rowCount - 1 ) - m_cur_grid->SetGridCursor( curRow-1, getCursorCol() ); - } - - void moveUpHandler( wxMouseEvent& event ) - { - int curRow = getCursorRow(); - if( curRow >= 1 ) - { - int curCol = getCursorCol(); - - FP_TBL_MODEL* tbl = (FP_TBL_MODEL*) m_cur_grid->GetTable(); - - ROW move_me = tbl->rows[curRow]; - - tbl->rows.erase( tbl->rows.begin() + curRow ); - --curRow; - tbl->rows.insert( tbl->rows.begin() + curRow, move_me ); - - if( tbl->GetView() ) - { - // fire a msg to cause redrawing - wxGridTableMessage msg( tbl, - wxGRIDTABLE_NOTIFY_ROWS_INSERTED, - curRow, - 0 ); - - tbl->GetView()->ProcessTableMessage( msg ); - } - - m_cur_grid->SetGridCursor( curRow, curCol ); - } - } - - void moveDownHandler( wxMouseEvent& event ) - { - FP_TBL_MODEL* tbl = (FP_TBL_MODEL*) m_cur_grid->GetTable(); - - int curRow = getCursorRow(); - if( unsigned( curRow + 1 ) < tbl->rows.size() ) - { - int curCol = getCursorCol(); - - ROW move_me = tbl->rows[curRow]; - - tbl->rows.erase( tbl->rows.begin() + curRow ); - ++curRow; - tbl->rows.insert( tbl->rows.begin() + curRow, move_me ); - - if( tbl->GetView() ) - { - // fire a msg to cause redrawing - wxGridTableMessage msg( tbl, - wxGRIDTABLE_NOTIFY_ROWS_INSERTED, - curRow - 1, - 0 ); - - tbl->GetView()->ProcessTableMessage( msg ); - } - - m_cur_grid->SetGridCursor( curRow, curCol ); - } - DBG(printf("%s\n", __func__);) - } - - void optionsEditor( wxMouseEvent& event ) - { - FP_TBL_MODEL* tbl = (FP_TBL_MODEL*) m_cur_grid->GetTable(); - - int curRow = getCursorRow(); - ROW& row = tbl->rows[curRow]; - - wxString result; - const wxString& options = row.GetOptions(); - - InvokePluginOptionsEditor( this, row.GetNickName(), options, &result ); - - if( options != result ) - { - row.SetOptions( result ); - m_cur_grid->AutoSizeColumn( COL_OPTIONS, false ); - } - } - - void onCancelButtonClick( wxCommandEvent& event ) - { - EndModal( 0 ); - } - - void onCancelButtonClick( wxCloseEvent& event ) - { - EndModal( 0 ); - } - - void onOKButtonClick( wxCommandEvent& event ) - { - int dialogRet = 0; - - // stuff any pending cell editor text into the table. - m_cur_grid->SaveEditControlValue(); - - if( verifyTables() ) - { - if( m_global_model != *m_global ) - { - dialogRet |= 1; - - *m_global = m_global_model; - m_global->reindex(); - } - - if( m_project_model != *m_project ) - { - dialogRet |= 2; - - *m_project = m_project_model; - m_project->reindex(); - } - - EndModal( dialogRet ); - } - } - - /// Populate the readonly environment variable table with names and values - /// by examining all the full_uri columns. - void populateEnvironReadOnlyTable() - { - wxRegEx re( wxT( ".*?\\$\\{(.+?)\\}.*?" ), wxRE_ADVANCED ); - wxASSERT( re.IsValid() ); // wxRE_ADVANCED is required. - - std::set< wxString > unique; - typedef std::set::const_iterator SET_CITER; - - // clear the table - m_path_subs_grid->DeleteRows( 0, m_path_subs_grid->GetNumberRows() ); - - int gblRowCount = m_global_model.GetNumberRows(); - int prjRowCount = m_project_model.GetNumberRows(); - int row; - - for( row = 0; row < gblRowCount; ++row ) - { - wxString uri = m_global_model.GetValue( row, COL_URI ); - - while( re.Matches( uri ) ) - { - wxString envvar = re.GetMatch( uri, 1 ); - - // ignore duplicates - unique.insert( envvar ); - - // delete the last match and search again - uri.Replace( re.GetMatch( uri, 0 ), wxEmptyString ); - } - } - - for( row = 0; row < prjRowCount; ++row ) - { - wxString uri = m_project_model.GetValue( row, COL_URI ); - - while( re.Matches( uri ) ) - { - wxString envvar = re.GetMatch( uri, 1 ); - - // ignore duplicates - unique.insert( envvar ); - - // delete the last match and search again - uri.Replace( re.GetMatch( uri, 0 ), wxEmptyString ); - } - } - - m_path_subs_grid->AppendRows( unique.size() ); - - row = 0; - for( SET_CITER it = unique.begin(); it != unique.end(); ++it, ++row ) - { - wxString evName = *it; - wxString evValue; - - m_path_subs_grid->SetCellValue( row, 0, evName ); - - if( wxGetEnv( evName, &evValue ) ) - m_path_subs_grid->SetCellValue( row, 1, evValue ); - } - - m_path_subs_grid->AutoSizeColumns(); - } - - //-------------------------------------- - - // caller's tables are modified only on OK button. - FP_LIB_TABLE* m_global; - FP_LIB_TABLE* m_project; - - // local copies which are edited, but aborted if Cancel button. - FP_TBL_MODEL m_global_model; - FP_TBL_MODEL m_project_model; - - wxGrid* m_cur_grid; ///< changed based on tab choice public: DIALOG_FP_LIB_TABLE( wxTopLevelWindow* aParent, FP_LIB_TABLE* aGlobal, FP_LIB_TABLE* aProject ) : DIALOG_FP_LIB_TABLE_BASE( aParent ), m_global( aGlobal ), - m_project( aProject ), - m_global_model( *aGlobal ), - m_project_model( *aProject ) + m_project( aProject ) { - m_global_grid->SetTable( (wxGridTableBase*) &m_global_model ); - m_project_grid->SetTable( (wxGridTableBase*) &m_project_model ); + // wxGrid only supports user owned tables if they exist past end of ~wxGrid(), + // so make it a grid owned table. + m_global_grid->SetTable( new FP_TBL_MODEL( *aGlobal ), true ); + m_project_grid->SetTable( new FP_TBL_MODEL( *aProject ), true ); // add Cut, Copy, and Paste to wxGrids m_global_grid->PushEventHandler( new FP_GRID_TRICKS( m_global_grid ) ); @@ -703,13 +351,366 @@ public: // Any additional event handlers should be popped before the window is deleted. m_global_grid->PopEventHandler( true ); m_project_grid->PopEventHandler( true ); - - // ~wxGrid() examines its table, and the tables will have been destroyed before - // the wxGrids are, so remove the tables from the wxGrids' awareness. - // Otherwise there is a segfault. - m_global_grid->SetTable( NULL ); - m_project_grid->SetTable( NULL ); } + + +private: + typedef FP_LIB_TABLE::ROW ROW; + + /// If the cursor is not on a valid cell, because there are no rows at all, return -1, + /// else return a 0 based column index. + int getCursorCol() const + { + return m_cur_grid->GetGridCursorCol(); + } + + /// If the cursor is not on a valid cell, because there are no rows at all, return -1, + /// else return a 0 based row index. + int getCursorRow() const + { + return m_cur_grid->GetGridCursorRow(); + } + + /** + * Function verifyTables + * trims important fields, removes blank row entries, and checks for duplicates. + * @return bool - true if tables are OK, else false. + */ + bool verifyTables() + { + for( int t=0; t<2; ++t ) + { + FP_TBL_MODEL& model = t==0 ? *global_model() : *project_model(); + + for( int r = 0; r < model.GetNumberRows(); ) + { + wxString nick = model.GetValue( r, COL_NICKNAME ).Trim( false ).Trim(); + wxString uri = model.GetValue( r, COL_URI ).Trim( false ).Trim(); + + if( !nick || !uri ) + { + // Delete the "empty" row, where empty means missing nick or uri. + // This also updates the UI which could be slow, but there should only be a few + // rows to delete, unless the user fell asleep on the Add Row + // button. + model.DeleteRows( r, 1 ); + } + else if( nick.find(':') != size_t(-1) ) + { + wxString msg = wxString::Format( + _( "Illegal character '%s' found in Nickname: '%s' in row %d" ), + wxT( ":" ), GetChars( nick ), r ); + + // show the tabbed panel holding the grid we have flunked: + if( &model != cur_model() ) + { + m_auinotebook->SetSelection( &model == global_model() ? 0 : 1 ); + } + + // go to the problematic row + m_cur_grid->SetGridCursor( r, 0 ); + m_cur_grid->SelectBlock( r, 0, r, 0 ); + m_cur_grid->MakeCellVisible( r, 0 ); + + wxMessageDialog errdlg( this, msg, _( "No Colon in Nicknames" ) ); + errdlg.ShowModal(); + return false; + } + else + { + // set the trimmed values back into the table so they get saved to disk. + model.SetValue( r, COL_NICKNAME, nick ); + model.SetValue( r, COL_URI, uri ); + ++r; // this row was OK. + } + } + } + + // check for duplicate nickNames, separately in each table. + for( int t=0; t<2; ++t ) + { + FP_TBL_MODEL& model = t==0 ? *global_model() : *project_model(); + + for( int r1 = 0; r1 < model.GetNumberRows() - 1; ++r1 ) + { + wxString nick1 = model.GetValue( r1, COL_NICKNAME ); + + for( int r2=r1+1; r2 < model.GetNumberRows(); ++r2 ) + { + wxString nick2 = model.GetValue( r2, COL_NICKNAME ); + + if( nick1 == nick2 ) + { + wxString msg = wxString::Format( + _( "Duplicate Nickname: '%s' in rows %d and %d" ), + GetChars( nick1 ), r1+1, r2+1 + ); + + // show the tabbed panel holding the grid we have flunked: + if( &model != cur_model() ) + { + m_auinotebook->SetSelection( &model == global_model() ? 0 : 1 ); + } + + // go to the lower of the two rows, it is technically the duplicate: + m_cur_grid->SetGridCursor( r2, 0 ); + m_cur_grid->SelectBlock( r2, 0, r2, 0 ); + m_cur_grid->MakeCellVisible( r2, 0 ); + + wxMessageDialog errdlg( this, msg, _( "Please Delete or Modify One" ) ); + errdlg.ShowModal(); + return false; + } + } + } + } + + return true; + } + + //--------------------------------------- + + void onKeyDown( wxKeyEvent& ev ) + { +#if 0 + // send the key to the current grid + ((wxEvtHandler*)m_cur_grid)->ProcessEvent( ev ); +#else + // or no: + // m_cur_grid has the focus most of the time anyways, so above not needed. + ev.Skip(); +#endif + } + + void pageChangedHandler( wxAuiNotebookEvent& event ) + { + int pageNdx = m_auinotebook->GetSelection(); + m_cur_grid = ( pageNdx == 0 ) ? m_global_grid : m_project_grid; + } + + void appendRowHandler( wxMouseEvent& event ) + { + if( m_cur_grid->AppendRows( 1 ) ) + { + int last_row = m_cur_grid->GetNumberRows() - 1; + + // wx documentation is wrong, SetGridCursor does not make visible. + m_cur_grid->MakeCellVisible( last_row, 0 ); + m_cur_grid->SetGridCursor( last_row, 0 ); + } + } + + void deleteRowHandler( wxMouseEvent& event ) + { + int rowCount = m_cur_grid->GetNumberRows(); + int curRow = getCursorRow(); + + m_cur_grid->DeleteRows( curRow ); + + if( curRow && curRow == rowCount - 1 ) + m_cur_grid->SetGridCursor( curRow-1, getCursorCol() ); + } + + void moveUpHandler( wxMouseEvent& event ) + { + int curRow = getCursorRow(); + if( curRow >= 1 ) + { + int curCol = getCursorCol(); + + FP_TBL_MODEL* tbl = cur_model(); + + ROW move_me = tbl->rows[curRow]; + + tbl->rows.erase( tbl->rows.begin() + curRow ); + --curRow; + tbl->rows.insert( tbl->rows.begin() + curRow, move_me ); + + if( tbl->GetView() ) + { + // fire a msg to cause redrawing + wxGridTableMessage msg( tbl, + wxGRIDTABLE_NOTIFY_ROWS_INSERTED, + curRow, + 0 ); + + tbl->GetView()->ProcessTableMessage( msg ); + } + + m_cur_grid->MakeCellVisible( curRow, curCol ); + m_cur_grid->SetGridCursor( curRow, curCol ); + } + } + + void moveDownHandler( wxMouseEvent& event ) + { + FP_TBL_MODEL* tbl = cur_model(); + + int curRow = getCursorRow(); + if( unsigned( curRow + 1 ) < tbl->rows.size() ) + { + int curCol = getCursorCol(); + + ROW move_me = tbl->rows[curRow]; + + tbl->rows.erase( tbl->rows.begin() + curRow ); + ++curRow; + tbl->rows.insert( tbl->rows.begin() + curRow, move_me ); + + if( tbl->GetView() ) + { + // fire a msg to cause redrawing + wxGridTableMessage msg( tbl, + wxGRIDTABLE_NOTIFY_ROWS_INSERTED, + curRow - 1, + 0 ); + + tbl->GetView()->ProcessTableMessage( msg ); + } + + m_cur_grid->MakeCellVisible( curRow, curCol ); + m_cur_grid->SetGridCursor( curRow, curCol ); + } + } + + void optionsEditor( wxMouseEvent& event ) + { + FP_TBL_MODEL* tbl = cur_model(); + + int curRow = getCursorRow(); + ROW& row = tbl->rows[curRow]; + + wxString result; + const wxString& options = row.GetOptions(); + + InvokePluginOptionsEditor( this, row.GetNickName(), options, &result ); + + if( options != result ) + { + row.SetOptions( result ); + m_cur_grid->AutoSizeColumn( COL_OPTIONS, false ); + } + } + + void onCancelButtonClick( wxCommandEvent& event ) + { + EndModal( 0 ); + } + + void onCancelButtonClick( wxCloseEvent& event ) + { + EndModal( 0 ); + } + + void onOKButtonClick( wxCommandEvent& event ) + { + int dialogRet = 0; + + // stuff any pending cell editor text into the table. + m_cur_grid->SaveEditControlValue(); + + if( verifyTables() ) + { + if( *global_model() != *m_global ) + { + dialogRet |= 1; + + *m_global = *global_model(); + m_global->reindex(); + } + + if( *project_model() != *m_project ) + { + dialogRet |= 2; + + *m_project = *project_model(); + m_project->reindex(); + } + + EndModal( dialogRet ); + } + } + + /// Populate the readonly environment variable table with names and values + /// by examining all the full_uri columns. + void populateEnvironReadOnlyTable() + { + wxRegEx re( wxT( ".*?\\$\\{(.+?)\\}.*?" ), wxRE_ADVANCED ); + wxASSERT( re.IsValid() ); // wxRE_ADVANCED is required. + + std::set< wxString > unique; + typedef std::set::const_iterator SET_CITER; + + // clear the table + m_path_subs_grid->DeleteRows( 0, m_path_subs_grid->GetNumberRows() ); + + FP_TBL_MODEL* gbl = global_model(); + FP_TBL_MODEL* prj = project_model(); + + int gblRowCount = gbl->GetNumberRows(); + int prjRowCount = prj->GetNumberRows(); + int row; + + for( row = 0; row < gblRowCount; ++row ) + { + wxString uri = gbl->GetValue( row, COL_URI ); + + while( re.Matches( uri ) ) + { + wxString envvar = re.GetMatch( uri, 1 ); + + // ignore duplicates + unique.insert( envvar ); + + // delete the last match and search again + uri.Replace( re.GetMatch( uri, 0 ), wxEmptyString ); + } + } + + for( row = 0; row < prjRowCount; ++row ) + { + wxString uri = prj->GetValue( row, COL_URI ); + + while( re.Matches( uri ) ) + { + wxString envvar = re.GetMatch( uri, 1 ); + + // ignore duplicates + unique.insert( envvar ); + + // delete the last match and search again + uri.Replace( re.GetMatch( uri, 0 ), wxEmptyString ); + } + } + + m_path_subs_grid->AppendRows( unique.size() ); + + row = 0; + for( SET_CITER it = unique.begin(); it != unique.end(); ++it, ++row ) + { + wxString evName = *it; + wxString evValue; + + m_path_subs_grid->SetCellValue( row, 0, evName ); + + if( wxGetEnv( evName, &evValue ) ) + m_path_subs_grid->SetCellValue( row, 1, evValue ); + } + + m_path_subs_grid->AutoSizeColumns(); + } + + //-------------------------------------- + + // caller's tables are modified only on OK button and successful verification. + FP_LIB_TABLE* m_global; + FP_LIB_TABLE* m_project; + + FP_TBL_MODEL* global_model() const { return (FP_TBL_MODEL*) m_global_grid->GetTable(); } + FP_TBL_MODEL* project_model() const { return (FP_TBL_MODEL*) m_project_grid->GetTable(); } + FP_TBL_MODEL* cur_model() const { return (FP_TBL_MODEL*) m_cur_grid->GetTable(); } + + wxGrid* m_cur_grid; ///< changed based on tab choice }; diff --git a/pcbnew/dialogs/dialog_fp_plugin_options.cpp b/pcbnew/dialogs/dialog_fp_plugin_options.cpp index c47bbcce40..5a5845c3d2 100644 --- a/pcbnew/dialogs/dialog_fp_plugin_options.cpp +++ b/pcbnew/dialogs/dialog_fp_plugin_options.cpp @@ -24,6 +24,7 @@ */ +#include #include #include #include @@ -36,6 +37,12 @@ static int col_width_option; static int col_width_value; +/** + * Class DIALOG_FP_PLUGIN_OPTIONS + * is an options editor in the form of a two column name/value + * spreadsheet like (table) UI. It takes hints from a pcbnew PLUGIN as to + * supported options. + */ class DIALOG_FP_PLUGIN_OPTIONS : public DIALOG_FP_PLUGIN_OPTIONS_BASE { @@ -60,7 +67,7 @@ public: if( props ) { - if( props->size() > m_grid->GetNumberRows() ) + if( (int) props->size() > m_grid->GetNumberRows() ) m_grid->AppendRows( props->size() - m_grid->GetNumberRows() ); int row = 0; @@ -98,6 +105,42 @@ private: const wxString& m_callers_options; wxString* m_result; + /// If the cursor is not on a valid cell, because there are no rows at all, return -1, + /// else return a 0 based column index. + int getCursorCol() const + { + return m_grid->GetGridCursorCol(); + } + + /// If the cursor is not on a valid cell, because there are no rows at all, return -1, + /// else return a 0 based row index. + int getCursorRow() const + { + return m_grid->GetGridCursorRow(); + } + + wxArrayString getRow( int aRow ) + { + wxArrayString row; + + const int col_count = m_grid->GetNumberCols(); + for( int col = 0; col < col_count; ++col ) + { + row.Add( m_grid->GetCellValue( aRow, col ) ); + } + + return row; + } + + void setRow( int aRow, const wxArrayString& aPair ) + { + const int col_count = m_grid->GetNumberCols(); + for( int col = 0; col < col_count; ++col ) + { + m_grid->SetCellValue( aRow, col, aPair[col] ); + } + } + wxString makeResult() { PROPERTIES props; @@ -133,21 +176,98 @@ private: EndModal( 0 ); } + + //----------------------------------------------------------- void onAddRow( wxCommandEvent& event ) { + if( m_grid->AppendRows( 1 ) ) + { + int last_row = m_grid->GetNumberRows() - 1; + + // wx documentation is wrong, SetGridCursor does not make visible. + m_grid->MakeCellVisible( last_row, 0 ); + m_grid->SetGridCursor( last_row, 0 ); + } } void onDeleteRow( wxCommandEvent& event ) { + int rowCount = m_grid->GetNumberRows(); + int curRow = getCursorRow(); + + m_grid->DeleteRows( curRow ); + + if( curRow && curRow == rowCount - 1 ) + { + m_grid->MakeCellVisible( curRow-1, getCursorCol() ); + m_grid->SetGridCursor( curRow-1, getCursorCol() ); + } } void onMoveUp( wxCommandEvent& event ) { + int curRow = getCursorRow(); + if( curRow >= 1 ) + { + int curCol = getCursorCol(); + + wxArrayString move_me = getRow( curRow ); + + m_grid->DeleteRows( curRow ); + --curRow; + m_grid->InsertRows( curRow ); + + setRow( curRow, move_me ); + + wxGridTableBase* tbl = m_grid->GetTable(); + + if( tbl->GetView() ) + { + // fire a msg to cause redrawing + wxGridTableMessage msg( tbl, + wxGRIDTABLE_NOTIFY_ROWS_INSERTED, + curRow, + 0 ); + + tbl->GetView()->ProcessTableMessage( msg ); + } + + m_grid->MakeCellVisible( curRow, curCol ); + m_grid->SetGridCursor( curRow, curCol ); + } } void onMoveDown( wxCommandEvent& event ) { + int curRow = getCursorRow(); + if( curRow + 1 < m_grid->GetNumberRows() ) + { + int curCol = getCursorCol(); + + wxArrayString move_me = getRow( curRow ); + + m_grid->DeleteRows( curRow ); + ++curRow; + m_grid->InsertRows( curRow ); + setRow( curRow, move_me ); + + wxGridTableBase* tbl = m_grid->GetTable(); + + if( tbl->GetView() ) + { + // fire a msg to cause redrawing + wxGridTableMessage msg( tbl, + wxGRIDTABLE_NOTIFY_ROWS_INSERTED, + curRow - 1, + 0 ); + + tbl->GetView()->ProcessTableMessage( msg ); + } + + m_grid->MakeCellVisible( curRow, curCol ); + m_grid->SetGridCursor( curRow, curCol ); + } } void onCancelButtonClick( wxCommandEvent& event )