From 1dddc22a9b1096fe9104f79edecefaae34ac3036 Mon Sep 17 00:00:00 2001 From: Dick Hollenbeck Date: Sun, 9 Dec 2012 14:51:42 -0600 Subject: [PATCH] embellish fp_lib_table editor with beginnings of cut, copy, paste --- common/fp_lib_table.cpp | 14 +- pcbnew/dialogs/dialog_fp_lib_table.cpp | 224 +++++++++++++++++--- pcbnew/dialogs/dialog_fp_lib_table_base.cpp | 20 +- pcbnew/dialogs/dialog_fp_lib_table_base.fbp | 20 +- pcbnew/dialogs/dialog_fp_lib_table_base.h | 4 + 5 files changed, 237 insertions(+), 45 deletions(-) diff --git a/common/fp_lib_table.cpp b/common/fp_lib_table.cpp index 1129146a33..e35cda8809 100644 --- a/common/fp_lib_table.cpp +++ b/common/fp_lib_table.cpp @@ -59,7 +59,7 @@ void FP_LIB_TABLE::Parse( FP_LIB_TABLE_LEXER* in ) throw( IO_ERROR, PARSE_ERROR T tok; // This table may be nested within a larger s-expression, or not. - // Allow for parser of that optional outter s-epression to have looked ahead. + // Allow for parser of that optional containing s-epression to have looked ahead. if( in->CurTok() != T_fp_lib_table ) { in->NeedLEFT(); @@ -84,7 +84,7 @@ void FP_LIB_TABLE::Parse( FP_LIB_TABLE_LEXER* in ) throw( IO_ERROR, PARSE_ERROR if( ( tok = in->NextTok() ) != T_lib ) in->Expecting( T_lib ); - // (name LOGICAL_NAME) + // (name NICKNAME) in->NeedLEFT(); if( ( tok = in->NextTok() ) != T_name ) @@ -97,7 +97,7 @@ void FP_LIB_TABLE::Parse( FP_LIB_TABLE_LEXER* in ) throw( IO_ERROR, PARSE_ERROR in->NeedRIGHT(); // After (name), remaining (lib) elements are order independent, and in - // the future, perhaps optional. Flexibility for future changes. + // some cases optional. bool sawType = false; bool sawOpts = false; @@ -191,12 +191,12 @@ void FP_LIB_TABLE::Format( OUTPUTFORMATTER* out, int nestLevel ) const void FP_LIB_TABLE::ROW::Format( OUTPUTFORMATTER* out, int nestLevel ) const throw( IO_ERROR ) { - out->Print( nestLevel, "(lib (name %s)(descr %s)(uri %s)(type %s)(options %s))\n", + out->Print( nestLevel, "(lib (name %s)(type %s)(uri %s)(options %s)(descr %s))\n", out->Quotew( GetNickName() ).c_str(), - out->Quotew( GetDescr() ).c_str(), - out->Quotew( GetFullURI() ).c_str(), out->Quotew( GetType() ).c_str(), - out->Quotew( GetOptions() ).c_str() + out->Quotew( GetFullURI() ).c_str(), + out->Quotew( GetOptions() ).c_str(), + out->Quotew( GetDescr() ).c_str() ); } diff --git a/pcbnew/dialogs/dialog_fp_lib_table.cpp b/pcbnew/dialogs/dialog_fp_lib_table.cpp index b8fadde2c3..1e669d4ba7 100644 --- a/pcbnew/dialogs/dialog_fp_lib_table.cpp +++ b/pcbnew/dialogs/dialog_fp_lib_table.cpp @@ -28,7 +28,8 @@ #include #include #include - +#include +#include /** * Class FP_TBL_MODEL @@ -39,6 +40,16 @@ class FP_TBL_MODEL : public wxGridTableBase, public FP_LIB_TABLE { public: + enum COL_ORDER // grid column order, established here by this sequence + { + COL_NICKNAME, + COL_URI, + COL_TYPE, + COL_OPTIONS, + COL_DESCR, + COL_COUNT // keep as last + }; + /** * Constructor FP_TBL_MODEL * is a copy constructor that builds a wxGridTableBase (table model) by wrapping @@ -52,7 +63,7 @@ public: //------------------------------------------------ int GetNumberRows () { return rows.size(); } - int GetNumberCols () { return 4; } + int GetNumberCols () { return COL_COUNT; } wxString GetValue( int aRow, int aCol ) { @@ -62,10 +73,11 @@ public: switch( aCol ) { - case 0: return r.GetNickName(); - case 1: return r.GetFullURI(); - case 2: return r.GetType(); - case 3: return r.GetOptions(); + case COL_NICKNAME: return r.GetNickName(); + case COL_URI: return r.GetFullURI(); + case COL_TYPE: return r.GetType(); + case COL_OPTIONS: return r.GetOptions(); + case COL_DESCR: return r.GetDescr(); default: ; // fall thru to wxEmptyString } @@ -82,10 +94,11 @@ public: switch( aCol ) { - case 0: r.SetNickName( aValue ); break; - case 1: r.SetFullURI( aValue ); break; - case 2: r.SetType( aValue ); break; - case 3: r.SetOptions( aValue ); break; + case COL_NICKNAME: r.SetNickName( aValue ); break; + case COL_URI: r.SetFullURI( aValue ); break; + case COL_TYPE: r.SetType( aValue ); break; + case COL_OPTIONS: r.SetOptions( aValue ); break; + case COL_DESCR: r.SetDescr( aValue ); break; } } } @@ -169,19 +182,24 @@ public: { switch( aCol ) { - case 0: return _( "Nickname" ); - case 1: return _( "Library Path" ); - case 2: return _( "Plugin" ); - case 3: return _( "Options" ); - default: return wxEmptyString; + case COL_NICKNAME: return _( "Nickname" ); + case COL_URI: return _( "Library Path" ); + case COL_TYPE: return _( "Plugin" ); + case COL_OPTIONS: return _( "Options" ); + case COL_DESCR: return _( "Description" ); + default: return wxEmptyString; } } //----------------------------------------------- - }; +// It works for table data on clipboard for an excell spreadsheet, +// why not us too for now. +#define COL_SEP wxT( '\t' ) +#define ROW_SEP wxT( '\n' ) + /** * Class DIALOG_FP_LIB_TABLE @@ -192,19 +210,31 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE { typedef FP_LIB_TABLE::ROW ROW; - /* row & col "selection" acquisition, not currently used but works. + enum + { + ID_CUT, // = wxID_HIGHEST + 1, + ID_COPY, + ID_PASTE, + }; + + // row & col "selection" acquisition // selected area by cell coordinate and count int selRowStart; int selColStart; int selRowCount; int selColCount; - /// Gets the selected area into a sensible rectable of sel{Row,Col}{Start,Count} above. + /// Gets the selected area into a sensible rectangle of sel{Row,Col}{Start,Count} above. void getSelectedArea() { wxGridCellCoordsArray topLeft = m_cur_grid->GetSelectionBlockTopLeft(); wxGridCellCoordsArray botRight = m_cur_grid->GetSelectionBlockBottomRight(); + wxArrayInt cols = m_cur_grid->GetSelectedCols(); + wxArrayInt rows = m_cur_grid->GetSelectedRows(); + + D(printf("topLeft.Count():%zd botRight:Count():%zd\n", topLeft.Count(), botRight.Count() );) + if( topLeft.Count() && botRight.Count() ) { selRowStart = topLeft[0].GetRow(); @@ -213,6 +243,20 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE selRowCount = botRight[0].GetRow() - selRowStart + 1; selColCount = botRight[0].GetCol() - selColStart + 1; } + else if( cols.Count() ) + { + selColStart = cols[0]; + selColCount = cols.Count(); + selRowStart = 0; + selRowCount = m_cur_grid->GetNumberRows(); + } + else if( rows.Count() ) + { + selColStart = 0; + selColCount = m_cur_grid->GetNumberCols(); + selRowStart = rows[0]; + selRowCount = rows.Count(); + } else { selRowStart = -1; @@ -221,19 +265,113 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE selColCount = 0; } - D(printf("selRowStart:%d selColStart:%d selRowCount:%d selColCount:%d\n", - selRowStart, selColStart, selRowCount, selColCount );) + // D(printf("selRowStart:%d selColStart:%d selRowCount:%d selColCount:%d\n", selRowStart, selColStart, selRowCount, selColCount );) + } + + void rightClickCellPopupMenu() + { + wxMenu menu; + + menu.Append( ID_CUT, _( "Cut" ), _( "Clear selected cells" ) ); + menu.Append( ID_COPY, _( "Copy" ), _( "Copy selected cells to clipboard" ) ); + menu.Append( ID_PASTE, _( "Paste" ), _( "Paste clipboard cells to matrix at current cell" ) ); + + getSelectedArea(); + + // if nothing is selected, diable cut and copy. + if( !selRowCount && !selColCount ) + { + menu.Enable( ID_CUT, false ); + menu.Enable( ID_COPY, false ); + } + + // if there is no current cell cursor, disable paste. + if( m_cur_row == -1 || m_cur_col == -1 ) + menu.Enable( ID_PASTE, false ); + + PopupMenu( &menu ); + + // passOnFocus(); + } + + // the user clicked on a popup menu choice: + void onPopupSelection( wxCommandEvent& event ) + { + int menuId = event.GetId(); + + // assume getSelectedArea() was called by rightClickPopupMenu() and there's + // no way to have gotten here without that having been called. + + switch( menuId ) + { + case ID_CUT: + case ID_COPY: + if( wxTheClipboard->Open() ) + { + wxGridTableBase* tbl = m_cur_grid->GetTable(); + wxString txt; + + for( int row = selRowStart; row < selRowStart + selRowCount; ++row ) + { + for( int col = selColStart; col < selColStart + selColCount; ++col ) + { + txt += tbl->GetValue( row, col ); + + if( col < selColStart + selColCount - 1 ) // that was not last column + txt += COL_SEP; + + if( menuId == ID_CUT ) + tbl->SetValue( row, col, wxEmptyString ); + } + txt += ROW_SEP; + } + + wxTheClipboard->SetData( new wxTextDataObject( txt ) ); + wxTheClipboard->Close(); + m_cur_grid->ForceRefresh(); + } + break; + + case ID_PASTE: + D(printf( "paste\n" );) + if( wxTheClipboard->Open() ) + { + if( wxTheClipboard->IsSupported( wxDF_TEXT ) ) + { + wxGridTableBase* tbl = m_cur_grid->GetTable(); + wxTextDataObject data; + + wxTheClipboard->GetData( data ); + + wxStringTokenizer rows( data.GetText(), ROW_SEP, wxTOKEN_RET_EMPTY ); + + for( int row = m_cur_row; rows.HasMoreTokens(); ++row ) + { + wxString rowTxt = rows.GetNextToken(); + + wxStringTokenizer cols( rowTxt, COL_SEP, wxTOKEN_RET_EMPTY ); + + for( int col = m_cur_col; cols.HasMoreTokens(); ++col ) + { + wxString cellTxt = cols.GetNextToken(); + tbl->SetValue( row, col, cellTxt ); + } + } + } + + wxTheClipboard->Close(); + m_cur_grid->ForceRefresh(); + } + break; + } } - */ //--------------------------------------- void pageChangedHandler( wxAuiNotebookEvent& event ) { int pageNdx = m_auinotebook->GetSelection(); - m_cur_grid = pageNdx==0 ? m_global_grid : m_project_grid; - - D(printf("%s cur_grid is %s\n", __func__, pageNdx==0 ? "global" : "project" );) + m_cur_grid = ( pageNdx == 0 ) ? m_global_grid : m_project_grid; } void appendRowHandler( wxMouseEvent& event ) @@ -336,8 +474,33 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE EndModal( dialogRet ); } - //-------------------------------------- + void onGridCellLeftClick( wxGridEvent& event ) + { + event.Skip(); + } + void onGridCellLeftDClick( wxGridEvent& event ) + { + event.Skip(); + } + + void onGridCellRightClick( wxGridEvent& event ) + { + rightClickCellPopupMenu(); + } + + void onGridCmdSelectCell( wxGridEvent& event ) + { + m_cur_row = event.GetRow(); + m_cur_col = event.GetCol(); + + D(printf("change cursor(%d,%d)\n", m_cur_row, m_cur_col );) + + // somebody else wants this + event.Skip(); + } + + //-------------------------------------- // caller's tables are modified only on OK button. FP_LIB_TABLE* m_global; @@ -349,6 +512,10 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE wxGrid* m_cur_grid; ///< changed based on tab choice + // wxGrid makes it difficult to know if the cursor is yet visible, + // use this to solve that, initial values are -1 + int m_cur_row; ///< cursor position + int m_cur_col; public: DIALOG_FP_LIB_TABLE( wxFrame* aParent, FP_LIB_TABLE* aGlobal, FP_LIB_TABLE* aProject ) : @@ -356,7 +523,9 @@ public: m_global( aGlobal ), m_project( aProject ), m_global_model( *aGlobal ), - m_project_model( *aProject ) + m_project_model( *aProject ), + m_cur_row( -1 ), + m_cur_col( -1 ) { m_global_grid->SetTable( (wxGridTableBase*) &m_global_model ); m_project_grid->SetTable( (wxGridTableBase*) &m_project_model ); @@ -367,6 +536,9 @@ public: m_path_subs_grid->AutoSizeColumns( false ); + Connect( ID_CUT, ID_PASTE, wxEVT_COMMAND_MENU_SELECTED, + wxCommandEventHandler( DIALOG_FP_LIB_TABLE::onPopupSelection ), NULL, this ); + // fire pageChangedHandler() so m_cur_grid gets set wxAuiNotebookEvent uneventful; pageChangedHandler( uneventful ); diff --git a/pcbnew/dialogs/dialog_fp_lib_table_base.cpp b/pcbnew/dialogs/dialog_fp_lib_table_base.cpp index 6844652cf5..5e525ecd3f 100644 --- a/pcbnew/dialogs/dialog_fp_lib_table_base.cpp +++ b/pcbnew/dialogs/dialog_fp_lib_table_base.cpp @@ -34,7 +34,7 @@ DIALOG_FP_LIB_TABLE_BASE::DIALOG_FP_LIB_TABLE_BASE( wxWindow* parent, wxWindowID m_global_grid = new wxGrid( m_global_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); // Grid - m_global_grid->CreateGrid( 1, 4 ); + m_global_grid->CreateGrid( 1, 5 ); m_global_grid->EnableEditing( true ); m_global_grid->EnableGridLines( true ); m_global_grid->EnableDragGridSize( true ); @@ -70,7 +70,7 @@ DIALOG_FP_LIB_TABLE_BASE::DIALOG_FP_LIB_TABLE_BASE( wxWindow* parent, wxWindowID m_project_grid = new wxGrid( m_project_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); // Grid - m_project_grid->CreateGrid( 1, 4 ); + m_project_grid->CreateGrid( 1, 5 ); m_project_grid->EnableEditing( true ); m_project_grid->EnableGridLines( true ); m_project_grid->EnableDragGridSize( true ); @@ -199,6 +199,14 @@ DIALOG_FP_LIB_TABLE_BASE::DIALOG_FP_LIB_TABLE_BASE( wxWindow* parent, wxWindowID // Connect Events m_auinotebook->Connect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, wxAuiNotebookEventHandler( DIALOG_FP_LIB_TABLE_BASE::pageChangedHandler ), NULL, this ); + m_global_grid->Connect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellLeftClick ), NULL, this ); + m_global_grid->Connect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellLeftDClick ), NULL, this ); + m_global_grid->Connect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellRightClick ), NULL, this ); + m_global_grid->Connect( wxEVT_GRID_SELECT_CELL, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCmdSelectCell ), NULL, this ); + m_project_grid->Connect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellLeftClick ), NULL, this ); + m_project_grid->Connect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellLeftDClick ), NULL, this ); + m_project_grid->Connect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellRightClick ), NULL, this ); + m_project_grid->Connect( wxEVT_GRID_SELECT_CELL, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCmdSelectCell ), NULL, this ); m_append_button->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( DIALOG_FP_LIB_TABLE_BASE::appendRowHandler ), NULL, this ); m_delete_button->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( DIALOG_FP_LIB_TABLE_BASE::deleteRowHandler ), NULL, this ); m_move_up_button->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( DIALOG_FP_LIB_TABLE_BASE::moveUpHandler ), NULL, this ); @@ -211,6 +219,14 @@ DIALOG_FP_LIB_TABLE_BASE::~DIALOG_FP_LIB_TABLE_BASE() { // Disconnect Events m_auinotebook->Disconnect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, wxAuiNotebookEventHandler( DIALOG_FP_LIB_TABLE_BASE::pageChangedHandler ), NULL, this ); + m_global_grid->Disconnect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellLeftClick ), NULL, this ); + m_global_grid->Disconnect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellLeftDClick ), NULL, this ); + m_global_grid->Disconnect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellRightClick ), NULL, this ); + m_global_grid->Disconnect( wxEVT_GRID_SELECT_CELL, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCmdSelectCell ), NULL, this ); + m_project_grid->Disconnect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellLeftClick ), NULL, this ); + m_project_grid->Disconnect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellLeftDClick ), NULL, this ); + m_project_grid->Disconnect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellRightClick ), NULL, this ); + m_project_grid->Disconnect( wxEVT_GRID_SELECT_CELL, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCmdSelectCell ), NULL, this ); m_append_button->Disconnect( wxEVT_LEFT_DOWN, wxMouseEventHandler( DIALOG_FP_LIB_TABLE_BASE::appendRowHandler ), NULL, this ); m_delete_button->Disconnect( wxEVT_LEFT_DOWN, wxMouseEventHandler( DIALOG_FP_LIB_TABLE_BASE::deleteRowHandler ), NULL, this ); m_move_up_button->Disconnect( wxEVT_LEFT_DOWN, wxMouseEventHandler( DIALOG_FP_LIB_TABLE_BASE::moveUpHandler ), NULL, this ); diff --git a/pcbnew/dialogs/dialog_fp_lib_table_base.fbp b/pcbnew/dialogs/dialog_fp_lib_table_base.fbp index be77cf4205..79bdad58e7 100644 --- a/pcbnew/dialogs/dialog_fp_lib_table_base.fbp +++ b/pcbnew/dialogs/dialog_fp_lib_table_base.fbp @@ -464,7 +464,7 @@ 30 wxALIGN_CENTRE - 4 + 5 1 @@ -524,9 +524,9 @@ - - - + onGridCellLeftClick + onGridCellLeftDClick + onGridCellRightClick @@ -543,7 +543,7 @@ - + onGridCmdSelectCell @@ -693,7 +693,7 @@ 30 wxALIGN_CENTRE - 4 + 5 1 @@ -753,9 +753,9 @@ - - - + onGridCellLeftClick + onGridCellLeftDClick + onGridCellRightClick @@ -772,7 +772,7 @@ - + onGridCmdSelectCell diff --git a/pcbnew/dialogs/dialog_fp_lib_table_base.h b/pcbnew/dialogs/dialog_fp_lib_table_base.h index 3156b1cdf5..44ef78ef8a 100644 --- a/pcbnew/dialogs/dialog_fp_lib_table_base.h +++ b/pcbnew/dialogs/dialog_fp_lib_table_base.h @@ -61,6 +61,10 @@ class DIALOG_FP_LIB_TABLE_BASE : public DIALOG_SHIM // Virtual event handlers, overide them in your derived class virtual void pageChangedHandler( wxAuiNotebookEvent& event ) { event.Skip(); } + virtual void onGridCellLeftClick( wxGridEvent& event ) { event.Skip(); } + virtual void onGridCellLeftDClick( wxGridEvent& event ) { event.Skip(); } + virtual void onGridCellRightClick( wxGridEvent& event ) { event.Skip(); } + virtual void onGridCmdSelectCell( wxGridEvent& event ) { event.Skip(); } virtual void appendRowHandler( wxMouseEvent& event ) { event.Skip(); } virtual void deleteRowHandler( wxMouseEvent& event ) { event.Skip(); } virtual void moveUpHandler( wxMouseEvent& event ) { event.Skip(); }