|
|
@ -26,18 +26,13 @@ |
|
|
|
|
|
|
|
/* TODO:
|
|
|
|
|
|
|
|
*) Check for duplicate nicknames per table |
|
|
|
|
|
|
|
*) Grab text from any pending ChoiceEditor when OK button pressed. |
|
|
|
|
|
|
|
*) Test wxRE_ADVANCED on Windows. |
|
|
|
|
|
|
|
*) Do environment variable substitution on lookup |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <fctsys.h>
|
|
|
|
#include <dialog_fp_lib_table_base.h>
|
|
|
|
#include <fp_lib_table.h>
|
|
|
@ -224,6 +219,12 @@ public: |
|
|
|
#define ROW_SEP wxT( '\n' )
|
|
|
|
|
|
|
|
|
|
|
|
inline bool isCtl( int aChar, const wxKeyEvent& e ) |
|
|
|
{ |
|
|
|
return e.GetKeyCode() == aChar && e.ControlDown() && !e.AltDown() && !e.ShiftDown() && !e.MetaDown(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Class DIALOG_FP_LIB_TABLE |
|
|
|
* shows and edits the PCB library tables. Two tables are expected, one global |
|
|
@ -235,9 +236,11 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE |
|
|
|
|
|
|
|
enum |
|
|
|
{ |
|
|
|
ID_CUT, // = wxID_HIGHEST + 1,
|
|
|
|
ID_COPY, |
|
|
|
ID_PASTE, |
|
|
|
MYID_CUT, // = wxID_HIGHEST + 1,
|
|
|
|
MYID_COPY, |
|
|
|
MYID_PASTE, |
|
|
|
MYID_SELECT, |
|
|
|
MYID_SENTINEL, |
|
|
|
}; |
|
|
|
|
|
|
|
// row & col "selection" acquisition
|
|
|
@ -295,17 +298,18 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE |
|
|
|
{ |
|
|
|
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" ) ); |
|
|
|
menu.Append( MYID_CUT, _( "Cut\tCTRL+X" ), _( "Clear selected cells pasting original contents to clipboard" ) ); |
|
|
|
menu.Append( MYID_COPY, _( "Copy\tCTRL+C" ), _( "Copy selected cells to clipboard" ) ); |
|
|
|
menu.Append( MYID_PASTE, _( "Paste\tCTRL+V" ), _( "Paste clipboard cells to matrix at current cell" ) ); |
|
|
|
menu.Append( MYID_SELECT, _( "Select All\tCTRL+A" ), _( "Select all cells" ) ); |
|
|
|
|
|
|
|
getSelectedArea(); |
|
|
|
|
|
|
|
// if nothing is selected, disable cut and copy.
|
|
|
|
if( !selRowCount && !selColCount ) |
|
|
|
{ |
|
|
|
menu.Enable( ID_CUT, false ); |
|
|
|
menu.Enable( ID_COPY, false ); |
|
|
|
menu.Enable( MYID_CUT, false ); |
|
|
|
menu.Enable( MYID_COPY, false ); |
|
|
|
} |
|
|
|
|
|
|
|
bool have_cb_text = false; |
|
|
@ -320,137 +324,151 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE |
|
|
|
if( !have_cb_text ) |
|
|
|
{ |
|
|
|
// if nothing on clipboard, disable paste.
|
|
|
|
menu.Enable( ID_PASTE, false ); |
|
|
|
menu.Enable( MYID_PASTE, false ); |
|
|
|
} |
|
|
|
|
|
|
|
// if there is no current cell cursor, disable paste.
|
|
|
|
else if( m_cur_row == -1 || m_cur_col == -1 ) |
|
|
|
menu.Enable( ID_PASTE, false ); |
|
|
|
menu.Enable( MYID_PASTE, false ); |
|
|
|
|
|
|
|
PopupMenu( &menu ); |
|
|
|
|
|
|
|
// passOnFocus();
|
|
|
|
} |
|
|
|
|
|
|
|
// the user clicked on a popup menu choice:
|
|
|
|
void onPopupSelection( wxCommandEvent& event ) |
|
|
|
void cutcopy( bool doCut ) |
|
|
|
{ |
|
|
|
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 ) |
|
|
|
// this format is compatible with most spreadsheets
|
|
|
|
if( wxTheClipboard->Open() ) |
|
|
|
{ |
|
|
|
case ID_CUT: |
|
|
|
case ID_COPY: |
|
|
|
// this format is compatible with most spreadsheets
|
|
|
|
if( wxTheClipboard->Open() ) |
|
|
|
{ |
|
|
|
wxGridTableBase* tbl = m_cur_grid->GetTable(); |
|
|
|
wxString txt; |
|
|
|
wxGridTableBase* tbl = m_cur_grid->GetTable(); |
|
|
|
wxString txt; |
|
|
|
|
|
|
|
for( int row = selRowStart; row < selRowStart + selRowCount; ++row ) |
|
|
|
for( int row = selRowStart; row < selRowStart + selRowCount; ++row ) |
|
|
|
{ |
|
|
|
for( int col = selColStart; col < selColStart + selColCount; ++col ) |
|
|
|
{ |
|
|
|
for( int col = selColStart; col < selColStart + selColCount; ++col ) |
|
|
|
{ |
|
|
|
txt += tbl->GetValue( row, col ); |
|
|
|
txt += tbl->GetValue( row, col ); |
|
|
|
|
|
|
|
if( col < selColStart + selColCount - 1 ) // that was not last column
|
|
|
|
txt += COL_SEP; |
|
|
|
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; |
|
|
|
if( doCut ) |
|
|
|
tbl->SetValue( row, col, wxEmptyString ); |
|
|
|
} |
|
|
|
|
|
|
|
wxTheClipboard->SetData( new wxTextDataObject( txt ) ); |
|
|
|
wxTheClipboard->Close(); |
|
|
|
m_cur_grid->ForceRefresh(); |
|
|
|
txt += ROW_SEP; |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case ID_PASTE: |
|
|
|
D(printf( "paste\n" );) |
|
|
|
// assume format came from a spreadsheet or us.
|
|
|
|
if( wxTheClipboard->Open() ) |
|
|
|
{ |
|
|
|
if( wxTheClipboard->IsSupported( wxDF_TEXT ) ) |
|
|
|
{ |
|
|
|
wxTextDataObject data; |
|
|
|
FP_TBL_MODEL* tbl = (FP_TBL_MODEL*) m_cur_grid->GetTable(); |
|
|
|
wxTheClipboard->SetData( new wxTextDataObject( txt ) ); |
|
|
|
wxTheClipboard->Close(); |
|
|
|
m_cur_grid->ForceRefresh(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
wxTheClipboard->GetData( data ); |
|
|
|
void paste() |
|
|
|
{ |
|
|
|
D(printf( "paste\n" );) |
|
|
|
// assume format came from a spreadsheet or us.
|
|
|
|
if( wxTheClipboard->Open() ) |
|
|
|
{ |
|
|
|
if( wxTheClipboard->IsSupported( wxDF_TEXT ) ) |
|
|
|
{ |
|
|
|
wxTextDataObject data; |
|
|
|
FP_TBL_MODEL* tbl = (FP_TBL_MODEL*) m_cur_grid->GetTable(); |
|
|
|
|
|
|
|
wxString cb_text = data.GetText(); |
|
|
|
size_t ndx = cb_text.find_first_of( wxT( "(fp_lib_table " ) ); |
|
|
|
wxTheClipboard->GetData( data ); |
|
|
|
|
|
|
|
if( ndx != std::string::npos ) |
|
|
|
{ |
|
|
|
// paste the ROWs of s-expression (fp_lib_table), starting
|
|
|
|
// at column 0 regardless of current cursor column.
|
|
|
|
wxString cb_text = data.GetText(); |
|
|
|
size_t ndx = cb_text.find( wxT( "(fp_lib_table " ) ); |
|
|
|
|
|
|
|
STRING_LINE_READER slr( TO_UTF8( cb_text ), wxT( "Clipboard" ) ); |
|
|
|
FP_LIB_TABLE_LEXER lexer( &slr ); |
|
|
|
FP_LIB_TABLE tmp_tbl; |
|
|
|
bool parsed = true; |
|
|
|
if( ndx != std::string::npos ) |
|
|
|
{ |
|
|
|
// paste the ROWs of s-expression (fp_lib_table), starting
|
|
|
|
// at column 0 regardless of current cursor column.
|
|
|
|
|
|
|
|
try |
|
|
|
{ |
|
|
|
tmp_tbl.Parse( &lexer ); |
|
|
|
} |
|
|
|
catch( PARSE_ERROR& pe ) |
|
|
|
{ |
|
|
|
// @todo tell what line and offset
|
|
|
|
parsed = false; |
|
|
|
} |
|
|
|
STRING_LINE_READER slr( TO_UTF8( cb_text ), wxT( "Clipboard" ) ); |
|
|
|
FP_LIB_TABLE_LEXER lexer( &slr ); |
|
|
|
FP_LIB_TABLE tmp_tbl; |
|
|
|
bool parsed = true; |
|
|
|
|
|
|
|
if( parsed ) |
|
|
|
{ |
|
|
|
// if clipboard rows would extend past end of current table size...
|
|
|
|
if( int( tmp_tbl.rows.size() ) > tbl->GetNumberRows() - m_cur_row ) |
|
|
|
{ |
|
|
|
int newRowsNeeded = tmp_tbl.rows.size() - ( tbl->GetNumberRows() - m_cur_row ); |
|
|
|
tbl->AppendRows( newRowsNeeded ); |
|
|
|
} |
|
|
|
|
|
|
|
for( int i = 0; i < (int) tmp_tbl.rows.size(); ++i ) |
|
|
|
{ |
|
|
|
tbl->rows[m_cur_row+i] = tmp_tbl.rows[i]; |
|
|
|
} |
|
|
|
} |
|
|
|
m_cur_grid->AutoSizeColumns(); |
|
|
|
try |
|
|
|
{ |
|
|
|
tmp_tbl.Parse( &lexer ); |
|
|
|
} |
|
|
|
else |
|
|
|
catch( PARSE_ERROR& pe ) |
|
|
|
{ |
|
|
|
wxStringTokenizer rows( cb_text, ROW_SEP, wxTOKEN_RET_EMPTY ); |
|
|
|
// @todo tell what line and offset
|
|
|
|
parsed = false; |
|
|
|
} |
|
|
|
|
|
|
|
if( parsed ) |
|
|
|
{ |
|
|
|
// if clipboard rows would extend past end of current table size...
|
|
|
|
if( int( rows.CountTokens() ) > tbl->GetNumberRows() - m_cur_row ) |
|
|
|
if( int( tmp_tbl.rows.size() ) > tbl->GetNumberRows() - m_cur_row ) |
|
|
|
{ |
|
|
|
int newRowsNeeded = rows.CountTokens() - ( tbl->GetNumberRows() - m_cur_row ); |
|
|
|
int newRowsNeeded = tmp_tbl.rows.size() - ( tbl->GetNumberRows() - m_cur_row ); |
|
|
|
tbl->AppendRows( newRowsNeeded ); |
|
|
|
} |
|
|
|
|
|
|
|
for( int row = m_cur_row; rows.HasMoreTokens(); ++row ) |
|
|
|
for( int i = 0; i < (int) tmp_tbl.rows.size(); ++i ) |
|
|
|
{ |
|
|
|
wxString rowTxt = rows.GetNextToken(); |
|
|
|
tbl->rows[m_cur_row+i] = tmp_tbl.rows[i]; |
|
|
|
} |
|
|
|
} |
|
|
|
m_cur_grid->AutoSizeColumns(); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
wxStringTokenizer rows( cb_text, ROW_SEP, wxTOKEN_RET_EMPTY ); |
|
|
|
|
|
|
|
wxStringTokenizer cols( rowTxt, COL_SEP, wxTOKEN_RET_EMPTY ); |
|
|
|
// if clipboard rows would extend past end of current table size...
|
|
|
|
if( int( rows.CountTokens() ) > tbl->GetNumberRows() - m_cur_row ) |
|
|
|
{ |
|
|
|
int newRowsNeeded = rows.CountTokens() - ( tbl->GetNumberRows() - m_cur_row ); |
|
|
|
tbl->AppendRows( newRowsNeeded ); |
|
|
|
} |
|
|
|
|
|
|
|
for( int col = m_cur_col; cols.HasMoreTokens(); ++col ) |
|
|
|
{ |
|
|
|
wxString cellTxt = cols.GetNextToken(); |
|
|
|
tbl->SetValue( row, col, cellTxt ); |
|
|
|
} |
|
|
|
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(); |
|
|
|
} |
|
|
|
|
|
|
|
wxTheClipboard->Close(); |
|
|
|
m_cur_grid->ForceRefresh(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 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 MYID_CUT: |
|
|
|
case MYID_COPY: |
|
|
|
cutcopy( menuId == MYID_CUT ); |
|
|
|
break; |
|
|
|
|
|
|
|
case MYID_PASTE: |
|
|
|
paste(); |
|
|
|
break; |
|
|
|
|
|
|
|
case MYID_SELECT: |
|
|
|
m_cur_grid->SelectAll(); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
@ -552,6 +570,31 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE |
|
|
|
|
|
|
|
//-----<event handlers>----------------------------------
|
|
|
|
|
|
|
|
void onKeyDown( wxKeyEvent& ev ) |
|
|
|
{ |
|
|
|
if( isCtl( 'A', ev ) ) |
|
|
|
{ |
|
|
|
m_cur_grid->SelectAll(); |
|
|
|
} |
|
|
|
else if( isCtl( 'C', ev ) ) |
|
|
|
{ |
|
|
|
getSelectedArea(); |
|
|
|
cutcopy( false ); |
|
|
|
} |
|
|
|
else if( isCtl( 'V', ev ) ) |
|
|
|
{ |
|
|
|
getSelectedArea(); |
|
|
|
paste(); |
|
|
|
} |
|
|
|
else if( isCtl( 'X', ev ) ) |
|
|
|
{ |
|
|
|
getSelectedArea(); |
|
|
|
cutcopy( true ); |
|
|
|
} |
|
|
|
else |
|
|
|
ev.Skip(); |
|
|
|
} |
|
|
|
|
|
|
|
void pageChangedHandler( wxAuiNotebookEvent& event ) |
|
|
|
{ |
|
|
|
int pageNdx = m_auinotebook->GetSelection(); |
|
|
@ -822,7 +865,7 @@ public: |
|
|
|
m_global_grid->AutoSizeColumns(); |
|
|
|
m_project_grid->AutoSizeColumns(); |
|
|
|
|
|
|
|
Connect( ID_CUT, ID_PASTE, wxEVT_COMMAND_MENU_SELECTED, |
|
|
|
Connect( MYID_CUT, MYID_SENTINEL-1, wxEVT_COMMAND_MENU_SELECTED, |
|
|
|
wxCommandEventHandler( DIALOG_FP_LIB_TABLE::onPopupSelection ), NULL, this ); |
|
|
|
|
|
|
|
populateEnvironReadOnlyTable(); |
|
|
@ -834,11 +877,14 @@ public: |
|
|
|
// fire pageChangedHandler() so m_cur_grid gets set
|
|
|
|
wxAuiNotebookEvent uneventful; |
|
|
|
pageChangedHandler( uneventful ); |
|
|
|
|
|
|
|
// for ALT+A handling, we want the initial focus to be on the first selected grid.
|
|
|
|
m_cur_grid->SetFocus(); |
|
|
|
} |
|
|
|
|
|
|
|
~DIALOG_FP_LIB_TABLE() |
|
|
|
{ |
|
|
|
Disconnect( ID_CUT, ID_PASTE, wxEVT_COMMAND_MENU_SELECTED, |
|
|
|
Disconnect( MYID_CUT, MYID_SENTINEL-1, wxEVT_COMMAND_MENU_SELECTED, |
|
|
|
wxCommandEventHandler( DIALOG_FP_LIB_TABLE::onPopupSelection ), NULL, this ); |
|
|
|
|
|
|
|
// ~wxGrid() examines its table, and the tables will have been destroyed before
|
|
|
|